diff options
84 files changed, 5936 insertions, 28066 deletions
@@ -1,6 +1,6 @@ Metadata-Version: 1.0 Name: PyMca -Version: 4.7.0 +Version: 4.7.1 Summary: Mapping and X-Ray Fluorescence Analysis Home-page: http://pymca.sourceforge.net Author: V. Armando Sole diff --git a/PyMca/ClassMcaTheory.py b/PyMca/ClassMcaTheory.py index 619f9c3..58211e3 100644 --- a/PyMca/ClassMcaTheory.py +++ b/PyMca/ClassMcaTheory.py @@ -1,5 +1,5 @@ #/*########################################################################## -# Copyright (C) 2004-2012 European Synchrotron Radiation Facility +# Copyright (C) 2004-2013 European Synchrotron Radiation Facility # # This file is part of the PyMca X-ray Fluorescence Toolkit developed at # the ESRF by the Software group. @@ -39,8 +39,8 @@ DEBUG = 0 CONTINUUM_LIST = [None,'Constant','Linear','Parabolic','Linear Polynomial','Exp. Polynomial'] OLDESCAPE = 0 MAX_ATTENUATION = 1.0E-300 -class McaTheory: - def __init__(self,initdict=None,filelist=None,**kw): +class McaTheory(object): + def __init__(self, initdict=None, filelist=None, **kw): self.ydata0 = None self.xdata0 = None self.sigmay0 = None @@ -117,8 +117,10 @@ class McaTheory: return self.configure() def configure(self,newdict=None): - if newdict is None:return copy.deepcopy(self.config) - if newdict == {} :return copy.deepcopy(self.config) + if newdict is None: + return copy.deepcopy(self.config) + if newdict == {}: + return copy.deepcopy(self.config) self.config.update(newdict) self.__configure() return copy.deepcopy(self.config) @@ -959,14 +961,20 @@ class McaTheory: if not self.config['fit']['use_limit']: if 'xmin' in kw: xmin=kw['xmin'] - self.config['fit']['xmin'] = xmin + if xmin is not None: + self.config['fit']['xmin'] = xmin + else: + xmin=min(self.xdata) elif len(self.xdata): xmin=min(self.xdata) xmax = self.config['fit']['xmax'] if not self.config['fit']['use_limit']: if 'xmax' in kw: xmax=kw['xmax'] - self.config['fit']['xmax'] = xmax + if xmax is not None: + self.config['fit']['xmax'] = xmax + else: + xmax=max(self.xdata) elif len(self.xdata): xmax=max(self.xdata) @@ -1250,8 +1258,7 @@ class McaTheory: matrix[:,i] = result[:,0] return matrix - def linearMcaTheory(self,param0,t0,hypermet=None, - continuum=None,summing=None): + def linearMcaTheory(self, param0, t0, hypermet=None, continuum=None, summing=None): if continuum is None: continuum = self.__CONTINUUM if hypermet is None: @@ -1463,7 +1470,7 @@ class McaTheory: def linearMcaTheoryDerivative(self,param0,index,t0): NGLOBAL = self.NGLOBAL if index > NGLOBAL-1: - return self.linearMatrix[:,index-NGLOBAL] + return self.linearMatrix[:, index-NGLOBAL] PARAMETERS = self.PARAMETERS if self.__CONTINUUM and (PARAMETERS[index] == 'Constant'): return numpy.ones(len(t0)).astype(numpy.float) @@ -1659,7 +1666,7 @@ class McaTheory: return (f1-f2) / (2.0 * delta) def estimate(self): - self.parameters,self.codes = self.specfitestimate(self.xdata, self.ydata,self.zz) + self.parameters, self.codes = self.specfitestimate(self.xdata, self.ydata,self.zz) #self.estimatelinpoly(self.xdata, self.ydata,self.zz) #self.estimateexppoly(self.xdata, self.ydata,self.zz) #print self.codes[:,3] @@ -1984,7 +1991,7 @@ class McaTheory: #print "Elapsed = ",time.time() - e0 if self._batchFlag and self.linearMatrix is None: self.linearMatrix = self.getPeakMatrixContribution(newpar) - return newpar,codes + return newpar, codes def startfit(self,digest=0, linear=None): if linear is None: diff --git a/PyMca/FastXRFLinearFit.py b/PyMca/FastXRFLinearFit.py new file mode 100644 index 0000000..47c7e0c --- /dev/null +++ b/PyMca/FastXRFLinearFit.py @@ -0,0 +1,469 @@ +#/*########################################################################## +# Copyright (C) 2013 European Synchrotron Radiation Facility +# +# This file is part of the PyMca X-ray Fluorescence Toolkit developed at +# the ESRF by the Software group. +# +# This file is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by the +# Free Software Foundation; either version 2 of the License, or (at your option) +# any later version. +# +# This file is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +# details. +# +#############################################################################*/ +__author__ = "V.A. Sole - ESRF Data Analysis" +__license__ = "LGPL" +import numpy +from PyMca.linalg import lstsq +from PyMca import ClassMcaTheory +from PyMca import Gefit +from PyMca import ConcentrationsTool +from PyMca import SpecfitFuns +from PyMca import ConfigDict + +DEBUG = 0 + +class FastXRFLinearFit(object): + def __init__(self, mcafit=None): + self._config = None + if mcafit is None: + self._mcaTheory = ClassMcaTheory.McaTheory() + else: + self._mcaTheory = mcafit + + def setFitConfiguration(self, configuration): + self._mcaTheory.setConfiguration(configuration) + + def setFitConfigurationFile(self, ffile): + configuration = ConfigDict.ConfigDict() + configuration.read(ffile) + self.setFitConfiguration(configuration) + + def fitMultipleSpectra(self, x=None, y=None, xmin=None, xmax=None, + configuration=None, concentrations=False, + ysum=None): + if y is None: + raise RuntimeError("y keyword argument is mandatory!") + + #if concentrations: + # txt = "Fast concentration calculation not implemented yet" + # raise NotImplemented(txt) + + if configuration is not None: + self._mcaTheory.setConfiguration(configuration) + + # read the current configuration + config = self._mcaTheory.getConfiguration() + + #make sure we force a linear fit + config['fit']['linearfitflag'] = 1 + weight = config['fit']['fitweight'] + + # background + if config['fit']['stripflag']: + if config['fit']['stripalgorithm'] == 1: + if DEBUG: + print("SNIP") + else: + raise RuntimeError("Please use the faster SNIP background") + + # and now configure the fit + self._mcaTheory.setConfiguration(config) + + if hasattr(y, "info") and hasattr(y, "data"): + data = y.data + mcaIndex = y.info.get("McaIndex", -1) + else: + data = y + mcaIndex = -1 + + if len(data.shape) != 3: + txt = "For the time being only three dimensional arrays supported" + raise IndexError(txt) + elif mcaIndex not in [-1, 2]: + txt = "For the time being only mca arrays supported" + raise IndexError(txt) + else: + # if the cumulated spectrum is present it should be better + nRows = data.shape[0] + nColumns = data.shape[1] + nPixels = nRows * nColumns + if ysum is not None: + firstSpectrum = ysum + elif not concentrations: + # just one spectrum is enough for the setup + firstSpectrum = data[0, 0, :] + else: + firstSpectrum = data[0, :, :].sum(axis=0, dtype=numpy.float) + + # make sure we calculate the matrix of the contributions + self._mcaTheory.enableOptimizedLinearFit() + + # initialize the fit + # print("xmin = ", xmin) + # print("xmax = ", xmax) + # print("firstShape = ", firstSpectrum.shape) + self._mcaTheory.setData(x=x, y=firstSpectrum, xmin=xmin, xmax=xmax) + + #loop for anchors + if config['fit']['stripflag']: + anchorslist = [] + if config['fit']['stripanchorsflag']: + if config['fit']['stripanchorslist'] is not None: + ravelled = numpy.ravel(self._mcaTheory.xdata) + for channel in config['fit']['stripanchorslist']: + if channel <= ravelled[0]: + continue + index = numpy.nonzero(ravelled >= channel)[0] + if len(index): + index = min(index) + if index > 0: + anchorslist.append(index) + if len(anchorslist) == 0: + anchorlist = [0, self._mcaTheory.ydata.size - 1] + anchorslist.sort() + + # and initialize the derivatives + self._mcaTheory.estimate() + + # now we can get the derivatives respect to the free parameters + # These are the "derivatives" respect to the peaks + # linearMatrix = self._mcaTheory.linearMatrix + + # but we are still missing the derivatives from the background + nFree = 0 + freeNames = [] + nFreeBackgroundParameters = 0 + for i, param in enumerate(self._mcaTheory.PARAMETERS): + if self._mcaTheory.codes[0][i] != ClassMcaTheory.Gefit.CFIXED: + nFree += 1 + freeNames.append(param) + if i < self._mcaTheory.NGLOBAL: + nFreeBackgroundParameters += 1 + + #build the matrix of derivatives + derivatives = None + idx = 0 + for i, param in enumerate(self._mcaTheory.PARAMETERS): + if self._mcaTheory.codes[0][i] == ClassMcaTheory.Gefit.CFIXED: + continue + deriv= self._mcaTheory.linearMcaTheoryDerivative(self._mcaTheory.parameters[i], + i, + self._mcaTheory.xdata) + if derivatives is None: + derivatives = numpy.zeros((deriv.shape[0], nFree), numpy.float) + derivatives[:, idx] = deriv + idx += 1 + + + #loop for anchors + xdata = self._mcaTheory.xdata + + if config['fit']['stripflag']: + anchorslist = [] + if config['fit']['stripanchorsflag']: + if config['fit']['stripanchorslist'] is not None: + ravelled = numpy.ravel(xdata) + for channel in config['fit']['stripanchorslist']: + if channel <= ravelled[0]:continue + index = numpy.nonzero(ravelled >= channel)[0] + if len(index): + index = min(index) + if index > 0: + anchorslist.append(index) + if len(anchorslist) == 0: + anchorlist = [0, self._mcaTheory.ydata.size - 1] + anchorslist.sort() + + # find the indices to be used for selecting the appropriate data + # if the original x data were nor ordered we have a problem + # TODO: check for original ordering. + if x is None: + # we have an enumerated channels axis + iXMin = xdata[0] + iXMax = xdata[-1] + else: + iXMin = numpy.nonzero(x <= xdata[0])[0][0] + iXMax = numpy.nonzero(x >= xdata[-1])[0][0] + + dummySpectrum = firstSpectrum[iXMin:iXMax+1].reshape(-1, 1) + # print("dummy = ", dummySpectrum.shape) + + # allocate the output buffer + results = numpy.zeros((nFree, nRows, nColumns), numpy.float32) + uncertainties = numpy.zeros((nFree, nRows, nColumns), numpy.float32) + + #perform the inital fit + for i in range(data.shape[0]): + #chunks of nColumns spectra + if i == 0: + chunk = numpy.zeros((dummySpectrum.shape[0], data.shape[1]), + numpy.float) + + chunk[:,:] = data[i, :, iXMin:iXMax+1].T + if config['fit']['stripflag']: + for k in range(chunk.shape[0]): + # obtain the smoothed spectrum + background=SpecfitFuns.SavitskyGolay(chunk[k], + config['fit']['stripfilterwidth']) + lastAnchor = 0 + for anchor in anchorslist: + if (anchor > lastAnchor) and (anchor < background.size): + background[lastAnchor:anchor] =\ + SpecfitFuns.snip1d(background[lastAnchor:anchor], + config['fit']['snipwidth'], + 0) + lastAnchor = anchor + if lastAnchor < background.size: + background[lastAnchor:] =\ + SpecfitFuns.snip1d(background[lastAnchor:], + config['fit']['snipwidth'], + 0) + chunk[k] -= background + + # perform the multiple fit to all the spectra in the chunk + # print("SHAPES") + # print(derivatives.shape) + # print(chunk.shape) + ddict=lstsq(derivatives, chunk, weight=weight, digested_output=True) + parameters = ddict['parameters'] + results[:, i, :] = parameters + uncertainties[:, i, :] = ddict['uncertainties'] + + # cleanup zeros + # start with the parameter with the largest amount of negative values + negativePresent = True + nFits = 0 + while negativePresent: + zeroList = [] + for i in range(nFree): + #we have to skip the background parameters + if i >= nFreeBackgroundParameters: + t = results[i] < 0 + if t.sum() > 0: + zeroList.append((t.sum(), i, t)) + + if len(zeroList) == 0: + negativePresent = False + continue + + if nFits > (2 * (nFree - nFreeBackgroundParameters)): + # we are probably in an endless loop + # force negative pixels + for item in zeroList: + i = item[1] + badMask = item[2] + results[i][badMask] = 0.0 + print("WARNING: %d pixels of parameter %s set to zero" % (item[0], freeNames[i])) + continue + zeroList.sort() + zeroList.reverse() + + badParameters = [] + badParameters.append(zeroList[0][1]) + badMask = zeroList[0][2] + if 1: + # prevent and endless loop if two or more parameters have common pixels where they are + # negative and one of them remains negative when forcing other one to zero + for i, item in enumerate(zeroList): + if item[1] not in badParameters: + if item[0] > 0: + #check if they have common negative pixels + t = badMask * item[-1] + if t.sum() > 0: + badParameters.append(item[1]) + badMask = t + if badMask.sum() < (0.0025 * nPixels): + # fit not worth + for i in badParameters: + results[i][badMask] = 0.0 + uncertainties[i][badMask] = 0.0 + if DEBUG: + print("WARNING: %d pixels of parameter %s set to zero" % (badMask.sum(), + freeNames[i])) + else: + if DEBUG: + print("Number of secondary fits = %d" % (nFits + 1)) + nFits += 1 + A = derivatives[:, [i for i in range(nFree) if i not in badParameters]] + #assume we'll not have too many spectra + spectra = data[badMask, iXMin:iXMax+1] + spectra.shape = badMask.sum(), -1 + spectra = spectra.T + # + if config['fit']['stripflag']: + for k in range(spectra.shape[0]): + # obtain the smoothed spectrum + background=SpecfitFuns.SavitskyGolay(spectra[k], + config['fit']['stripfilterwidth']) + lastAnchor = 0 + for anchor in anchorslist: + if (anchor > lastAnchor) and (anchor < background.size): + background[lastAnchor:anchor] =\ + SpecfitFuns.snip1d(background[lastAnchor:anchor], + config['fit']['snipwidth'], + 0) + lastAnchor = anchor + if lastAnchor < background.size: + background[lastAnchor:] =\ + SpecfitFuns.snip1d(background[lastAnchor:], + config['fit']['snipwidth'], + 0) + spectra[k] -= background + ddict = lstsq(A, spectra, weight=weight, digested_output=True) + idx = 0 + for i in range(nFree): + if i in badParameters: + results[i][badMask] = 0.0 + uncertainties[i][badMask] = 0.0 + else: + results[i][badMask] = ddict['parameters'][idx] + uncertainties[i][badMask] = ddict['uncertainties'][idx] + idx += 1 + outputDict = {'parameters':results, 'uncertainties':uncertainties, 'names':freeNames} + + if concentrations: + # check if an internal reference is used and if it is set to auto + #################################################### + # CONCENTRATIONS + cTool = ConcentrationsTool.ConcentrationsTool() + cToolConf = cTool.configure() + cToolConf.update(config['concentrations']) + + fitFirstSpectrum = False + if config['concentrations']['usematrix']: + if DEBUG: + print("USING MATRIX") + if config['concentrations']['reference'].upper() == "AUTO": + fitFirstSpectrum = True + + fitresult = {} + if fitFirstSpectrum: + # we have to fit the "reference" spectrum just to get the reference element + mcafitresult = self._mcaTheory.startfit(digest=0, linear=True) + # if one of the elements has zero area this cannot be made directly + fitresult['result'] = self._mcaTheory.imagingDigestResult() + fitresult['result']['config'] = config + concentrationsResult, addInfo = cTool.processFitResult(config=cToolConf, + fitresult=fitresult, + elementsfrommatrix=False, + fluorates=self._mcaTheory._fluoRates, + addinfo=True) + # and we have to make sure that all the areas are positive + for group in fitresult['result']['groups']: + if fitresult['result'][group]['fitarea'] <= 0.0: + # give a tiny area + fitresult['result'][group]['fitarea'] = 1.0e-6 + config['concentrations']['reference'] = addInfo['ReferenceElement'] + else: + fitresult['result'] = {} + fitresult['result']['config'] = config + fitresult['result']['groups'] = [] + idx = 0 + for i, param in enumerate(self._mcaTheory.PARAMETERS): + if self._mcaTheory.codes[0][i] == Gefit.CFIXED: + continue + if i < self._mcaTheory.NGLOBAL: + # background + pass + else: + fitresult['result']['groups'].append(param) + fitresult['result'][param] = {} + # we are just interested on the factor to be applied to the area to get the + # concentrations + fitresult['result'][param]['fitarea'] = 1.0 + fitresult['result'][param]['sigmaarea'] = 1.0 + idx += 1 + concentrationsResult, addInfo = cTool.processFitResult(config=cToolConf, + fitresult=fitresult, + elementsfrommatrix=False, + fluorates=self._mcaTheory._fluoRates, + addinfo=True) + nValues = 1 + if len(concentrationsResult['layerlist']) > 1: + nValues += len(concentrationsResult['layerlist']) + massFractions = numpy.zeros((nValues * (nFree - nFreeBackgroundParameters), nRows, nColumns), + numpy.float32) + + + referenceElement = addInfo['ReferenceElement'] + referenceTransitions = addInfo['ReferenceTransitions'] + if DEBUG: + print("Reference <%s> transition <%s>" % (referenceElement, referenceTransitions)) + if referenceElement in ["", None, "None"]: + if DEBUG: + print("No reference") + counter = 0 + for i, group in enumerate(fitresult['result']['groups']): + outputDict['names'].append("C(%s)" % group) + massFractions[counter] = results[nFreeBackgroundParameters+i] *\ + (concentrationsResult['mass fraction'][group]/fitresult['result'][param]['fitarea']) + if len(concentrationsResult['layerlist']) > 1: + for layer in concentrationsResult['layerlist']: + outputDict['names'].append("C(%s)-%s" % (group, layer)) + massFractions[counter] = results[nFreeBackgroundParameters+i] *\ + (concentrationsResult[layer]['mass fraction'][group]/fitresult['result'][param]['fitarea']) + counter += 1 + counter += 1 + else: + if DEBUG: + print("With reference") + idx = None + testGroup = referenceElement+ " " + referenceTransitions.split()[0] + for i, group in enumerate(fitresult['result']['groups']): + if group == testGroup: + idx = i + if idx is None: + raise ValueError("Invalid reference: <%s> <%s>" %\ + (referenceElement, referenceTransitions)) + + group = fitresult['result']['groups'][idx] + referenceArea = fitresult['result'][group]['fitarea'] + referenceConcentrations = concentrationsResult['mass fraction'][group] + goodIdx = results[nFreeBackgroundParameters+idx] > 0 + massFractions[idx] = referenceConcentrations + counter = 0 + for i, group in enumerate(fitresult['result']['groups']): + outputDict['names'].append("C(%s)" % group) + if i == idx: + continue + goodI = results[nFreeBackgroundParameters+i] > 0 + tmp = results[nFreeBackgroundParameters+idx][goodI] + massFractions[i][goodI] = (results[nFreeBackgroundParameters+i][goodI]/(tmp + (tmp == 0))) *\ + ((referenceArea/fitresult['result'][group]['fitarea']) *\ + (concentrationsResult['mass fraction'][group])) + if len(concentrationsResult['layerlist']) > 1: + for layer in concentrationsResult['layerlist']: + outputDict['names'].append("C(%s)-%s" % (group, layer)) + massFractions[i][goodI] = (results[nFreeBackgroundParameters+i][goodI]/(tmp + (tmp == 0))) *\ + ((referenceArea/fitresult['result'][group]['fitarea']) *\ + (concentrationsResult[layer]['mass fraction'][group])) + counter += 1 + counter += 1 + outputDict['concentrations'] = massFractions + #################################################### + return outputDict + +if __name__ == "__main__": + import time + import glob + from PyMca import EDFStack + if 1: + configurationFile = "E:\DATA\COTTE\CH1777\G4-4720eV-NOWEIGHT-NO_Constant-batch.cfg" + fileList = glob.glob("E:\DATA\COTTE\CH1777\G4_mca_0012_0000_0*.edf") + else: + configurationFile = "E2_line.cfg" + fileList = glob.glob("E:\DATA\PyMca-Training\FDM55\AS_EDF\E2_line*.edf") + dataStack = EDFStack.EDFStack(filelist=fileList) + + t0 = time.time() + fastFit = FastXRFLinearFit() + fastFit.setFitConfigurationFile(configurationFile) + print("Configuring Elapsed = % s " % (time.time() - t0)) + results = fastFit.fitMultipleSpectra(y=dataStack, concentrations=True) + print("Total Elapsed = % s " % (time.time() - t0)) + diff --git a/PyMca/FastXRFLinearFitWindow.py b/PyMca/FastXRFLinearFitWindow.py new file mode 100644 index 0000000..4030d88 --- /dev/null +++ b/PyMca/FastXRFLinearFitWindow.py @@ -0,0 +1,154 @@ +#/*########################################################################## +# Copyright (C) 2013 European Synchrotron Radiation Facility +# +# This file is part of the PyMca X-ray Fluorescence Toolkit developed at +# the ESRF by the Software group. +# +# This toolkit is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the Free +# Software Foundation; either version 2 of the License, or (at your option) +# any later version. +# +# PyMca is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +# details. +# +# You should have received a copy of the GNU General Public License along with +# PyMca; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +# +# PyMca follows the dual licensing model of Riverbank's PyQt and cannot be +# used as a free plugin for a non-free program. +# +# Please contact the ESRF industrial unit (industry@esrf.fr) if this license +# is a problem for you. +#############################################################################*/ +__author__ = "V.A. Sole - ESRF Data Analysis" +import sys +import numpy +from PyMca import PyMcaQt as qt +from PyMca.PyMca_Icons import IconDict +from PyMca import PyMcaFileDialogs + +DEBUG = 0 + +class FastXRFLinearFitWindow(qt.QWidget): + def __init__(self, parent=None): + qt.QWidget.__init__(self, parent) + self.setWindowTitle("FastXRFLinearFitWindow") + self.setWindowIcon(qt.QIcon(qt.QPixmap(IconDict['gioconda16']))) + self.mainLayout = qt.QGridLayout(self) + self.mainLayout.setContentsMargins(0, 0, 0, 0) + + # configuration file + configLabel = qt.QLabel(self) + configLabel.setText("Fit Configuration File:") + self._configLine = qt.QLineEdit(self) + self._configLine.setReadOnly(True) + + self._configButton = qt.QPushButton(self) + self._configButton.setText("Browse") + self._configButton.setAutoDefault(False) + self._configButton.clicked.connect(self.browseConfigurationFile) + + # output directory + outLabel = qt.QLabel(self) + outLabel.setText("Output dir:") + self._outLine = qt.QLineEdit(self) + self._outLine.setReadOnly(True) + + self._outButton = qt.QPushButton(self) + self._outButton.setText('Browse') + self._outButton.setAutoDefault(False) + self._outButton.clicked.connect(self.browseOutputDir) + + # output file name + fileLabel = qt.QLabel(self) + fileLabel.setText("Output file root:") + self._fileLine = qt.QLineEdit(self) + self._fileLine.setReadOnly(False) + self._fileLine.setText("images") + + # concentrations + self._concentrationsBox = qt.QCheckBox(self) + self._concentrationsBox.setText("calculate concentrations") + self._concentrationsBox.setChecked(False) + self._concentrationsBox.setEnabled(True) + + + self.mainLayout.addWidget(configLabel, 0, 0) + self.mainLayout.addWidget(self._configLine, 0, 1) + self.mainLayout.addWidget(self._configButton, 0, 2) + self.mainLayout.addWidget(outLabel, 1, 0) + self.mainLayout.addWidget(self._outLine, 1, 1) + self.mainLayout.addWidget(self._outButton, 1, 2) + self.mainLayout.addWidget(fileLabel, 2, 0) + self.mainLayout.addWidget(self._fileLine, 2, 1) + self.mainLayout.addWidget(self._concentrationsBox, 3, 0, 1, 2) + + def sizeHint(self): + return qt.QSize(int(1.8 * qt.QWidget.sizeHint(self).width()), + qt.QWidget.sizeHint(self).height()) + + def browseConfigurationFile(self): + f = PyMcaFileDialogs.getFileList(parent=self, + filetypelist=["Configuration files (*.cfg)"], + message="Open a new fit config file", + mode="OPEN", + single=True) + if len(f): + self._configLine.setText(f[0]) + + def browseOutputDir(self): + f = PyMcaFileDialogs.getExistingDirectory(parent=self, + message="Please select output directory", + mode="OPEN") + if len(f): + self._outLine.setText(f) + + def getParameters(self): + ddict = {} + ddict['configuration'] = qt.safe_str(self._configLine.text()) + ddict['output_dir'] = qt.safe_str(self._outLine.text()) + ddict['file_root'] = qt.safe_str(self._fileLine.text()) + if self._concentrationsBox.isChecked(): + ddict['concentrations'] = 1 + else: + ddict['concentrations'] = 0 + return ddict + +class FastXRFLinearFitDialog(qt.QDialog): + def __init__(self, parent=None): + qt.QDialog.__init__(self, parent) + self.setWindowTitle("Fast XRF Linear Fit Dialog") + self.setWindowIcon(qt.QIcon(qt.QPixmap(IconDict['gioconda16']))) + self.mainLayout = qt.QGridLayout(self) + self.mainLayout.setContentsMargins(10, 10, 10, 10) + self.parametersWidget = FastXRFLinearFitWindow(self) + + self.rejectButton= qt.QPushButton(self) + self.rejectButton.setAutoDefault(False) + self.rejectButton.setText("Cancel") + + self.acceptButton= qt.QPushButton(self) + self.acceptButton.setAutoDefault(False) + self.acceptButton.setText("OK") + + self.rejectButton.clicked.connect(self.reject) + self.acceptButton.clicked.connect(self.accept) + + self.mainLayout.addWidget(self.parametersWidget, 0, 0, 5, 5) + self.mainLayout.addWidget(self.rejectButton, 6, 1) + self.mainLayout.addWidget(self.acceptButton, 6, 2) + + def getParameters(self): + return self.parametersWidget.getParameters() + +if __name__ == "__main__": + app = qt.QApplication([]) + w = FastXRFLinearFitDialog() + ret = w.exec_() + if ret: + print(w.getParameters()) + #app.exec_() diff --git a/PyMca/Gefit.py b/PyMca/Gefit.py index 10f8fe5..4d43af0 100644 --- a/PyMca/Gefit.py +++ b/PyMca/Gefit.py @@ -14,8 +14,11 @@ # FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more # details. # +# Please contact the ESRF industrial unit (industry@esrf.fr) if this license +# is a problem for you. #############################################################################*/ __author__ = "V.A. Sole - ESRF Software Group" +__license__ = "LGPL" import numpy from numpy.linalg import inv import time diff --git a/PyMca/HDF5Stack1D.py b/PyMca/HDF5Stack1D.py index 44ade89..179149a 100644 --- a/PyMca/HDF5Stack1D.py +++ b/PyMca/HDF5Stack1D.py @@ -40,7 +40,7 @@ except ImportError: print("HDF5Stack1D importing NexusDataSource from local directory!") import NexusDataSource -DEBUG = 0 +DEBUG = 0 SOURCE_TYPE = "HDF5Stack1D" class HDF5Stack1D(DataObject.DataObject): @@ -74,6 +74,10 @@ class HDF5Stack1D(DataObject.DataObject): That means scanlist = ["/whatever1"] and selection['y'] = "/whatever2/counts" """ + if DEBUG: + print("filelist = ", filelist) + print("selection = ", selection) + print("scanlist = ", scanlist) # all the files in the same source hdfStack = NexusDataSource.NexusDataSource(filelist) @@ -86,7 +90,7 @@ class HDF5Stack1D(DataObject.DataObject): entryNames.append(key) # built the selection in terms of HDF terms - # for the time being, the only the firs item in x selection used + # for the time being, only the first item in x selection used xSelection = selection['x'] if type(xSelection) == type([]): if len(xSelection): @@ -110,6 +114,7 @@ class HDF5Stack1D(DataObject.DataObject): else: mSelection = None + USE_JUST_KEYS = False # deal with the pathological case where the scanlist corresponds # to a selected top level dataset if len(entryNames) == 0: @@ -117,8 +122,13 @@ class HDF5Stack1D(DataObject.DataObject): if len(scanlist) == 1: if scanlist[0] == ySelection: scanlist = None - - if scanlist in [None, []]: + elif len(entryNames) == 1: + # deal with the SOLEIL case of one entry but with different name + # in different files + USE_JUST_KEYS = True + elif scanlist in [None, []]: + USE_JUST_KEYS = True + if USE_JUST_KEYS: #if the scanlist is None, it is assumed we are interested on all #the scans containing the selection, not that all the scans #contain the selection. @@ -126,6 +136,7 @@ class HDF5Stack1D(DataObject.DataObject): if 0: JUST_KEYS = False #expect same entry names in the files + #Unfortunately this does not work for SOLEIL for entry in entryNames: path = "/"+entry + ySelection dirname = posixpath.dirname(path) @@ -137,19 +148,18 @@ class HDF5Stack1D(DataObject.DataObject): pass else: JUST_KEYS = True - #expect same structure in the files + #expect same structure in the files even if the + #names are different (SOLEIL ...) if len(entryNames): i = 0 for entry in entryNames: - i += 1 path = "/"+entry + ySelection dirname = posixpath.dirname(path) base = posixpath.basename(path) - try: - if base in tmpHdf[dirname].keys(): + if hasattr(tmpHdf[dirname], "keys"): + i += 1 + if base in tmpHdf[dirname].keys(): scanlist.append("1.%d" % i) - except: - pass if not len(scanlist): path = "/" + ySelection dirname = posixpath.dirname(path) @@ -185,6 +195,10 @@ class HDF5Stack1D(DataObject.DataObject): if not nScans: raise IOError("No entry contains the required data") + if DEBUG: + print("Retained number of files = %d" % nFiles) + print("Retained number of scans = %d" % nScans) + #Now is to decide the number of mca ... #I assume all the scans contain the same number of mca if JUST_KEYS: @@ -214,6 +228,8 @@ class HDF5Stack1D(DataObject.DataObject): mcaIndex = selection.get('index', len(shape)-1) if mcaIndex == -1: mcaIndex = len(shape) - 1 + if DEBUG: + print("mcaIndex = %d" % mcaIndex) considerAsImages = False dim0, dim1, mcaDim = self.getDimensions(nFiles, nScans, shape, index=mcaIndex) @@ -227,7 +243,7 @@ class HDF5Stack1D(DataObject.DataObject): else: bytefactor = 8 - neededMegaBytes = nFiles * dim0 * dim1 * mcaDim * bytefactor/(1024*1024.) + neededMegaBytes = nFiles * dim0 * dim1 * (mcaDim * bytefactor/(1024*1024.)) physicalMemory = PhysicalMemory.getPhysicalMemoryOrNone() if physicalMemory is None: # 5 Gigabytes should be a good compromise @@ -283,9 +299,14 @@ class HDF5Stack1D(DataObject.DataObject): self.incrProgressBar=0 for hdf in hdfStack._sourceObjectList: entryNames = list(hdf["/"].keys()) + goodEntryNames = [] + for entry in entryNames: + tmpPath = "/" + entry + if hasattr(hdf[tmpPath], "keys"): + goodEntryNames.append(entry) for scan in scanlist: if JUST_KEYS: - entryName = entryNames[int(scan.split(".")[-1])-1] + entryName = goodEntryNames[int(scan.split(".")[-1])-1] path = entryName + ySelection if mSelection is not None: mpath = entryName + mSelection @@ -456,8 +477,7 @@ class HDF5Stack1D(DataObject.DataObject): elif not DONE: # data into memory but as images self.info["McaIndex"] = mcaIndex - if 1:#for hdf in hdfStack._sourceObjectList: - hdf = hdfStack._sourceObjectList[0] + for hdf in hdfStack._sourceObjectList: entryNames = list(hdf["/"].keys()) for scan in scanlist: if JUST_KEYS: diff --git a/PyMca/ImageRegistration.py b/PyMca/ImageRegistration.py index 6ef1bc3..2a82919 100644 --- a/PyMca/ImageRegistration.py +++ b/PyMca/ImageRegistration.py @@ -1,5 +1,4 @@ # coding: utf8 -# #/********************************************************************************************* # # Copyright (c) 2013 J. Kieffer and V.A. Sole, European Synchrotron Radiation Facility (ESRF) @@ -23,13 +22,12 @@ # SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # #********************************************************************************************/ - _author__ = "Jérôme Kieffer and V.Armando Solé" __contact__ = "sole@esrf.fr" __license__ = "MIT" __copyright__ = "2013, ESRF, Grenoble" __date__ = "20131028" -__doc__ = "This is a python module to measure image offsets using fftpack" +__doc__ = "This is a python module to measure image offsets" import os, time import numpy @@ -48,11 +46,10 @@ except ImportError: def shiftFFT(img, shift): """ - Do shift using FFTs - Shift an array like scipy.ndimage.interpolation.shift(input, shift, mode="wrap", order="infinity") - @param input: 2d numpy array - @param shift: 2-tuple of float - @return: shifted image + Shift an array using FFTs + :param input: 2d numpy array + :param shift: 2-tuple of float + :return: shifted image """ d0, d1 = img.shape @@ -67,6 +64,13 @@ def shiftFFT(img, shift): return abs(out) def shiftBilinear(img, shift): + """ + Shift an array like scipy.ndimage.interpolation.shift(input, shift, mode="wrap", order="infinity") + :param input: 2d numpy array + :param shift: 2-tuple of float + :return: shifted image + + """ shape = img.shape x = numpy.zeros((shape[0] * shape[1], 2), numpy.float) x[:,0] = shift[0] + numpy.outer(numpy.arange(shape[1]), numpy.ones(shape[0])).reshape(-1) @@ -77,6 +81,14 @@ def shiftBilinear(img, shift): return shifted def shiftImage(img, shift, method=None): + """ + Shift an array like scipy.ndimage.interpolation.shift(input, shift, mode="wrap", order="infinity") + :param input: 2d numpy array + :param shift: 2-tuple of float + :param method: string set to PYMCA, SCIPY or FFT. Default is to try the first of those that is possible. + :return: shifted image + + """ if method is None: if PYMCA: return shiftBilinear(img, shift) @@ -95,10 +107,10 @@ def measure_offset(img1, img2, method="fft", withLog=False): """ Measure the actual offset between 2 images. The first one is the reference. That means, if the image to be shifted is the second one, the shift has to be multiplied byt -1. - @param img1: ndarray, first image - @param img2: ndarray, second image, same shape as img1 - @param withLog: shall we return logs as well ? boolean - @return: tuple of floats with the offsets of the second respect to the first + :param img1: ndarray, first image + :param img2: ndarray, second image, same shape as img1 + :param withLog: shall we return logs as well ? boolean + :return: tuple of floats with the offsets of the second respect to the first """ method = str(method) shape = img1.shape @@ -114,12 +126,40 @@ def measure_offset(img1, img2, method="fft", withLog=False): return measure_offset_from_ffts(i1f, i2f, withLog=withLog) def measure_offset_from_ffts(img0_fft2, img1_fft2, withLog=False): + """ + Convenience method to measure the actual offset between 2 images taing their FFTs as inpuy + The first FFT one is the one of the reference. That means, if the image to be shifted is the + second one, the shift has to be multiplied byt -1. + :param img1: ndarray, FFT of first image + :param img2: ndarray, FFT of the second image, same shape as img1 + :param withLog: shall we return logs as well ? boolean + :return: tuple of floats with the offsets of the second respect to the first + """ shape = img0_fft2.shape logs = [] f0 = img0_fft2 f1 = img1_fft2 t0 = time.time() - res = abs(fftshift(ifft2((f0 * f1.conjugate()) / (abs(f0) * abs(f1))))) + absf0 = abs(f0) + absf1 = abs(f1) + if 0: + # one way to deal with zeros + if (absf0 < 1.0e-20).any() or (absf1 < 1.0e-20).any(): + ofsset = [0.0, 0.0] + logs.append("MeasureOffset: empty or uniform image?") + if withLog: + return offset, logs + else: + return offset + else: + # this one seems better because numerator is expected to be zero + idx = absf0 < 1.0e-20 + if idx.any(): + absf0[idx] = 1.0 + idx = absf1 < 1.0e-20 + if idx.any(): + absf1[idx] = 1.0 + res = abs(fftshift(ifft2((f0 * f1.conjugate()) / (absf0 * absf1)))) t1 = time.time() a0, a1 = numpy.unravel_index(numpy.argmax(res), shape) resmax = res[a0, a1] @@ -131,8 +171,12 @@ def measure_offset_from_ffts(img0_fft2, img1_fft2, withLog=False): x0 = 0.0 x1 = 0.0 total = 0.0 - for i in range(a0-w, a0+w+1): - for j in range(a1-w, a1 + w + 1): + a00 = int(max(a0-w, 0)) + a01 = int(min(a0+w+1, shape[0])) + a10 = int(max(a1-w, 0)) + a11 = int(min(a1+w+1, shape[1])) + for i in range(a00, a01): + for j in range(a10, a11): if res[i, j] > 0.1 * resmax: tmp = res[i, j] x0 += i * tmp @@ -148,6 +192,11 @@ def measure_offset_from_ffts(img0_fft2, img1_fft2, withLog=False): return offset def get_crop_indices(shape, shifts0, shifts1): + """ + Get the indices of the valid region to be used when aligning a set of images + :param shitfs0: Shifts applied to the first dimension + :param shitfs1: Shifts applied to the second dimension + """ shifts0_min = numpy.min(shifts0) shifts0_max = numpy.max(shifts0) shifts1_min = numpy.min(shifts1) diff --git a/PyMca/Lanczos.py b/PyMca/Lanczos.py index 2196789..9a2a991 100644 --- a/PyMca/Lanczos.py +++ b/PyMca/Lanczos.py @@ -1,18 +1,18 @@ ## /************************************************************************ - +## ## Copyright ## Alessandro MIRONE ## mirone@esrf.fr - +## ## Copyright 2002 by European Synchrotron Radiation Facility, Grenoble, ## France - +## ## ---------- - +## ## All Rights Reserved - +## ## ---------- - +## ## Permission to use, copy, modify, and distribute this software and its ## documentation for any purpose and without fee is hereby granted, ## provided that the above copyright notice appear in all copies and that @@ -21,7 +21,7 @@ ## Radiation Facility or ESRF or SCISOFT not be used in advertising or ## publicity pertaining to distribution of the software without specific, ## written prior permission. - +## ## EUROPEAN SYNCHROTRON RADIATION FACILITY DISCLAIMS ALL WARRANTIES WITH ## REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF ## MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL EUROPEAN SYNCHROTRON @@ -30,9 +30,10 @@ ## DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER ## TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR ## PERFORMANCE OF THIS SOFTWARE. - +## ## **************************************************************************/ __author__ = "A. Mirone - ESRF SciSoft Group" +__license__ = "BSD" import math sparsamodulo=0 PARALLEL=0 diff --git a/PyMca/MEDFile.py b/PyMca/MEDFile.py index b99b507..a0a92f6 100644 --- a/PyMca/MEDFile.py +++ b/PyMca/MEDFile.py @@ -18,6 +18,8 @@ # TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE # SOFTWARE OR THE USE OR OTHER DEALINGS IN THIS SOFTWARE. # +__license__ = "BSD" +__author__ = "M. Newville - The University of Chicago" """ Simple interface to M. River's Multi-Element MCA Data Format diff --git a/PyMca/MRCMap.py b/PyMca/MRCMap.py new file mode 100644 index 0000000..62971ed --- /dev/null +++ b/PyMca/MRCMap.py @@ -0,0 +1,183 @@ +#/*########################################################################## +# Copyright (C) 2008-2013 European Synchrotron Radiation Facility +# +# This file is part of the PyMca X-ray Fluorescence Toolkit developed at +# the ESRF by the Software group. +# +# This file is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation; either version 2 of the License, or (at your +# option) any later version. +# +# PyMca is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +# details. +# +#############################################################################*/ +import os +import sys +import re +import struct +import numpy +import copy +from PyMca import DataObject + +if sys.version < '2.6': + def bytes(x): + return str(x) + +DEBUG = 0 +SOURCE_TYPE = "EdfFileStack" + +class MRCMap(DataObject.DataObject): + ''' + Class to read MRC files + + It reads the spectra into a DataObject instance. + This class info member contains all the parsed information. + This class data member contains the map itself as a 3D array. + ''' + def __init__(self, filename): + ''' + Parameters: + ----------- + filename : str + Name of the input file. + It is expected to work with files generated at BESSY with raw2mrc + ''' + DataObject.DataObject.__init__(self) + try: + fid = open(filename, 'rb') + header = fid.read(1024) + fid.close() + except: + fid.close() + raise + + if not _isMRCHeader(header): + raise IOError("File does not seem to be an MRC file") + + self.sourceName = filename + + # check endianness + flag = struct.unpack("4B", header[212:216])[0] + if flag in [17, 18]: + # high endian (Motorola) + endianness = ">" + else: + # little endian (Intel) + endianness = "<" + + fmt = endianness + "10i" + tenIntegers = struct.unpack(fmt, header[0:40]) + nColumns, nRows, nImages, mode = tenIntegers[0:4] + + + fmt = endianness + "6f" + sixFloats = struct.unpack(fmt, header[40:64]) + fmt = endianness + "3i" + threeIntegers = struct.unpack(fmt, header[64:76]) + fmt = endianness + "3f" + threeFloats = struct.unpack(fmt, header[76:88]) + + # number of bytes in extended header + fmt = endianness + "i" + offset = struct.unpack(fmt, header[92:96])[0] + + fmt = endianness + "ii" + imodStamp, imodFlags = struct.unpack(fmt, header[152:160]) + + if mode == 0: + # bytes + dataFormat = endianness + "%dB" % (nRows * nColumns) + elif mode == 1: + # signed short integers (16 bit) + dataFormat = endianness + "%dh" % (nRows * nColumns) + elif mode == 2: + # float + dataFormat = endianness + "%df" % (nRows * nColumns) + elif mode == 3: + # two shorts, complex data + dataFormat = endianness + "%dh" % (2 * nRows * nColumns) + elif mode == 4: + # two floats, complex data + dataFormat = endianness + "%df" % (2 * nRows * nColumns) + elif mode == 6: + # unsigned 16 bit integers (non-standard) + dataFormat = endianness + "%dH" % (nRows * nColumns) + elif mode == 16: + # unsigned char * 3(rgb data, non-standard) + dataFormat = endianness + "%dB" % (3 * nRows * nColumns) + else: + raise IOError("Data format not undestood") + + if imodFlags == 1: + # bytes stored as signed + dataFormat = dataFormat.lower() + + + data = numpy.zeros((nImages, nRows * nColumns), numpy.float) + fid = open(filename, 'rb') + fileOffset = 1024 + offset + fid.seek(fileOffset) + dataSize= struct.calcsize(dataFormat) + try: + for i in range(nImages): + tmpData = fid.read(dataSize) + data[i] = struct.unpack(dataFormat, tmpData) + fid.close() + except: + fid.close() + raise + + data.shape = nImages, nRows, nColumns + self.data = data + + self.info = {} + self.info["SourceType"] = SOURCE_TYPE + self.info["SourceName"] = self.sourceName + shape = self.data.shape + for i in range(len(shape)): + key = 'Dim_%d' % (i + 1,) + self.info[key] = shape[i] + self.info["NumberOfFiles"] = 1 + self.info["McaIndex"] = 0 + self.info["McaCalib"] = [0.0, 1.0, 0.0] + self.info["Channel0"] = 0.0 + +def _isMRCHeader(header): + if sys.version < '3.0': + test = "MAP " + else: + test = bytes("MAP ", "utf-8") + if struct.unpack("4s", header[208:212])[0] == test: + return True + else: + return False + +def isMRCFile(filename): + try: + fid = open(filename, 'rb') + header = fid.read(1024) + fid.close() + except: + fid.close() + return False + nColumns, nRows, nImages = struct.unpack("iii", header[0:12]) + imodStamp, imodFlags = struct.unpack("ii", header[152:160]) + #print(imodStamp, imodFlags) + + # system byte order + #print("system ",sys.byteorder) + + return _isMRCHeader(header) + +if __name__ == "__main__": + filename = None + if len(sys.argv) > 1: + filename = sys.argv[1] + print("is MRC File?", isMRCFile(filename)) + instance = MRCMap(filename) + print(instance.info) + print(instance.data) diff --git a/PyMca/McaAdvancedFitBatch.py b/PyMca/McaAdvancedFitBatch.py index d335191..e161863 100644 --- a/PyMca/McaAdvancedFitBatch.py +++ b/PyMca/McaAdvancedFitBatch.py @@ -1,5 +1,5 @@ #/*########################################################################## -# Copyright (C) 2004-2012 European Synchrotron Radiation Facility +# Copyright (C) 2004-2013 European Synchrotron Radiation Facility # # This file is part of the PyMca X-ray Fluorescence Toolkit developed at # the ESRF by the Software group. @@ -157,7 +157,7 @@ class McaAdvancedFitBatch(object): self.mcafit = ClassMcaTheory.McaTheory(self.__configList[i]) self.mcafit.enableOptimizedLinearFit() inputfile = self._filelist[i] - self.__row += 1 + self.__row += 1 #should be plus fileStep? self.onNewFile(inputfile, self._filelist) self.file = self.getFileHandle(inputfile) if self.pleaseBreak: break @@ -170,6 +170,9 @@ class McaAdvancedFitBatch(object): self.__stack = True if self.__stack: self.__processStack() + if self._HDF5: + # The complete stack has been analyzed + break else: self.__processOneFile() if self.counter: @@ -188,7 +191,8 @@ class McaAdvancedFitBatch(object): if h5py.is_hdf5(inputfile): self._HDF5 = True try: - return HDF5Stack1D.HDF5Stack1D([inputfile], self.selection) + return HDF5Stack1D.HDF5Stack1D(self._filelist, + self.selection) except: raise ffile = self.__tryEdf(inputfile) diff --git a/PyMca/NNMAModule.py b/PyMca/NNMAModule.py index 6ece00f..4bdb2c2 100644 --- a/PyMca/NNMAModule.py +++ b/PyMca/NNMAModule.py @@ -1,4 +1,5 @@ __author__ = "Uwe Schmitt uschmitt@mineway.de, wrapped by V.A. Sole - ESRF" +__license__ = "BSD" __doc__ = """ This module is a simple wrapper to the py_nnma module of Uwe Schmitt (uschmitt@mineway.de) in order to integrate it into PyMca. What follows is the documentation of py_nnma diff --git a/PyMca/Object3D/Object3DQhull/Announce.txt b/PyMca/Object3D/Object3DQhull/Announce.txt deleted file mode 100644 index ac8e052..0000000 --- a/PyMca/Object3D/Object3DQhull/Announce.txt +++ /dev/null @@ -1,51 +0,0 @@ - - Qhull 2012.1 2012/02/18 - - http://www.qhull.org - git@gitorious.org:qhull/qhull.git - http://packages.debian.org/sid/libqhull5 [out-of-date] - http://www6.uniovi.es/ftp/pub/mirrors/geom.umn.edu/software/ghindex.html - http://www.geomview.org - http://www.geom.uiuc.edu - -Qhull computes convex hulls, Delaunay triangulations, Voronoi diagrams, -furthest-site Voronoi diagrams, and halfspace intersections about a point. -It runs in 2-d, 3-d, 4-d, or higher. It implements the Quickhull algorithm -for computing convex hulls. Qhull handles round-off errors from floating -point arithmetic. It can approximate a convex hull. - -The program includes options for hull volume, facet area, partial hulls, -input transformations, randomization, tracing, multiple output formats, and -execution statistics. The program can be called from within your application. -You can view the results in 2-d, 3-d and 4-d with Geomview. - -To download Qhull: - http://www.qhull.org/download - git@gitorious.org:qhull/qhull.git - http://packages.debian.org/sid/libqhull5 [out-of-date] - -Download qhull-96.ps for: - - Barber, C. B., D.P. Dobkin, and H.T. Huhdanpaa, "The - Quickhull Algorithm for Convex Hulls," ACM Trans. on - Mathematical Software, 22(4):469-483, Dec. 1996. - http://www.acm.org/pubs/citations/journals/toms/1996-22-4/p469-barber/ - http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.117.405 - -Abstract: - -The convex hull of a set of points is the smallest convex set that contains -the points. This article presents a practical convex hull algorithm that -combines the two-dimensional Quickhull Algorithm with the general dimension -Beneath-Beyond Algorithm. It is similar to the randomized, incremental -algorithms for convex hull and Delaunay triangulation. We provide empirical -evidence that the algorithm runs faster when the input contains non-extreme -points, and that it uses less memory. - -Computational geometry algorithms have traditionally assumed that input sets -are well behaved. When an algorithm is implemented with floating point -arithmetic, this assumption can lead to serious errors. We briefly describe -a solution to this problem when computing the convex hull in two, three, or -four dimensions. The output is a set of "thick" facets that contain all -possible exact convex hulls of the input. A variation is effective in five -or more dimensions. diff --git a/PyMca/Object3D/Object3DQhull/COPYING.txt b/PyMca/Object3D/Object3DQhull/COPYING.txt deleted file mode 100644 index 7a73d9f..0000000 --- a/PyMca/Object3D/Object3DQhull/COPYING.txt +++ /dev/null @@ -1,38 +0,0 @@ - Qhull, Copyright (c) 1993-2012 - - C.B. Barber - Arlington, MA - - and - - The National Science and Technology Research Center for - Computation and Visualization of Geometric Structures - (The Geometry Center) - University of Minnesota - - email: qhull@qhull.org - -This software includes Qhull from C.B. Barber and The Geometry Center. -Qhull is copyrighted as noted above. Qhull is free software and may -be obtained via http from www.qhull.org. It may be freely copied, modified, -and redistributed under the following conditions: - -1. All copyright notices must remain intact in all files. - -2. A copy of this text file must be distributed along with any copies - of Qhull that you redistribute; this includes copies that you have - modified, or copies of programs or other software products that - include Qhull. - -3. If you modify Qhull, you must include a notice giving the - name of the person performing the modification, the date of - modification, and the reason for such modification. - -4. When distributing modified versions of Qhull, or other software - products that include Qhull, you must provide notice that the original - source code may be obtained as noted above. - -5. There is no warranty or other guarantee of fitness for Qhull, it is - provided solely "as is". Bug reports or fixes may be sent to - qhull_bug@qhull.org; the authors may or may not act on them as - they desire. diff --git a/PyMca/Object3D/Object3DQhull/src/Object3DQhull.c b/PyMca/Object3D/Object3DQhull/Object3DQhull.c index 7595c4f..7595c4f 100644 --- a/PyMca/Object3D/Object3DQhull/src/Object3DQhull.c +++ b/PyMca/Object3D/Object3DQhull/Object3DQhull.c diff --git a/PyMca/Object3D/Object3DQhull/REGISTER.txt b/PyMca/Object3D/Object3DQhull/REGISTER.txt deleted file mode 100644 index 16ccb1a..0000000 --- a/PyMca/Object3D/Object3DQhull/REGISTER.txt +++ /dev/null @@ -1,32 +0,0 @@ -Dear Qhull User - -We would like to find out how you are using our software. Think of -Qhull as a new kind of shareware: you share your science and successes -with us, and we share our software and support with you. - -If you use Qhull, please send us a note telling -us what you are doing with it. - -We need to know: - - (1) What you are working on - an abstract of your work would be - fine. - - (2) How Qhull has helped you, for example, by increasing your - productivity or allowing you to do things you could not do - before. If Qhull had a direct bearing on your work, please - tell us about this. - -We encourage you to cite Qhull in your publications. - -To cite Qhull, please use - - Barber, C.B., Dobkin, D.P., and Huhdanpaa, H.T., "The Quickhull - algorithm for convex hulls," ACM Trans. on Mathematical Software, - 22(4):469-483, Dec 1996, http://www.qhull.org. - -Please send e-mail to - - bradb@shore.net - -Thank you! diff --git a/PyMca/Object3D/Object3DQhull/src/geom.c b/PyMca/Object3D/Object3DQhull/src/geom.c deleted file mode 100644 index 0f3b9d9..0000000 --- a/PyMca/Object3D/Object3DQhull/src/geom.c +++ /dev/null @@ -1,1234 +0,0 @@ -/*<html><pre> -<a href="qh-geom.htm" - >-------------------------------</a><a name="TOP">-</a> - - geom.c - geometric routines of qhull - - see qh-geom.htm and geom.h - - Copyright (c) 1993-2012 The Geometry Center. - $Id: //main/2011/qhull/src/libqhull/geom.c#3 $$Change: 1464 $ - $DateTime: 2012/01/25 22:58:41 $$Author: bbarber $ - - infrequent code goes into geom2.c -*/ - -#include "qhull_a.h" - -/*-<a href="qh-geom.htm#TOC" - >-------------------------------</a><a name="distplane">-</a> - - qh_distplane( point, facet, dist ) - return distance from point to facet - - returns: - dist - if qh.RANDOMdist, joggles result - - notes: - dist > 0 if point is above facet (i.e., outside) - does not error (for qh_sortfacets, qh_outerinner) - - see: - qh_distnorm in geom2.c - qh_distplane [geom.c], QhullFacet::distance, and QhullHyperplane::distance are copies -*/ -void qh_distplane(pointT *point, facetT *facet, realT *dist) { - coordT *normal= facet->normal, *coordp, randr; - int k; - - switch (qh hull_dim){ - case 2: - *dist= facet->offset + point[0] * normal[0] + point[1] * normal[1]; - break; - case 3: - *dist= facet->offset + point[0] * normal[0] + point[1] * normal[1] + point[2] * normal[2]; - break; - case 4: - *dist= facet->offset+point[0]*normal[0]+point[1]*normal[1]+point[2]*normal[2]+point[3]*normal[3]; - break; - case 5: - *dist= facet->offset+point[0]*normal[0]+point[1]*normal[1]+point[2]*normal[2]+point[3]*normal[3]+point[4]*normal[4]; - break; - case 6: - *dist= facet->offset+point[0]*normal[0]+point[1]*normal[1]+point[2]*normal[2]+point[3]*normal[3]+point[4]*normal[4]+point[5]*normal[5]; - break; - case 7: - *dist= facet->offset+point[0]*normal[0]+point[1]*normal[1]+point[2]*normal[2]+point[3]*normal[3]+point[4]*normal[4]+point[5]*normal[5]+point[6]*normal[6]; - break; - case 8: - *dist= facet->offset+point[0]*normal[0]+point[1]*normal[1]+point[2]*normal[2]+point[3]*normal[3]+point[4]*normal[4]+point[5]*normal[5]+point[6]*normal[6]+point[7]*normal[7]; - break; - default: - *dist= facet->offset; - coordp= point; - for (k=qh hull_dim; k--; ) - *dist += *coordp++ * *normal++; - break; - } - zinc_(Zdistplane); - if (!qh RANDOMdist && qh IStracing < 4) - return; - if (qh RANDOMdist) { - randr= qh_RANDOMint; - *dist += (2.0 * randr / qh_RANDOMmax - 1.0) * - qh RANDOMfactor * qh MAXabs_coord; - } - if (qh IStracing >= 4) { - qh_fprintf(qh ferr, 8001, "qh_distplane: "); - qh_fprintf(qh ferr, 8002, qh_REAL_1, *dist); - qh_fprintf(qh ferr, 8003, "from p%d to f%d\n", qh_pointid(point), facet->id); - } - return; -} /* distplane */ - - -/*-<a href="qh-geom.htm#TOC" - >-------------------------------</a><a name="findbest">-</a> - - qh_findbest( point, startfacet, bestoutside, qh_ISnewfacets, qh_NOupper, dist, isoutside, numpart ) - find facet that is furthest below a point - for upperDelaunay facets - returns facet only if !qh_NOupper and clearly above - - input: - starts search at 'startfacet' (can not be flipped) - if !bestoutside(qh_ALL), stops at qh.MINoutside - - returns: - best facet (reports error if NULL) - early out if isoutside defined and bestdist > qh.MINoutside - dist is distance to facet - isoutside is true if point is outside of facet - numpart counts the number of distance tests - - see also: - qh_findbestnew() - - notes: - If merging (testhorizon), searches horizon facets of coplanar best facets because - after qh_distplane, this and qh_partitionpoint are the most expensive in 3-d - avoid calls to distplane, function calls, and real number operations. - caller traces result - Optimized for outside points. Tried recording a search set for qh_findhorizon. - Made code more complicated. - - when called by qh_partitionvisible(): - indicated by qh_ISnewfacets - qh.newfacet_list is list of simplicial, new facets - qh_findbestnew set if qh_sharpnewfacets returns True (to use qh_findbestnew) - qh.bestfacet_notsharp set if qh_sharpnewfacets returns False - - when called by qh_findfacet(), qh_partitionpoint(), qh_partitioncoplanar(), - qh_check_bestdist(), qh_addpoint() - indicated by !qh_ISnewfacets - returns best facet in neighborhood of given facet - this is best facet overall if dist > - qh.MAXcoplanar - or hull has at least a "spherical" curvature - - design: - initialize and test for early exit - repeat while there are better facets - for each neighbor of facet - exit if outside facet found - test for better facet - if point is inside and partitioning - test for new facets with a "sharp" intersection - if so, future calls go to qh_findbestnew() - test horizon facets -*/ -facetT *qh_findbest(pointT *point, facetT *startfacet, - boolT bestoutside, boolT isnewfacets, boolT noupper, - realT *dist, boolT *isoutside, int *numpart) { - realT bestdist= -REALmax/2 /* avoid underflow */; - facetT *facet, *neighbor, **neighborp; - facetT *bestfacet= NULL, *lastfacet= NULL; - int oldtrace= qh IStracing; - unsigned int visitid= ++qh visit_id; - int numpartnew=0; - boolT testhorizon = True; /* needed if precise, e.g., rbox c D6 | qhull Q0 Tv */ - - zinc_(Zfindbest); - if (qh IStracing >= 3 || (qh TRACElevel && qh TRACEpoint >= 0 && qh TRACEpoint == qh_pointid(point))) { - if (qh TRACElevel > qh IStracing) - qh IStracing= qh TRACElevel; - qh_fprintf(qh ferr, 8004, "qh_findbest: point p%d starting at f%d isnewfacets? %d, unless %d exit if > %2.2g\n", - qh_pointid(point), startfacet->id, isnewfacets, bestoutside, qh MINoutside); - qh_fprintf(qh ferr, 8005, " testhorizon? %d noupper? %d", testhorizon, noupper); - qh_fprintf(qh ferr, 8006, " Last point added was p%d.", qh furthest_id); - qh_fprintf(qh ferr, 8007, " Last merge was #%d. max_outside %2.2g\n", zzval_(Ztotmerge), qh max_outside); - } - if (isoutside) - *isoutside= True; - if (!startfacet->flipped) { /* test startfacet */ - *numpart= 1; - qh_distplane(point, startfacet, dist); /* this code is duplicated below */ - if (!bestoutside && *dist >= qh MINoutside - && (!startfacet->upperdelaunay || !noupper)) { - bestfacet= startfacet; - goto LABELreturn_best; - } - bestdist= *dist; - if (!startfacet->upperdelaunay) { - bestfacet= startfacet; - } - }else - *numpart= 0; - startfacet->visitid= visitid; - facet= startfacet; - while (facet) { - trace4((qh ferr, 4001, "qh_findbest: neighbors of f%d, bestdist %2.2g f%d\n", - facet->id, bestdist, getid_(bestfacet))); - lastfacet= facet; - FOREACHneighbor_(facet) { - if (!neighbor->newfacet && isnewfacets) - continue; - if (neighbor->visitid == visitid) - continue; - neighbor->visitid= visitid; - if (!neighbor->flipped) { /* code duplicated above */ - (*numpart)++; - qh_distplane(point, neighbor, dist); - if (*dist > bestdist) { - if (!bestoutside && *dist >= qh MINoutside - && (!neighbor->upperdelaunay || !noupper)) { - bestfacet= neighbor; - goto LABELreturn_best; - } - if (!neighbor->upperdelaunay) { - bestfacet= neighbor; - bestdist= *dist; - break; /* switch to neighbor */ - }else if (!bestfacet) { - bestdist= *dist; - break; /* switch to neighbor */ - } - } /* end of *dist>bestdist */ - } /* end of !flipped */ - } /* end of FOREACHneighbor */ - facet= neighbor; /* non-NULL only if *dist>bestdist */ - } /* end of while facet (directed search) */ - if (isnewfacets) { - if (!bestfacet) { - bestdist= -REALmax/2; - bestfacet= qh_findbestnew(point, startfacet->next, &bestdist, bestoutside, isoutside, &numpartnew); - testhorizon= False; /* qh_findbestnew calls qh_findbesthorizon */ - }else if (!qh findbest_notsharp && bestdist < - qh DISTround) { - if (qh_sharpnewfacets()) { - /* seldom used, qh_findbestnew will retest all facets */ - zinc_(Zfindnewsharp); - bestfacet= qh_findbestnew(point, bestfacet, &bestdist, bestoutside, isoutside, &numpartnew); - testhorizon= False; /* qh_findbestnew calls qh_findbesthorizon */ - qh findbestnew= True; - }else - qh findbest_notsharp= True; - } - } - if (!bestfacet) - bestfacet= qh_findbestlower(lastfacet, point, &bestdist, numpart); - if (testhorizon) - bestfacet= qh_findbesthorizon(!qh_IScheckmax, point, bestfacet, noupper, &bestdist, &numpartnew); - *dist= bestdist; - if (isoutside && bestdist < qh MINoutside) - *isoutside= False; -LABELreturn_best: - zadd_(Zfindbesttot, *numpart); - zmax_(Zfindbestmax, *numpart); - (*numpart) += numpartnew; - qh IStracing= oldtrace; - return bestfacet; -} /* findbest */ - - -/*-<a href="qh-geom.htm#TOC" - >-------------------------------</a><a name="findbesthorizon">-</a> - - qh_findbesthorizon( qh_IScheckmax, point, startfacet, qh_NOupper, &bestdist, &numpart ) - search coplanar and better horizon facets from startfacet/bestdist - ischeckmax turns off statistics and minsearch update - all arguments must be initialized - returns(ischeckmax): - best facet - returns(!ischeckmax): - best facet that is not upperdelaunay - allows upperdelaunay that is clearly outside - returns: - bestdist is distance to bestfacet - numpart -- updates number of distance tests - - notes: - no early out -- use qh_findbest() or qh_findbestnew() - Searches coplanar or better horizon facets - - when called by qh_check_maxout() (qh_IScheckmax) - startfacet must be closest to the point - Otherwise, if point is beyond and below startfacet, startfacet may be a local minimum - even though other facets are below the point. - updates facet->maxoutside for good, visited facets - may return NULL - - searchdist is qh.max_outside + 2 * DISTround - + max( MINvisible('Vn'), MAXcoplanar('Un')); - This setting is a guess. It must be at least max_outside + 2*DISTround - because a facet may have a geometric neighbor across a vertex - - design: - for each horizon facet of coplanar best facets - continue if clearly inside - unless upperdelaunay or clearly outside - update best facet -*/ -facetT *qh_findbesthorizon(boolT ischeckmax, pointT* point, facetT *startfacet, boolT noupper, realT *bestdist, int *numpart) { - facetT *bestfacet= startfacet; - realT dist; - facetT *neighbor, **neighborp, *facet; - facetT *nextfacet= NULL; /* optimize last facet of coplanarfacetset */ - int numpartinit= *numpart, coplanarfacetset_size; - unsigned int visitid= ++qh visit_id; - boolT newbest= False; /* for tracing */ - realT minsearch, searchdist; /* skip facets that are too far from point */ - - if (!ischeckmax) { - zinc_(Zfindhorizon); - }else { -#if qh_MAXoutside - if ((!qh ONLYgood || startfacet->good) && *bestdist > startfacet->maxoutside) - startfacet->maxoutside= *bestdist; -#endif - } - searchdist= qh_SEARCHdist; /* multiple of qh.max_outside and precision constants */ - minsearch= *bestdist - searchdist; - if (ischeckmax) { - /* Always check coplanar facets. Needed for RBOX 1000 s Z1 G1e-13 t996564279 | QHULL Tv */ - minimize_(minsearch, -searchdist); - } - coplanarfacetset_size= 0; - facet= startfacet; - while (True) { - trace4((qh ferr, 4002, "qh_findbesthorizon: neighbors of f%d bestdist %2.2g f%d ischeckmax? %d noupper? %d minsearch %2.2g searchdist %2.2g\n", - facet->id, *bestdist, getid_(bestfacet), ischeckmax, noupper, - minsearch, searchdist)); - FOREACHneighbor_(facet) { - if (neighbor->visitid == visitid) - continue; - neighbor->visitid= visitid; - if (!neighbor->flipped) { - qh_distplane(point, neighbor, &dist); - (*numpart)++; - if (dist > *bestdist) { - if (!neighbor->upperdelaunay || ischeckmax || (!noupper && dist >= qh MINoutside)) { - bestfacet= neighbor; - *bestdist= dist; - newbest= True; - if (!ischeckmax) { - minsearch= dist - searchdist; - if (dist > *bestdist + searchdist) { - zinc_(Zfindjump); /* everything in qh.coplanarfacetset at least searchdist below */ - coplanarfacetset_size= 0; - } - } - } - }else if (dist < minsearch) - continue; /* if ischeckmax, dist can't be positive */ -#if qh_MAXoutside - if (ischeckmax && dist > neighbor->maxoutside) - neighbor->maxoutside= dist; -#endif - } /* end of !flipped */ - if (nextfacet) { - if (!coplanarfacetset_size++) { - SETfirst_(qh coplanarfacetset)= nextfacet; - SETtruncate_(qh coplanarfacetset, 1); - }else - qh_setappend(&qh coplanarfacetset, nextfacet); /* Was needed for RBOX 1000 s W1e-13 P0 t996547055 | QHULL d Qbb Qc Tv - and RBOX 1000 s Z1 G1e-13 t996564279 | qhull Tv */ - } - nextfacet= neighbor; - } /* end of EACHneighbor */ - facet= nextfacet; - if (facet) - nextfacet= NULL; - else if (!coplanarfacetset_size) - break; - else if (!--coplanarfacetset_size) { - facet= SETfirstt_(qh coplanarfacetset, facetT); - SETtruncate_(qh coplanarfacetset, 0); - }else - facet= (facetT*)qh_setdellast(qh coplanarfacetset); - } /* while True, for each facet in qh.coplanarfacetset */ - if (!ischeckmax) { - zadd_(Zfindhorizontot, *numpart - numpartinit); - zmax_(Zfindhorizonmax, *numpart - numpartinit); - if (newbest) - zinc_(Zparthorizon); - } - trace4((qh ferr, 4003, "qh_findbesthorizon: newbest? %d bestfacet f%d bestdist %2.2g\n", newbest, getid_(bestfacet), *bestdist)); - return bestfacet; -} /* findbesthorizon */ - -/*-<a href="qh-geom.htm#TOC" - >-------------------------------</a><a name="findbestnew">-</a> - - qh_findbestnew( point, startfacet, dist, isoutside, numpart ) - find best newfacet for point - searches all of qh.newfacet_list starting at startfacet - searches horizon facets of coplanar best newfacets - searches all facets if startfacet == qh.facet_list - returns: - best new or horizon facet that is not upperdelaunay - early out if isoutside and not 'Qf' - dist is distance to facet - isoutside is true if point is outside of facet - numpart is number of distance tests - - notes: - Always used for merged new facets (see qh_USEfindbestnew) - Avoids upperdelaunay facet unless (isoutside and outside) - - Uses qh.visit_id, qh.coplanarfacetset. - If share visit_id with qh_findbest, coplanarfacetset is incorrect. - - If merging (testhorizon), searches horizon facets of coplanar best facets because - a point maybe coplanar to the bestfacet, below its horizon facet, - and above a horizon facet of a coplanar newfacet. For example, - rbox 1000 s Z1 G1e-13 | qhull - rbox 1000 s W1e-13 P0 t992110337 | QHULL d Qbb Qc - - qh_findbestnew() used if - qh_sharpnewfacets -- newfacets contains a sharp angle - if many merges, qh_premerge found a merge, or 'Qf' (qh.findbestnew) - - see also: - qh_partitionall() and qh_findbest() - - design: - for each new facet starting from startfacet - test distance from point to facet - return facet if clearly outside - unless upperdelaunay and a lowerdelaunay exists - update best facet - test horizon facets -*/ -facetT *qh_findbestnew(pointT *point, facetT *startfacet, - realT *dist, boolT bestoutside, boolT *isoutside, int *numpart) { - realT bestdist= -REALmax/2; - facetT *bestfacet= NULL, *facet; - int oldtrace= qh IStracing, i; - unsigned int visitid= ++qh visit_id; - realT distoutside= 0.0; - boolT isdistoutside; /* True if distoutside is defined */ - boolT testhorizon = True; /* needed if precise, e.g., rbox c D6 | qhull Q0 Tv */ - - if (!startfacet) { - if (qh MERGING) - qh_fprintf(qh ferr, 6001, "qhull precision error (qh_findbestnew): merging has formed and deleted a cone of new facets. Can not continue.\n"); - else - qh_fprintf(qh ferr, 6002, "qhull internal error (qh_findbestnew): no new facets for point p%d\n", - qh furthest_id); - qh_errexit(qh_ERRqhull, NULL, NULL); - } - zinc_(Zfindnew); - if (qh BESToutside || bestoutside) - isdistoutside= False; - else { - isdistoutside= True; - distoutside= qh_DISToutside; /* multiple of qh.MINoutside & qh.max_outside, see user.h */ - } - if (isoutside) - *isoutside= True; - *numpart= 0; - if (qh IStracing >= 3 || (qh TRACElevel && qh TRACEpoint >= 0 && qh TRACEpoint == qh_pointid(point))) { - if (qh TRACElevel > qh IStracing) - qh IStracing= qh TRACElevel; - qh_fprintf(qh ferr, 8008, "qh_findbestnew: point p%d facet f%d. Stop? %d if dist > %2.2g\n", - qh_pointid(point), startfacet->id, isdistoutside, distoutside); - qh_fprintf(qh ferr, 8009, " Last point added p%d visitid %d.", qh furthest_id, visitid); - qh_fprintf(qh ferr, 8010, " Last merge was #%d.\n", zzval_(Ztotmerge)); - } - /* visit all new facets starting with startfacet, maybe qh facet_list */ - for (i=0, facet=startfacet; i < 2; i++, facet= qh newfacet_list) { - FORALLfacet_(facet) { - if (facet == startfacet && i) - break; - facet->visitid= visitid; - if (!facet->flipped) { - qh_distplane(point, facet, dist); - (*numpart)++; - if (*dist > bestdist) { - if (!facet->upperdelaunay || *dist >= qh MINoutside) { - bestfacet= facet; - if (isdistoutside && *dist >= distoutside) - goto LABELreturn_bestnew; - bestdist= *dist; - } - } - } /* end of !flipped */ - } /* FORALLfacet from startfacet or qh newfacet_list */ - } - if (testhorizon || !bestfacet) - bestfacet= qh_findbesthorizon(!qh_IScheckmax, point, bestfacet ? bestfacet : startfacet, - !qh_NOupper, &bestdist, numpart); - *dist= bestdist; - if (isoutside && *dist < qh MINoutside) - *isoutside= False; -LABELreturn_bestnew: - zadd_(Zfindnewtot, *numpart); - zmax_(Zfindnewmax, *numpart); - trace4((qh ferr, 4004, "qh_findbestnew: bestfacet f%d bestdist %2.2g\n", getid_(bestfacet), *dist)); - qh IStracing= oldtrace; - return bestfacet; -} /* findbestnew */ - -/* ============ hyperplane functions -- keep code together [?] ============ */ - -/*-<a href="qh-geom.htm#TOC" - >-------------------------------</a><a name="backnormal">-</a> - - qh_backnormal( rows, numrow, numcol, sign, normal, nearzero ) - given an upper-triangular rows array and a sign, - solve for normal equation x using back substitution over rows U - - returns: - normal= x - - if will not be able to divzero() when normalized(qh.MINdenom_2 and qh.MINdenom_1_2), - if fails on last row - this means that the hyperplane intersects [0,..,1] - sets last coordinate of normal to sign - otherwise - sets tail of normal to [...,sign,0,...], i.e., solves for b= [0...0] - sets nearzero - - notes: - assumes numrow == numcol-1 - - see Golub & van Loan 4.4-9 for back substitution - - solves Ux=b where Ax=b and PA=LU - b= [0,...,0,sign or 0] (sign is either -1 or +1) - last row of A= [0,...,0,1] - - 1) Ly=Pb == y=b since P only permutes the 0's of b - - design: - for each row from end - perform back substitution - if near zero - use qh_divzero for division - if zero divide and not last row - set tail of normal to 0 -*/ -void qh_backnormal(realT **rows, int numrow, int numcol, boolT sign, - coordT *normal, boolT *nearzero) { - int i, j; - coordT *normalp, *normal_tail, *ai, *ak; - realT diagonal; - boolT waszero; - int zerocol= -1; - - normalp= normal + numcol - 1; - *normalp--= (sign ? -1.0 : 1.0); - for (i=numrow; i--; ) { - *normalp= 0.0; - ai= rows[i] + i + 1; - ak= normalp+1; - for (j=i+1; j < numcol; j++) - *normalp -= *ai++ * *ak++; - diagonal= (rows[i])[i]; - if (fabs_(diagonal) > qh MINdenom_2) - *(normalp--) /= diagonal; - else { - waszero= False; - *normalp= qh_divzero(*normalp, diagonal, qh MINdenom_1_2, &waszero); - if (waszero) { - zerocol= i; - *(normalp--)= (sign ? -1.0 : 1.0); - for (normal_tail= normalp+2; normal_tail < normal + numcol; normal_tail++) - *normal_tail= 0.0; - }else - normalp--; - } - } - if (zerocol != -1) { - zzinc_(Zback0); - *nearzero= True; - trace4((qh ferr, 4005, "qh_backnormal: zero diagonal at column %d.\n", i)); - qh_precision("zero diagonal on back substitution"); - } -} /* backnormal */ - -/*-<a href="qh-geom.htm#TOC" - >-------------------------------</a><a name="gausselim">-</a> - - qh_gausselim( rows, numrow, numcol, sign ) - Gaussian elimination with partial pivoting - - returns: - rows is upper triangular (includes row exchanges) - flips sign for each row exchange - sets nearzero if pivot[k] < qh.NEARzero[k], else clears it - - notes: - if nearzero, the determinant's sign may be incorrect. - assumes numrow <= numcol - - design: - for each row - determine pivot and exchange rows if necessary - test for near zero - perform gaussian elimination step -*/ -void qh_gausselim(realT **rows, int numrow, int numcol, boolT *sign, boolT *nearzero) { - realT *ai, *ak, *rowp, *pivotrow; - realT n, pivot, pivot_abs= 0.0, temp; - int i, j, k, pivoti, flip=0; - - *nearzero= False; - for (k=0; k < numrow; k++) { - pivot_abs= fabs_((rows[k])[k]); - pivoti= k; - for (i=k+1; i < numrow; i++) { - if ((temp= fabs_((rows[i])[k])) > pivot_abs) { - pivot_abs= temp; - pivoti= i; - } - } - if (pivoti != k) { - rowp= rows[pivoti]; - rows[pivoti]= rows[k]; - rows[k]= rowp; - *sign ^= 1; - flip ^= 1; - } - if (pivot_abs <= qh NEARzero[k]) { - *nearzero= True; - if (pivot_abs == 0.0) { /* remainder of column == 0 */ - if (qh IStracing >= 4) { - qh_fprintf(qh ferr, 8011, "qh_gausselim: 0 pivot at column %d. (%2.2g < %2.2g)\n", k, pivot_abs, qh DISTround); - qh_printmatrix(qh ferr, "Matrix:", rows, numrow, numcol); - } - zzinc_(Zgauss0); - qh_precision("zero pivot for Gaussian elimination"); - goto LABELnextcol; - } - } - pivotrow= rows[k] + k; - pivot= *pivotrow++; /* signed value of pivot, and remainder of row */ - for (i=k+1; i < numrow; i++) { - ai= rows[i] + k; - ak= pivotrow; - n= (*ai++)/pivot; /* divzero() not needed since |pivot| >= |*ai| */ - for (j= numcol - (k+1); j--; ) - *ai++ -= n * *ak++; - } - LABELnextcol: - ; - } - wmin_(Wmindenom, pivot_abs); /* last pivot element */ - if (qh IStracing >= 5) - qh_printmatrix(qh ferr, "qh_gausselem: result", rows, numrow, numcol); -} /* gausselim */ - - -/*-<a href="qh-geom.htm#TOC" - >-------------------------------</a><a name="getangle">-</a> - - qh_getangle( vect1, vect2 ) - returns the dot product of two vectors - if qh.RANDOMdist, joggles result - - notes: - the angle may be > 1.0 or < -1.0 because of roundoff errors - -*/ -realT qh_getangle(pointT *vect1, pointT *vect2) { - realT angle= 0, randr; - int k; - - for (k=qh hull_dim; k--; ) - angle += *vect1++ * *vect2++; - if (qh RANDOMdist) { - randr= qh_RANDOMint; - angle += (2.0 * randr / qh_RANDOMmax - 1.0) * - qh RANDOMfactor; - } - trace4((qh ferr, 4006, "qh_getangle: %2.2g\n", angle)); - return(angle); -} /* getangle */ - - -/*-<a href="qh-geom.htm#TOC" - >-------------------------------</a><a name="getcenter">-</a> - - qh_getcenter( vertices ) - returns arithmetic center of a set of vertices as a new point - - notes: - allocates point array for center -*/ -pointT *qh_getcenter(setT *vertices) { - int k; - pointT *center, *coord; - vertexT *vertex, **vertexp; - int count= qh_setsize(vertices); - - if (count < 2) { - qh_fprintf(qh ferr, 6003, "qhull internal error (qh_getcenter): not defined for %d points\n", count); - qh_errexit(qh_ERRqhull, NULL, NULL); - } - center= (pointT *)qh_memalloc(qh normal_size); - for (k=0; k < qh hull_dim; k++) { - coord= center+k; - *coord= 0.0; - FOREACHvertex_(vertices) - *coord += vertex->point[k]; - *coord /= count; - } - return(center); -} /* getcenter */ - - -/*-<a href="qh-geom.htm#TOC" - >-------------------------------</a><a name="getcentrum">-</a> - - qh_getcentrum( facet ) - returns the centrum for a facet as a new point - - notes: - allocates the centrum -*/ -pointT *qh_getcentrum(facetT *facet) { - realT dist; - pointT *centrum, *point; - - point= qh_getcenter(facet->vertices); - zzinc_(Zcentrumtests); - qh_distplane(point, facet, &dist); - centrum= qh_projectpoint(point, facet, dist); - qh_memfree(point, qh normal_size); - trace4((qh ferr, 4007, "qh_getcentrum: for f%d, %d vertices dist= %2.2g\n", - facet->id, qh_setsize(facet->vertices), dist)); - return centrum; -} /* getcentrum */ - - -/*-<a href="qh-geom.htm#TOC" - >-------------------------------</a><a name="getdistance">-</a> - - qh_getdistance( facet, neighbor, mindist, maxdist ) - returns the maxdist and mindist distance of any vertex from neighbor - - returns: - the max absolute value - - design: - for each vertex of facet that is not in neighbor - test the distance from vertex to neighbor -*/ -realT qh_getdistance(facetT *facet, facetT *neighbor, realT *mindist, realT *maxdist) { - vertexT *vertex, **vertexp; - realT dist, maxd, mind; - - FOREACHvertex_(facet->vertices) - vertex->seen= False; - FOREACHvertex_(neighbor->vertices) - vertex->seen= True; - mind= 0.0; - maxd= 0.0; - FOREACHvertex_(facet->vertices) { - if (!vertex->seen) { - zzinc_(Zbestdist); - qh_distplane(vertex->point, neighbor, &dist); - if (dist < mind) - mind= dist; - else if (dist > maxd) - maxd= dist; - } - } - *mindist= mind; - *maxdist= maxd; - mind= -mind; - if (maxd > mind) - return maxd; - else - return mind; -} /* getdistance */ - - -/*-<a href="qh-geom.htm#TOC" - >-------------------------------</a><a name="normalize">-</a> - - qh_normalize( normal, dim, toporient ) - normalize a vector and report if too small - does not use min norm - - see: - qh_normalize2 -*/ -void qh_normalize(coordT *normal, int dim, boolT toporient) { - qh_normalize2( normal, dim, toporient, NULL, NULL); -} /* normalize */ - -/*-<a href="qh-geom.htm#TOC" - >-------------------------------</a><a name="normalize2">-</a> - - qh_normalize2( normal, dim, toporient, minnorm, ismin ) - normalize a vector and report if too small - qh.MINdenom/MINdenom1 are the upper limits for divide overflow - - returns: - normalized vector - flips sign if !toporient - if minnorm non-NULL, - sets ismin if normal < minnorm - - notes: - if zero norm - sets all elements to sqrt(1.0/dim) - if divide by zero (divzero()) - sets largest element to +/-1 - bumps Znearlysingular - - design: - computes norm - test for minnorm - if not near zero - normalizes normal - else if zero norm - sets normal to standard value - else - uses qh_divzero to normalize - if nearzero - sets norm to direction of maximum value -*/ -void qh_normalize2 (coordT *normal, int dim, boolT toporient, - realT *minnorm, boolT *ismin) { - int k; - realT *colp, *maxp, norm= 0, temp, *norm1, *norm2, *norm3; - boolT zerodiv; - - norm1= normal+1; - norm2= normal+2; - norm3= normal+3; - if (dim == 2) - norm= sqrt((*normal)*(*normal) + (*norm1)*(*norm1)); - else if (dim == 3) - norm= sqrt((*normal)*(*normal) + (*norm1)*(*norm1) + (*norm2)*(*norm2)); - else if (dim == 4) { - norm= sqrt((*normal)*(*normal) + (*norm1)*(*norm1) + (*norm2)*(*norm2) - + (*norm3)*(*norm3)); - }else if (dim > 4) { - norm= (*normal)*(*normal) + (*norm1)*(*norm1) + (*norm2)*(*norm2) - + (*norm3)*(*norm3); - for (k=dim-4, colp=normal+4; k--; colp++) - norm += (*colp) * (*colp); - norm= sqrt(norm); - } - if (minnorm) { - if (norm < *minnorm) - *ismin= True; - else - *ismin= False; - } - wmin_(Wmindenom, norm); - if (norm > qh MINdenom) { - if (!toporient) - norm= -norm; - *normal /= norm; - *norm1 /= norm; - if (dim == 2) - ; /* all done */ - else if (dim == 3) - *norm2 /= norm; - else if (dim == 4) { - *norm2 /= norm; - *norm3 /= norm; - }else if (dim >4) { - *norm2 /= norm; - *norm3 /= norm; - for (k=dim-4, colp=normal+4; k--; ) - *colp++ /= norm; - } - }else if (norm == 0.0) { - temp= sqrt(1.0/dim); - for (k=dim, colp=normal; k--; ) - *colp++ = temp; - }else { - if (!toporient) - norm= -norm; - for (k=dim, colp=normal; k--; colp++) { /* k used below */ - temp= qh_divzero(*colp, norm, qh MINdenom_1, &zerodiv); - if (!zerodiv) - *colp= temp; - else { - maxp= qh_maxabsval(normal, dim); - temp= ((*maxp * norm >= 0.0) ? 1.0 : -1.0); - for (k=dim, colp=normal; k--; colp++) - *colp= 0.0; - *maxp= temp; - zzinc_(Znearlysingular); - trace0((qh ferr, 1, "qh_normalize: norm=%2.2g too small during p%d\n", - norm, qh furthest_id)); - return; - } - } - } -} /* normalize */ - - -/*-<a href="qh-geom.htm#TOC" - >-------------------------------</a><a name="projectpoint">-</a> - - qh_projectpoint( point, facet, dist ) - project point onto a facet by dist - - returns: - returns a new point - - notes: - if dist= distplane(point,facet) - this projects point to hyperplane - assumes qh_memfree_() is valid for normal_size -*/ -pointT *qh_projectpoint(pointT *point, facetT *facet, realT dist) { - pointT *newpoint, *np, *normal; - int normsize= qh normal_size; - int k; - void **freelistp; /* used !qh_NOmem */ - - qh_memalloc_(normsize, freelistp, newpoint, pointT); - np= newpoint; - normal= facet->normal; - for (k=qh hull_dim; k--; ) - *(np++)= *point++ - dist * *normal++; - return(newpoint); -} /* projectpoint */ - - -/*-<a href="qh-geom.htm#TOC" - >-------------------------------</a><a name="setfacetplane">-</a> - - qh_setfacetplane( facet ) - sets the hyperplane for a facet - if qh.RANDOMdist, joggles hyperplane - - notes: - uses global buffers qh.gm_matrix and qh.gm_row - overwrites facet->normal if already defined - updates Wnewvertex if PRINTstatistics - sets facet->upperdelaunay if upper envelope of Delaunay triangulation - - design: - copy vertex coordinates to qh.gm_matrix/gm_row - compute determinate - if nearzero - recompute determinate with gaussian elimination - if nearzero - force outside orientation by testing interior point -*/ -void qh_setfacetplane(facetT *facet) { - pointT *point; - vertexT *vertex, **vertexp; - int normsize= qh normal_size; - int k,i, oldtrace= 0; - realT dist; - void **freelistp; /* used !qh_NOmem */ - coordT *coord, *gmcoord; - pointT *point0= SETfirstt_(facet->vertices, vertexT)->point; - boolT nearzero= False; - - zzinc_(Zsetplane); - if (!facet->normal) - qh_memalloc_(normsize, freelistp, facet->normal, coordT); - if (facet == qh tracefacet) { - oldtrace= qh IStracing; - qh IStracing= 5; - qh_fprintf(qh ferr, 8012, "qh_setfacetplane: facet f%d created.\n", facet->id); - qh_fprintf(qh ferr, 8013, " Last point added to hull was p%d.", qh furthest_id); - if (zzval_(Ztotmerge)) - qh_fprintf(qh ferr, 8014, " Last merge was #%d.", zzval_(Ztotmerge)); - qh_fprintf(qh ferr, 8015, "\n\nCurrent summary is:\n"); - qh_printsummary(qh ferr); - } - if (qh hull_dim <= 4) { - i= 0; - if (qh RANDOMdist) { - gmcoord= qh gm_matrix; - FOREACHvertex_(facet->vertices) { - qh gm_row[i++]= gmcoord; - coord= vertex->point; - for (k=qh hull_dim; k--; ) - *(gmcoord++)= *coord++ * qh_randomfactor(qh RANDOMa, qh RANDOMb); - } - }else { - FOREACHvertex_(facet->vertices) - qh gm_row[i++]= vertex->point; - } - qh_sethyperplane_det(qh hull_dim, qh gm_row, point0, facet->toporient, - facet->normal, &facet->offset, &nearzero); - } - if (qh hull_dim > 4 || nearzero) { - i= 0; - gmcoord= qh gm_matrix; - FOREACHvertex_(facet->vertices) { - if (vertex->point != point0) { - qh gm_row[i++]= gmcoord; - coord= vertex->point; - point= point0; - for (k=qh hull_dim; k--; ) - *(gmcoord++)= *coord++ - *point++; - } - } - qh gm_row[i]= gmcoord; /* for areasimplex */ - if (qh RANDOMdist) { - gmcoord= qh gm_matrix; - for (i=qh hull_dim-1; i--; ) { - for (k=qh hull_dim; k--; ) - *(gmcoord++) *= qh_randomfactor(qh RANDOMa, qh RANDOMb); - } - } - qh_sethyperplane_gauss(qh hull_dim, qh gm_row, point0, facet->toporient, - facet->normal, &facet->offset, &nearzero); - if (nearzero) { - if (qh_orientoutside(facet)) { - trace0((qh ferr, 2, "qh_setfacetplane: flipped orientation after testing interior_point during p%d\n", qh furthest_id)); - /* this is part of using Gaussian Elimination. For example in 5-d - 1 1 1 1 0 - 1 1 1 1 1 - 0 0 0 1 0 - 0 1 0 0 0 - 1 0 0 0 0 - norm= 0.38 0.38 -0.76 0.38 0 - has a determinate of 1, but g.e. after subtracting pt. 0 has - 0's in the diagonal, even with full pivoting. It does work - if you subtract pt. 4 instead. */ - } - } - } - facet->upperdelaunay= False; - if (qh DELAUNAY) { - if (qh UPPERdelaunay) { /* matches qh_triangulate_facet and qh.lower_threshold in qh_initbuild */ - if (facet->normal[qh hull_dim -1] >= qh ANGLEround * qh_ZEROdelaunay) - facet->upperdelaunay= True; - }else { - if (facet->normal[qh hull_dim -1] > -qh ANGLEround * qh_ZEROdelaunay) - facet->upperdelaunay= True; - } - } - if (qh PRINTstatistics || qh IStracing || qh TRACElevel || qh JOGGLEmax < REALmax) { - qh old_randomdist= qh RANDOMdist; - qh RANDOMdist= False; - FOREACHvertex_(facet->vertices) { - if (vertex->point != point0) { - boolT istrace= False; - zinc_(Zdiststat); - qh_distplane(vertex->point, facet, &dist); - dist= fabs_(dist); - zinc_(Znewvertex); - wadd_(Wnewvertex, dist); - if (dist > wwval_(Wnewvertexmax)) { - wwval_(Wnewvertexmax)= dist; - if (dist > qh max_outside) { - qh max_outside= dist; /* used by qh_maxouter() */ - if (dist > qh TRACEdist) - istrace= True; - } - }else if (-dist > qh TRACEdist) - istrace= True; - if (istrace) { - qh_fprintf(qh ferr, 8016, "qh_setfacetplane: ====== vertex p%d(v%d) increases max_outside to %2.2g for new facet f%d last p%d\n", - qh_pointid(vertex->point), vertex->id, dist, facet->id, qh furthest_id); - qh_errprint("DISTANT", facet, NULL, NULL, NULL); - } - } - } - qh RANDOMdist= qh old_randomdist; - } - if (qh IStracing >= 3) { - qh_fprintf(qh ferr, 8017, "qh_setfacetplane: f%d offset %2.2g normal: ", - facet->id, facet->offset); - for (k=0; k < qh hull_dim; k++) - qh_fprintf(qh ferr, 8018, "%2.2g ", facet->normal[k]); - qh_fprintf(qh ferr, 8019, "\n"); - } - if (facet == qh tracefacet) - qh IStracing= oldtrace; -} /* setfacetplane */ - - -/*-<a href="qh-geom.htm#TOC" - >-------------------------------</a><a name="sethyperplane_det">-</a> - - qh_sethyperplane_det( dim, rows, point0, toporient, normal, offset, nearzero ) - given dim X dim array indexed by rows[], one row per point, - toporient(flips all signs), - and point0 (any row) - set normalized hyperplane equation from oriented simplex - - returns: - normal (normalized) - offset (places point0 on the hyperplane) - sets nearzero if hyperplane not through points - - notes: - only defined for dim == 2..4 - rows[] is not modified - solves det(P-V_0, V_n-V_0, ..., V_1-V_0)=0, i.e. every point is on hyperplane - see Bower & Woodworth, A programmer's geometry, Butterworths 1983. - - derivation of 3-d minnorm - Goal: all vertices V_i within qh.one_merge of hyperplane - Plan: exactly translate the facet so that V_0 is the origin - exactly rotate the facet so that V_1 is on the x-axis and y_2=0. - exactly rotate the effective perturbation to only effect n_0 - this introduces a factor of sqrt(3) - n_0 = ((y_2-y_0)*(z_1-z_0) - (z_2-z_0)*(y_1-y_0)) / norm - Let M_d be the max coordinate difference - Let M_a be the greater of M_d and the max abs. coordinate - Let u be machine roundoff and distround be max error for distance computation - The max error for n_0 is sqrt(3) u M_a M_d / norm. n_1 is approx. 1 and n_2 is approx. 0 - The max error for distance of V_1 is sqrt(3) u M_a M_d M_d / norm. Offset=0 at origin - Then minnorm = 1.8 u M_a M_d M_d / qh.ONEmerge - Note that qh.one_merge is approx. 45.5 u M_a and norm is usually about M_d M_d - - derivation of 4-d minnorm - same as above except rotate the facet so that V_1 on x-axis and w_2, y_3, w_3=0 - [if two vertices fixed on x-axis, can rotate the other two in yzw.] - n_0 = det3_(...) = y_2 det2_(z_1, w_1, z_3, w_3) = - y_2 w_1 z_3 - [all other terms contain at least two factors nearly zero.] - The max error for n_0 is sqrt(4) u M_a M_d M_d / norm - Then minnorm = 2 u M_a M_d M_d M_d / qh.ONEmerge - Note that qh.one_merge is approx. 82 u M_a and norm is usually about M_d M_d M_d -*/ -void qh_sethyperplane_det(int dim, coordT **rows, coordT *point0, - boolT toporient, coordT *normal, realT *offset, boolT *nearzero) { - realT maxround, dist; - int i; - pointT *point; - - - if (dim == 2) { - normal[0]= dY(1,0); - normal[1]= dX(0,1); - qh_normalize2 (normal, dim, toporient, NULL, NULL); - *offset= -(point0[0]*normal[0]+point0[1]*normal[1]); - *nearzero= False; /* since nearzero norm => incident points */ - }else if (dim == 3) { - normal[0]= det2_(dY(2,0), dZ(2,0), - dY(1,0), dZ(1,0)); - normal[1]= det2_(dX(1,0), dZ(1,0), - dX(2,0), dZ(2,0)); - normal[2]= det2_(dX(2,0), dY(2,0), - dX(1,0), dY(1,0)); - qh_normalize2 (normal, dim, toporient, NULL, NULL); - *offset= -(point0[0]*normal[0] + point0[1]*normal[1] - + point0[2]*normal[2]); - maxround= qh DISTround; - for (i=dim; i--; ) { - point= rows[i]; - if (point != point0) { - dist= *offset + (point[0]*normal[0] + point[1]*normal[1] - + point[2]*normal[2]); - if (dist > maxround || dist < -maxround) { - *nearzero= True; - break; - } - } - } - }else if (dim == 4) { - normal[0]= - det3_(dY(2,0), dZ(2,0), dW(2,0), - dY(1,0), dZ(1,0), dW(1,0), - dY(3,0), dZ(3,0), dW(3,0)); - normal[1]= det3_(dX(2,0), dZ(2,0), dW(2,0), - dX(1,0), dZ(1,0), dW(1,0), - dX(3,0), dZ(3,0), dW(3,0)); - normal[2]= - det3_(dX(2,0), dY(2,0), dW(2,0), - dX(1,0), dY(1,0), dW(1,0), - dX(3,0), dY(3,0), dW(3,0)); - normal[3]= det3_(dX(2,0), dY(2,0), dZ(2,0), - dX(1,0), dY(1,0), dZ(1,0), - dX(3,0), dY(3,0), dZ(3,0)); - qh_normalize2 (normal, dim, toporient, NULL, NULL); - *offset= -(point0[0]*normal[0] + point0[1]*normal[1] - + point0[2]*normal[2] + point0[3]*normal[3]); - maxround= qh DISTround; - for (i=dim; i--; ) { - point= rows[i]; - if (point != point0) { - dist= *offset + (point[0]*normal[0] + point[1]*normal[1] - + point[2]*normal[2] + point[3]*normal[3]); - if (dist > maxround || dist < -maxround) { - *nearzero= True; - break; - } - } - } - } - if (*nearzero) { - zzinc_(Zminnorm); - trace0((qh ferr, 3, "qh_sethyperplane_det: degenerate norm during p%d.\n", qh furthest_id)); - zzinc_(Znearlysingular); - } -} /* sethyperplane_det */ - - -/*-<a href="qh-geom.htm#TOC" - >-------------------------------</a><a name="sethyperplane_gauss">-</a> - - qh_sethyperplane_gauss( dim, rows, point0, toporient, normal, offset, nearzero ) - given(dim-1) X dim array of rows[i]= V_{i+1} - V_0 (point0) - set normalized hyperplane equation from oriented simplex - - returns: - normal (normalized) - offset (places point0 on the hyperplane) - - notes: - if nearzero - orientation may be incorrect because of incorrect sign flips in gausselim - solves [V_n-V_0,...,V_1-V_0, 0 .. 0 1] * N == [0 .. 0 1] - or [V_n-V_0,...,V_1-V_0, 0 .. 0 1] * N == [0] - i.e., N is normal to the hyperplane, and the unnormalized - distance to [0 .. 1] is either 1 or 0 - - design: - perform gaussian elimination - flip sign for negative values - perform back substitution - normalize result - compute offset -*/ -void qh_sethyperplane_gauss(int dim, coordT **rows, pointT *point0, - boolT toporient, coordT *normal, coordT *offset, boolT *nearzero) { - coordT *pointcoord, *normalcoef; - int k; - boolT sign= toporient, nearzero2= False; - - qh_gausselim(rows, dim-1, dim, &sign, nearzero); - for (k=dim-1; k--; ) { - if ((rows[k])[k] < 0) - sign ^= 1; - } - if (*nearzero) { - zzinc_(Znearlysingular); - trace0((qh ferr, 4, "qh_sethyperplane_gauss: nearly singular or axis parallel hyperplane during p%d.\n", qh furthest_id)); - qh_backnormal(rows, dim-1, dim, sign, normal, &nearzero2); - }else { - qh_backnormal(rows, dim-1, dim, sign, normal, &nearzero2); - if (nearzero2) { - zzinc_(Znearlysingular); - trace0((qh ferr, 5, "qh_sethyperplane_gauss: singular or axis parallel hyperplane at normalization during p%d.\n", qh furthest_id)); - } - } - if (nearzero2) - *nearzero= True; - qh_normalize2(normal, dim, True, NULL, NULL); - pointcoord= point0; - normalcoef= normal; - *offset= -(*pointcoord++ * *normalcoef++); - for (k=dim-1; k--; ) - *offset -= *pointcoord++ * *normalcoef++; -} /* sethyperplane_gauss */ - - - diff --git a/PyMca/Object3D/Object3DQhull/src/geom.h b/PyMca/Object3D/Object3DQhull/src/geom.h deleted file mode 100644 index c85049b..0000000 --- a/PyMca/Object3D/Object3DQhull/src/geom.h +++ /dev/null @@ -1,176 +0,0 @@ -/*<html><pre> -<a href="qh-geom.htm" - >-------------------------------</a><a name="TOP">-</a> - - geom.h - header file for geometric routines - - see qh-geom.htm and geom.c - - Copyright (c) 1993-2012 The Geometry Center. - $Id: //main/2011/qhull/src/libqhull/geom.h#3 $$Change: 1464 $ - $DateTime: 2012/01/25 22:58:41 $$Author: bbarber $ -*/ - -#ifndef qhDEFgeom -#define qhDEFgeom 1 - -#include "libqhull.h" - -/* ============ -macros- ======================== */ - -/*-<a href="qh-geom.htm#TOC" - >--------------------------------</a><a name="fabs_">-</a> - - fabs_(a) - returns the absolute value of a -*/ -#define fabs_( a ) ((( a ) < 0 ) ? -( a ):( a )) - -/*-<a href="qh-geom.htm#TOC" - >--------------------------------</a><a name="fmax_">-</a> - - fmax_(a,b) - returns the maximum value of a and b -*/ -#define fmax_( a,b ) ( ( a ) < ( b ) ? ( b ) : ( a ) ) - -/*-<a href="qh-geom.htm#TOC" - >--------------------------------</a><a name="fmin_">-</a> - - fmin_(a,b) - returns the minimum value of a and b -*/ -#define fmin_( a,b ) ( ( a ) > ( b ) ? ( b ) : ( a ) ) - -/*-<a href="qh-geom.htm#TOC" - >--------------------------------</a><a name="maximize_">-</a> - - maximize_(maxval, val) - set maxval to val if val is greater than maxval -*/ -#define maximize_( maxval, val ) { if (( maxval ) < ( val )) ( maxval )= ( val ); } - -/*-<a href="qh-geom.htm#TOC" - >--------------------------------</a><a name="minimize_">-</a> - - minimize_(minval, val) - set minval to val if val is less than minval -*/ -#define minimize_( minval, val ) { if (( minval ) > ( val )) ( minval )= ( val ); } - -/*-<a href="qh-geom.htm#TOC" - >--------------------------------</a><a name="det2_">-</a> - - det2_(a1, a2, - b1, b2) - - compute a 2-d determinate -*/ -#define det2_( a1,a2,b1,b2 ) (( a1 )*( b2 ) - ( a2 )*( b1 )) - -/*-<a href="qh-geom.htm#TOC" - >--------------------------------</a><a name="det3_">-</a> - - det3_(a1, a2, a3, - b1, b2, b3, - c1, c2, c3) - - compute a 3-d determinate -*/ -#define det3_( a1,a2,a3,b1,b2,b3,c1,c2,c3 ) ( ( a1 )*det2_( b2,b3,c2,c3 ) \ - - ( b1 )*det2_( a2,a3,c2,c3 ) + ( c1 )*det2_( a2,a3,b2,b3 ) ) - -/*-<a href="qh-geom.htm#TOC" - >--------------------------------</a><a name="dX">-</a> - - dX( p1, p2 ) - dY( p1, p2 ) - dZ( p1, p2 ) - - given two indices into rows[], - - compute the difference between X, Y, or Z coordinates -*/ -#define dX( p1,p2 ) ( *( rows[p1] ) - *( rows[p2] )) -#define dY( p1,p2 ) ( *( rows[p1]+1 ) - *( rows[p2]+1 )) -#define dZ( p1,p2 ) ( *( rows[p1]+2 ) - *( rows[p2]+2 )) -#define dW( p1,p2 ) ( *( rows[p1]+3 ) - *( rows[p2]+3 )) - -/*============= prototypes in alphabetical order, infrequent at end ======= */ - -void qh_backnormal(realT **rows, int numrow, int numcol, boolT sign, coordT *normal, boolT *nearzero); -void qh_distplane(pointT *point, facetT *facet, realT *dist); -facetT *qh_findbest(pointT *point, facetT *startfacet, - boolT bestoutside, boolT isnewfacets, boolT noupper, - realT *dist, boolT *isoutside, int *numpart); -facetT *qh_findbesthorizon(boolT ischeckmax, pointT *point, - facetT *startfacet, boolT noupper, realT *bestdist, int *numpart); -facetT *qh_findbestnew(pointT *point, facetT *startfacet, realT *dist, - boolT bestoutside, boolT *isoutside, int *numpart); -void qh_gausselim(realT **rows, int numrow, int numcol, boolT *sign, boolT *nearzero); -realT qh_getangle(pointT *vect1, pointT *vect2); -pointT *qh_getcenter(setT *vertices); -pointT *qh_getcentrum(facetT *facet); -realT qh_getdistance(facetT *facet, facetT *neighbor, realT *mindist, realT *maxdist); -void qh_normalize(coordT *normal, int dim, boolT toporient); -void qh_normalize2 (coordT *normal, int dim, boolT toporient, - realT *minnorm, boolT *ismin); -pointT *qh_projectpoint(pointT *point, facetT *facet, realT dist); - -void qh_setfacetplane(facetT *newfacets); -void qh_sethyperplane_det(int dim, coordT **rows, coordT *point0, - boolT toporient, coordT *normal, realT *offset, boolT *nearzero); -void qh_sethyperplane_gauss(int dim, coordT **rows, pointT *point0, - boolT toporient, coordT *normal, coordT *offset, boolT *nearzero); -boolT qh_sharpnewfacets(void); - -/*========= infrequently used code in geom2.c =============*/ - -coordT *qh_copypoints(coordT *points, int numpoints, int dimension); -void qh_crossproduct(int dim, realT vecA[3], realT vecB[3], realT vecC[3]); -realT qh_determinant(realT **rows, int dim, boolT *nearzero); -realT qh_detjoggle(pointT *points, int numpoints, int dimension); -void qh_detroundoff(void); -realT qh_detsimplex(pointT *apex, setT *points, int dim, boolT *nearzero); -realT qh_distnorm(int dim, pointT *point, pointT *normal, realT *offsetp); -realT qh_distround(int dimension, realT maxabs, realT maxsumabs); -realT qh_divzero(realT numer, realT denom, realT mindenom1, boolT *zerodiv); -realT qh_facetarea(facetT *facet); -realT qh_facetarea_simplex(int dim, coordT *apex, setT *vertices, - vertexT *notvertex, boolT toporient, coordT *normal, realT *offset); -pointT *qh_facetcenter(setT *vertices); -facetT *qh_findgooddist(pointT *point, facetT *facetA, realT *distp, facetT **facetlist); -void qh_getarea(facetT *facetlist); -boolT qh_gram_schmidt(int dim, realT **rows); -boolT qh_inthresholds(coordT *normal, realT *angle); -void qh_joggleinput(void); -realT *qh_maxabsval(realT *normal, int dim); -setT *qh_maxmin(pointT *points, int numpoints, int dimension); -realT qh_maxouter(void); -void qh_maxsimplex(int dim, setT *maxpoints, pointT *points, int numpoints, setT **simplex); -realT qh_minabsval(realT *normal, int dim); -int qh_mindiff(realT *vecA, realT *vecB, int dim); -boolT qh_orientoutside(facetT *facet); -void qh_outerinner(facetT *facet, realT *outerplane, realT *innerplane); -coordT qh_pointdist(pointT *point1, pointT *point2, int dim); -void qh_printmatrix(FILE *fp, const char *string, realT **rows, int numrow, int numcol); -void qh_printpoints(FILE *fp, const char *string, setT *points); -void qh_projectinput(void); -void qh_projectpoints(signed char *project, int n, realT *points, - int numpoints, int dim, realT *newpoints, int newdim); -void qh_rotateinput(realT **rows); -void qh_rotatepoints(realT *points, int numpoints, int dim, realT **rows); -void qh_scaleinput(void); -void qh_scalelast(coordT *points, int numpoints, int dim, coordT low, - coordT high, coordT newhigh); -void qh_scalepoints(pointT *points, int numpoints, int dim, - realT *newlows, realT *newhighs); -boolT qh_sethalfspace(int dim, coordT *coords, coordT **nextp, - coordT *normal, coordT *offset, coordT *feasible); -coordT *qh_sethalfspace_all(int dim, int count, coordT *halfspaces, pointT *feasible); -pointT *qh_voronoi_center(int dim, setT *points); - -#endif /* qhDEFgeom */ - - - diff --git a/PyMca/Object3D/Object3DQhull/src/geom2.c b/PyMca/Object3D/Object3DQhull/src/geom2.c deleted file mode 100644 index a78a1cb..0000000 --- a/PyMca/Object3D/Object3DQhull/src/geom2.c +++ /dev/null @@ -1,2081 +0,0 @@ -/*<html><pre> -<a href="qh-geom.htm" - >-------------------------------</a><a name="TOP">-</a> - - - geom2.c - infrequently used geometric routines of qhull - - see qh-geom.htm and geom.h - - Copyright (c) 1993-2012 The Geometry Center. - $Id: //main/2011/qhull/src/libqhull/geom2.c#3 $$Change: 1464 $ - $DateTime: 2012/01/25 22:58:41 $$Author: bbarber $ - - frequently used code goes into geom.c -*/ - -#include "qhull_a.h" - -/*================== functions in alphabetic order ============*/ - -/*-<a href="qh-geom.htm#TOC" - >-------------------------------</a><a name="copypoints">-</a> - - qh_copypoints( points, numpoints, dimension) - return qh_malloc'd copy of points -*/ -coordT *qh_copypoints(coordT *points, int numpoints, int dimension) { - int size; - coordT *newpoints; - - size= numpoints * dimension * (int)sizeof(coordT); - if (!(newpoints=(coordT*)qh_malloc((size_t)size))) { - qh_fprintf(qh ferr, 6004, "qhull error: insufficient memory to copy %d points\n", - numpoints); - qh_errexit(qh_ERRmem, NULL, NULL); - } - memcpy((char *)newpoints, (char *)points, (size_t)size); - return newpoints; -} /* copypoints */ - -/*-<a href="qh-geom.htm#TOC" - >-------------------------------</a><a name="crossproduct">-</a> - - qh_crossproduct( dim, vecA, vecB, vecC ) - crossproduct of 2 dim vectors - C= A x B - - notes: - from Glasner, Graphics Gems I, p. 639 - only defined for dim==3 -*/ -void qh_crossproduct(int dim, realT vecA[3], realT vecB[3], realT vecC[3]){ - - if (dim == 3) { - vecC[0]= det2_(vecA[1], vecA[2], - vecB[1], vecB[2]); - vecC[1]= - det2_(vecA[0], vecA[2], - vecB[0], vecB[2]); - vecC[2]= det2_(vecA[0], vecA[1], - vecB[0], vecB[1]); - } -} /* vcross */ - -/*-<a href="qh-geom.htm#TOC" - >-------------------------------</a><a name="determinant">-</a> - - qh_determinant( rows, dim, nearzero ) - compute signed determinant of a square matrix - uses qh.NEARzero to test for degenerate matrices - - returns: - determinant - overwrites rows and the matrix - if dim == 2 or 3 - nearzero iff determinant < qh NEARzero[dim-1] - (!quite correct, not critical) - if dim >= 4 - nearzero iff diagonal[k] < qh NEARzero[k] -*/ -realT qh_determinant(realT **rows, int dim, boolT *nearzero) { - realT det=0; - int i; - boolT sign= False; - - *nearzero= False; - if (dim < 2) { - qh_fprintf(qh ferr, 6005, "qhull internal error (qh_determinate): only implemented for dimension >= 2\n"); - qh_errexit(qh_ERRqhull, NULL, NULL); - }else if (dim == 2) { - det= det2_(rows[0][0], rows[0][1], - rows[1][0], rows[1][1]); - if (fabs_(det) < qh NEARzero[1]) /* not really correct, what should this be? */ - *nearzero= True; - }else if (dim == 3) { - det= det3_(rows[0][0], rows[0][1], rows[0][2], - rows[1][0], rows[1][1], rows[1][2], - rows[2][0], rows[2][1], rows[2][2]); - if (fabs_(det) < qh NEARzero[2]) /* not really correct, what should this be? */ - *nearzero= True; - }else { - qh_gausselim(rows, dim, dim, &sign, nearzero); /* if nearzero, diagonal still ok*/ - det= 1.0; - for (i=dim; i--; ) - det *= (rows[i])[i]; - if (sign) - det= -det; - } - return det; -} /* determinant */ - -/*-<a href="qh-geom.htm#TOC" - >-------------------------------</a><a name="detjoggle">-</a> - - qh_detjoggle( points, numpoints, dimension ) - determine default max joggle for point array - as qh_distround * qh_JOGGLEdefault - - returns: - initial value for JOGGLEmax from points and REALepsilon - - notes: - computes DISTround since qh_maxmin not called yet - if qh SCALElast, last dimension will be scaled later to MAXwidth - - loop duplicated from qh_maxmin -*/ -realT qh_detjoggle(pointT *points, int numpoints, int dimension) { - realT abscoord, distround, joggle, maxcoord, mincoord; - pointT *point, *pointtemp; - realT maxabs= -REALmax; - realT sumabs= 0; - realT maxwidth= 0; - int k; - - for (k=0; k < dimension; k++) { - if (qh SCALElast && k == dimension-1) - abscoord= maxwidth; - else if (qh DELAUNAY && k == dimension-1) /* will qh_setdelaunay() */ - abscoord= 2 * maxabs * maxabs; /* may be low by qh hull_dim/2 */ - else { - maxcoord= -REALmax; - mincoord= REALmax; - FORALLpoint_(points, numpoints) { - maximize_(maxcoord, point[k]); - minimize_(mincoord, point[k]); - } - maximize_(maxwidth, maxcoord-mincoord); - abscoord= fmax_(maxcoord, -mincoord); - } - sumabs += abscoord; - maximize_(maxabs, abscoord); - } /* for k */ - distround= qh_distround(qh hull_dim, maxabs, sumabs); - joggle= distround * qh_JOGGLEdefault; - maximize_(joggle, REALepsilon * qh_JOGGLEdefault); - trace2((qh ferr, 2001, "qh_detjoggle: joggle=%2.2g maxwidth=%2.2g\n", joggle, maxwidth)); - return joggle; -} /* detjoggle */ - -/*-<a href="qh-geom.htm#TOC" - >-------------------------------</a><a name="detroundoff">-</a> - - qh_detroundoff() - determine maximum roundoff errors from - REALepsilon, REALmax, REALmin, qh.hull_dim, qh.MAXabs_coord, - qh.MAXsumcoord, qh.MAXwidth, qh.MINdenom_1 - - accounts for qh.SETroundoff, qh.RANDOMdist, qh MERGEexact - qh.premerge_cos, qh.postmerge_cos, qh.premerge_centrum, - qh.postmerge_centrum, qh.MINoutside, - qh_RATIOnearinside, qh_COPLANARratio, qh_WIDEcoplanar - - returns: - sets qh.DISTround, etc. (see below) - appends precision constants to qh.qhull_options - - see: - qh_maxmin() for qh.NEARzero - - design: - determine qh.DISTround for distance computations - determine minimum denominators for qh_divzero - determine qh.ANGLEround for angle computations - adjust qh.premerge_cos,... for roundoff error - determine qh.ONEmerge for maximum error due to a single merge - determine qh.NEARinside, qh.MAXcoplanar, qh.MINvisible, - qh.MINoutside, qh.WIDEfacet - initialize qh.max_vertex and qh.minvertex -*/ -void qh_detroundoff(void) { - - qh_option("_max-width", NULL, &qh MAXwidth); - if (!qh SETroundoff) { - qh DISTround= qh_distround(qh hull_dim, qh MAXabs_coord, qh MAXsumcoord); - if (qh RANDOMdist) - qh DISTround += qh RANDOMfactor * qh MAXabs_coord; - qh_option("Error-roundoff", NULL, &qh DISTround); - } - qh MINdenom= qh MINdenom_1 * qh MAXabs_coord; - qh MINdenom_1_2= sqrt(qh MINdenom_1 * qh hull_dim) ; /* if will be normalized */ - qh MINdenom_2= qh MINdenom_1_2 * qh MAXabs_coord; - /* for inner product */ - qh ANGLEround= 1.01 * qh hull_dim * REALepsilon; - if (qh RANDOMdist) - qh ANGLEround += qh RANDOMfactor; - if (qh premerge_cos < REALmax/2) { - qh premerge_cos -= qh ANGLEround; - if (qh RANDOMdist) - qh_option("Angle-premerge-with-random", NULL, &qh premerge_cos); - } - if (qh postmerge_cos < REALmax/2) { - qh postmerge_cos -= qh ANGLEround; - if (qh RANDOMdist) - qh_option("Angle-postmerge-with-random", NULL, &qh postmerge_cos); - } - qh premerge_centrum += 2 * qh DISTround; /*2 for centrum and distplane()*/ - qh postmerge_centrum += 2 * qh DISTround; - if (qh RANDOMdist && (qh MERGEexact || qh PREmerge)) - qh_option("Centrum-premerge-with-random", NULL, &qh premerge_centrum); - if (qh RANDOMdist && qh POSTmerge) - qh_option("Centrum-postmerge-with-random", NULL, &qh postmerge_centrum); - { /* compute ONEmerge, max vertex offset for merging simplicial facets */ - realT maxangle= 1.0, maxrho; - - minimize_(maxangle, qh premerge_cos); - minimize_(maxangle, qh postmerge_cos); - /* max diameter * sin theta + DISTround for vertex to its hyperplane */ - qh ONEmerge= sqrt((realT)qh hull_dim) * qh MAXwidth * - sqrt(1.0 - maxangle * maxangle) + qh DISTround; - maxrho= qh hull_dim * qh premerge_centrum + qh DISTround; - maximize_(qh ONEmerge, maxrho); - maxrho= qh hull_dim * qh postmerge_centrum + qh DISTround; - maximize_(qh ONEmerge, maxrho); - if (qh MERGING) - qh_option("_one-merge", NULL, &qh ONEmerge); - } - qh NEARinside= qh ONEmerge * qh_RATIOnearinside; /* only used if qh KEEPnearinside */ - if (qh JOGGLEmax < REALmax/2 && (qh KEEPcoplanar || qh KEEPinside)) { - realT maxdist; /* adjust qh.NEARinside for joggle */ - qh KEEPnearinside= True; - maxdist= sqrt((realT)qh hull_dim) * qh JOGGLEmax + qh DISTround; - maxdist= 2*maxdist; /* vertex and coplanar point can joggle in opposite directions */ - maximize_(qh NEARinside, maxdist); /* must agree with qh_nearcoplanar() */ - } - if (qh KEEPnearinside) - qh_option("_near-inside", NULL, &qh NEARinside); - if (qh JOGGLEmax < qh DISTround) { - qh_fprintf(qh ferr, 6006, "qhull error: the joggle for 'QJn', %.2g, is below roundoff for distance computations, %.2g\n", - qh JOGGLEmax, qh DISTround); - qh_errexit(qh_ERRinput, NULL, NULL); - } - if (qh MINvisible > REALmax/2) { - if (!qh MERGING) - qh MINvisible= qh DISTround; - else if (qh hull_dim <= 3) - qh MINvisible= qh premerge_centrum; - else - qh MINvisible= qh_COPLANARratio * qh premerge_centrum; - if (qh APPROXhull && qh MINvisible > qh MINoutside) - qh MINvisible= qh MINoutside; - qh_option("Visible-distance", NULL, &qh MINvisible); - } - if (qh MAXcoplanar > REALmax/2) { - qh MAXcoplanar= qh MINvisible; - qh_option("U-coplanar-distance", NULL, &qh MAXcoplanar); - } - if (!qh APPROXhull) { /* user may specify qh MINoutside */ - qh MINoutside= 2 * qh MINvisible; - if (qh premerge_cos < REALmax/2) - maximize_(qh MINoutside, (1- qh premerge_cos) * qh MAXabs_coord); - qh_option("Width-outside", NULL, &qh MINoutside); - } - qh WIDEfacet= qh MINoutside; - maximize_(qh WIDEfacet, qh_WIDEcoplanar * qh MAXcoplanar); - maximize_(qh WIDEfacet, qh_WIDEcoplanar * qh MINvisible); - qh_option("_wide-facet", NULL, &qh WIDEfacet); - if (qh MINvisible > qh MINoutside + 3 * REALepsilon - && !qh BESToutside && !qh FORCEoutput) - qh_fprintf(qh ferr, 7001, "qhull input warning: minimum visibility V%.2g is greater than \nminimum outside W%.2g. Flipped facets are likely.\n", - qh MINvisible, qh MINoutside); - qh max_vertex= qh DISTround; - qh min_vertex= -qh DISTround; - /* numeric constants reported in printsummary */ -} /* detroundoff */ - -/*-<a href="qh-geom.htm#TOC" - >-------------------------------</a><a name="detsimplex">-</a> - - qh_detsimplex( apex, points, dim, nearzero ) - compute determinant of a simplex with point apex and base points - - returns: - signed determinant and nearzero from qh_determinant - - notes: - uses qh.gm_matrix/qh.gm_row (assumes they're big enough) - - design: - construct qm_matrix by subtracting apex from points - compute determinate -*/ -realT qh_detsimplex(pointT *apex, setT *points, int dim, boolT *nearzero) { - pointT *coorda, *coordp, *gmcoord, *point, **pointp; - coordT **rows; - int k, i=0; - realT det; - - zinc_(Zdetsimplex); - gmcoord= qh gm_matrix; - rows= qh gm_row; - FOREACHpoint_(points) { - if (i == dim) - break; - rows[i++]= gmcoord; - coordp= point; - coorda= apex; - for (k=dim; k--; ) - *(gmcoord++)= *coordp++ - *coorda++; - } - if (i < dim) { - qh_fprintf(qh ferr, 6007, "qhull internal error (qh_detsimplex): #points %d < dimension %d\n", - i, dim); - qh_errexit(qh_ERRqhull, NULL, NULL); - } - det= qh_determinant(rows, dim, nearzero); - trace2((qh ferr, 2002, "qh_detsimplex: det=%2.2g for point p%d, dim %d, nearzero? %d\n", - det, qh_pointid(apex), dim, *nearzero)); - return det; -} /* detsimplex */ - -/*-<a href="qh-geom.htm#TOC" - >-------------------------------</a><a name="distnorm">-</a> - - qh_distnorm( dim, point, normal, offset ) - return distance from point to hyperplane at normal/offset - - returns: - dist - - notes: - dist > 0 if point is outside of hyperplane - - see: - qh_distplane in geom.c -*/ -realT qh_distnorm(int dim, pointT *point, pointT *normal, realT *offsetp) { - coordT *normalp= normal, *coordp= point; - realT dist; - int k; - - dist= *offsetp; - for (k=dim; k--; ) - dist += *(coordp++) * *(normalp++); - return dist; -} /* distnorm */ - -/*-<a href="qh-geom.htm#TOC" - >-------------------------------</a><a name="distround">-</a> - - qh_distround(dimension, maxabs, maxsumabs ) - compute maximum round-off error for a distance computation - to a normalized hyperplane - maxabs is the maximum absolute value of a coordinate - maxsumabs is the maximum possible sum of absolute coordinate values - - returns: - max dist round for REALepsilon - - notes: - calculate roundoff error according to - Lemma 3.2-1 of Golub and van Loan "Matrix Computation" - use sqrt(dim) since one vector is normalized - or use maxsumabs since one vector is < 1 -*/ -realT qh_distround(int dimension, realT maxabs, realT maxsumabs) { - realT maxdistsum, maxround; - - maxdistsum= sqrt((realT)dimension) * maxabs; - minimize_( maxdistsum, maxsumabs); - maxround= REALepsilon * (dimension * maxdistsum * 1.01 + maxabs); - /* adds maxabs for offset */ - trace4((qh ferr, 4008, "qh_distround: %2.2g maxabs %2.2g maxsumabs %2.2g maxdistsum %2.2g\n", - maxround, maxabs, maxsumabs, maxdistsum)); - return maxround; -} /* distround */ - -/*-<a href="qh-geom.htm#TOC" - >-------------------------------</a><a name="divzero">-</a> - - qh_divzero( numer, denom, mindenom1, zerodiv ) - divide by a number that's nearly zero - mindenom1= minimum denominator for dividing into 1.0 - - returns: - quotient - sets zerodiv and returns 0.0 if it would overflow - - design: - if numer is nearly zero and abs(numer) < abs(denom) - return numer/denom - else if numer is nearly zero - return 0 and zerodiv - else if denom/numer non-zero - return numer/denom - else - return 0 and zerodiv -*/ -realT qh_divzero(realT numer, realT denom, realT mindenom1, boolT *zerodiv) { - realT temp, numerx, denomx; - - - if (numer < mindenom1 && numer > -mindenom1) { - numerx= fabs_(numer); - denomx= fabs_(denom); - if (numerx < denomx) { - *zerodiv= False; - return numer/denom; - }else { - *zerodiv= True; - return 0.0; - } - } - temp= denom/numer; - if (temp > mindenom1 || temp < -mindenom1) { - *zerodiv= False; - return numer/denom; - }else { - *zerodiv= True; - return 0.0; - } -} /* divzero */ - - -/*-<a href="qh-geom.htm#TOC" - >-------------------------------</a><a name="facetarea">-</a> - - qh_facetarea( facet ) - return area for a facet - - notes: - if non-simplicial, - uses centrum to triangulate facet and sums the projected areas. - if (qh DELAUNAY), - computes projected area instead for last coordinate - assumes facet->normal exists - projecting tricoplanar facets to the hyperplane does not appear to make a difference - - design: - if simplicial - compute area - else - for each ridge - compute area from centrum to ridge - negate area if upper Delaunay facet -*/ -realT qh_facetarea(facetT *facet) { - vertexT *apex; - pointT *centrum; - realT area= 0.0; - ridgeT *ridge, **ridgep; - - if (facet->simplicial) { - apex= SETfirstt_(facet->vertices, vertexT); - area= qh_facetarea_simplex(qh hull_dim, apex->point, facet->vertices, - apex, facet->toporient, facet->normal, &facet->offset); - }else { - if (qh CENTERtype == qh_AScentrum) - centrum= facet->center; - else - centrum= qh_getcentrum(facet); - FOREACHridge_(facet->ridges) - area += qh_facetarea_simplex(qh hull_dim, centrum, ridge->vertices, - NULL, (boolT)(ridge->top == facet), facet->normal, &facet->offset); - if (qh CENTERtype != qh_AScentrum) - qh_memfree(centrum, qh normal_size); - } - if (facet->upperdelaunay && qh DELAUNAY) - area= -area; /* the normal should be [0,...,1] */ - trace4((qh ferr, 4009, "qh_facetarea: f%d area %2.2g\n", facet->id, area)); - return area; -} /* facetarea */ - -/*-<a href="qh-geom.htm#TOC" - >-------------------------------</a><a name="facetarea_simplex">-</a> - - qh_facetarea_simplex( dim, apex, vertices, notvertex, toporient, normal, offset ) - return area for a simplex defined by - an apex, a base of vertices, an orientation, and a unit normal - if simplicial or tricoplanar facet, - notvertex is defined and it is skipped in vertices - - returns: - computes area of simplex projected to plane [normal,offset] - returns 0 if vertex too far below plane (qh WIDEfacet) - vertex can't be apex of tricoplanar facet - - notes: - if (qh DELAUNAY), - computes projected area instead for last coordinate - uses qh gm_matrix/gm_row and qh hull_dim - helper function for qh_facetarea - - design: - if Notvertex - translate simplex to apex - else - project simplex to normal/offset - translate simplex to apex - if Delaunay - set last row/column to 0 with -1 on diagonal - else - set last row to Normal - compute determinate - scale and flip sign for area -*/ -realT qh_facetarea_simplex(int dim, coordT *apex, setT *vertices, - vertexT *notvertex, boolT toporient, coordT *normal, realT *offset) { - pointT *coorda, *coordp, *gmcoord; - coordT **rows, *normalp; - int k, i=0; - realT area, dist; - vertexT *vertex, **vertexp; - boolT nearzero; - - gmcoord= qh gm_matrix; - rows= qh gm_row; - FOREACHvertex_(vertices) { - if (vertex == notvertex) - continue; - rows[i++]= gmcoord; - coorda= apex; - coordp= vertex->point; - normalp= normal; - if (notvertex) { - for (k=dim; k--; ) - *(gmcoord++)= *coordp++ - *coorda++; - }else { - dist= *offset; - for (k=dim; k--; ) - dist += *coordp++ * *normalp++; - if (dist < -qh WIDEfacet) { - zinc_(Znoarea); - return 0.0; - } - coordp= vertex->point; - normalp= normal; - for (k=dim; k--; ) - *(gmcoord++)= (*coordp++ - dist * *normalp++) - *coorda++; - } - } - if (i != dim-1) { - qh_fprintf(qh ferr, 6008, "qhull internal error (qh_facetarea_simplex): #points %d != dim %d -1\n", - i, dim); - qh_errexit(qh_ERRqhull, NULL, NULL); - } - rows[i]= gmcoord; - if (qh DELAUNAY) { - for (i=0; i < dim-1; i++) - rows[i][dim-1]= 0.0; - for (k=dim; k--; ) - *(gmcoord++)= 0.0; - rows[dim-1][dim-1]= -1.0; - }else { - normalp= normal; - for (k=dim; k--; ) - *(gmcoord++)= *normalp++; - } - zinc_(Zdetsimplex); - area= qh_determinant(rows, dim, &nearzero); - if (toporient) - area= -area; - area *= qh AREAfactor; - trace4((qh ferr, 4010, "qh_facetarea_simplex: area=%2.2g for point p%d, toporient %d, nearzero? %d\n", - area, qh_pointid(apex), toporient, nearzero)); - return area; -} /* facetarea_simplex */ - -/*-<a href="qh-geom.htm#TOC" - >-------------------------------</a><a name="facetcenter">-</a> - - qh_facetcenter( vertices ) - return Voronoi center (Voronoi vertex) for a facet's vertices - - returns: - return temporary point equal to the center - - see: - qh_voronoi_center() -*/ -pointT *qh_facetcenter(setT *vertices) { - setT *points= qh_settemp(qh_setsize(vertices)); - vertexT *vertex, **vertexp; - pointT *center; - - FOREACHvertex_(vertices) - qh_setappend(&points, vertex->point); - center= qh_voronoi_center(qh hull_dim-1, points); - qh_settempfree(&points); - return center; -} /* facetcenter */ - -/*-<a href="qh-geom.htm#TOC" - >-------------------------------</a><a name="findgooddist">-</a> - - qh_findgooddist( point, facetA, dist, facetlist ) - find best good facet visible for point from facetA - assumes facetA is visible from point - - returns: - best facet, i.e., good facet that is furthest from point - distance to best facet - NULL if none - - moves good, visible facets (and some other visible facets) - to end of qh facet_list - - notes: - uses qh visit_id - - design: - initialize bestfacet if facetA is good - move facetA to end of facetlist - for each facet on facetlist - for each unvisited neighbor of facet - move visible neighbors to end of facetlist - update best good neighbor - if no good neighbors, update best facet -*/ -facetT *qh_findgooddist(pointT *point, facetT *facetA, realT *distp, - facetT **facetlist) { - realT bestdist= -REALmax, dist; - facetT *neighbor, **neighborp, *bestfacet=NULL, *facet; - boolT goodseen= False; - - if (facetA->good) { - zzinc_(Zcheckpart); /* calls from check_bestdist occur after print stats */ - qh_distplane(point, facetA, &bestdist); - bestfacet= facetA; - goodseen= True; - } - qh_removefacet(facetA); - qh_appendfacet(facetA); - *facetlist= facetA; - facetA->visitid= ++qh visit_id; - FORALLfacet_(*facetlist) { - FOREACHneighbor_(facet) { - if (neighbor->visitid == qh visit_id) - continue; - neighbor->visitid= qh visit_id; - if (goodseen && !neighbor->good) - continue; - zzinc_(Zcheckpart); - qh_distplane(point, neighbor, &dist); - if (dist > 0) { - qh_removefacet(neighbor); - qh_appendfacet(neighbor); - if (neighbor->good) { - goodseen= True; - if (dist > bestdist) { - bestdist= dist; - bestfacet= neighbor; - } - } - } - } - } - if (bestfacet) { - *distp= bestdist; - trace2((qh ferr, 2003, "qh_findgooddist: p%d is %2.2g above good facet f%d\n", - qh_pointid(point), bestdist, bestfacet->id)); - return bestfacet; - } - trace4((qh ferr, 4011, "qh_findgooddist: no good facet for p%d above f%d\n", - qh_pointid(point), facetA->id)); - return NULL; -} /* findgooddist */ - -/*-<a href="qh-geom.htm#TOC" - >-------------------------------</a><a name="getarea">-</a> - - qh_getarea( facetlist ) - set area of all facets in facetlist - collect statistics - nop if hasAreaVolume - - returns: - sets qh totarea/totvol to total area and volume of convex hull - for Delaunay triangulation, computes projected area of the lower or upper hull - ignores upper hull if qh ATinfinity - - notes: - could compute outer volume by expanding facet area by rays from interior - the following attempt at perpendicular projection underestimated badly: - qh.totoutvol += (-dist + facet->maxoutside + qh DISTround) - * area/ qh hull_dim; - design: - for each facet on facetlist - compute facet->area - update qh.totarea and qh.totvol -*/ -void qh_getarea(facetT *facetlist) { - realT area; - realT dist; - facetT *facet; - - if (qh hasAreaVolume) - return; - if (qh REPORTfreq) - qh_fprintf(qh ferr, 8020, "computing area of each facet and volume of the convex hull\n"); - else - trace1((qh ferr, 1001, "qh_getarea: computing volume and area for each facet\n")); - qh totarea= qh totvol= 0.0; - FORALLfacet_(facetlist) { - if (!facet->normal) - continue; - if (facet->upperdelaunay && qh ATinfinity) - continue; - if (!facet->isarea) { - facet->f.area= qh_facetarea(facet); - facet->isarea= True; - } - area= facet->f.area; - if (qh DELAUNAY) { - if (facet->upperdelaunay == qh UPPERdelaunay) - qh totarea += area; - }else { - qh totarea += area; - qh_distplane(qh interior_point, facet, &dist); - qh totvol += -dist * area/ qh hull_dim; - } - if (qh PRINTstatistics) { - wadd_(Wareatot, area); - wmax_(Wareamax, area); - wmin_(Wareamin, area); - } - } - qh hasAreaVolume= True; -} /* getarea */ - -/*-<a href="qh-geom.htm#TOC" - >-------------------------------</a><a name="gram_schmidt">-</a> - - qh_gram_schmidt( dim, row ) - implements Gram-Schmidt orthogonalization by rows - - returns: - false if zero norm - overwrites rows[dim][dim] - - notes: - see Golub & van Loan Algorithm 6.2-2 - overflow due to small divisors not handled - - design: - for each row - compute norm for row - if non-zero, normalize row - for each remaining rowA - compute inner product of row and rowA - reduce rowA by row * inner product -*/ -boolT qh_gram_schmidt(int dim, realT **row) { - realT *rowi, *rowj, norm; - int i, j, k; - - for (i=0; i < dim; i++) { - rowi= row[i]; - for (norm= 0.0, k= dim; k--; rowi++) - norm += *rowi * *rowi; - norm= sqrt(norm); - wmin_(Wmindenom, norm); - if (norm == 0.0) /* either 0 or overflow due to sqrt */ - return False; - for (k=dim; k--; ) - *(--rowi) /= norm; - for (j=i+1; j < dim; j++) { - rowj= row[j]; - for (norm= 0.0, k=dim; k--; ) - norm += *rowi++ * *rowj++; - for (k=dim; k--; ) - *(--rowj) -= *(--rowi) * norm; - } - } - return True; -} /* gram_schmidt */ - - -/*-<a href="qh-geom.htm#TOC" - >-------------------------------</a><a name="inthresholds">-</a> - - qh_inthresholds( normal, angle ) - return True if normal within qh.lower_/upper_threshold - - returns: - estimate of angle by summing of threshold diffs - angle may be NULL - smaller "angle" is better - - notes: - invalid if qh.SPLITthresholds - - see: - qh.lower_threshold in qh_initbuild() - qh_initthresholds() - - design: - for each dimension - test threshold -*/ -boolT qh_inthresholds(coordT *normal, realT *angle) { - boolT within= True; - int k; - realT threshold; - - if (angle) - *angle= 0.0; - for (k=0; k < qh hull_dim; k++) { - threshold= qh lower_threshold[k]; - if (threshold > -REALmax/2) { - if (normal[k] < threshold) - within= False; - if (angle) { - threshold -= normal[k]; - *angle += fabs_(threshold); - } - } - if (qh upper_threshold[k] < REALmax/2) { - threshold= qh upper_threshold[k]; - if (normal[k] > threshold) - within= False; - if (angle) { - threshold -= normal[k]; - *angle += fabs_(threshold); - } - } - } - return within; -} /* inthresholds */ - - -/*-<a href="qh-geom.htm#TOC" - >-------------------------------</a><a name="joggleinput">-</a> - - qh_joggleinput() - randomly joggle input to Qhull by qh.JOGGLEmax - initial input is qh.first_point/qh.num_points of qh.hull_dim - repeated calls use qh.input_points/qh.num_points - - returns: - joggles points at qh.first_point/qh.num_points - copies data to qh.input_points/qh.input_malloc if first time - determines qh.JOGGLEmax if it was zero - if qh.DELAUNAY - computes the Delaunay projection of the joggled points - - notes: - if qh.DELAUNAY, unnecessarily joggles the last coordinate - the initial 'QJn' may be set larger than qh_JOGGLEmaxincrease - - design: - if qh.DELAUNAY - set qh.SCALElast for reduced precision errors - if first call - initialize qh.input_points to the original input points - if qh.JOGGLEmax == 0 - determine default qh.JOGGLEmax - else - increase qh.JOGGLEmax according to qh.build_cnt - joggle the input by adding a random number in [-qh.JOGGLEmax,qh.JOGGLEmax] - if qh.DELAUNAY - sets the Delaunay projection -*/ -void qh_joggleinput(void) { - int i, seed, size; - coordT *coordp, *inputp; - realT randr, randa, randb; - - if (!qh input_points) { /* first call */ - qh input_points= qh first_point; - qh input_malloc= qh POINTSmalloc; - size= qh num_points * qh hull_dim * sizeof(coordT); - if (!(qh first_point=(coordT*)qh_malloc((size_t)size))) { - qh_fprintf(qh ferr, 6009, "qhull error: insufficient memory to joggle %d points\n", - qh num_points); - qh_errexit(qh_ERRmem, NULL, NULL); - } - qh POINTSmalloc= True; - if (qh JOGGLEmax == 0.0) { - qh JOGGLEmax= qh_detjoggle(qh input_points, qh num_points, qh hull_dim); - qh_option("QJoggle", NULL, &qh JOGGLEmax); - } - }else { /* repeated call */ - if (!qh RERUN && qh build_cnt > qh_JOGGLEretry) { - if (((qh build_cnt-qh_JOGGLEretry-1) % qh_JOGGLEagain) == 0) { - realT maxjoggle= qh MAXwidth * qh_JOGGLEmaxincrease; - if (qh JOGGLEmax < maxjoggle) { - qh JOGGLEmax *= qh_JOGGLEincrease; - minimize_(qh JOGGLEmax, maxjoggle); - } - } - } - qh_option("QJoggle", NULL, &qh JOGGLEmax); - } - if (qh build_cnt > 1 && qh JOGGLEmax > fmax_(qh MAXwidth/4, 0.1)) { - qh_fprintf(qh ferr, 6010, "qhull error: the current joggle for 'QJn', %.2g, is too large for the width\nof the input. If possible, recompile Qhull with higher-precision reals.\n", - qh JOGGLEmax); - qh_errexit(qh_ERRqhull, NULL, NULL); - } - /* for some reason, using qh ROTATErandom and qh_RANDOMseed does not repeat the run. Use 'TRn' instead */ - seed= qh_RANDOMint; - qh_option("_joggle-seed", &seed, NULL); - trace0((qh ferr, 6, "qh_joggleinput: joggle input by %2.2g with seed %d\n", - qh JOGGLEmax, seed)); - inputp= qh input_points; - coordp= qh first_point; - randa= 2.0 * qh JOGGLEmax/qh_RANDOMmax; - randb= -qh JOGGLEmax; - size= qh num_points * qh hull_dim; - for (i=size; i--; ) { - randr= qh_RANDOMint; - *(coordp++)= *(inputp++) + (randr * randa + randb); - } - if (qh DELAUNAY) { - qh last_low= qh last_high= qh last_newhigh= REALmax; - qh_setdelaunay(qh hull_dim, qh num_points, qh first_point); - } -} /* joggleinput */ - -/*-<a href="qh-geom.htm#TOC" - >-------------------------------</a><a name="maxabsval">-</a> - - qh_maxabsval( normal, dim ) - return pointer to maximum absolute value of a dim vector - returns NULL if dim=0 -*/ -realT *qh_maxabsval(realT *normal, int dim) { - realT maxval= -REALmax; - realT *maxp= NULL, *colp, absval; - int k; - - for (k=dim, colp= normal; k--; colp++) { - absval= fabs_(*colp); - if (absval > maxval) { - maxval= absval; - maxp= colp; - } - } - return maxp; -} /* maxabsval */ - - -/*-<a href="qh-geom.htm#TOC" - >-------------------------------</a><a name="maxmin">-</a> - - qh_maxmin( points, numpoints, dimension ) - return max/min points for each dimension - determine max and min coordinates - - returns: - returns a temporary set of max and min points - may include duplicate points. Does not include qh.GOODpoint - sets qh.NEARzero, qh.MAXabs_coord, qh.MAXsumcoord, qh.MAXwidth - qh.MAXlastcoord, qh.MINlastcoord - initializes qh.max_outside, qh.min_vertex, qh.WAScoplanar, qh.ZEROall_ok - - notes: - loop duplicated in qh_detjoggle() - - design: - initialize global precision variables - checks definition of REAL... - for each dimension - for each point - collect maximum and minimum point - collect maximum of maximums and minimum of minimums - determine qh.NEARzero for Gaussian Elimination -*/ -setT *qh_maxmin(pointT *points, int numpoints, int dimension) { - int k; - realT maxcoord, temp; - pointT *minimum, *maximum, *point, *pointtemp; - setT *set; - - qh max_outside= 0.0; - qh MAXabs_coord= 0.0; - qh MAXwidth= -REALmax; - qh MAXsumcoord= 0.0; - qh min_vertex= 0.0; - qh WAScoplanar= False; - if (qh ZEROcentrum) - qh ZEROall_ok= True; - if (REALmin < REALepsilon && REALmin < REALmax && REALmin > -REALmax - && REALmax > 0.0 && -REALmax < 0.0) - ; /* all ok */ - else { - qh_fprintf(qh ferr, 6011, "qhull error: floating point constants in user.h are wrong\n\ -REALepsilon %g REALmin %g REALmax %g -REALmax %g\n", - REALepsilon, REALmin, REALmax, -REALmax); - qh_errexit(qh_ERRinput, NULL, NULL); - } - set= qh_settemp(2*dimension); - for (k=0; k < dimension; k++) { - if (points == qh GOODpointp) - minimum= maximum= points + dimension; - else - minimum= maximum= points; - FORALLpoint_(points, numpoints) { - if (point == qh GOODpointp) - continue; - if (maximum[k] < point[k]) - maximum= point; - else if (minimum[k] > point[k]) - minimum= point; - } - if (k == dimension-1) { - qh MINlastcoord= minimum[k]; - qh MAXlastcoord= maximum[k]; - } - if (qh SCALElast && k == dimension-1) - maxcoord= qh MAXwidth; - else { - maxcoord= fmax_(maximum[k], -minimum[k]); - if (qh GOODpointp) { - temp= fmax_(qh GOODpointp[k], -qh GOODpointp[k]); - maximize_(maxcoord, temp); - } - temp= maximum[k] - minimum[k]; - maximize_(qh MAXwidth, temp); - } - maximize_(qh MAXabs_coord, maxcoord); - qh MAXsumcoord += maxcoord; - qh_setappend(&set, maximum); - qh_setappend(&set, minimum); - /* calculation of qh NEARzero is based on error formula 4.4-13 of - Golub & van Loan, authors say n^3 can be ignored and 10 be used in - place of rho */ - qh NEARzero[k]= 80 * qh MAXsumcoord * REALepsilon; - } - if (qh IStracing >=1) - qh_printpoints(qh ferr, "qh_maxmin: found the max and min points(by dim):", set); - return(set); -} /* maxmin */ - -/*-<a href="qh-geom.htm#TOC" - >-------------------------------</a><a name="maxouter">-</a> - - qh_maxouter() - return maximum distance from facet to outer plane - normally this is qh.max_outside+qh.DISTround - does not include qh.JOGGLEmax - - see: - qh_outerinner() - - notes: - need to add another qh.DISTround if testing actual point with computation - - for joggle: - qh_setfacetplane() updated qh.max_outer for Wnewvertexmax (max distance to vertex) - need to use Wnewvertexmax since could have a coplanar point for a high - facet that is replaced by a low facet - need to add qh.JOGGLEmax if testing input points -*/ -realT qh_maxouter(void) { - realT dist; - - dist= fmax_(qh max_outside, qh DISTround); - dist += qh DISTround; - trace4((qh ferr, 4012, "qh_maxouter: max distance from facet to outer plane is %2.2g max_outside is %2.2g\n", dist, qh max_outside)); - return dist; -} /* maxouter */ - -/*-<a href="qh-geom.htm#TOC" - >-------------------------------</a><a name="maxsimplex">-</a> - - qh_maxsimplex( dim, maxpoints, points, numpoints, simplex ) - determines maximum simplex for a set of points - starts from points already in simplex - skips qh.GOODpointp (assumes that it isn't in maxpoints) - - returns: - simplex with dim+1 points - - notes: - assumes at least pointsneeded points in points - maximizes determinate for x,y,z,w, etc. - uses maxpoints as long as determinate is clearly non-zero - - design: - initialize simplex with at least two points - (find points with max or min x coordinate) - for each remaining dimension - add point that maximizes the determinate - (use points from maxpoints first) -*/ -void qh_maxsimplex(int dim, setT *maxpoints, pointT *points, int numpoints, setT **simplex) { - pointT *point, **pointp, *pointtemp, *maxpoint, *minx=NULL, *maxx=NULL; - boolT nearzero, maxnearzero= False; - int k, sizinit; - realT maxdet= -REALmax, det, mincoord= REALmax, maxcoord= -REALmax; - - sizinit= qh_setsize(*simplex); - if (sizinit < 2) { - if (qh_setsize(maxpoints) >= 2) { - FOREACHpoint_(maxpoints) { - if (maxcoord < point[0]) { - maxcoord= point[0]; - maxx= point; - } - if (mincoord > point[0]) { - mincoord= point[0]; - minx= point; - } - } - }else { - FORALLpoint_(points, numpoints) { - if (point == qh GOODpointp) - continue; - if (maxcoord < point[0]) { - maxcoord= point[0]; - maxx= point; - } - if (mincoord > point[0]) { - mincoord= point[0]; - minx= point; - } - } - } - qh_setunique(simplex, minx); - if (qh_setsize(*simplex) < 2) - qh_setunique(simplex, maxx); - sizinit= qh_setsize(*simplex); - if (sizinit < 2) { - qh_precision("input has same x coordinate"); - if (zzval_(Zsetplane) > qh hull_dim+1) { - qh_fprintf(qh ferr, 6012, "qhull precision error (qh_maxsimplex for voronoi_center):\n%d points with the same x coordinate.\n", - qh_setsize(maxpoints)+numpoints); - qh_errexit(qh_ERRprec, NULL, NULL); - }else { - qh_fprintf(qh ferr, 6013, "qhull input error: input is less than %d-dimensional since it has the same x coordinate\n", qh hull_dim); - qh_errexit(qh_ERRinput, NULL, NULL); - } - } - } - for (k=sizinit; k < dim+1; k++) { - maxpoint= NULL; - maxdet= -REALmax; - FOREACHpoint_(maxpoints) { - if (!qh_setin(*simplex, point)) { - det= qh_detsimplex(point, *simplex, k, &nearzero); - if ((det= fabs_(det)) > maxdet) { - maxdet= det; - maxpoint= point; - maxnearzero= nearzero; - } - } - } - if (!maxpoint || maxnearzero) { - zinc_(Zsearchpoints); - if (!maxpoint) { - trace0((qh ferr, 7, "qh_maxsimplex: searching all points for %d-th initial vertex.\n", k+1)); - }else { - trace0((qh ferr, 8, "qh_maxsimplex: searching all points for %d-th initial vertex, better than p%d det %2.2g\n", - k+1, qh_pointid(maxpoint), maxdet)); - } - FORALLpoint_(points, numpoints) { - if (point == qh GOODpointp) - continue; - if (!qh_setin(*simplex, point)) { - det= qh_detsimplex(point, *simplex, k, &nearzero); - if ((det= fabs_(det)) > maxdet) { - maxdet= det; - maxpoint= point; - maxnearzero= nearzero; - } - } - } - } /* !maxpoint */ - if (!maxpoint) { - qh_fprintf(qh ferr, 6014, "qhull internal error (qh_maxsimplex): not enough points available\n"); - qh_errexit(qh_ERRqhull, NULL, NULL); - } - qh_setappend(simplex, maxpoint); - trace1((qh ferr, 1002, "qh_maxsimplex: selected point p%d for %d`th initial vertex, det=%2.2g\n", - qh_pointid(maxpoint), k+1, maxdet)); - } /* k */ -} /* maxsimplex */ - -/*-<a href="qh-geom.htm#TOC" - >-------------------------------</a><a name="minabsval">-</a> - - qh_minabsval( normal, dim ) - return minimum absolute value of a dim vector -*/ -realT qh_minabsval(realT *normal, int dim) { - realT minval= 0; - realT maxval= 0; - realT *colp; - int k; - - for (k=dim, colp=normal; k--; colp++) { - maximize_(maxval, *colp); - minimize_(minval, *colp); - } - return fmax_(maxval, -minval); -} /* minabsval */ - - -/*-<a href="qh-geom.htm#TOC" - >-------------------------------</a><a name="mindiff">-</a> - - qh_mindif ( vecA, vecB, dim ) - return index of min abs. difference of two vectors -*/ -int qh_mindiff(realT *vecA, realT *vecB, int dim) { - realT mindiff= REALmax, diff; - realT *vecAp= vecA, *vecBp= vecB; - int k, mink= 0; - - for (k=0; k < dim; k++) { - diff= *vecAp++ - *vecBp++; - diff= fabs_(diff); - if (diff < mindiff) { - mindiff= diff; - mink= k; - } - } - return mink; -} /* mindiff */ - - - -/*-<a href="qh-geom.htm#TOC" - >-------------------------------</a><a name="orientoutside">-</a> - - qh_orientoutside( facet ) - make facet outside oriented via qh.interior_point - - returns: - True if facet reversed orientation. -*/ -boolT qh_orientoutside(facetT *facet) { - int k; - realT dist; - - qh_distplane(qh interior_point, facet, &dist); - if (dist > 0) { - for (k=qh hull_dim; k--; ) - facet->normal[k]= -facet->normal[k]; - facet->offset= -facet->offset; - return True; - } - return False; -} /* orientoutside */ - -/*-<a href="qh-geom.htm#TOC" - >-------------------------------</a><a name="outerinner">-</a> - - qh_outerinner( facet, outerplane, innerplane ) - if facet and qh.maxoutdone (i.e., qh_check_maxout) - returns outer and inner plane for facet - else - returns maximum outer and inner plane - accounts for qh.JOGGLEmax - - see: - qh_maxouter(), qh_check_bestdist(), qh_check_points() - - notes: - outerplaner or innerplane may be NULL - facet is const - Does not error (QhullFacet) - - includes qh.DISTround for actual points - adds another qh.DISTround if testing with floating point arithmetic -*/ -void qh_outerinner(facetT *facet, realT *outerplane, realT *innerplane) { - realT dist, mindist; - vertexT *vertex, **vertexp; - - if (outerplane) { - if (!qh_MAXoutside || !facet || !qh maxoutdone) { - *outerplane= qh_maxouter(); /* includes qh.DISTround */ - }else { /* qh_MAXoutside ... */ -#if qh_MAXoutside - *outerplane= facet->maxoutside + qh DISTround; -#endif - - } - if (qh JOGGLEmax < REALmax/2) - *outerplane += qh JOGGLEmax * sqrt((realT)qh hull_dim); - } - if (innerplane) { - if (facet) { - mindist= REALmax; - FOREACHvertex_(facet->vertices) { - zinc_(Zdistio); - qh_distplane(vertex->point, facet, &dist); - minimize_(mindist, dist); - } - *innerplane= mindist - qh DISTround; - }else - *innerplane= qh min_vertex - qh DISTround; - if (qh JOGGLEmax < REALmax/2) - *innerplane -= qh JOGGLEmax * sqrt((realT)qh hull_dim); - } -} /* outerinner */ - -/*-<a href="qh-geom.htm#TOC" - >-------------------------------</a><a name="pointdist">-</a> - - qh_pointdist( point1, point2, dim ) - return distance between two points - - notes: - returns distance squared if 'dim' is negative -*/ -coordT qh_pointdist(pointT *point1, pointT *point2, int dim) { - coordT dist, diff; - int k; - - dist= 0.0; - for (k= (dim > 0 ? dim : -dim); k--; ) { - diff= *point1++ - *point2++; - dist += diff * diff; - } - if (dim > 0) - return(sqrt(dist)); - return dist; -} /* pointdist */ - - -/*-<a href="qh-geom.htm#TOC" - >-------------------------------</a><a name="printmatrix">-</a> - - qh_printmatrix( fp, string, rows, numrow, numcol ) - print matrix to fp given by row vectors - print string as header - - notes: - print a vector by qh_printmatrix(fp, "", &vect, 1, len) -*/ -void qh_printmatrix(FILE *fp, const char *string, realT **rows, int numrow, int numcol) { - realT *rowp; - realT r; /*bug fix*/ - int i,k; - - qh_fprintf(fp, 9001, "%s\n", string); - for (i=0; i < numrow; i++) { - rowp= rows[i]; - for (k=0; k < numcol; k++) { - r= *rowp++; - qh_fprintf(fp, 9002, "%6.3g ", r); - } - qh_fprintf(fp, 9003, "\n"); - } -} /* printmatrix */ - - -/*-<a href="qh-geom.htm#TOC" - >-------------------------------</a><a name="printpoints">-</a> - - qh_printpoints( fp, string, points ) - print pointids to fp for a set of points - if string, prints string and 'p' point ids -*/ -void qh_printpoints(FILE *fp, const char *string, setT *points) { - pointT *point, **pointp; - - if (string) { - qh_fprintf(fp, 9004, "%s", string); - FOREACHpoint_(points) - qh_fprintf(fp, 9005, " p%d", qh_pointid(point)); - qh_fprintf(fp, 9006, "\n"); - }else { - FOREACHpoint_(points) - qh_fprintf(fp, 9007, " %d", qh_pointid(point)); - qh_fprintf(fp, 9008, "\n"); - } -} /* printpoints */ - - -/*-<a href="qh-geom.htm#TOC" - >-------------------------------</a><a name="projectinput">-</a> - - qh_projectinput() - project input points using qh.lower_bound/upper_bound and qh DELAUNAY - if qh.lower_bound[k]=qh.upper_bound[k]= 0, - removes dimension k - if halfspace intersection - removes dimension k from qh.feasible_point - input points in qh first_point, num_points, input_dim - - returns: - new point array in qh first_point of qh hull_dim coordinates - sets qh POINTSmalloc - if qh DELAUNAY - projects points to paraboloid - lowbound/highbound is also projected - if qh ATinfinity - adds point "at-infinity" - if qh POINTSmalloc - frees old point array - - notes: - checks that qh.hull_dim agrees with qh.input_dim, PROJECTinput, and DELAUNAY - - - design: - sets project[k] to -1 (delete), 0 (keep), 1 (add for Delaunay) - determines newdim and newnum for qh hull_dim and qh num_points - projects points to newpoints - projects qh.lower_bound to itself - projects qh.upper_bound to itself - if qh DELAUNAY - if qh ATINFINITY - projects points to paraboloid - computes "infinity" point as vertex average and 10% above all points - else - uses qh_setdelaunay to project points to paraboloid -*/ -void qh_projectinput(void) { - int k,i; - int newdim= qh input_dim, newnum= qh num_points; - signed char *project; - int size= (qh input_dim+1)*sizeof(*project); - pointT *newpoints, *coord, *infinity; - realT paraboloid, maxboloid= 0; - - project= (signed char*)qh_memalloc(size); - memset((char*)project, 0, (size_t)size); - for (k=0; k < qh input_dim; k++) { /* skip Delaunay bound */ - if (qh lower_bound[k] == 0 && qh upper_bound[k] == 0) { - project[k]= -1; - newdim--; - } - } - if (qh DELAUNAY) { - project[k]= 1; - newdim++; - if (qh ATinfinity) - newnum++; - } - if (newdim != qh hull_dim) { - qh_fprintf(qh ferr, 6015, "qhull internal error (qh_projectinput): dimension after projection %d != hull_dim %d\n", newdim, qh hull_dim); - qh_errexit(qh_ERRqhull, NULL, NULL); - } - if (!(newpoints=(coordT*)qh_malloc(newnum*newdim*sizeof(coordT)))){ - qh_fprintf(qh ferr, 6016, "qhull error: insufficient memory to project %d points\n", - qh num_points); - qh_errexit(qh_ERRmem, NULL, NULL); - } - qh_projectpoints(project, qh input_dim+1, qh first_point, - qh num_points, qh input_dim, newpoints, newdim); - trace1((qh ferr, 1003, "qh_projectinput: updating lower and upper_bound\n")); - qh_projectpoints(project, qh input_dim+1, qh lower_bound, - 1, qh input_dim+1, qh lower_bound, newdim+1); - qh_projectpoints(project, qh input_dim+1, qh upper_bound, - 1, qh input_dim+1, qh upper_bound, newdim+1); - if (qh HALFspace) { - if (!qh feasible_point) { - qh_fprintf(qh ferr, 6017, "qhull internal error (qh_projectinput): HALFspace defined without qh.feasible_point\n"); - qh_errexit(qh_ERRqhull, NULL, NULL); - } - qh_projectpoints(project, qh input_dim, qh feasible_point, - 1, qh input_dim, qh feasible_point, newdim); - } - qh_memfree(project, (qh input_dim+1)*sizeof(*project)); - if (qh POINTSmalloc) - qh_free(qh first_point); - qh first_point= newpoints; - qh POINTSmalloc= True; - if (qh DELAUNAY && qh ATinfinity) { - coord= qh first_point; - infinity= qh first_point + qh hull_dim * qh num_points; - for (k=qh hull_dim-1; k--; ) - infinity[k]= 0.0; - for (i=qh num_points; i--; ) { - paraboloid= 0.0; - for (k=0; k < qh hull_dim-1; k++) { - paraboloid += *coord * *coord; - infinity[k] += *coord; - coord++; - } - *(coord++)= paraboloid; - maximize_(maxboloid, paraboloid); - } - /* coord == infinity */ - for (k=qh hull_dim-1; k--; ) - *(coord++) /= qh num_points; - *(coord++)= maxboloid * 1.1; - qh num_points++; - trace0((qh ferr, 9, "qh_projectinput: projected points to paraboloid for Delaunay\n")); - }else if (qh DELAUNAY) /* !qh ATinfinity */ - qh_setdelaunay( qh hull_dim, qh num_points, qh first_point); -} /* projectinput */ - - -/*-<a href="qh-geom.htm#TOC" - >-------------------------------</a><a name="projectpoints">-</a> - - qh_projectpoints( project, n, points, numpoints, dim, newpoints, newdim ) - project points/numpoints/dim to newpoints/newdim - if project[k] == -1 - delete dimension k - if project[k] == 1 - add dimension k by duplicating previous column - n is size of project - - notes: - newpoints may be points if only adding dimension at end - - design: - check that 'project' and 'newdim' agree - for each dimension - if project == -1 - skip dimension - else - determine start of column in newpoints - determine start of column in points - if project == +1, duplicate previous column - copy dimension (column) from points to newpoints -*/ -void qh_projectpoints(signed char *project, int n, realT *points, - int numpoints, int dim, realT *newpoints, int newdim) { - int testdim= dim, oldk=0, newk=0, i,j=0,k; - realT *newp, *oldp; - - for (k=0; k < n; k++) - testdim += project[k]; - if (testdim != newdim) { - qh_fprintf(qh ferr, 6018, "qhull internal error (qh_projectpoints): newdim %d should be %d after projection\n", - newdim, testdim); - qh_errexit(qh_ERRqhull, NULL, NULL); - } - for (j=0; j<n; j++) { - if (project[j] == -1) - oldk++; - else { - newp= newpoints+newk++; - if (project[j] == +1) { - if (oldk >= dim) - continue; - oldp= points+oldk; - }else - oldp= points+oldk++; - for (i=numpoints; i--; ) { - *newp= *oldp; - newp += newdim; - oldp += dim; - } - } - if (oldk >= dim) - break; - } - trace1((qh ferr, 1004, "qh_projectpoints: projected %d points from dim %d to dim %d\n", - numpoints, dim, newdim)); -} /* projectpoints */ - - -/*-<a href="qh-geom.htm#TOC" - >-------------------------------</a><a name="rotateinput">-</a> - - qh_rotateinput( rows ) - rotate input using row matrix - input points given by qh first_point, num_points, hull_dim - assumes rows[dim] is a scratch buffer - if qh POINTSmalloc, overwrites input points, else mallocs a new array - - returns: - rotated input - sets qh POINTSmalloc - - design: - see qh_rotatepoints -*/ -void qh_rotateinput(realT **rows) { - - if (!qh POINTSmalloc) { - qh first_point= qh_copypoints(qh first_point, qh num_points, qh hull_dim); - qh POINTSmalloc= True; - } - qh_rotatepoints(qh first_point, qh num_points, qh hull_dim, rows); -} /* rotateinput */ - -/*-<a href="qh-geom.htm#TOC" - >-------------------------------</a><a name="rotatepoints">-</a> - - qh_rotatepoints( points, numpoints, dim, row ) - rotate numpoints points by a d-dim row matrix - assumes rows[dim] is a scratch buffer - - returns: - rotated points in place - - design: - for each point - for each coordinate - use row[dim] to compute partial inner product - for each coordinate - rotate by partial inner product -*/ -void qh_rotatepoints(realT *points, int numpoints, int dim, realT **row) { - realT *point, *rowi, *coord= NULL, sum, *newval; - int i,j,k; - - if (qh IStracing >= 1) - qh_printmatrix(qh ferr, "qh_rotatepoints: rotate points by", row, dim, dim); - for (point= points, j= numpoints; j--; point += dim) { - newval= row[dim]; - for (i=0; i < dim; i++) { - rowi= row[i]; - coord= point; - for (sum= 0.0, k= dim; k--; ) - sum += *rowi++ * *coord++; - *(newval++)= sum; - } - for (k=dim; k--; ) - *(--coord)= *(--newval); - } -} /* rotatepoints */ - - -/*-<a href="qh-geom.htm#TOC" - >-------------------------------</a><a name="scaleinput">-</a> - - qh_scaleinput() - scale input points using qh low_bound/high_bound - input points given by qh first_point, num_points, hull_dim - if qh POINTSmalloc, overwrites input points, else mallocs a new array - - returns: - scales coordinates of points to low_bound[k], high_bound[k] - sets qh POINTSmalloc - - design: - see qh_scalepoints -*/ -void qh_scaleinput(void) { - - if (!qh POINTSmalloc) { - qh first_point= qh_copypoints(qh first_point, qh num_points, qh hull_dim); - qh POINTSmalloc= True; - } - qh_scalepoints(qh first_point, qh num_points, qh hull_dim, - qh lower_bound, qh upper_bound); -} /* scaleinput */ - -/*-<a href="qh-geom.htm#TOC" - >-------------------------------</a><a name="scalelast">-</a> - - qh_scalelast( points, numpoints, dim, low, high, newhigh ) - scale last coordinate to [0,m] for Delaunay triangulations - input points given by points, numpoints, dim - - returns: - changes scale of last coordinate from [low, high] to [0, newhigh] - overwrites last coordinate of each point - saves low/high/newhigh in qh.last_low, etc. for qh_setdelaunay() - - notes: - when called by qh_setdelaunay, low/high may not match actual data - - design: - compute scale and shift factors - apply to last coordinate of each point -*/ -void qh_scalelast(coordT *points, int numpoints, int dim, coordT low, - coordT high, coordT newhigh) { - realT scale, shift; - coordT *coord; - int i; - boolT nearzero= False; - - trace4((qh ferr, 4013, "qh_scalelast: scale last coordinate from [%2.2g, %2.2g] to [0,%2.2g]\n", - low, high, newhigh)); - qh last_low= low; - qh last_high= high; - qh last_newhigh= newhigh; - scale= qh_divzero(newhigh, high - low, - qh MINdenom_1, &nearzero); - if (nearzero) { - if (qh DELAUNAY) - qh_fprintf(qh ferr, 6019, "qhull input error: can not scale last coordinate. Input is cocircular\n or cospherical. Use option 'Qz' to add a point at infinity.\n"); - else - qh_fprintf(qh ferr, 6020, "qhull input error: can not scale last coordinate. New bounds [0, %2.2g] are too wide for\nexisting bounds [%2.2g, %2.2g] (width %2.2g)\n", - newhigh, low, high, high-low); - qh_errexit(qh_ERRinput, NULL, NULL); - } - shift= - low * newhigh / (high-low); - coord= points + dim - 1; - for (i=numpoints; i--; coord += dim) - *coord= *coord * scale + shift; -} /* scalelast */ - -/*-<a href="qh-geom.htm#TOC" - >-------------------------------</a><a name="scalepoints">-</a> - - qh_scalepoints( points, numpoints, dim, newlows, newhighs ) - scale points to new lowbound and highbound - retains old bound when newlow= -REALmax or newhigh= +REALmax - - returns: - scaled points - overwrites old points - - design: - for each coordinate - compute current low and high bound - compute scale and shift factors - scale all points - enforce new low and high bound for all points -*/ -void qh_scalepoints(pointT *points, int numpoints, int dim, - realT *newlows, realT *newhighs) { - int i,k; - realT shift, scale, *coord, low, high, newlow, newhigh, mincoord, maxcoord; - boolT nearzero= False; - - for (k=0; k < dim; k++) { - newhigh= newhighs[k]; - newlow= newlows[k]; - if (newhigh > REALmax/2 && newlow < -REALmax/2) - continue; - low= REALmax; - high= -REALmax; - for (i=numpoints, coord=points+k; i--; coord += dim) { - minimize_(low, *coord); - maximize_(high, *coord); - } - if (newhigh > REALmax/2) - newhigh= high; - if (newlow < -REALmax/2) - newlow= low; - if (qh DELAUNAY && k == dim-1 && newhigh < newlow) { - qh_fprintf(qh ferr, 6021, "qhull input error: 'Qb%d' or 'QB%d' inverts paraboloid since high bound %.2g < low bound %.2g\n", - k, k, newhigh, newlow); - qh_errexit(qh_ERRinput, NULL, NULL); - } - scale= qh_divzero(newhigh - newlow, high - low, - qh MINdenom_1, &nearzero); - if (nearzero) { - qh_fprintf(qh ferr, 6022, "qhull input error: %d'th dimension's new bounds [%2.2g, %2.2g] too wide for\nexisting bounds [%2.2g, %2.2g]\n", - k, newlow, newhigh, low, high); - qh_errexit(qh_ERRinput, NULL, NULL); - } - shift= (newlow * high - low * newhigh)/(high-low); - coord= points+k; - for (i=numpoints; i--; coord += dim) - *coord= *coord * scale + shift; - coord= points+k; - if (newlow < newhigh) { - mincoord= newlow; - maxcoord= newhigh; - }else { - mincoord= newhigh; - maxcoord= newlow; - } - for (i=numpoints; i--; coord += dim) { - minimize_(*coord, maxcoord); /* because of roundoff error */ - maximize_(*coord, mincoord); - } - trace0((qh ferr, 10, "qh_scalepoints: scaled %d'th coordinate [%2.2g, %2.2g] to [%.2g, %.2g] for %d points by %2.2g and shifted %2.2g\n", - k, low, high, newlow, newhigh, numpoints, scale, shift)); - } -} /* scalepoints */ - - -/*-<a href="qh-geom.htm#TOC" - >-------------------------------</a><a name="setdelaunay">-</a> - - qh_setdelaunay( dim, count, points ) - project count points to dim-d paraboloid for Delaunay triangulation - - dim is one more than the dimension of the input set - assumes dim is at least 3 (i.e., at least a 2-d Delaunay triangulation) - - points is a dim*count realT array. The first dim-1 coordinates - are the coordinates of the first input point. array[dim] is - the first coordinate of the second input point. array[2*dim] is - the first coordinate of the third input point. - - if qh.last_low defined (i.e., 'Qbb' called qh_scalelast) - calls qh_scalelast to scale the last coordinate the same as the other points - - returns: - for each point - sets point[dim-1] to sum of squares of coordinates - scale points to 'Qbb' if needed - - notes: - to project one point, use - qh_setdelaunay(qh hull_dim, 1, point) - - Do not use options 'Qbk', 'QBk', or 'QbB' since they scale - the coordinates after the original projection. - -*/ -void qh_setdelaunay(int dim, int count, pointT *points) { - int i, k; - coordT *coordp, coord; - realT paraboloid; - - trace0((qh ferr, 11, "qh_setdelaunay: project %d points to paraboloid for Delaunay triangulation\n", count)); - coordp= points; - for (i=0; i < count; i++) { - coord= *coordp++; - paraboloid= coord*coord; - for (k=dim-2; k--; ) { - coord= *coordp++; - paraboloid += coord*coord; - } - *coordp++ = paraboloid; - } - if (qh last_low < REALmax/2) - qh_scalelast(points, count, dim, qh last_low, qh last_high, qh last_newhigh); -} /* setdelaunay */ - - -/*-<a href="qh-geom.htm#TOC" - >-------------------------------</a><a name="sethalfspace">-</a> - - qh_sethalfspace( dim, coords, nextp, normal, offset, feasible ) - set point to dual of halfspace relative to feasible point - halfspace is normal coefficients and offset. - - returns: - false if feasible point is outside of hull (error message already reported) - overwrites coordinates for point at dim coords - nextp= next point (coords) - - design: - compute distance from feasible point to halfspace - divide each normal coefficient by -dist -*/ -boolT qh_sethalfspace(int dim, coordT *coords, coordT **nextp, - coordT *normal, coordT *offset, coordT *feasible) { - coordT *normp= normal, *feasiblep= feasible, *coordp= coords; - realT dist; - realT r; /*bug fix*/ - int k; - boolT zerodiv; - - dist= *offset; - for (k=dim; k--; ) - dist += *(normp++) * *(feasiblep++); - if (dist > 0) - goto LABELerroroutside; - normp= normal; - if (dist < -qh MINdenom) { - for (k=dim; k--; ) - *(coordp++)= *(normp++) / -dist; - }else { - for (k=dim; k--; ) { - *(coordp++)= qh_divzero(*(normp++), -dist, qh MINdenom_1, &zerodiv); - if (zerodiv) - goto LABELerroroutside; - } - } - *nextp= coordp; - if (qh IStracing >= 4) { - qh_fprintf(qh ferr, 8021, "qh_sethalfspace: halfspace at offset %6.2g to point: ", *offset); - for (k=dim, coordp=coords; k--; ) { - r= *coordp++; - qh_fprintf(qh ferr, 8022, " %6.2g", r); - } - qh_fprintf(qh ferr, 8023, "\n"); - } - return True; -LABELerroroutside: - feasiblep= feasible; - normp= normal; - qh_fprintf(qh ferr, 6023, "qhull input error: feasible point is not clearly inside halfspace\nfeasible point: "); - for (k=dim; k--; ) - qh_fprintf(qh ferr, 8024, qh_REAL_1, r=*(feasiblep++)); - qh_fprintf(qh ferr, 8025, "\n halfspace: "); - for (k=dim; k--; ) - qh_fprintf(qh ferr, 8026, qh_REAL_1, r=*(normp++)); - qh_fprintf(qh ferr, 8027, "\n at offset: "); - qh_fprintf(qh ferr, 8028, qh_REAL_1, *offset); - qh_fprintf(qh ferr, 8029, " and distance: "); - qh_fprintf(qh ferr, 8030, qh_REAL_1, dist); - qh_fprintf(qh ferr, 8031, "\n"); - return False; -} /* sethalfspace */ - -/*-<a href="qh-geom.htm#TOC" - >-------------------------------</a><a name="sethalfspace_all">-</a> - - qh_sethalfspace_all( dim, count, halfspaces, feasible ) - generate dual for halfspace intersection with feasible point - array of count halfspaces - each halfspace is normal coefficients followed by offset - the origin is inside the halfspace if the offset is negative - - returns: - malloc'd array of count X dim-1 points - - notes: - call before qh_init_B or qh_initqhull_globals - unused/untested code: please email bradb@shore.net if this works ok for you - If using option 'Fp', also set qh feasible_point. It is a malloc'd array - that is freed by qh_freebuffers. - - design: - see qh_sethalfspace -*/ -coordT *qh_sethalfspace_all(int dim, int count, coordT *halfspaces, pointT *feasible) { - int i, newdim; - pointT *newpoints; - coordT *coordp, *normalp, *offsetp; - - trace0((qh ferr, 12, "qh_sethalfspace_all: compute dual for halfspace intersection\n")); - newdim= dim - 1; - if (!(newpoints=(coordT*)qh_malloc(count*newdim*sizeof(coordT)))){ - qh_fprintf(qh ferr, 6024, "qhull error: insufficient memory to compute dual of %d halfspaces\n", - count); - qh_errexit(qh_ERRmem, NULL, NULL); - } - coordp= newpoints; - normalp= halfspaces; - for (i=0; i < count; i++) { - offsetp= normalp + newdim; - if (!qh_sethalfspace(newdim, coordp, &coordp, normalp, offsetp, feasible)) { - qh_fprintf(qh ferr, 8032, "The halfspace was at index %d\n", i); - qh_errexit(qh_ERRinput, NULL, NULL); - } - normalp= offsetp + 1; - } - return newpoints; -} /* sethalfspace_all */ - - -/*-<a href="qh-geom.htm#TOC" - >-------------------------------</a><a name="sharpnewfacets">-</a> - - qh_sharpnewfacets() - - returns: - true if could be an acute angle (facets in different quadrants) - - notes: - for qh_findbest - - design: - for all facets on qh.newfacet_list - if two facets are in different quadrants - set issharp -*/ -boolT qh_sharpnewfacets() { - facetT *facet; - boolT issharp = False; - int *quadrant, k; - - quadrant= (int*)qh_memalloc(qh hull_dim * sizeof(int)); - FORALLfacet_(qh newfacet_list) { - if (facet == qh newfacet_list) { - for (k=qh hull_dim; k--; ) - quadrant[ k]= (facet->normal[ k] > 0); - }else { - for (k=qh hull_dim; k--; ) { - if (quadrant[ k] != (facet->normal[ k] > 0)) { - issharp= True; - break; - } - } - } - if (issharp) - break; - } - qh_memfree( quadrant, qh hull_dim * sizeof(int)); - trace3((qh ferr, 3001, "qh_sharpnewfacets: %d\n", issharp)); - return issharp; -} /* sharpnewfacets */ - -/*-<a href="qh-geom.htm#TOC" - >-------------------------------</a><a name="voronoi_center">-</a> - - qh_voronoi_center( dim, points ) - return Voronoi center for a set of points - dim is the orginal dimension of the points - gh.gm_matrix/qh.gm_row are scratch buffers - - returns: - center as a temporary point - if non-simplicial, - returns center for max simplex of points - - notes: - from Bowyer & Woodwark, A Programmer's Geometry, 1983, p. 65 - - design: - if non-simplicial - determine max simplex for points - translate point0 of simplex to origin - compute sum of squares of diagonal - compute determinate - compute Voronoi center (see Bowyer & Woodwark) -*/ -pointT *qh_voronoi_center(int dim, setT *points) { - pointT *point, **pointp, *point0; - pointT *center= (pointT*)qh_memalloc(qh center_size); - setT *simplex; - int i, j, k, size= qh_setsize(points); - coordT *gmcoord; - realT *diffp, sum2, *sum2row, *sum2p, det, factor; - boolT nearzero, infinite; - - if (size == dim+1) - simplex= points; - else if (size < dim+1) { - qh_fprintf(qh ferr, 6025, "qhull internal error (qh_voronoi_center):\n need at least %d points to construct a Voronoi center\n", - dim+1); - qh_errexit(qh_ERRqhull, NULL, NULL); - simplex= points; /* never executed -- avoids warning */ - }else { - simplex= qh_settemp(dim+1); - qh_maxsimplex(dim, points, NULL, 0, &simplex); - } - point0= SETfirstt_(simplex, pointT); - gmcoord= qh gm_matrix; - for (k=0; k < dim; k++) { - qh gm_row[k]= gmcoord; - FOREACHpoint_(simplex) { - if (point != point0) - *(gmcoord++)= point[k] - point0[k]; - } - } - sum2row= gmcoord; - for (i=0; i < dim; i++) { - sum2= 0.0; - for (k=0; k < dim; k++) { - diffp= qh gm_row[k] + i; - sum2 += *diffp * *diffp; - } - *(gmcoord++)= sum2; - } - det= qh_determinant(qh gm_row, dim, &nearzero); - factor= qh_divzero(0.5, det, qh MINdenom, &infinite); - if (infinite) { - for (k=dim; k--; ) - center[k]= qh_INFINITE; - if (qh IStracing) - qh_printpoints(qh ferr, "qh_voronoi_center: at infinity for ", simplex); - }else { - for (i=0; i < dim; i++) { - gmcoord= qh gm_matrix; - sum2p= sum2row; - for (k=0; k < dim; k++) { - qh gm_row[k]= gmcoord; - if (k == i) { - for (j=dim; j--; ) - *(gmcoord++)= *sum2p++; - }else { - FOREACHpoint_(simplex) { - if (point != point0) - *(gmcoord++)= point[k] - point0[k]; - } - } - } - center[i]= qh_determinant(qh gm_row, dim, &nearzero)*factor + point0[i]; - } -#ifndef qh_NOtrace - if (qh IStracing >= 3) { - qh_fprintf(qh ferr, 8033, "qh_voronoi_center: det %2.2g factor %2.2g ", det, factor); - qh_printmatrix(qh ferr, "center:", ¢er, 1, dim); - if (qh IStracing >= 5) { - qh_printpoints(qh ferr, "points", simplex); - FOREACHpoint_(simplex) - qh_fprintf(qh ferr, 8034, "p%d dist %.2g, ", qh_pointid(point), - qh_pointdist(point, center, dim)); - qh_fprintf(qh ferr, 8035, "\n"); - } - } -#endif - } - if (simplex != points) - qh_settempfree(&simplex); - return center; -} /* voronoi_center */ - diff --git a/PyMca/Object3D/Object3DQhull/src/global.c b/PyMca/Object3D/Object3DQhull/src/global.c deleted file mode 100644 index a9063ea..0000000 --- a/PyMca/Object3D/Object3DQhull/src/global.c +++ /dev/null @@ -1,2127 +0,0 @@ - -/*<html><pre> -<a href="qh-globa.htm" - >-------------------------------</a><a name="TOP">-</a> - - global.c - initializes all the globals of the qhull application - - see README - - see libqhull.h for qh.globals and function prototypes - - see qhull_a.h for internal functions - - Copyright (c) 1993-2012 The Geometry Center. - $Id: //main/2011/qhull/src/libqhull/global.c#15 $$Change: 1490 $ - $DateTime: 2012/02/19 20:27:01 $$Author: bbarber $ - */ - -#include "qhull_a.h" - -/*========= qh definition -- globals defined in libqhull.h =======================*/ - -int qhull_inuse= 0; /* not used */ - -#if qh_QHpointer -qhT *qh_qh= NULL; /* pointer to all global variables */ -#else -qhT qh_qh; /* all global variables. - Add "= {0}" if this causes a compiler error. - Also qh_qhstat in stat.c and qhmem in mem.c. */ -#endif - -/*-<a href ="qh-globa.htm#TOC" - >--------------------------------</a><a name="qh_version">-</a> - - qh_version - version string by year and date - - the revision increases on code changes only - - notes: - change date: Changes.txt, Announce.txt, index.htm, README.txt, - qhull-news.html, Eudora signatures, CMakeLists.txt - change version: README.txt, qh-get.htm, File_id.diz, Makefile.txt - change year: Copying.txt - check download size - recompile user_eg.c, rbox.c, libqhull.c, qconvex.c, qdelaun.c qvoronoi.c, qhalf.c, testqset.c -*/ - -const char *qh_version = "2012.1 2012/02/18"; - -/*-<a href="qh-globa.htm#TOC" - >-------------------------------</a><a name="appendprint">-</a> - - qh_appendprint( printFormat ) - append printFormat to qh.PRINTout unless already defined -*/ -void qh_appendprint(qh_PRINT format) { - int i; - - for (i=0; i < qh_PRINTEND; i++) { - if (qh PRINTout[i] == format && format != qh_PRINTqhull) - break; - if (!qh PRINTout[i]) { - qh PRINTout[i]= format; - break; - } - } -} /* appendprint */ - -/*-<a href="qh-globa.htm#TOC" - >-------------------------------</a><a name="checkflags">-</a> - - qh_checkflags( commandStr, hiddenFlags ) - errors if commandStr contains hiddenFlags - hiddenFlags starts and ends with a space and is space deliminated (checked) - - notes: - ignores first word (e.g., "qconvex i") - use qh_strtol/strtod since strtol/strtod may or may not skip trailing spaces - - see: - qh_initflags() initializes Qhull according to commandStr -*/ -void qh_checkflags(char *command, char *hiddenflags) { - char *s= command, *t, *chkerr; /* qh_skipfilename is non-const */ - char key, opt, prevopt; - char chkkey[]= " "; - char chkopt[]= " "; - char chkopt2[]= " "; - boolT waserr= False; - - if (*hiddenflags != ' ' || hiddenflags[strlen(hiddenflags)-1] != ' ') { - qh_fprintf(qh ferr, 6026, "qhull error (qh_checkflags): hiddenflags must start and end with a space: \"%s\"", hiddenflags); - qh_errexit(qh_ERRinput, NULL, NULL); - } - if (strpbrk(hiddenflags, ",\n\r\t")) { - qh_fprintf(qh ferr, 6027, "qhull error (qh_checkflags): hiddenflags contains commas, newlines, or tabs: \"%s\"", hiddenflags); - qh_errexit(qh_ERRinput, NULL, NULL); - } - while (*s && !isspace(*s)) /* skip program name */ - s++; - while (*s) { - while (*s && isspace(*s)) - s++; - if (*s == '-') - s++; - if (!*s) - break; - key = *s++; - chkerr = NULL; - if (key == 'T' && (*s == 'I' || *s == 'O')) { /* TI or TO 'file name' */ - s= qh_skipfilename(++s); - continue; - } - chkkey[1]= key; - if (strstr(hiddenflags, chkkey)) { - chkerr= chkkey; - }else if (isupper(key)) { - opt= ' '; - prevopt= ' '; - chkopt[1]= key; - chkopt2[1]= key; - while (!chkerr && *s && !isspace(*s)) { - opt= *s++; - if (isalpha(opt)) { - chkopt[2]= opt; - if (strstr(hiddenflags, chkopt)) - chkerr= chkopt; - if (prevopt != ' ') { - chkopt2[2]= prevopt; - chkopt2[3]= opt; - if (strstr(hiddenflags, chkopt2)) - chkerr= chkopt2; - } - }else if (key == 'Q' && isdigit(opt) && prevopt != 'b' - && (prevopt == ' ' || islower(prevopt))) { - chkopt[2]= opt; - if (strstr(hiddenflags, chkopt)) - chkerr= chkopt; - }else { - qh_strtod(s-1, &t); - if (s < t) - s= t; - } - prevopt= opt; - } - } - if (chkerr) { - *chkerr= '\''; - chkerr[strlen(chkerr)-1]= '\''; - qh_fprintf(qh ferr, 6029, "qhull error: option %s is not used with this program.\n It may be used with qhull.\n", chkerr); - waserr= True; - } - } - if (waserr) - qh_errexit(qh_ERRinput, NULL, NULL); -} /* checkflags */ - -/*-<a href="qh-globa.htm#TOC" - >-------------------------------</a><a name="qh_clear_outputflags">-</a> - - qh_clear_outputflags() - Clear output flags for QhullPoints -*/ -void qh_clear_outputflags(void) { - int i,k; - - qh ANNOTATEoutput= False; - qh DOintersections= False; - qh DROPdim= -1; - qh FORCEoutput= False; - qh GETarea= False; - qh GOODpoint= 0; - qh GOODpointp= NULL; - qh GOODthreshold= False; - qh GOODvertex= 0; - qh GOODvertexp= NULL; - qh IStracing= 0; - qh KEEParea= False; - qh KEEPmerge= False; - qh KEEPminArea= REALmax; - qh PRINTcentrums= False; - qh PRINTcoplanar= False; - qh PRINTdots= False; - qh PRINTgood= False; - qh PRINTinner= False; - qh PRINTneighbors= False; - qh PRINTnoplanes= False; - qh PRINToptions1st= False; - qh PRINTouter= False; - qh PRINTprecision= True; - qh PRINTridges= False; - qh PRINTspheres= False; - qh PRINTstatistics= False; - qh PRINTsummary= False; - qh PRINTtransparent= False; - qh SPLITthresholds= False; - qh TRACElevel= 0; - qh TRInormals= False; - qh USEstdout= False; - qh VERIFYoutput= False; - for (k=qh input_dim+1; k--; ) { /* duplicated in qh_initqhull_buffers and qh_clear_ouputflags */ - qh lower_threshold[k]= -REALmax; - qh upper_threshold[k]= REALmax; - qh lower_bound[k]= -REALmax; - qh upper_bound[k]= REALmax; - } - - for (i=0; i < qh_PRINTEND; i++) { - qh PRINTout[i]= qh_PRINTnone; - } - - if (!qh qhull_commandsiz2) - qh qhull_commandsiz2= (int)strlen(qh qhull_command); /* WARN64 */ - else { - qh qhull_command[qh qhull_commandsiz2]= '\0'; - } - if (!qh qhull_optionsiz2) - qh qhull_optionsiz2= (int)strlen(qh qhull_options); /* WARN64 */ - else { - qh qhull_options[qh qhull_optionsiz2]= '\0'; - qh qhull_optionlen= qh_OPTIONline; /* start a new line */ - } -} /* clear_outputflags */ - -/*-<a href="qh-globa.htm#TOC" - >-------------------------------</a><a name="clock">-</a> - - qh_clock() - return user CPU time in 100ths (qh_SECtick) - only defined for qh_CLOCKtype == 2 - - notes: - use first value to determine time 0 - from Stevens '92 8.15 -*/ -unsigned long qh_clock(void) { - -#if (qh_CLOCKtype == 2) - struct tms time; - static long clktck; /* initialized first call */ - double ratio, cpu; - unsigned long ticks; - - if (!clktck) { - if ((clktck= sysconf(_SC_CLK_TCK)) < 0) { - qh_fprintf(qh ferr, 6030, "qhull internal error (qh_clock): sysconf() failed. Use qh_CLOCKtype 1 in user.h\n"); - qh_errexit(qh_ERRqhull, NULL, NULL); - } - } - if (times(&time) == -1) { - qh_fprintf(qh ferr, 6031, "qhull internal error (qh_clock): times() failed. Use qh_CLOCKtype 1 in user.h\n"); - qh_errexit(qh_ERRqhull, NULL, NULL); - } - ratio= qh_SECticks / (double)clktck; - ticks= time.tms_utime * ratio; - return ticks; -#else - qh_fprintf(qh ferr, 6032, "qhull internal error (qh_clock): use qh_CLOCKtype 2 in user.h\n"); - qh_errexit(qh_ERRqhull, NULL, NULL); /* never returns */ - return 0; -#endif -} /* clock */ - -/*-<a href="qh-globa.htm#TOC" - >-------------------------------</a><a name="freebuffers">-</a> - - qh_freebuffers() - free up global memory buffers - - notes: - must match qh_initbuffers() -*/ -void qh_freebuffers(void) { - - trace5((qh ferr, 5001, "qh_freebuffers: freeing up global memory buffers\n")); - /* allocated by qh_initqhull_buffers */ - qh_memfree(qh NEARzero, qh hull_dim * sizeof(realT)); - qh_memfree(qh lower_threshold, (qh input_dim+1) * sizeof(realT)); - qh_memfree(qh upper_threshold, (qh input_dim+1) * sizeof(realT)); - qh_memfree(qh lower_bound, (qh input_dim+1) * sizeof(realT)); - qh_memfree(qh upper_bound, (qh input_dim+1) * sizeof(realT)); - qh_memfree(qh gm_matrix, (qh hull_dim+1) * qh hull_dim * sizeof(coordT)); - qh_memfree(qh gm_row, (qh hull_dim+1) * sizeof(coordT *)); - qh NEARzero= qh lower_threshold= qh upper_threshold= NULL; - qh lower_bound= qh upper_bound= NULL; - qh gm_matrix= NULL; - qh gm_row= NULL; - qh_setfree(&qh other_points); - qh_setfree(&qh del_vertices); - qh_setfree(&qh coplanarfacetset); - if (qh line) /* allocated by qh_readinput, freed if no error */ - qh_free(qh line); - if (qh half_space) - qh_free(qh half_space); - if (qh temp_malloc) - qh_free(qh temp_malloc); - if (qh feasible_point) /* allocated by qh_readfeasible */ - qh_free(qh feasible_point); - if (qh feasible_string) /* allocated by qh_initflags */ - qh_free(qh feasible_string); - qh line= qh feasible_string= NULL; - qh half_space= qh feasible_point= qh temp_malloc= NULL; - /* usually allocated by qh_readinput */ - if (qh first_point && qh POINTSmalloc) { - qh_free(qh first_point); - qh first_point= NULL; - } - if (qh input_points && qh input_malloc) { /* set by qh_joggleinput */ - qh_free(qh input_points); - qh input_points= NULL; - } - trace5((qh ferr, 5002, "qh_freebuffers: finished\n")); -} /* freebuffers */ - - -/*-<a href="qh-globa.htm#TOC" - >-------------------------------</a><a name="freebuild">-</a> - - qh_freebuild( allmem ) - free global memory used by qh_initbuild and qh_buildhull - if !allmem, - does not free short memory (e.g., facetT, freed by qh_memfreeshort) - - design: - free centrums - free each vertex - mark unattached ridges - for each facet - free ridges - free outside set, coplanar set, neighbor set, ridge set, vertex set - free facet - free hash table - free interior point - free merge set - free temporary sets -*/ -void qh_freebuild(boolT allmem) { - facetT *facet; - vertexT *vertex; - ridgeT *ridge, **ridgep; - mergeT *merge, **mergep; - - trace1((qh ferr, 1005, "qh_freebuild: free memory from qh_inithull and qh_buildhull\n")); - if (qh del_vertices) - qh_settruncate(qh del_vertices, 0); - if (allmem) { - while ((vertex= qh vertex_list)) { - if (vertex->next) - qh_delvertex(vertex); - else { - qh_memfree(vertex, (int)sizeof(vertexT)); - qh newvertex_list= qh vertex_list= NULL; - } - } - }else if (qh VERTEXneighbors) { - FORALLvertices - qh_setfreelong(&(vertex->neighbors)); - } - qh VERTEXneighbors= False; - qh GOODclosest= NULL; - if (allmem) { - FORALLfacets { - FOREACHridge_(facet->ridges) - ridge->seen= False; - } - FORALLfacets { - if (facet->visible) { - FOREACHridge_(facet->ridges) { - if (!otherfacet_(ridge, facet)->visible) - ridge->seen= True; /* an unattached ridge */ - } - } - } - while ((facet= qh facet_list)) { - FOREACHridge_(facet->ridges) { - if (ridge->seen) { - qh_setfree(&(ridge->vertices)); - qh_memfree(ridge, (int)sizeof(ridgeT)); - }else - ridge->seen= True; - } - qh_setfree(&(facet->outsideset)); - qh_setfree(&(facet->coplanarset)); - qh_setfree(&(facet->neighbors)); - qh_setfree(&(facet->ridges)); - qh_setfree(&(facet->vertices)); - if (facet->next) - qh_delfacet(facet); - else { - qh_memfree(facet, (int)sizeof(facetT)); - qh visible_list= qh newfacet_list= qh facet_list= NULL; - } - } - }else { - FORALLfacets { - qh_setfreelong(&(facet->outsideset)); - qh_setfreelong(&(facet->coplanarset)); - if (!facet->simplicial) { - qh_setfreelong(&(facet->neighbors)); - qh_setfreelong(&(facet->ridges)); - qh_setfreelong(&(facet->vertices)); - } - } - } - qh_setfree(&(qh hash_table)); - qh_memfree(qh interior_point, qh normal_size); - qh interior_point= NULL; - FOREACHmerge_(qh facet_mergeset) /* usually empty */ - qh_memfree(merge, (int)sizeof(mergeT)); - qh facet_mergeset= NULL; /* temp set */ - qh degen_mergeset= NULL; /* temp set */ - qh_settempfree_all(); -} /* freebuild */ - -/*-<a href="qh-globa.htm#TOC" - >-------------------------------</a><a name="freeqhull">-</a> - - qh_freeqhull( allmem ) - see qh_freeqhull2 - if qh_QHpointer, frees qh_qh -*/ -void qh_freeqhull(boolT allmem) { - qh_freeqhull2(allmem); -#if qh_QHpointer - qh_free(qh_qh); - qh_qh= NULL; -#endif -} - -/*-<a href="qh-globa.htm#TOC" ->-------------------------------</a><a name="freeqhull2">-</a> - -qh_freeqhull2( allmem ) - free global memory - if !allmem, - does not free short memory (freed by qh_memfreeshort) - -notes: - sets qh.NOerrexit in case caller forgets to - -see: - see qh_initqhull_start2() - -design: - free global and temporary memory from qh_initbuild and qh_buildhull - free buffers - free statistics -*/ -void qh_freeqhull2(boolT allmem) { - - trace1((qh ferr, 1006, "qh_freeqhull2: free global memory\n")); - qh NOerrexit= True; /* no more setjmp since called at exit and ~QhullQh */ - qh_freebuild(allmem); - qh_freebuffers(); - qh_freestatistics(); -#if qh_QHpointer - memset((char *)qh_qh, 0, sizeof(qhT)); - /* qh_qh freed by caller, qh_freeqhull() */ -#else - memset((char *)&qh_qh, 0, sizeof(qhT)); -#endif - qh NOerrexit= True; -} /* freeqhull2 */ - -/*-<a href="qh-globa.htm#TOC" - >-------------------------------</a><a name="init_A">-</a> - - qh_init_A( infile, outfile, errfile, argc, argv ) - initialize memory and stdio files - convert input options to option string (qh.qhull_command) - - notes: - infile may be NULL if qh_readpoints() is not called - - errfile should always be defined. It is used for reporting - errors. outfile is used for output and format options. - - argc/argv may be 0/NULL - - called before error handling initialized - qh_errexit() may not be used -*/ -void qh_init_A(FILE *infile, FILE *outfile, FILE *errfile, int argc, char *argv[]) { - qh_meminit(errfile); - qh_initqhull_start(infile, outfile, errfile); - qh_init_qhull_command(argc, argv); -} /* init_A */ - -/*-<a href="qh-globa.htm#TOC" - >-------------------------------</a><a name="init_B">-</a> - - qh_init_B( points, numpoints, dim, ismalloc ) - initialize globals for points array - - points has numpoints dim-dimensional points - points[0] is the first coordinate of the first point - points[1] is the second coordinate of the first point - points[dim] is the first coordinate of the second point - - ismalloc=True - Qhull will call qh_free(points) on exit or input transformation - ismalloc=False - Qhull will allocate a new point array if needed for input transformation - - qh.qhull_command - is the option string. - It is defined by qh_init_B(), qh_qhull_command(), or qh_initflags - - returns: - if qh.PROJECTinput or (qh.DELAUNAY and qh.PROJECTdelaunay) - projects the input to a new point array - - if qh.DELAUNAY, - qh.hull_dim is increased by one - if qh.ATinfinity, - qh_projectinput adds point-at-infinity for Delaunay tri. - - if qh.SCALEinput - changes the upper and lower bounds of the input, see qh_scaleinput() - - if qh.ROTATEinput - rotates the input by a random rotation, see qh_rotateinput() - if qh.DELAUNAY - rotates about the last coordinate - - notes: - called after points are defined - qh_errexit() may be used -*/ -void qh_init_B(coordT *points, int numpoints, int dim, boolT ismalloc) { - qh_initqhull_globals(points, numpoints, dim, ismalloc); - if (qhmem.LASTsize == 0) - qh_initqhull_mem(); - /* mem.c and qset.c are initialized */ - qh_initqhull_buffers(); - qh_initthresholds(qh qhull_command); - if (qh PROJECTinput || (qh DELAUNAY && qh PROJECTdelaunay)) - qh_projectinput(); - if (qh SCALEinput) - qh_scaleinput(); - if (qh ROTATErandom >= 0) { - qh_randommatrix(qh gm_matrix, qh hull_dim, qh gm_row); - if (qh DELAUNAY) { - int k, lastk= qh hull_dim-1; - for (k=0; k < lastk; k++) { - qh gm_row[k][lastk]= 0.0; - qh gm_row[lastk][k]= 0.0; - } - qh gm_row[lastk][lastk]= 1.0; - } - qh_gram_schmidt(qh hull_dim, qh gm_row); - qh_rotateinput(qh gm_row); - } -} /* init_B */ - -/*-<a href="qh-globa.htm#TOC" - >-------------------------------</a><a name="init_qhull_command">-</a> - - qh_init_qhull_command( argc, argv ) - build qh.qhull_command from argc/argv - - returns: - a space-delimited string of options (just as typed) - - notes: - makes option string easy to input and output - - argc/argv may be 0/NULL -*/ -void qh_init_qhull_command(int argc, char *argv[]) { - - if (!qh_argv_to_command(argc, argv, qh qhull_command, (int)sizeof(qh qhull_command))){ - /* Assumes qh.ferr is defined. */ - qh_fprintf(qh ferr, 6033, "qhull input error: more than %d characters in command line\n", - (int)sizeof(qh qhull_command)); - qh_exit(qh_ERRinput); /* error reported, can not use qh_errexit */ - } -} /* init_qhull_command */ - -/*-<a href="qh-globa.htm#TOC" - >-------------------------------</a><a name="initflags">-</a> - - qh_initflags( commandStr ) - set flags and initialized constants from commandStr - - returns: - sets qh.qhull_command to command if needed - - notes: - ignores first word (e.g., "qhull d") - use qh_strtol/strtod since strtol/strtod may or may not skip trailing spaces - - see: - qh_initthresholds() continues processing of 'Pdn' and 'PDn' - 'prompt' in unix.c for documentation - - design: - for each space-deliminated option group - if top-level option - check syntax - append approriate option to option string - set appropriate global variable or append printFormat to print options - else - for each sub-option - check syntax - append approriate option to option string - set appropriate global variable or append printFormat to print options -*/ -void qh_initflags(char *command) { - int k, i, lastproject; - char *s= command, *t, *prev_s, *start, key; - boolT isgeom= False, wasproject; - realT r; - - if (command <= &qh qhull_command[0] || command > &qh qhull_command[0] + sizeof(qh qhull_command)) { - if (command != &qh qhull_command[0]) { - *qh qhull_command= '\0'; - strncat(qh qhull_command, command, sizeof(qh qhull_command)-strlen(qh qhull_command)-1); - } - while (*s && !isspace(*s)) /* skip program name */ - s++; - } - while (*s) { - while (*s && isspace(*s)) - s++; - if (*s == '-') - s++; - if (!*s) - break; - prev_s= s; - switch (*s++) { - case 'd': - qh_option("delaunay", NULL, NULL); - qh DELAUNAY= True; - break; - case 'f': - qh_option("facets", NULL, NULL); - qh_appendprint(qh_PRINTfacets); - break; - case 'i': - qh_option("incidence", NULL, NULL); - qh_appendprint(qh_PRINTincidences); - break; - case 'm': - qh_option("mathematica", NULL, NULL); - qh_appendprint(qh_PRINTmathematica); - break; - case 'n': - qh_option("normals", NULL, NULL); - qh_appendprint(qh_PRINTnormals); - break; - case 'o': - qh_option("offFile", NULL, NULL); - qh_appendprint(qh_PRINToff); - break; - case 'p': - qh_option("points", NULL, NULL); - qh_appendprint(qh_PRINTpoints); - break; - case 's': - qh_option("summary", NULL, NULL); - qh PRINTsummary= True; - break; - case 'v': - qh_option("voronoi", NULL, NULL); - qh VORONOI= True; - qh DELAUNAY= True; - break; - case 'A': - if (!isdigit(*s) && *s != '.' && *s != '-') - qh_fprintf(qh ferr, 7002, "qhull warning: no maximum cosine angle given for option 'An'. Ignored.\n"); - else { - if (*s == '-') { - qh premerge_cos= -qh_strtod(s, &s); - qh_option("Angle-premerge-", NULL, &qh premerge_cos); - qh PREmerge= True; - }else { - qh postmerge_cos= qh_strtod(s, &s); - qh_option("Angle-postmerge", NULL, &qh postmerge_cos); - qh POSTmerge= True; - } - qh MERGING= True; - } - break; - case 'C': - if (!isdigit(*s) && *s != '.' && *s != '-') - qh_fprintf(qh ferr, 7003, "qhull warning: no centrum radius given for option 'Cn'. Ignored.\n"); - else { - if (*s == '-') { - qh premerge_centrum= -qh_strtod(s, &s); - qh_option("Centrum-premerge-", NULL, &qh premerge_centrum); - qh PREmerge= True; - }else { - qh postmerge_centrum= qh_strtod(s, &s); - qh_option("Centrum-postmerge", NULL, &qh postmerge_centrum); - qh POSTmerge= True; - } - qh MERGING= True; - } - break; - case 'E': - if (*s == '-') - qh_fprintf(qh ferr, 7004, "qhull warning: negative maximum roundoff given for option 'An'. Ignored.\n"); - else if (!isdigit(*s)) - qh_fprintf(qh ferr, 7005, "qhull warning: no maximum roundoff given for option 'En'. Ignored.\n"); - else { - qh DISTround= qh_strtod(s, &s); - qh_option("Distance-roundoff", NULL, &qh DISTround); - qh SETroundoff= True; - } - break; - case 'H': - start= s; - qh HALFspace= True; - qh_strtod(s, &t); - while (t > s) { - if (*t && !isspace(*t)) { - if (*t == ',') - t++; - else - qh_fprintf(qh ferr, 7006, "qhull warning: origin for Halfspace intersection should be 'Hn,n,n,...'\n"); - } - s= t; - qh_strtod(s, &t); - } - if (start < t) { - if (!(qh feasible_string= (char*)calloc((size_t)(t-start+1), (size_t)1))) { - qh_fprintf(qh ferr, 6034, "qhull error: insufficient memory for 'Hn,n,n'\n"); - qh_errexit(qh_ERRmem, NULL, NULL); - } - strncpy(qh feasible_string, start, (size_t)(t-start)); - qh_option("Halfspace-about", NULL, NULL); - qh_option(qh feasible_string, NULL, NULL); - }else - qh_option("Halfspace", NULL, NULL); - break; - case 'R': - if (!isdigit(*s)) - qh_fprintf(qh ferr, 7007, "qhull warning: missing random perturbation for option 'Rn'. Ignored\n"); - else { - qh RANDOMfactor= qh_strtod(s, &s); - qh_option("Random_perturb", NULL, &qh RANDOMfactor); - qh RANDOMdist= True; - } - break; - case 'V': - if (!isdigit(*s) && *s != '-') - qh_fprintf(qh ferr, 7008, "qhull warning: missing visible distance for option 'Vn'. Ignored\n"); - else { - qh MINvisible= qh_strtod(s, &s); - qh_option("Visible", NULL, &qh MINvisible); - } - break; - case 'U': - if (!isdigit(*s) && *s != '-') - qh_fprintf(qh ferr, 7009, "qhull warning: missing coplanar distance for option 'Un'. Ignored\n"); - else { - qh MAXcoplanar= qh_strtod(s, &s); - qh_option("U-coplanar", NULL, &qh MAXcoplanar); - } - break; - case 'W': - if (*s == '-') - qh_fprintf(qh ferr, 7010, "qhull warning: negative outside width for option 'Wn'. Ignored.\n"); - else if (!isdigit(*s)) - qh_fprintf(qh ferr, 7011, "qhull warning: missing outside width for option 'Wn'. Ignored\n"); - else { - qh MINoutside= qh_strtod(s, &s); - qh_option("W-outside", NULL, &qh MINoutside); - qh APPROXhull= True; - } - break; - /************ sub menus ***************/ - case 'F': - while (*s && !isspace(*s)) { - switch (*s++) { - case 'a': - qh_option("Farea", NULL, NULL); - qh_appendprint(qh_PRINTarea); - qh GETarea= True; - break; - case 'A': - qh_option("FArea-total", NULL, NULL); - qh GETarea= True; - break; - case 'c': - qh_option("Fcoplanars", NULL, NULL); - qh_appendprint(qh_PRINTcoplanars); - break; - case 'C': - qh_option("FCentrums", NULL, NULL); - qh_appendprint(qh_PRINTcentrums); - break; - case 'd': - qh_option("Fd-cdd-in", NULL, NULL); - qh CDDinput= True; - break; - case 'D': - qh_option("FD-cdd-out", NULL, NULL); - qh CDDoutput= True; - break; - case 'F': - qh_option("FFacets-xridge", NULL, NULL); - qh_appendprint(qh_PRINTfacets_xridge); - break; - case 'i': - qh_option("Finner", NULL, NULL); - qh_appendprint(qh_PRINTinner); - break; - case 'I': - qh_option("FIDs", NULL, NULL); - qh_appendprint(qh_PRINTids); - break; - case 'm': - qh_option("Fmerges", NULL, NULL); - qh_appendprint(qh_PRINTmerges); - break; - case 'M': - qh_option("FMaple", NULL, NULL); - qh_appendprint(qh_PRINTmaple); - break; - case 'n': - qh_option("Fneighbors", NULL, NULL); - qh_appendprint(qh_PRINTneighbors); - break; - case 'N': - qh_option("FNeighbors-vertex", NULL, NULL); - qh_appendprint(qh_PRINTvneighbors); - break; - case 'o': - qh_option("Fouter", NULL, NULL); - qh_appendprint(qh_PRINTouter); - break; - case 'O': - if (qh PRINToptions1st) { - qh_option("FOptions", NULL, NULL); - qh_appendprint(qh_PRINToptions); - }else - qh PRINToptions1st= True; - break; - case 'p': - qh_option("Fpoint-intersect", NULL, NULL); - qh_appendprint(qh_PRINTpointintersect); - break; - case 'P': - qh_option("FPoint-nearest", NULL, NULL); - qh_appendprint(qh_PRINTpointnearest); - break; - case 'Q': - qh_option("FQhull", NULL, NULL); - qh_appendprint(qh_PRINTqhull); - break; - case 's': - qh_option("Fsummary", NULL, NULL); - qh_appendprint(qh_PRINTsummary); - break; - case 'S': - qh_option("FSize", NULL, NULL); - qh_appendprint(qh_PRINTsize); - qh GETarea= True; - break; - case 't': - qh_option("Ftriangles", NULL, NULL); - qh_appendprint(qh_PRINTtriangles); - break; - case 'v': - /* option set in qh_initqhull_globals */ - qh_appendprint(qh_PRINTvertices); - break; - case 'V': - qh_option("FVertex-average", NULL, NULL); - qh_appendprint(qh_PRINTaverage); - break; - case 'x': - qh_option("Fxtremes", NULL, NULL); - qh_appendprint(qh_PRINTextremes); - break; - default: - s--; - qh_fprintf(qh ferr, 7012, "qhull warning: unknown 'F' output option %c, rest ignored\n", (int)s[0]); - while (*++s && !isspace(*s)); - break; - } - } - break; - case 'G': - isgeom= True; - qh_appendprint(qh_PRINTgeom); - while (*s && !isspace(*s)) { - switch (*s++) { - case 'a': - qh_option("Gall-points", NULL, NULL); - qh PRINTdots= True; - break; - case 'c': - qh_option("Gcentrums", NULL, NULL); - qh PRINTcentrums= True; - break; - case 'h': - qh_option("Gintersections", NULL, NULL); - qh DOintersections= True; - break; - case 'i': - qh_option("Ginner", NULL, NULL); - qh PRINTinner= True; - break; - case 'n': - qh_option("Gno-planes", NULL, NULL); - qh PRINTnoplanes= True; - break; - case 'o': - qh_option("Gouter", NULL, NULL); - qh PRINTouter= True; - break; - case 'p': - qh_option("Gpoints", NULL, NULL); - qh PRINTcoplanar= True; - break; - case 'r': - qh_option("Gridges", NULL, NULL); - qh PRINTridges= True; - break; - case 't': - qh_option("Gtransparent", NULL, NULL); - qh PRINTtransparent= True; - break; - case 'v': - qh_option("Gvertices", NULL, NULL); - qh PRINTspheres= True; - break; - case 'D': - if (!isdigit(*s)) - qh_fprintf(qh ferr, 6035, "qhull input error: missing dimension for option 'GDn'\n"); - else { - if (qh DROPdim >= 0) - qh_fprintf(qh ferr, 7013, "qhull warning: can only drop one dimension. Previous 'GD%d' ignored\n", - qh DROPdim); - qh DROPdim= qh_strtol(s, &s); - qh_option("GDrop-dim", &qh DROPdim, NULL); - } - break; - default: - s--; - qh_fprintf(qh ferr, 7014, "qhull warning: unknown 'G' print option %c, rest ignored\n", (int)s[0]); - while (*++s && !isspace(*s)); - break; - } - } - break; - case 'P': - while (*s && !isspace(*s)) { - switch (*s++) { - case 'd': case 'D': /* see qh_initthresholds() */ - key= s[-1]; - i= qh_strtol(s, &s); - r= 0; - if (*s == ':') { - s++; - r= qh_strtod(s, &s); - } - if (key == 'd') - qh_option("Pdrop-facets-dim-less", &i, &r); - else - qh_option("PDrop-facets-dim-more", &i, &r); - break; - case 'g': - qh_option("Pgood-facets", NULL, NULL); - qh PRINTgood= True; - break; - case 'G': - qh_option("PGood-facet-neighbors", NULL, NULL); - qh PRINTneighbors= True; - break; - case 'o': - qh_option("Poutput-forced", NULL, NULL); - qh FORCEoutput= True; - break; - case 'p': - qh_option("Pprecision-ignore", NULL, NULL); - qh PRINTprecision= False; - break; - case 'A': - if (!isdigit(*s)) - qh_fprintf(qh ferr, 6036, "qhull input error: missing facet count for keep area option 'PAn'\n"); - else { - qh KEEParea= qh_strtol(s, &s); - qh_option("PArea-keep", &qh KEEParea, NULL); - qh GETarea= True; - } - break; - case 'F': - if (!isdigit(*s)) - qh_fprintf(qh ferr, 6037, "qhull input error: missing facet area for option 'PFn'\n"); - else { - qh KEEPminArea= qh_strtod(s, &s); - qh_option("PFacet-area-keep", NULL, &qh KEEPminArea); - qh GETarea= True; - } - break; - case 'M': - if (!isdigit(*s)) - qh_fprintf(qh ferr, 6038, "qhull input error: missing merge count for option 'PMn'\n"); - else { - qh KEEPmerge= qh_strtol(s, &s); - qh_option("PMerge-keep", &qh KEEPmerge, NULL); - } - break; - default: - s--; - qh_fprintf(qh ferr, 7015, "qhull warning: unknown 'P' print option %c, rest ignored\n", (int)s[0]); - while (*++s && !isspace(*s)); - break; - } - } - break; - case 'Q': - lastproject= -1; - while (*s && !isspace(*s)) { - switch (*s++) { - case 'b': case 'B': /* handled by qh_initthresholds */ - key= s[-1]; - if (key == 'b' && *s == 'B') { - s++; - r= qh_DEFAULTbox; - qh SCALEinput= True; - qh_option("QbBound-unit-box", NULL, &r); - break; - } - if (key == 'b' && *s == 'b') { - s++; - qh SCALElast= True; - qh_option("Qbbound-last", NULL, NULL); - break; - } - k= qh_strtol(s, &s); - r= 0.0; - wasproject= False; - if (*s == ':') { - s++; - if ((r= qh_strtod(s, &s)) == 0.0) { - t= s; /* need true dimension for memory allocation */ - while (*t && !isspace(*t)) { - if (toupper(*t++) == 'B' - && k == qh_strtol(t, &t) - && *t++ == ':' - && qh_strtod(t, &t) == 0.0) { - qh PROJECTinput++; - trace2((qh ferr, 2004, "qh_initflags: project dimension %d\n", k)); - qh_option("Qb-project-dim", &k, NULL); - wasproject= True; - lastproject= k; - break; - } - } - } - } - if (!wasproject) { - if (lastproject == k && r == 0.0) - lastproject= -1; /* doesn't catch all possible sequences */ - else if (key == 'b') { - qh SCALEinput= True; - if (r == 0.0) - r= -qh_DEFAULTbox; - qh_option("Qbound-dim-low", &k, &r); - }else { - qh SCALEinput= True; - if (r == 0.0) - r= qh_DEFAULTbox; - qh_option("QBound-dim-high", &k, &r); - } - } - break; - case 'c': - qh_option("Qcoplanar-keep", NULL, NULL); - qh KEEPcoplanar= True; - break; - case 'f': - qh_option("Qfurthest-outside", NULL, NULL); - qh BESToutside= True; - break; - case 'g': - qh_option("Qgood-facets-only", NULL, NULL); - qh ONLYgood= True; - break; - case 'i': - qh_option("Qinterior-keep", NULL, NULL); - qh KEEPinside= True; - break; - case 'm': - qh_option("Qmax-outside-only", NULL, NULL); - qh ONLYmax= True; - break; - case 'r': - qh_option("Qrandom-outside", NULL, NULL); - qh RANDOMoutside= True; - break; - case 's': - qh_option("Qsearch-initial-simplex", NULL, NULL); - qh ALLpoints= True; - break; - case 't': - qh_option("Qtriangulate", NULL, NULL); - qh TRIangulate= True; - break; - case 'T': - qh_option("QTestPoints", NULL, NULL); - if (!isdigit(*s)) - qh_fprintf(qh ferr, 6039, "qhull input error: missing number of test points for option 'QTn'\n"); - else { - qh TESTpoints= qh_strtol(s, &s); - qh_option("QTestPoints", &qh TESTpoints, NULL); - } - break; - case 'u': - qh_option("QupperDelaunay", NULL, NULL); - qh UPPERdelaunay= True; - break; - case 'v': - qh_option("Qvertex-neighbors-convex", NULL, NULL); - qh TESTvneighbors= True; - break; - case 'x': - qh_option("Qxact-merge", NULL, NULL); - qh MERGEexact= True; - break; - case 'z': - qh_option("Qz-infinity-point", NULL, NULL); - qh ATinfinity= True; - break; - case '0': - qh_option("Q0-no-premerge", NULL, NULL); - qh NOpremerge= True; - break; - case '1': - if (!isdigit(*s)) { - qh_option("Q1-no-angle-sort", NULL, NULL); - qh ANGLEmerge= False; - break; - } - switch (*s++) { - case '0': - qh_option("Q10-no-narrow", NULL, NULL); - qh NOnarrow= True; - break; - case '1': - qh_option("Q11-trinormals Qtriangulate", NULL, NULL); - qh TRInormals= True; - qh TRIangulate= True; - break; - default: - s--; - qh_fprintf(qh ferr, 7016, "qhull warning: unknown 'Q' qhull option 1%c, rest ignored\n", (int)s[0]); - while (*++s && !isspace(*s)); - break; - } - break; - case '2': - qh_option("Q2-no-merge-independent", NULL, NULL); - qh MERGEindependent= False; - goto LABELcheckdigit; - break; /* no warnings */ - case '3': - qh_option("Q3-no-merge-vertices", NULL, NULL); - qh MERGEvertices= False; - LABELcheckdigit: - if (isdigit(*s)) - qh_fprintf(qh ferr, 7017, "qhull warning: can not follow '1', '2', or '3' with a digit. '%c' skipped.\n", - *s++); - break; - case '4': - qh_option("Q4-avoid-old-into-new", NULL, NULL); - qh AVOIDold= True; - break; - case '5': - qh_option("Q5-no-check-outer", NULL, NULL); - qh SKIPcheckmax= True; - break; - case '6': - qh_option("Q6-no-concave-merge", NULL, NULL); - qh SKIPconvex= True; - break; - case '7': - qh_option("Q7-no-breadth-first", NULL, NULL); - qh VIRTUALmemory= True; - break; - case '8': - qh_option("Q8-no-near-inside", NULL, NULL); - qh NOnearinside= True; - break; - case '9': - qh_option("Q9-pick-furthest", NULL, NULL); - qh PICKfurthest= True; - break; - case 'G': - i= qh_strtol(s, &t); - if (qh GOODpoint) - qh_fprintf(qh ferr, 7018, "qhull warning: good point already defined for option 'QGn'. Ignored\n"); - else if (s == t) - qh_fprintf(qh ferr, 7019, "qhull warning: missing good point id for option 'QGn'. Ignored\n"); - else if (i < 0 || *s == '-') { - qh GOODpoint= i-1; - qh_option("QGood-if-dont-see-point", &i, NULL); - }else { - qh GOODpoint= i+1; - qh_option("QGood-if-see-point", &i, NULL); - } - s= t; - break; - case 'J': - if (!isdigit(*s) && *s != '-') - qh JOGGLEmax= 0.0; - else { - qh JOGGLEmax= (realT) qh_strtod(s, &s); - qh_option("QJoggle", NULL, &qh JOGGLEmax); - } - break; - case 'R': - if (!isdigit(*s) && *s != '-') - qh_fprintf(qh ferr, 7020, "qhull warning: missing random seed for option 'QRn'. Ignored\n"); - else { - qh ROTATErandom= i= qh_strtol(s, &s); - if (i > 0) - qh_option("QRotate-id", &i, NULL ); - else if (i < -1) - qh_option("QRandom-seed", &i, NULL ); - } - break; - case 'V': - i= qh_strtol(s, &t); - if (qh GOODvertex) - qh_fprintf(qh ferr, 7021, "qhull warning: good vertex already defined for option 'QVn'. Ignored\n"); - else if (s == t) - qh_fprintf(qh ferr, 7022, "qhull warning: no good point id given for option 'QVn'. Ignored\n"); - else if (i < 0) { - qh GOODvertex= i - 1; - qh_option("QV-good-facets-not-point", &i, NULL); - }else { - qh_option("QV-good-facets-point", &i, NULL); - qh GOODvertex= i + 1; - } - s= t; - break; - default: - s--; - qh_fprintf(qh ferr, 7023, "qhull warning: unknown 'Q' qhull option %c, rest ignored\n", (int)s[0]); - while (*++s && !isspace(*s)); - break; - } - } - break; - case 'T': - while (*s && !isspace(*s)) { - if (isdigit(*s) || *s == '-') - qh IStracing= qh_strtol(s, &s); - else switch (*s++) { - case 'a': - qh_option("Tannotate-output", NULL, NULL); - qh ANNOTATEoutput= True; - break; - case 'c': - qh_option("Tcheck-frequently", NULL, NULL); - qh CHECKfrequently= True; - break; - case 's': - qh_option("Tstatistics", NULL, NULL); - qh PRINTstatistics= True; - break; - case 'v': - qh_option("Tverify", NULL, NULL); - qh VERIFYoutput= True; - break; - case 'z': - if (qh ferr == qh_FILEstderr) { - /* The C++ interface captures the output in qh_fprint_qhull() */ - qh_option("Tz-stdout", NULL, NULL); - qh USEstdout= True; - }else if (!qh fout) - qh_fprintf(qh ferr, 7024, "qhull warning: output file undefined(stdout). Option 'Tz' ignored.\n"); - else { - qh_option("Tz-stdout", NULL, NULL); - qh USEstdout= True; - qh ferr= qh fout; - qhmem.ferr= qh fout; - } - break; - case 'C': - if (!isdigit(*s)) - qh_fprintf(qh ferr, 7025, "qhull warning: missing point id for cone for trace option 'TCn'. Ignored\n"); - else { - i= qh_strtol(s, &s); - qh_option("TCone-stop", &i, NULL); - qh STOPcone= i + 1; - } - break; - case 'F': - if (!isdigit(*s)) - qh_fprintf(qh ferr, 7026, "qhull warning: missing frequency count for trace option 'TFn'. Ignored\n"); - else { - qh REPORTfreq= qh_strtol(s, &s); - qh_option("TFacet-log", &qh REPORTfreq, NULL); - qh REPORTfreq2= qh REPORTfreq/2; /* for tracemerging() */ - } - break; - case 'I': - if (!isspace(*s)) - qh_fprintf(qh ferr, 7027, "qhull warning: missing space between 'TI' and filename, %s\n", s); - while (isspace(*s)) - s++; - t= qh_skipfilename(s); - { - char filename[qh_FILENAMElen]; - - qh_copyfilename(filename, (int)sizeof(filename), s, (int)(t-s)); /* WARN64 */ - s= t; - if (!freopen(filename, "r", stdin)) { - qh_fprintf(qh ferr, 6041, "qhull error: could not open file \"%s\".", filename); - qh_errexit(qh_ERRinput, NULL, NULL); - }else { - qh_option("TInput-file", NULL, NULL); - qh_option(filename, NULL, NULL); - } - } - break; - case 'O': - if (!isspace(*s)) - qh_fprintf(qh ferr, 7028, "qhull warning: missing space between 'TO' and filename, %s\n", s); - while (isspace(*s)) - s++; - t= qh_skipfilename(s); - { - char filename[qh_FILENAMElen]; - - qh_copyfilename(filename, (int)sizeof(filename), s, (int)(t-s)); /* WARN64 */ - s= t; - if (!freopen(filename, "w", stdout)) { - qh_fprintf(qh ferr, 6044, "qhull error: could not open file \"%s\".", filename); - qh_errexit(qh_ERRinput, NULL, NULL); - }else { - qh_option("TOutput-file", NULL, NULL); - qh_option(filename, NULL, NULL); - } - } - break; - case 'P': - if (!isdigit(*s)) - qh_fprintf(qh ferr, 7029, "qhull warning: missing point id for trace option 'TPn'. Ignored\n"); - else { - qh TRACEpoint= qh_strtol(s, &s); - qh_option("Trace-point", &qh TRACEpoint, NULL); - } - break; - case 'M': - if (!isdigit(*s)) - qh_fprintf(qh ferr, 7030, "qhull warning: missing merge id for trace option 'TMn'. Ignored\n"); - else { - qh TRACEmerge= qh_strtol(s, &s); - qh_option("Trace-merge", &qh TRACEmerge, NULL); - } - break; - case 'R': - if (!isdigit(*s)) - qh_fprintf(qh ferr, 7031, "qhull warning: missing rerun count for trace option 'TRn'. Ignored\n"); - else { - qh RERUN= qh_strtol(s, &s); - qh_option("TRerun", &qh RERUN, NULL); - } - break; - case 'V': - i= qh_strtol(s, &t); - if (s == t) - qh_fprintf(qh ferr, 7032, "qhull warning: missing furthest point id for trace option 'TVn'. Ignored\n"); - else if (i < 0) { - qh STOPpoint= i - 1; - qh_option("TV-stop-before-point", &i, NULL); - }else { - qh STOPpoint= i + 1; - qh_option("TV-stop-after-point", &i, NULL); - } - s= t; - break; - case 'W': - if (!isdigit(*s)) - qh_fprintf(qh ferr, 7033, "qhull warning: missing max width for trace option 'TWn'. Ignored\n"); - else { - qh TRACEdist= (realT) qh_strtod(s, &s); - qh_option("TWide-trace", NULL, &qh TRACEdist); - } - break; - default: - s--; - qh_fprintf(qh ferr, 7034, "qhull warning: unknown 'T' trace option %c, rest ignored\n", (int)s[0]); - while (*++s && !isspace(*s)); - break; - } - } - break; - default: - qh_fprintf(qh ferr, 7035, "qhull warning: unknown flag %c(%x)\n", (int)s[-1], - (int)s[-1]); - break; - } - if (s-1 == prev_s && *s && !isspace(*s)) { - qh_fprintf(qh ferr, 7036, "qhull warning: missing space after flag %c(%x); reserved for menu. Skipped.\n", - (int)*prev_s, (int)*prev_s); - while (*s && !isspace(*s)) - s++; - } - } - if (qh STOPcone && qh JOGGLEmax < REALmax/2) - qh_fprintf(qh ferr, 7078, "qhull warning: 'TCn' (stopCone) ignored when used with 'QJn' (joggle)\n"); - if (isgeom && !qh FORCEoutput && qh PRINTout[1]) - qh_fprintf(qh ferr, 7037, "qhull warning: additional output formats are not compatible with Geomview\n"); - /* set derived values in qh_initqhull_globals */ -} /* initflags */ - - -/*-<a href="qh-globa.htm#TOC" - >-------------------------------</a><a name="initqhull_buffers">-</a> - - qh_initqhull_buffers() - initialize global memory buffers - - notes: - must match qh_freebuffers() -*/ -void qh_initqhull_buffers(void) { - int k; - - qh TEMPsize= (qhmem.LASTsize - sizeof(setT))/SETelemsize; - if (qh TEMPsize <= 0 || qh TEMPsize > qhmem.LASTsize) - qh TEMPsize= 8; /* e.g., if qh_NOmem */ - qh other_points= qh_setnew(qh TEMPsize); - qh del_vertices= qh_setnew(qh TEMPsize); - qh coplanarfacetset= qh_setnew(qh TEMPsize); - qh NEARzero= (realT *)qh_memalloc(qh hull_dim * sizeof(realT)); - qh lower_threshold= (realT *)qh_memalloc((qh input_dim+1) * sizeof(realT)); - qh upper_threshold= (realT *)qh_memalloc((qh input_dim+1) * sizeof(realT)); - qh lower_bound= (realT *)qh_memalloc((qh input_dim+1) * sizeof(realT)); - qh upper_bound= (realT *)qh_memalloc((qh input_dim+1) * sizeof(realT)); - for (k=qh input_dim+1; k--; ) { /* duplicated in qh_initqhull_buffers and qh_clear_ouputflags */ - qh lower_threshold[k]= -REALmax; - qh upper_threshold[k]= REALmax; - qh lower_bound[k]= -REALmax; - qh upper_bound[k]= REALmax; - } - qh gm_matrix= (coordT *)qh_memalloc((qh hull_dim+1) * qh hull_dim * sizeof(coordT)); - qh gm_row= (coordT **)qh_memalloc((qh hull_dim+1) * sizeof(coordT *)); -} /* initqhull_buffers */ - -/*-<a href="qh-globa.htm#TOC" - >-------------------------------</a><a name="initqhull_globals">-</a> - - qh_initqhull_globals( points, numpoints, dim, ismalloc ) - initialize globals - if ismalloc - points were malloc'd and qhull should free at end - - returns: - sets qh.first_point, num_points, input_dim, hull_dim and others - seeds random number generator (seed=1 if tracing) - modifies qh.hull_dim if ((qh.DELAUNAY and qh.PROJECTdelaunay) or qh.PROJECTinput) - adjust user flags as needed - also checks DIM3 dependencies and constants - - notes: - do not use qh_point() since an input transformation may move them elsewhere - - see: - qh_initqhull_start() sets default values for non-zero globals - - design: - initialize points array from input arguments - test for qh.ZEROcentrum - (i.e., use opposite vertex instead of cetrum for convexity testing) - initialize qh.CENTERtype, qh.normal_size, - qh.center_size, qh.TRACEpoint/level, - initialize and test random numbers - qh_initqhull_outputflags() -- adjust and test output flags -*/ -void qh_initqhull_globals(coordT *points, int numpoints, int dim, boolT ismalloc) { - int seed, pointsneeded, extra= 0, i, randi, k; - realT randr; - realT factorial; - - time_t timedata; - - trace0((qh ferr, 13, "qh_initqhull_globals: for %s | %s\n", qh rbox_command, - qh qhull_command)); - qh POINTSmalloc= ismalloc; - qh first_point= points; - qh num_points= numpoints; - qh hull_dim= qh input_dim= dim; - if (!qh NOpremerge && !qh MERGEexact && !qh PREmerge && qh JOGGLEmax > REALmax/2) { - qh MERGING= True; - if (qh hull_dim <= 4) { - qh PREmerge= True; - qh_option("_pre-merge", NULL, NULL); - }else { - qh MERGEexact= True; - qh_option("Qxact_merge", NULL, NULL); - } - }else if (qh MERGEexact) - qh MERGING= True; - if (!qh NOpremerge && qh JOGGLEmax > REALmax/2) { -#ifdef qh_NOmerge - qh JOGGLEmax= 0.0; -#endif - } - if (qh TRIangulate && qh JOGGLEmax < REALmax/2 && qh PRINTprecision) - qh_fprintf(qh ferr, 7038, "qhull warning: joggle('QJ') always produces simplicial output. Triangulated output('Qt') does nothing.\n"); - if (qh JOGGLEmax < REALmax/2 && qh DELAUNAY && !qh SCALEinput && !qh SCALElast) { - qh SCALElast= True; - qh_option("Qbbound-last-qj", NULL, NULL); - } - if (qh MERGING && !qh POSTmerge && qh premerge_cos > REALmax/2 - && qh premerge_centrum == 0) { - qh ZEROcentrum= True; - qh ZEROall_ok= True; - qh_option("_zero-centrum", NULL, NULL); - } - if (qh JOGGLEmax < REALmax/2 && REALepsilon > 2e-8 && qh PRINTprecision) - qh_fprintf(qh ferr, 7039, "qhull warning: real epsilon, %2.2g, is probably too large for joggle('QJn')\nRecompile with double precision reals(see user.h).\n", - REALepsilon); -#ifdef qh_NOmerge - if (qh MERGING) { - qh_fprintf(qh ferr, 6045, "qhull input error: merging not installed(qh_NOmerge + 'Qx', 'Cn' or 'An')\n"); - qh_errexit(qh_ERRinput, NULL, NULL); - } -#endif - if (qh DELAUNAY && qh KEEPcoplanar && !qh KEEPinside) { - qh KEEPinside= True; - qh_option("Qinterior-keep", NULL, NULL); - } - if (qh DELAUNAY && qh HALFspace) { - qh_fprintf(qh ferr, 6046, "qhull input error: can not use Delaunay('d') or Voronoi('v') with halfspace intersection('H')\n"); - qh_errexit(qh_ERRinput, NULL, NULL); - } - if (!qh DELAUNAY && (qh UPPERdelaunay || qh ATinfinity)) { - qh_fprintf(qh ferr, 6047, "qhull input error: use upper-Delaunay('Qu') or infinity-point('Qz') with Delaunay('d') or Voronoi('v')\n"); - qh_errexit(qh_ERRinput, NULL, NULL); - } - if (qh UPPERdelaunay && qh ATinfinity) { - qh_fprintf(qh ferr, 6048, "qhull input error: can not use infinity-point('Qz') with upper-Delaunay('Qu')\n"); - qh_errexit(qh_ERRinput, NULL, NULL); - } - if (qh SCALElast && !qh DELAUNAY && qh PRINTprecision) - qh_fprintf(qh ferr, 7040, "qhull input warning: option 'Qbb' (scale-last-coordinate) is normally used with 'd' or 'v'\n"); - qh DOcheckmax= (!qh SKIPcheckmax && qh MERGING ); - qh KEEPnearinside= (qh DOcheckmax && !(qh KEEPinside && qh KEEPcoplanar) - && !qh NOnearinside); - if (qh MERGING) - qh CENTERtype= qh_AScentrum; - else if (qh VORONOI) - qh CENTERtype= qh_ASvoronoi; - if (qh TESTvneighbors && !qh MERGING) { - qh_fprintf(qh ferr, 6049, "qhull input error: test vertex neighbors('Qv') needs a merge option\n"); - qh_errexit(qh_ERRinput, NULL ,NULL); - } - if (qh PROJECTinput || (qh DELAUNAY && qh PROJECTdelaunay)) { - qh hull_dim -= qh PROJECTinput; - if (qh DELAUNAY) { - qh hull_dim++; - if (qh ATinfinity) - extra= 1; - } - } - if (qh hull_dim <= 1) { - qh_fprintf(qh ferr, 6050, "qhull error: dimension %d must be > 1\n", qh hull_dim); - qh_errexit(qh_ERRinput, NULL, NULL); - } - for (k=2, factorial=1.0; k < qh hull_dim; k++) - factorial *= k; - qh AREAfactor= 1.0 / factorial; - trace2((qh ferr, 2005, "qh_initqhull_globals: initialize globals. dim %d numpoints %d malloc? %d projected %d to hull_dim %d\n", - dim, numpoints, ismalloc, qh PROJECTinput, qh hull_dim)); - qh normal_size= qh hull_dim * sizeof(coordT); - qh center_size= qh normal_size - sizeof(coordT); - pointsneeded= qh hull_dim+1; - if (qh hull_dim > qh_DIMmergeVertex) { - qh MERGEvertices= False; - qh_option("Q3-no-merge-vertices-dim-high", NULL, NULL); - } - if (qh GOODpoint) - pointsneeded++; -#ifdef qh_NOtrace - if (qh IStracing) { - qh_fprintf(qh ferr, 6051, "qhull input error: tracing is not installed(qh_NOtrace in user.h)"); - qh_errexit(qh_ERRqhull, NULL, NULL); - } -#endif - if (qh RERUN > 1) { - qh TRACElastrun= qh IStracing; /* qh_build_withrestart duplicates next conditional */ - if (qh IStracing != -1) - qh IStracing= 0; - }else if (qh TRACEpoint != -1 || qh TRACEdist < REALmax/2 || qh TRACEmerge) { - qh TRACElevel= (qh IStracing? qh IStracing : 3); - qh IStracing= 0; - } - if (qh ROTATErandom == 0 || qh ROTATErandom == -1) { - seed= (int)time(&timedata); - if (qh ROTATErandom == -1) { - seed= -seed; - qh_option("QRandom-seed", &seed, NULL ); - }else - qh_option("QRotate-random", &seed, NULL); - qh ROTATErandom= seed; - } - seed= qh ROTATErandom; - if (seed == INT_MIN) /* default value */ - seed= 1; - else if (seed < 0) - seed= -seed; - qh_RANDOMseed_(seed); - randr= 0.0; - for (i=1000; i--; ) { - randi= qh_RANDOMint; - randr += randi; - if (randi > qh_RANDOMmax) { - qh_fprintf(qh ferr, 8036, "\ -qhull configuration error (qh_RANDOMmax in user.h):\n\ - random integer %d > qh_RANDOMmax(%.8g)\n", - randi, qh_RANDOMmax); - qh_errexit(qh_ERRinput, NULL, NULL); - } - } - qh_RANDOMseed_(seed); - randr = randr/1000; - if (randr < qh_RANDOMmax * 0.1 - || randr > qh_RANDOMmax * 0.9) - qh_fprintf(qh ferr, 8037, "\ -qhull configuration warning (qh_RANDOMmax in user.h):\n\ - average of 1000 random integers (%.2g) is much different than expected (%.2g).\n\ - Is qh_RANDOMmax (%.2g) wrong?\n", - randr, qh_RANDOMmax * 0.5, qh_RANDOMmax); - qh RANDOMa= 2.0 * qh RANDOMfactor/qh_RANDOMmax; - qh RANDOMb= 1.0 - qh RANDOMfactor; - if (qh_HASHfactor < 1.1) { - qh_fprintf(qh ferr, 6052, "qhull internal error (qh_initqhull_globals): qh_HASHfactor %d must be at least 1.1. Qhull uses linear hash probing\n", - qh_HASHfactor); - qh_errexit(qh_ERRqhull, NULL, NULL); - } - if (numpoints+extra < pointsneeded) { - qh_fprintf(qh ferr, 6214, "qhull input error: not enough points(%d) to construct initial simplex (need %d)\n", - numpoints, pointsneeded); - qh_errexit(qh_ERRinput, NULL, NULL); - } - qh_initqhull_outputflags(); -} /* initqhull_globals */ - -/*-<a href="qh-globa.htm#TOC" - >-------------------------------</a><a name="initqhull_mem">-</a> - - qh_initqhull_mem( ) - initialize mem.c for qhull - qh.hull_dim and qh.normal_size determine some of the allocation sizes - if qh.MERGING, - includes ridgeT - calls qh_user_memsizes() to add up to 10 additional sizes for quick allocation - (see numsizes below) - - returns: - mem.c already for qh_memalloc/qh_memfree (errors if called beforehand) - - notes: - qh_produceoutput() prints memsizes - -*/ -void qh_initqhull_mem(void) { - int numsizes; - int i; - - numsizes= 8+10; - qh_meminitbuffers(qh IStracing, qh_MEMalign, numsizes, - qh_MEMbufsize,qh_MEMinitbuf); - qh_memsize((int)sizeof(vertexT)); - if (qh MERGING) { - qh_memsize((int)sizeof(ridgeT)); - qh_memsize((int)sizeof(mergeT)); - } - qh_memsize((int)sizeof(facetT)); - i= sizeof(setT) + (qh hull_dim - 1) * SETelemsize; /* ridge.vertices */ - qh_memsize(i); - qh_memsize(qh normal_size); /* normal */ - i += SETelemsize; /* facet.vertices, .ridges, .neighbors */ - qh_memsize(i); - qh_user_memsizes(); - qh_memsetup(); -} /* initqhull_mem */ - -/*-<a href="qh-globa.htm#TOC" - >-------------------------------</a><a name="initqhull_outputflags">-</a> - - qh_initqhull_outputflags - initialize flags concerned with output - - returns: - adjust user flags as needed - - see: - qh_clear_outputflags() resets the flags - - design: - test for qh.PRINTgood (i.e., only print 'good' facets) - check for conflicting print output options -*/ -void qh_initqhull_outputflags(void) { - boolT printgeom= False, printmath= False, printcoplanar= False; - int i; - - trace3((qh ferr, 3024, "qh_initqhull_outputflags: %s\n", qh qhull_command)); - if (!(qh PRINTgood || qh PRINTneighbors)) { - if (qh KEEParea || qh KEEPminArea < REALmax/2 || qh KEEPmerge || qh DELAUNAY - || (!qh ONLYgood && (qh GOODvertex || qh GOODpoint))) { - qh PRINTgood= True; - qh_option("Pgood", NULL, NULL); - } - } - if (qh PRINTtransparent) { - if (qh hull_dim != 4 || !qh DELAUNAY || qh VORONOI || qh DROPdim >= 0) { - qh_fprintf(qh ferr, 6215, "qhull input error: transparent Delaunay('Gt') needs 3-d Delaunay('d') w/o 'GDn'\n"); - qh_errexit(qh_ERRinput, NULL, NULL); - } - qh DROPdim = 3; - qh PRINTridges = True; - } - for (i=qh_PRINTEND; i--; ) { - if (qh PRINTout[i] == qh_PRINTgeom) - printgeom= True; - else if (qh PRINTout[i] == qh_PRINTmathematica || qh PRINTout[i] == qh_PRINTmaple) - printmath= True; - else if (qh PRINTout[i] == qh_PRINTcoplanars) - printcoplanar= True; - else if (qh PRINTout[i] == qh_PRINTpointnearest) - printcoplanar= True; - else if (qh PRINTout[i] == qh_PRINTpointintersect && !qh HALFspace) { - qh_fprintf(qh ferr, 6053, "qhull input error: option 'Fp' is only used for \nhalfspace intersection('Hn,n,n').\n"); - qh_errexit(qh_ERRinput, NULL, NULL); - }else if (qh PRINTout[i] == qh_PRINTtriangles && (qh HALFspace || qh VORONOI)) { - qh_fprintf(qh ferr, 6054, "qhull input error: option 'Ft' is not available for Voronoi vertices or halfspace intersection\n"); - qh_errexit(qh_ERRinput, NULL, NULL); - }else if (qh PRINTout[i] == qh_PRINTcentrums && qh VORONOI) { - qh_fprintf(qh ferr, 6055, "qhull input error: option 'FC' is not available for Voronoi vertices('v')\n"); - qh_errexit(qh_ERRinput, NULL, NULL); - }else if (qh PRINTout[i] == qh_PRINTvertices) { - if (qh VORONOI) - qh_option("Fvoronoi", NULL, NULL); - else - qh_option("Fvertices", NULL, NULL); - } - } - if (printcoplanar && qh DELAUNAY && qh JOGGLEmax < REALmax/2) { - if (qh PRINTprecision) - qh_fprintf(qh ferr, 7041, "qhull input warning: 'QJ' (joggle) will usually prevent coincident input sites for options 'Fc' and 'FP'\n"); - } - if (printmath && (qh hull_dim > 3 || qh VORONOI)) { - qh_fprintf(qh ferr, 6056, "qhull input error: Mathematica and Maple output is only available for 2-d and 3-d convex hulls and 2-d Delaunay triangulations\n"); - qh_errexit(qh_ERRinput, NULL, NULL); - } - if (printgeom) { - if (qh hull_dim > 4) { - qh_fprintf(qh ferr, 6057, "qhull input error: Geomview output is only available for 2-d, 3-d and 4-d\n"); - qh_errexit(qh_ERRinput, NULL, NULL); - } - if (qh PRINTnoplanes && !(qh PRINTcoplanar + qh PRINTcentrums - + qh PRINTdots + qh PRINTspheres + qh DOintersections + qh PRINTridges)) { - qh_fprintf(qh ferr, 6058, "qhull input error: no output specified for Geomview\n"); - qh_errexit(qh_ERRinput, NULL, NULL); - } - if (qh VORONOI && (qh hull_dim > 3 || qh DROPdim >= 0)) { - qh_fprintf(qh ferr, 6059, "qhull input error: Geomview output for Voronoi diagrams only for 2-d\n"); - qh_errexit(qh_ERRinput, NULL, NULL); - } - /* can not warn about furthest-site Geomview output: no lower_threshold */ - if (qh hull_dim == 4 && qh DROPdim == -1 && - (qh PRINTcoplanar || qh PRINTspheres || qh PRINTcentrums)) { - qh_fprintf(qh ferr, 7042, "qhull input warning: coplanars, vertices, and centrums output not\n\ -available for 4-d output(ignored). Could use 'GDn' instead.\n"); - qh PRINTcoplanar= qh PRINTspheres= qh PRINTcentrums= False; - } - } - if (!qh KEEPcoplanar && !qh KEEPinside && !qh ONLYgood) { - if ((qh PRINTcoplanar && qh PRINTspheres) || printcoplanar) { - if (qh QHULLfinished) { - qh_fprintf(qh ferr, 7072, "qhull output warning: ignoring coplanar points, option 'Qc' was not set for the first run of qhull.\n"); - }else { - qh KEEPcoplanar = True; - qh_option("Qcoplanar", NULL, NULL); - } - } - } - qh PRINTdim= qh hull_dim; - if (qh DROPdim >=0) { /* after Geomview checks */ - if (qh DROPdim < qh hull_dim) { - qh PRINTdim--; - if (!printgeom || qh hull_dim < 3) - qh_fprintf(qh ferr, 7043, "qhull input warning: drop dimension 'GD%d' is only available for 3-d/4-d Geomview\n", qh DROPdim); - }else - qh DROPdim= -1; - }else if (qh VORONOI) { - qh DROPdim= qh hull_dim-1; - qh PRINTdim= qh hull_dim-1; - } -} /* qh_initqhull_outputflags */ - -/*-<a href="qh-globa.htm#TOC" - >-------------------------------</a><a name="initqhull_start">-</a> - - qh_initqhull_start( infile, outfile, errfile ) - allocate memory if needed and call qh_initqhull_start2() -*/ -void qh_initqhull_start(FILE *infile, FILE *outfile, FILE *errfile) { - -#if qh_QHpointer - if (qh_qh) { - qh_fprintf(errfile, 6205, "qhull error (qh_initqhull_start): qh_qh already defined. Call qh_save_qhull() first\n"); - qh_exit(qh_ERRqhull); /* no error handler */ - } - if (!(qh_qh= (qhT *)qh_malloc(sizeof(qhT)))) { - qh_fprintf(errfile, 6060, "qhull error (qh_initqhull_start): insufficient memory\n"); - qh_exit(qh_ERRmem); /* no error handler */ - } -#endif - qh_initstatistics(); - qh_initqhull_start2(infile, outfile, errfile); -} /* initqhull_start */ - -/*-<a href="qh-globa.htm#TOC" - >-------------------------------</a><a name="initqhull_start2">-</a> - - qh_initqhull_start2( infile, outfile, errfile ) - start initialization of qhull - initialize statistics, stdio, default values for global variables - assumes qh_qh is defined - notes: - report errors elsewhere, error handling and g_qhull_output [Qhull.cpp, QhullQh()] not in initialized - see: - qh_maxmin() determines the precision constants - qh_freeqhull2() -*/ -void qh_initqhull_start2(FILE *infile, FILE *outfile, FILE *errfile) { - time_t timedata; - int seed; - - qh_CPUclock; /* start the clock(for qh_clock). One-shot. */ -#if qh_QHpointer - memset((char *)qh_qh, 0, sizeof(qhT)); /* every field is 0, FALSE, NULL */ -#else - memset((char *)&qh_qh, 0, sizeof(qhT)); -#endif - qh ANGLEmerge= True; - qh DROPdim= -1; - qh ferr= errfile; - qh fin= infile; - qh fout= outfile; - qh furthest_id= -1; - qh JOGGLEmax= REALmax; - qh KEEPminArea = REALmax; - qh last_low= REALmax; - qh last_high= REALmax; - qh last_newhigh= REALmax; - qh max_outside= 0.0; - qh max_vertex= 0.0; - qh MAXabs_coord= 0.0; - qh MAXsumcoord= 0.0; - qh MAXwidth= -REALmax; - qh MERGEindependent= True; - qh MINdenom_1= fmax_(1.0/REALmax, REALmin); /* used by qh_scalepoints */ - qh MINoutside= 0.0; - qh MINvisible= REALmax; - qh MAXcoplanar= REALmax; - qh outside_err= REALmax; - qh premerge_centrum= 0.0; - qh premerge_cos= REALmax; - qh PRINTprecision= True; - qh PRINTradius= 0.0; - qh postmerge_cos= REALmax; - qh postmerge_centrum= 0.0; - qh ROTATErandom= INT_MIN; - qh MERGEvertices= True; - qh totarea= 0.0; - qh totvol= 0.0; - qh TRACEdist= REALmax; - qh TRACEpoint= -1; /* recompile or use 'TPn' */ - qh tracefacet_id= UINT_MAX; /* recompile to trace a facet */ - qh tracevertex_id= UINT_MAX; /* recompile to trace a vertex */ - seed= (int)time(&timedata); - qh_RANDOMseed_(seed); - qh run_id= qh_RANDOMint+1; /* disallow 0 [UsingLibQhull::NOqhRunId] */ - qh_option("run-id", &qh run_id, NULL); - strcat(qh qhull, "qhull"); -} /* initqhull_start2 */ - -/*-<a href="qh-globa.htm#TOC" - >-------------------------------</a><a name="initthresholds">-</a> - - qh_initthresholds( commandString ) - set thresholds for printing and scaling from commandString - - returns: - sets qh.GOODthreshold or qh.SPLITthreshold if 'Pd0D1' used - - see: - qh_initflags(), 'Qbk' 'QBk' 'Pdk' and 'PDk' - qh_inthresholds() - - design: - for each 'Pdn' or 'PDn' option - check syntax - set qh.lower_threshold or qh.upper_threshold - set qh.GOODthreshold if an unbounded threshold is used - set qh.SPLITthreshold if a bounded threshold is used -*/ -void qh_initthresholds(char *command) { - realT value; - int idx, maxdim, k; - char *s= command; /* non-const due to strtol */ - char key; - - maxdim= qh input_dim; - if (qh DELAUNAY && (qh PROJECTdelaunay || qh PROJECTinput)) - maxdim++; - while (*s) { - if (*s == '-') - s++; - if (*s == 'P') { - s++; - while (*s && !isspace(key= *s++)) { - if (key == 'd' || key == 'D') { - if (!isdigit(*s)) { - qh_fprintf(qh ferr, 7044, "qhull warning: no dimension given for Print option '%c' at: %s. Ignored\n", - key, s-1); - continue; - } - idx= qh_strtol(s, &s); - if (idx >= qh hull_dim) { - qh_fprintf(qh ferr, 7045, "qhull warning: dimension %d for Print option '%c' is >= %d. Ignored\n", - idx, key, qh hull_dim); - continue; - } - if (*s == ':') { - s++; - value= qh_strtod(s, &s); - if (fabs((double)value) > 1.0) { - qh_fprintf(qh ferr, 7046, "qhull warning: value %2.4g for Print option %c is > +1 or < -1. Ignored\n", - value, key); - continue; - } - }else - value= 0.0; - if (key == 'd') - qh lower_threshold[idx]= value; - else - qh upper_threshold[idx]= value; - } - } - }else if (*s == 'Q') { - s++; - while (*s && !isspace(key= *s++)) { - if (key == 'b' && *s == 'B') { - s++; - for (k=maxdim; k--; ) { - qh lower_bound[k]= -qh_DEFAULTbox; - qh upper_bound[k]= qh_DEFAULTbox; - } - }else if (key == 'b' && *s == 'b') - s++; - else if (key == 'b' || key == 'B') { - if (!isdigit(*s)) { - qh_fprintf(qh ferr, 7047, "qhull warning: no dimension given for Qhull option %c. Ignored\n", - key); - continue; - } - idx= qh_strtol(s, &s); - if (idx >= maxdim) { - qh_fprintf(qh ferr, 7048, "qhull warning: dimension %d for Qhull option %c is >= %d. Ignored\n", - idx, key, maxdim); - continue; - } - if (*s == ':') { - s++; - value= qh_strtod(s, &s); - }else if (key == 'b') - value= -qh_DEFAULTbox; - else - value= qh_DEFAULTbox; - if (key == 'b') - qh lower_bound[idx]= value; - else - qh upper_bound[idx]= value; - } - } - }else { - while (*s && !isspace(*s)) - s++; - } - while (isspace(*s)) - s++; - } - for (k=qh hull_dim; k--; ) { - if (qh lower_threshold[k] > -REALmax/2) { - qh GOODthreshold= True; - if (qh upper_threshold[k] < REALmax/2) { - qh SPLITthresholds= True; - qh GOODthreshold= False; - break; - } - }else if (qh upper_threshold[k] < REALmax/2) - qh GOODthreshold= True; - } -} /* initthresholds */ - -/*-<a href="qh-globa.htm#TOC" - >-------------------------------</a><a name="option">-</a> - - qh_option( option, intVal, realVal ) - add an option description to qh.qhull_options - - notes: - NOerrors -- qh_option can not call qh_errexit() [qh_initqhull_start2] - will be printed with statistics ('Ts') and errors - strlen(option) < 40 -*/ -void qh_option(const char *option, int *i, realT *r) { - char buf[200]; - int len, maxlen; - - sprintf(buf, " %s", option); - if (i) - sprintf(buf+strlen(buf), " %d", *i); - if (r) - sprintf(buf+strlen(buf), " %2.2g", *r); - len= (int)strlen(buf); /* WARN64 */ - qh qhull_optionlen += len; - maxlen= sizeof(qh qhull_options) - len -1; - maximize_(maxlen, 0); - if (qh qhull_optionlen >= qh_OPTIONline && maxlen > 0) { - qh qhull_optionlen= len; - strncat(qh qhull_options, "\n", (size_t)(maxlen--)); - } - strncat(qh qhull_options, buf, (size_t)maxlen); -} /* option */ - -#if qh_QHpointer -/*-<a href="qh-globa.htm#TOC" - >-------------------------------</a><a name="restore_qhull">-</a> - - qh_restore_qhull( oldqh ) - restores a previously saved qhull - also restores qh_qhstat and qhmem.tempstack - Sets *oldqh to NULL - notes: - errors if current qhull hasn't been saved or freed - uses qhmem for error reporting - - NOTE 1998/5/11: - Freeing memory after qh_save_qhull and qh_restore_qhull - is complicated. The procedures will be redesigned. - - see: - qh_save_qhull(), UsingLibQhull -*/ -void qh_restore_qhull(qhT **oldqh) { - - if (*oldqh && strcmp((*oldqh)->qhull, "qhull")) { - qh_fprintf(qhmem.ferr, 6061, "qhull internal error (qh_restore_qhull): %p is not a qhull data structure\n", - *oldqh); - qh_errexit(qh_ERRqhull, NULL, NULL); - } - if (qh_qh) { - qh_fprintf(qhmem.ferr, 6062, "qhull internal error (qh_restore_qhull): did not save or free existing qhull\n"); - qh_errexit(qh_ERRqhull, NULL, NULL); - } - if (!*oldqh || !(*oldqh)->old_qhstat) { - qh_fprintf(qhmem.ferr, 6063, "qhull internal error (qh_restore_qhull): did not previously save qhull %p\n", - *oldqh); - qh_errexit(qh_ERRqhull, NULL, NULL); - } - qh_qh= *oldqh; - *oldqh= NULL; - qh_qhstat= qh old_qhstat; - qhmem.tempstack= qh old_tempstack; - qh old_qhstat= 0; - qh old_tempstack= 0; - trace1((qh ferr, 1007, "qh_restore_qhull: restored qhull from %p\n", *oldqh)); -} /* restore_qhull */ - -/*-<a href="qh-globa.htm#TOC" - >-------------------------------</a><a name="save_qhull">-</a> - - qh_save_qhull( ) - saves qhull for a later qh_restore_qhull - also saves qh_qhstat and qhmem.tempstack - - returns: - qh_qh=NULL - - notes: - need to initialize qhull or call qh_restore_qhull before continuing - - NOTE 1998/5/11: - Freeing memory after qh_save_qhull and qh_restore_qhull - is complicated. The procedures will be redesigned. - - see: - qh_restore_qhull() -*/ -qhT *qh_save_qhull(void) { - qhT *oldqh; - - trace1((qhmem.ferr, 1045, "qh_save_qhull: save qhull %p\n", qh_qh)); - if (!qh_qh) { - qh_fprintf(qhmem.ferr, 6064, "qhull internal error (qh_save_qhull): qhull not initialized\n"); - qh_errexit(qh_ERRqhull, NULL, NULL); - } - qh old_qhstat= qh_qhstat; - qh_qhstat= NULL; - qh old_tempstack= qhmem.tempstack; - qhmem.tempstack= NULL; - oldqh= qh_qh; - qh_qh= NULL; - return oldqh; -} /* save_qhull */ - -#endif - diff --git a/PyMca/Object3D/Object3DQhull/src/io.c b/PyMca/Object3D/Object3DQhull/src/io.c deleted file mode 100644 index 09a0079..0000000 --- a/PyMca/Object3D/Object3DQhull/src/io.c +++ /dev/null @@ -1,4060 +0,0 @@ -/*<html><pre> -<a href="qh-io.htm" - >-------------------------------</a><a name="TOP">-</a> - - io.c - Input/Output routines of qhull application - - see qh-io.htm and io.h - - see user.c for qh_errprint and qh_printfacetlist - - unix.c calls qh_readpoints and qh_produce_output - - unix.c and user.c are the only callers of io.c functions - This allows the user to avoid loading io.o from qhull.a - - Copyright (c) 1993-2012 The Geometry Center. - $Id: //main/2011/qhull/src/libqhull/io.c#3 $$Change: 1464 $ - $DateTime: 2012/01/25 22:58:41 $$Author: bbarber $ -*/ - -#include "qhull_a.h" - -/*========= -functions in alphabetical order after qh_produce_output() =====*/ - -/*-<a href="qh-io.htm#TOC" - >-------------------------------</a><a name="produce_output">-</a> - - qh_produce_output() - qh_produce_output2() - prints out the result of qhull in desired format - qh_produce_output2() does not call qh_prepare_output() - if qh.GETarea - computes and prints area and volume - qh.PRINTout[] is an array of output formats - - notes: - prints output in qh.PRINTout order -*/ -void qh_produce_output(void) { - int tempsize= qh_setsize(qhmem.tempstack); - - qh_prepare_output(); - qh_produce_output2(); - if (qh_setsize(qhmem.tempstack) != tempsize) { - qh_fprintf(qh ferr, 6206, "qhull internal error (qh_produce_output): temporary sets not empty(%d)\n", - qh_setsize(qhmem.tempstack)); - qh_errexit(qh_ERRqhull, NULL, NULL); - } -} /* produce_output */ - - -void qh_produce_output2(void) { - int i, tempsize= qh_setsize(qhmem.tempstack), d_1; - - if (qh PRINTsummary) - qh_printsummary(qh ferr); - else if (qh PRINTout[0] == qh_PRINTnone) - qh_printsummary(qh fout); - for (i=0; i < qh_PRINTEND; i++) - qh_printfacets(qh fout, qh PRINTout[i], qh facet_list, NULL, !qh_ALL); - qh_allstatistics(); - if (qh PRINTprecision && !qh MERGING && (qh JOGGLEmax > REALmax/2 || qh RERUN)) - qh_printstats(qh ferr, qhstat precision, NULL); - if (qh VERIFYoutput && (zzval_(Zridge) > 0 || zzval_(Zridgemid) > 0)) - qh_printstats(qh ferr, qhstat vridges, NULL); - if (qh PRINTstatistics) { - qh_printstatistics(qh ferr, ""); - qh_memstatistics(qh ferr); - d_1= sizeof(setT) + (qh hull_dim - 1) * SETelemsize; - qh_fprintf(qh ferr, 8040, "\ - size in bytes: merge %d ridge %d vertex %d facet %d\n\ - normal %d ridge vertices %d facet vertices or neighbors %d\n", - (int)sizeof(mergeT), (int)sizeof(ridgeT), - (int)sizeof(vertexT), (int)sizeof(facetT), - qh normal_size, d_1, d_1 + SETelemsize); - } - if (qh_setsize(qhmem.tempstack) != tempsize) { - qh_fprintf(qh ferr, 6065, "qhull internal error (qh_produce_output2): temporary sets not empty(%d)\n", - qh_setsize(qhmem.tempstack)); - qh_errexit(qh_ERRqhull, NULL, NULL); - } -} /* produce_output2 */ - -/*-<a href="qh-io.htm#TOC" - >-------------------------------</a><a name="dfacet">-</a> - - dfacet( id ) - print facet by id, for debugging - -*/ -void dfacet(unsigned id) { - facetT *facet; - - FORALLfacets { - if (facet->id == id) { - qh_printfacet(qh fout, facet); - break; - } - } -} /* dfacet */ - - -/*-<a href="qh-io.htm#TOC" - >-------------------------------</a><a name="dvertex">-</a> - - dvertex( id ) - print vertex by id, for debugging -*/ -void dvertex(unsigned id) { - vertexT *vertex; - - FORALLvertices { - if (vertex->id == id) { - qh_printvertex(qh fout, vertex); - break; - } - } -} /* dvertex */ - - -/*-<a href="qh-io.htm#TOC" - >-------------------------------</a><a name="compare_vertexpoint">-</a> - - qh_compare_vertexpoint( p1, p2 ) - used by qsort() to order vertices by point id -*/ -int qh_compare_vertexpoint(const void *p1, const void *p2) { - const vertexT *a= *((vertexT *const*)p1), *b= *((vertexT *const*)p2); - - return((qh_pointid(a->point) > qh_pointid(b->point)?1:-1)); -} /* compare_vertexpoint */ - -/*-<a href="qh-io.htm#TOC" - >-------------------------------</a><a name="compare_facetarea">-</a> - - qh_compare_facetarea( p1, p2 ) - used by qsort() to order facets by area -*/ -int qh_compare_facetarea(const void *p1, const void *p2) { - const facetT *a= *((facetT *const*)p1), *b= *((facetT *const*)p2); - - if (!a->isarea) - return -1; - if (!b->isarea) - return 1; - if (a->f.area > b->f.area) - return 1; - else if (a->f.area == b->f.area) - return 0; - return -1; -} /* compare_facetarea */ - -/*-<a href="qh-io.htm#TOC" - >-------------------------------</a><a name="compare_facetmerge">-</a> - - qh_compare_facetmerge( p1, p2 ) - used by qsort() to order facets by number of merges -*/ -int qh_compare_facetmerge(const void *p1, const void *p2) { - const facetT *a= *((facetT *const*)p1), *b= *((facetT *const*)p2); - - return(a->nummerge - b->nummerge); -} /* compare_facetvisit */ - -/*-<a href="qh-io.htm#TOC" - >-------------------------------</a><a name="compare_facetvisit">-</a> - - qh_compare_facetvisit( p1, p2 ) - used by qsort() to order facets by visit id or id -*/ -int qh_compare_facetvisit(const void *p1, const void *p2) { - const facetT *a= *((facetT *const*)p1), *b= *((facetT *const*)p2); - int i,j; - - if (!(i= a->visitid)) - i= 0 - a->id; /* do not convert to int, sign distinguishes id from visitid */ - if (!(j= b->visitid)) - j= 0 - b->id; - return(i - j); -} /* compare_facetvisit */ - -/*-<a href="qh-io.htm#TOC" - >-------------------------------</a><a name="copyfilename">-</a> - - qh_copyfilename( dest, size, source, length ) - copy filename identified by qh_skipfilename() - - notes: - see qh_skipfilename() for syntax -*/ -void qh_copyfilename(char *filename, int size, const char* source, int length) { - char c= *source; - - if (length > size + 1) { - qh_fprintf(qh ferr, 6040, "qhull error: filename is more than %d characters, %s\n", size-1, source); - qh_errexit(qh_ERRinput, NULL, NULL); - } - strncpy(filename, source, length); - filename[length]= '\0'; - if (c == '\'' || c == '"') { - char *s= filename + 1; - char *t= filename; - while (*s) { - if (*s == c) { - if (s[-1] == '\\') - t[-1]= c; - }else - *t++= *s; - s++; - } - *t= '\0'; - } -} /* copyfilename */ - -/*-<a href="qh-io.htm#TOC" - >-------------------------------</a><a name="countfacets">-</a> - - qh_countfacets( facetlist, facets, printall, - numfacets, numsimplicial, totneighbors, numridges, numcoplanar, numtricoplanars ) - count good facets for printing and set visitid - if allfacets, ignores qh_skipfacet() - - notes: - qh_printsummary and qh_countfacets must match counts - - returns: - numfacets, numsimplicial, total neighbors, numridges, coplanars - each facet with ->visitid indicating 1-relative position - ->visitid==0 indicates not good - - notes - numfacets >= numsimplicial - if qh.NEWfacets, - does not count visible facets (matches qh_printafacet) - - design: - for all facets on facetlist and in facets set - unless facet is skipped or visible (i.e., will be deleted) - mark facet->visitid - update counts -*/ -void qh_countfacets(facetT *facetlist, setT *facets, boolT printall, - int *numfacetsp, int *numsimplicialp, int *totneighborsp, int *numridgesp, int *numcoplanarsp, int *numtricoplanarsp) { - facetT *facet, **facetp; - int numfacets= 0, numsimplicial= 0, numridges= 0, totneighbors= 0, numcoplanars= 0, numtricoplanars= 0; - - FORALLfacet_(facetlist) { - if ((facet->visible && qh NEWfacets) - || (!printall && qh_skipfacet(facet))) - facet->visitid= 0; - else { - facet->visitid= ++numfacets; - totneighbors += qh_setsize(facet->neighbors); - if (facet->simplicial) { - numsimplicial++; - if (facet->keepcentrum && facet->tricoplanar) - numtricoplanars++; - }else - numridges += qh_setsize(facet->ridges); - if (facet->coplanarset) - numcoplanars += qh_setsize(facet->coplanarset); - } - } - - FOREACHfacet_(facets) { - if ((facet->visible && qh NEWfacets) - || (!printall && qh_skipfacet(facet))) - facet->visitid= 0; - else { - facet->visitid= ++numfacets; - totneighbors += qh_setsize(facet->neighbors); - if (facet->simplicial){ - numsimplicial++; - if (facet->keepcentrum && facet->tricoplanar) - numtricoplanars++; - }else - numridges += qh_setsize(facet->ridges); - if (facet->coplanarset) - numcoplanars += qh_setsize(facet->coplanarset); - } - } - qh visit_id += numfacets+1; - *numfacetsp= numfacets; - *numsimplicialp= numsimplicial; - *totneighborsp= totneighbors; - *numridgesp= numridges; - *numcoplanarsp= numcoplanars; - *numtricoplanarsp= numtricoplanars; -} /* countfacets */ - -/*-<a href="qh-io.htm#TOC" - >-------------------------------</a><a name="detvnorm">-</a> - - qh_detvnorm( vertex, vertexA, centers, offset ) - compute separating plane of the Voronoi diagram for a pair of input sites - centers= set of facets (i.e., Voronoi vertices) - facet->visitid= 0 iff vertex-at-infinity (i.e., unbounded) - - assumes: - qh_ASvoronoi and qh_vertexneighbors() already set - - returns: - norm - a pointer into qh.gm_matrix to qh.hull_dim-1 reals - copy the data before reusing qh.gm_matrix - offset - if 'QVn' - sign adjusted so that qh.GOODvertexp is inside - else - sign adjusted so that vertex is inside - - qh.gm_matrix= simplex of points from centers relative to first center - - notes: - in io.c so that code for 'v Tv' can be removed by removing io.c - returns pointer into qh.gm_matrix to avoid tracking of temporary memory - - design: - determine midpoint of input sites - build points as the set of Voronoi vertices - select a simplex from points (if necessary) - include midpoint if the Voronoi region is unbounded - relocate the first vertex of the simplex to the origin - compute the normalized hyperplane through the simplex - orient the hyperplane toward 'QVn' or 'vertex' - if 'Tv' or 'Ts' - if bounded - test that hyperplane is the perpendicular bisector of the input sites - test that Voronoi vertices not in the simplex are still on the hyperplane - free up temporary memory -*/ -pointT *qh_detvnorm(vertexT *vertex, vertexT *vertexA, setT *centers, realT *offsetp) { - facetT *facet, **facetp; - int i, k, pointid, pointidA, point_i, point_n; - setT *simplex= NULL; - pointT *point, **pointp, *point0, *midpoint, *normal, *inpoint; - coordT *coord, *gmcoord, *normalp; - setT *points= qh_settemp(qh TEMPsize); - boolT nearzero= False; - boolT unbounded= False; - int numcenters= 0; - int dim= qh hull_dim - 1; - realT dist, offset, angle, zero= 0.0; - - midpoint= qh gm_matrix + qh hull_dim * qh hull_dim; /* last row */ - for (k=0; k < dim; k++) - midpoint[k]= (vertex->point[k] + vertexA->point[k])/2; - FOREACHfacet_(centers) { - numcenters++; - if (!facet->visitid) - unbounded= True; - else { - if (!facet->center) - facet->center= qh_facetcenter(facet->vertices); - qh_setappend(&points, facet->center); - } - } - if (numcenters > dim) { - simplex= qh_settemp(qh TEMPsize); - qh_setappend(&simplex, vertex->point); - if (unbounded) - qh_setappend(&simplex, midpoint); - qh_maxsimplex(dim, points, NULL, 0, &simplex); - qh_setdelnth(simplex, 0); - }else if (numcenters == dim) { - if (unbounded) - qh_setappend(&points, midpoint); - simplex= points; - }else { - qh_fprintf(qh ferr, 6216, "qhull internal error (qh_detvnorm): too few points(%d) to compute separating plane\n", numcenters); - qh_errexit(qh_ERRqhull, NULL, NULL); - } - i= 0; - gmcoord= qh gm_matrix; - point0= SETfirstt_(simplex, pointT); - FOREACHpoint_(simplex) { - if (qh IStracing >= 4) - qh_printmatrix(qh ferr, "qh_detvnorm: Voronoi vertex or midpoint", - &point, 1, dim); - if (point != point0) { - qh gm_row[i++]= gmcoord; - coord= point0; - for (k=dim; k--; ) - *(gmcoord++)= *point++ - *coord++; - } - } - qh gm_row[i]= gmcoord; /* does not overlap midpoint, may be used later for qh_areasimplex */ - normal= gmcoord; - qh_sethyperplane_gauss(dim, qh gm_row, point0, True, - normal, &offset, &nearzero); - if (qh GOODvertexp == vertexA->point) - inpoint= vertexA->point; - else - inpoint= vertex->point; - zinc_(Zdistio); - dist= qh_distnorm(dim, inpoint, normal, &offset); - if (dist > 0) { - offset= -offset; - normalp= normal; - for (k=dim; k--; ) { - *normalp= -(*normalp); - normalp++; - } - } - if (qh VERIFYoutput || qh PRINTstatistics) { - pointid= qh_pointid(vertex->point); - pointidA= qh_pointid(vertexA->point); - if (!unbounded) { - zinc_(Zdiststat); - dist= qh_distnorm(dim, midpoint, normal, &offset); - if (dist < 0) - dist= -dist; - zzinc_(Zridgemid); - wwmax_(Wridgemidmax, dist); - wwadd_(Wridgemid, dist); - trace4((qh ferr, 4014, "qh_detvnorm: points %d %d midpoint dist %2.2g\n", - pointid, pointidA, dist)); - for (k=0; k < dim; k++) - midpoint[k]= vertexA->point[k] - vertex->point[k]; /* overwrites midpoint! */ - qh_normalize(midpoint, dim, False); - angle= qh_distnorm(dim, midpoint, normal, &zero); /* qh_detangle uses dim+1 */ - if (angle < 0.0) - angle= angle + 1.0; - else - angle= angle - 1.0; - if (angle < 0.0) - angle -= angle; - trace4((qh ferr, 4015, "qh_detvnorm: points %d %d angle %2.2g nearzero %d\n", - pointid, pointidA, angle, nearzero)); - if (nearzero) { - zzinc_(Zridge0); - wwmax_(Wridge0max, angle); - wwadd_(Wridge0, angle); - }else { - zzinc_(Zridgeok) - wwmax_(Wridgeokmax, angle); - wwadd_(Wridgeok, angle); - } - } - if (simplex != points) { - FOREACHpoint_i_(points) { - if (!qh_setin(simplex, point)) { - facet= SETelemt_(centers, point_i, facetT); - zinc_(Zdiststat); - dist= qh_distnorm(dim, point, normal, &offset); - if (dist < 0) - dist= -dist; - zzinc_(Zridge); - wwmax_(Wridgemax, dist); - wwadd_(Wridge, dist); - trace4((qh ferr, 4016, "qh_detvnorm: points %d %d Voronoi vertex %d dist %2.2g\n", - pointid, pointidA, facet->visitid, dist)); - } - } - } - } - *offsetp= offset; - if (simplex != points) - qh_settempfree(&simplex); - qh_settempfree(&points); - return normal; -} /* detvnorm */ - -/*-<a href="qh-io.htm#TOC" - >-------------------------------</a><a name="detvridge">-</a> - - qh_detvridge( vertexA ) - determine Voronoi ridge from 'seen' neighbors of vertexA - include one vertex-at-infinite if an !neighbor->visitid - - returns: - temporary set of centers (facets, i.e., Voronoi vertices) - sorted by center id -*/ -setT *qh_detvridge(vertexT *vertex) { - setT *centers= qh_settemp(qh TEMPsize); - setT *tricenters= qh_settemp(qh TEMPsize); - facetT *neighbor, **neighborp; - boolT firstinf= True; - - FOREACHneighbor_(vertex) { - if (neighbor->seen) { - if (neighbor->visitid) { - if (!neighbor->tricoplanar || qh_setunique(&tricenters, neighbor->center)) - qh_setappend(¢ers, neighbor); - }else if (firstinf) { - firstinf= False; - qh_setappend(¢ers, neighbor); - } - } - } - qsort(SETaddr_(centers, facetT), (size_t)qh_setsize(centers), - sizeof(facetT *), qh_compare_facetvisit); - qh_settempfree(&tricenters); - return centers; -} /* detvridge */ - -/*-<a href="qh-io.htm#TOC" - >-------------------------------</a><a name="detvridge3">-</a> - - qh_detvridge3( atvertex, vertex ) - determine 3-d Voronoi ridge from 'seen' neighbors of atvertex and vertex - include one vertex-at-infinite for !neighbor->visitid - assumes all facet->seen2= True - - returns: - temporary set of centers (facets, i.e., Voronoi vertices) - listed in adjacency order (!oriented) - all facet->seen2= True - - design: - mark all neighbors of atvertex - for each adjacent neighbor of both atvertex and vertex - if neighbor selected - add neighbor to set of Voronoi vertices -*/ -setT *qh_detvridge3 (vertexT *atvertex, vertexT *vertex) { - setT *centers= qh_settemp(qh TEMPsize); - setT *tricenters= qh_settemp(qh TEMPsize); - facetT *neighbor, **neighborp, *facet= NULL; - boolT firstinf= True; - - FOREACHneighbor_(atvertex) - neighbor->seen2= False; - FOREACHneighbor_(vertex) { - if (!neighbor->seen2) { - facet= neighbor; - break; - } - } - while (facet) { - facet->seen2= True; - if (neighbor->seen) { - if (facet->visitid) { - if (!facet->tricoplanar || qh_setunique(&tricenters, facet->center)) - qh_setappend(¢ers, facet); - }else if (firstinf) { - firstinf= False; - qh_setappend(¢ers, facet); - } - } - FOREACHneighbor_(facet) { - if (!neighbor->seen2) { - if (qh_setin(vertex->neighbors, neighbor)) - break; - else - neighbor->seen2= True; - } - } - facet= neighbor; - } - if (qh CHECKfrequently) { - FOREACHneighbor_(vertex) { - if (!neighbor->seen2) { - qh_fprintf(qh ferr, 6217, "qhull internal error (qh_detvridge3): neighbors of vertex p%d are not connected at facet %d\n", - qh_pointid(vertex->point), neighbor->id); - qh_errexit(qh_ERRqhull, neighbor, NULL); - } - } - } - FOREACHneighbor_(atvertex) - neighbor->seen2= True; - qh_settempfree(&tricenters); - return centers; -} /* detvridge3 */ - -/*-<a href="qh-io.htm#TOC" - >-------------------------------</a><a name="eachvoronoi">-</a> - - qh_eachvoronoi( fp, printvridge, vertex, visitall, innerouter, inorder ) - if visitall, - visit all Voronoi ridges for vertex (i.e., an input site) - else - visit all unvisited Voronoi ridges for vertex - all vertex->seen= False if unvisited - assumes - all facet->seen= False - all facet->seen2= True (for qh_detvridge3) - all facet->visitid == 0 if vertex_at_infinity - == index of Voronoi vertex - >= qh.num_facets if ignored - innerouter: - qh_RIDGEall-- both inner (bounded) and outer(unbounded) ridges - qh_RIDGEinner- only inner - qh_RIDGEouter- only outer - - if inorder - orders vertices for 3-d Voronoi diagrams - - returns: - number of visited ridges (does not include previously visited ridges) - - if printvridge, - calls printvridge( fp, vertex, vertexA, centers) - fp== any pointer (assumes FILE*) - vertex,vertexA= pair of input sites that define a Voronoi ridge - centers= set of facets (i.e., Voronoi vertices) - ->visitid == index or 0 if vertex_at_infinity - ordered for 3-d Voronoi diagram - notes: - uses qh.vertex_visit - - see: - qh_eachvoronoi_all() - - design: - mark selected neighbors of atvertex - for each selected neighbor (either Voronoi vertex or vertex-at-infinity) - for each unvisited vertex - if atvertex and vertex share more than d-1 neighbors - bump totalcount - if printvridge defined - build the set of shared neighbors (i.e., Voronoi vertices) - call printvridge -*/ -int qh_eachvoronoi(FILE *fp, printvridgeT printvridge, vertexT *atvertex, boolT visitall, qh_RIDGE innerouter, boolT inorder) { - boolT unbounded; - int count; - facetT *neighbor, **neighborp, *neighborA, **neighborAp; - setT *centers; - setT *tricenters= qh_settemp(qh TEMPsize); - - vertexT *vertex, **vertexp; - boolT firstinf; - unsigned int numfacets= (unsigned int)qh num_facets; - int totridges= 0; - - qh vertex_visit++; - atvertex->seen= True; - if (visitall) { - FORALLvertices - vertex->seen= False; - } - FOREACHneighbor_(atvertex) { - if (neighbor->visitid < numfacets) - neighbor->seen= True; - } - FOREACHneighbor_(atvertex) { - if (neighbor->seen) { - FOREACHvertex_(neighbor->vertices) { - if (vertex->visitid != qh vertex_visit && !vertex->seen) { - vertex->visitid= qh vertex_visit; - count= 0; - firstinf= True; - qh_settruncate(tricenters, 0); - FOREACHneighborA_(vertex) { - if (neighborA->seen) { - if (neighborA->visitid) { - if (!neighborA->tricoplanar || qh_setunique(&tricenters, neighborA->center)) - count++; - }else if (firstinf) { - count++; - firstinf= False; - } - } - } - if (count >= qh hull_dim - 1) { /* e.g., 3 for 3-d Voronoi */ - if (firstinf) { - if (innerouter == qh_RIDGEouter) - continue; - unbounded= False; - }else { - if (innerouter == qh_RIDGEinner) - continue; - unbounded= True; - } - totridges++; - trace4((qh ferr, 4017, "qh_eachvoronoi: Voronoi ridge of %d vertices between sites %d and %d\n", - count, qh_pointid(atvertex->point), qh_pointid(vertex->point))); - if (printvridge && fp) { - if (inorder && qh hull_dim == 3+1) /* 3-d Voronoi diagram */ - centers= qh_detvridge3 (atvertex, vertex); - else - centers= qh_detvridge(vertex); - (*printvridge) (fp, atvertex, vertex, centers, unbounded); - qh_settempfree(¢ers); - } - } - } - } - } - } - FOREACHneighbor_(atvertex) - neighbor->seen= False; - qh_settempfree(&tricenters); - return totridges; -} /* eachvoronoi */ - - -/*-<a href="qh-poly.htm#TOC" - >-------------------------------</a><a name="eachvoronoi_all">-</a> - - qh_eachvoronoi_all( fp, printvridge, isUpper, innerouter, inorder ) - visit all Voronoi ridges - - innerouter: - see qh_eachvoronoi() - - if inorder - orders vertices for 3-d Voronoi diagrams - - returns - total number of ridges - - if isUpper == facet->upperdelaunay (i.e., a Vornoi vertex) - facet->visitid= Voronoi vertex index(same as 'o' format) - else - facet->visitid= 0 - - if printvridge, - calls printvridge( fp, vertex, vertexA, centers) - [see qh_eachvoronoi] - - notes: - Not used for qhull.exe - same effect as qh_printvdiagram but ridges not sorted by point id -*/ -int qh_eachvoronoi_all(FILE *fp, printvridgeT printvridge, boolT isUpper, qh_RIDGE innerouter, boolT inorder) { - facetT *facet; - vertexT *vertex; - int numcenters= 1; /* vertex 0 is vertex-at-infinity */ - int totridges= 0; - - qh_clearcenters(qh_ASvoronoi); - qh_vertexneighbors(); - maximize_(qh visit_id, (unsigned) qh num_facets); - FORALLfacets { - facet->visitid= 0; - facet->seen= False; - facet->seen2= True; - } - FORALLfacets { - if (facet->upperdelaunay == isUpper) - facet->visitid= numcenters++; - } - FORALLvertices - vertex->seen= False; - FORALLvertices { - if (qh GOODvertex > 0 && qh_pointid(vertex->point)+1 != qh GOODvertex) - continue; - totridges += qh_eachvoronoi(fp, printvridge, vertex, - !qh_ALL, innerouter, inorder); - } - return totridges; -} /* eachvoronoi_all */ - -/*-<a href="qh-io.htm#TOC" - >-------------------------------</a><a name="facet2point">-</a> - - qh_facet2point( facet, point0, point1, mindist ) - return two projected temporary vertices for a 2-d facet - may be non-simplicial - - returns: - point0 and point1 oriented and projected to the facet - returns mindist (maximum distance below plane) -*/ -void qh_facet2point(facetT *facet, pointT **point0, pointT **point1, realT *mindist) { - vertexT *vertex0, *vertex1; - realT dist; - - if (facet->toporient ^ qh_ORIENTclock) { - vertex0= SETfirstt_(facet->vertices, vertexT); - vertex1= SETsecondt_(facet->vertices, vertexT); - }else { - vertex1= SETfirstt_(facet->vertices, vertexT); - vertex0= SETsecondt_(facet->vertices, vertexT); - } - zadd_(Zdistio, 2); - qh_distplane(vertex0->point, facet, &dist); - *mindist= dist; - *point0= qh_projectpoint(vertex0->point, facet, dist); - qh_distplane(vertex1->point, facet, &dist); - minimize_(*mindist, dist); - *point1= qh_projectpoint(vertex1->point, facet, dist); -} /* facet2point */ - - -/*-<a href="qh-io.htm#TOC" - >-------------------------------</a><a name="facetvertices">-</a> - - qh_facetvertices( facetlist, facets, allfacets ) - returns temporary set of vertices in a set and/or list of facets - if allfacets, ignores qh_skipfacet() - - returns: - vertices with qh.vertex_visit - - notes: - optimized for allfacets of facet_list - - design: - if allfacets of facet_list - create vertex set from vertex_list - else - for each selected facet in facets or facetlist - append unvisited vertices to vertex set -*/ -setT *qh_facetvertices(facetT *facetlist, setT *facets, boolT allfacets) { - setT *vertices; - facetT *facet, **facetp; - vertexT *vertex, **vertexp; - - qh vertex_visit++; - if (facetlist == qh facet_list && allfacets && !facets) { - vertices= qh_settemp(qh num_vertices); - FORALLvertices { - vertex->visitid= qh vertex_visit; - qh_setappend(&vertices, vertex); - } - }else { - vertices= qh_settemp(qh TEMPsize); - FORALLfacet_(facetlist) { - if (!allfacets && qh_skipfacet(facet)) - continue; - FOREACHvertex_(facet->vertices) { - if (vertex->visitid != qh vertex_visit) { - vertex->visitid= qh vertex_visit; - qh_setappend(&vertices, vertex); - } - } - } - } - FOREACHfacet_(facets) { - if (!allfacets && qh_skipfacet(facet)) - continue; - FOREACHvertex_(facet->vertices) { - if (vertex->visitid != qh vertex_visit) { - vertex->visitid= qh vertex_visit; - qh_setappend(&vertices, vertex); - } - } - } - return vertices; -} /* facetvertices */ - -/*-<a href="qh-geom.htm#TOC" - >-------------------------------</a><a name="geomplanes">-</a> - - qh_geomplanes( facet, outerplane, innerplane ) - return outer and inner planes for Geomview - qh.PRINTradius is size of vertices and points (includes qh.JOGGLEmax) - - notes: - assume precise calculations in io.c with roundoff covered by qh_GEOMepsilon -*/ -void qh_geomplanes(facetT *facet, realT *outerplane, realT *innerplane) { - realT radius; - - if (qh MERGING || qh JOGGLEmax < REALmax/2) { - qh_outerinner(facet, outerplane, innerplane); - radius= qh PRINTradius; - if (qh JOGGLEmax < REALmax/2) - radius -= qh JOGGLEmax * sqrt((realT)qh hull_dim); /* already accounted for in qh_outerinner() */ - *outerplane += radius; - *innerplane -= radius; - if (qh PRINTcoplanar || qh PRINTspheres) { - *outerplane += qh MAXabs_coord * qh_GEOMepsilon; - *innerplane -= qh MAXabs_coord * qh_GEOMepsilon; - } - }else - *innerplane= *outerplane= 0; -} /* geomplanes */ - - -/*-<a href="qh-io.htm#TOC" - >-------------------------------</a><a name="markkeep">-</a> - - qh_markkeep( facetlist ) - mark good facets that meet qh.KEEParea, qh.KEEPmerge, and qh.KEEPminArea - ignores visible facets (!part of convex hull) - - returns: - may clear facet->good - recomputes qh.num_good - - design: - get set of good facets - if qh.KEEParea - sort facets by area - clear facet->good for all but n largest facets - if qh.KEEPmerge - sort facets by merge count - clear facet->good for all but n most merged facets - if qh.KEEPminarea - clear facet->good if area too small - update qh.num_good -*/ -void qh_markkeep(facetT *facetlist) { - facetT *facet, **facetp; - setT *facets= qh_settemp(qh num_facets); - int size, count; - - trace2((qh ferr, 2006, "qh_markkeep: only keep %d largest and/or %d most merged facets and/or min area %.2g\n", - qh KEEParea, qh KEEPmerge, qh KEEPminArea)); - FORALLfacet_(facetlist) { - if (!facet->visible && facet->good) - qh_setappend(&facets, facet); - } - size= qh_setsize(facets); - if (qh KEEParea) { - qsort(SETaddr_(facets, facetT), (size_t)size, - sizeof(facetT *), qh_compare_facetarea); - if ((count= size - qh KEEParea) > 0) { - FOREACHfacet_(facets) { - facet->good= False; - if (--count == 0) - break; - } - } - } - if (qh KEEPmerge) { - qsort(SETaddr_(facets, facetT), (size_t)size, - sizeof(facetT *), qh_compare_facetmerge); - if ((count= size - qh KEEPmerge) > 0) { - FOREACHfacet_(facets) { - facet->good= False; - if (--count == 0) - break; - } - } - } - if (qh KEEPminArea < REALmax/2) { - FOREACHfacet_(facets) { - if (!facet->isarea || facet->f.area < qh KEEPminArea) - facet->good= False; - } - } - qh_settempfree(&facets); - count= 0; - FORALLfacet_(facetlist) { - if (facet->good) - count++; - } - qh num_good= count; -} /* markkeep */ - - -/*-<a href="qh-io.htm#TOC" - >-------------------------------</a><a name="markvoronoi">-</a> - - qh_markvoronoi( facetlist, facets, printall, isLower, numcenters ) - mark voronoi vertices for printing by site pairs - - returns: - temporary set of vertices indexed by pointid - isLower set if printing lower hull (i.e., at least one facet is lower hull) - numcenters= total number of Voronoi vertices - bumps qh.printoutnum for vertex-at-infinity - clears all facet->seen and sets facet->seen2 - - if selected - facet->visitid= Voronoi vertex id - else if upper hull (or 'Qu' and lower hull) - facet->visitid= 0 - else - facet->visitid >= qh num_facets - - notes: - ignores qh.ATinfinity, if defined -*/ -setT *qh_markvoronoi(facetT *facetlist, setT *facets, boolT printall, boolT *isLowerp, int *numcentersp) { - int numcenters=0; - facetT *facet, **facetp; - setT *vertices; - boolT isLower= False; - - qh printoutnum++; - qh_clearcenters(qh_ASvoronoi); /* in case, qh_printvdiagram2 called by user */ - qh_vertexneighbors(); - vertices= qh_pointvertex(); - if (qh ATinfinity) - SETelem_(vertices, qh num_points-1)= NULL; - qh visit_id++; - maximize_(qh visit_id, (unsigned) qh num_facets); - FORALLfacet_(facetlist) { - if (printall || !qh_skipfacet(facet)) { - if (!facet->upperdelaunay) { - isLower= True; - break; - } - } - } - FOREACHfacet_(facets) { - if (printall || !qh_skipfacet(facet)) { - if (!facet->upperdelaunay) { - isLower= True; - break; - } - } - } - FORALLfacets { - if (facet->normal && (facet->upperdelaunay == isLower)) - facet->visitid= 0; /* facetlist or facets may overwrite */ - else - facet->visitid= qh visit_id; - facet->seen= False; - facet->seen2= True; - } - numcenters++; /* qh_INFINITE */ - FORALLfacet_(facetlist) { - if (printall || !qh_skipfacet(facet)) - facet->visitid= numcenters++; - } - FOREACHfacet_(facets) { - if (printall || !qh_skipfacet(facet)) - facet->visitid= numcenters++; - } - *isLowerp= isLower; - *numcentersp= numcenters; - trace2((qh ferr, 2007, "qh_markvoronoi: isLower %d numcenters %d\n", isLower, numcenters)); - return vertices; -} /* markvoronoi */ - -/*-<a href="qh-io.htm#TOC" - >-------------------------------</a><a name="order_vertexneighbors">-</a> - - qh_order_vertexneighbors( vertex ) - order facet neighbors of a 2-d or 3-d vertex by adjacency - - notes: - does not orient the neighbors - - design: - initialize a new neighbor set with the first facet in vertex->neighbors - while vertex->neighbors non-empty - select next neighbor in the previous facet's neighbor set - set vertex->neighbors to the new neighbor set -*/ -void qh_order_vertexneighbors(vertexT *vertex) { - setT *newset; - facetT *facet, *neighbor, **neighborp; - - trace4((qh ferr, 4018, "qh_order_vertexneighbors: order neighbors of v%d for 3-d\n", vertex->id)); - newset= qh_settemp(qh_setsize(vertex->neighbors)); - facet= (facetT*)qh_setdellast(vertex->neighbors); - qh_setappend(&newset, facet); - while (qh_setsize(vertex->neighbors)) { - FOREACHneighbor_(vertex) { - if (qh_setin(facet->neighbors, neighbor)) { - qh_setdel(vertex->neighbors, neighbor); - qh_setappend(&newset, neighbor); - facet= neighbor; - break; - } - } - if (!neighbor) { - qh_fprintf(qh ferr, 6066, "qhull internal error (qh_order_vertexneighbors): no neighbor of v%d for f%d\n", - vertex->id, facet->id); - qh_errexit(qh_ERRqhull, facet, NULL); - } - } - qh_setfree(&vertex->neighbors); - qh_settemppop(); - vertex->neighbors= newset; -} /* order_vertexneighbors */ - -/*-<a href="qh-io.htm#TOC" - >-------------------------------</a><a name="prepare_output">-</a> - - qh_prepare_output( ) - prepare for qh_produce_output2() according to - qh.KEEPminArea, KEEParea, KEEPmerge, GOODvertex, GOODthreshold, GOODpoint, ONLYgood, SPLITthresholds - does not reset facet->good - - notes - except for PRINTstatistics, no-op if previously called with same options -*/ -void qh_prepare_output(void) { - if (qh VORONOI) { - qh_clearcenters (qh_ASvoronoi); - qh_vertexneighbors(); - } - if (qh TRIangulate && !qh hasTriangulation) { - qh_triangulate(); - if (qh VERIFYoutput && !qh CHECKfrequently) - qh_checkpolygon (qh facet_list); - } - qh_findgood_all (qh facet_list); - if (qh GETarea) - qh_getarea(qh facet_list); - if (qh KEEParea || qh KEEPmerge || qh KEEPminArea < REALmax/2) - qh_markkeep (qh facet_list); - if (qh PRINTstatistics) - qh_collectstatistics(); -} - -/*-<a href="qh-io.htm#TOC" - >-------------------------------</a><a name="printafacet">-</a> - - qh_printafacet( fp, format, facet, printall ) - print facet to fp in given output format (see qh.PRINTout) - - returns: - nop if !printall and qh_skipfacet() - nop if visible facet and NEWfacets and format != PRINTfacets - must match qh_countfacets - - notes - preserves qh.visit_id - facet->normal may be null if PREmerge/MERGEexact and STOPcone before merge - - see - qh_printbegin() and qh_printend() - - design: - test for printing facet - call appropriate routine for format - or output results directly -*/ -void qh_printafacet(FILE *fp, qh_PRINT format, facetT *facet, boolT printall) { - realT color[4], offset, dist, outerplane, innerplane; - boolT zerodiv; - coordT *point, *normp, *coordp, **pointp, *feasiblep; - int k; - vertexT *vertex, **vertexp; - facetT *neighbor, **neighborp; - - if (!printall && qh_skipfacet(facet)) - return; - if (facet->visible && qh NEWfacets && format != qh_PRINTfacets) - return; - qh printoutnum++; - switch (format) { - case qh_PRINTarea: - if (facet->isarea) { - qh_fprintf(fp, 9009, qh_REAL_1, facet->f.area); - qh_fprintf(fp, 9010, "\n"); - }else - qh_fprintf(fp, 9011, "0\n"); - break; - case qh_PRINTcoplanars: - qh_fprintf(fp, 9012, "%d", qh_setsize(facet->coplanarset)); - FOREACHpoint_(facet->coplanarset) - qh_fprintf(fp, 9013, " %d", qh_pointid(point)); - qh_fprintf(fp, 9014, "\n"); - break; - case qh_PRINTcentrums: - qh_printcenter(fp, format, NULL, facet); - break; - case qh_PRINTfacets: - qh_printfacet(fp, facet); - break; - case qh_PRINTfacets_xridge: - qh_printfacetheader(fp, facet); - break; - case qh_PRINTgeom: /* either 2 , 3, or 4-d by qh_printbegin */ - if (!facet->normal) - break; - for (k=qh hull_dim; k--; ) { - color[k]= (facet->normal[k]+1.0)/2.0; - maximize_(color[k], -1.0); - minimize_(color[k], +1.0); - } - qh_projectdim3 (color, color); - if (qh PRINTdim != qh hull_dim) - qh_normalize2 (color, 3, True, NULL, NULL); - if (qh hull_dim <= 2) - qh_printfacet2geom(fp, facet, color); - else if (qh hull_dim == 3) { - if (facet->simplicial) - qh_printfacet3geom_simplicial(fp, facet, color); - else - qh_printfacet3geom_nonsimplicial(fp, facet, color); - }else { - if (facet->simplicial) - qh_printfacet4geom_simplicial(fp, facet, color); - else - qh_printfacet4geom_nonsimplicial(fp, facet, color); - } - break; - case qh_PRINTids: - qh_fprintf(fp, 9015, "%d\n", facet->id); - break; - case qh_PRINTincidences: - case qh_PRINToff: - case qh_PRINTtriangles: - if (qh hull_dim == 3 && format != qh_PRINTtriangles) - qh_printfacet3vertex(fp, facet, format); - else if (facet->simplicial || qh hull_dim == 2 || format == qh_PRINToff) - qh_printfacetNvertex_simplicial(fp, facet, format); - else - qh_printfacetNvertex_nonsimplicial(fp, facet, qh printoutvar++, format); - break; - case qh_PRINTinner: - qh_outerinner(facet, NULL, &innerplane); - offset= facet->offset - innerplane; - goto LABELprintnorm; - break; /* prevent warning */ - case qh_PRINTmerges: - qh_fprintf(fp, 9016, "%d\n", facet->nummerge); - break; - case qh_PRINTnormals: - offset= facet->offset; - goto LABELprintnorm; - break; /* prevent warning */ - case qh_PRINTouter: - qh_outerinner(facet, &outerplane, NULL); - offset= facet->offset - outerplane; - LABELprintnorm: - if (!facet->normal) { - qh_fprintf(fp, 9017, "no normal for facet f%d\n", facet->id); - break; - } - if (qh CDDoutput) { - qh_fprintf(fp, 9018, qh_REAL_1, -offset); - for (k=0; k < qh hull_dim; k++) - qh_fprintf(fp, 9019, qh_REAL_1, -facet->normal[k]); - }else { - for (k=0; k < qh hull_dim; k++) - qh_fprintf(fp, 9020, qh_REAL_1, facet->normal[k]); - qh_fprintf(fp, 9021, qh_REAL_1, offset); - } - qh_fprintf(fp, 9022, "\n"); - break; - case qh_PRINTmathematica: /* either 2 or 3-d by qh_printbegin */ - case qh_PRINTmaple: - if (qh hull_dim == 2) - qh_printfacet2math(fp, facet, format, qh printoutvar++); - else - qh_printfacet3math(fp, facet, format, qh printoutvar++); - break; - case qh_PRINTneighbors: - qh_fprintf(fp, 9023, "%d", qh_setsize(facet->neighbors)); - FOREACHneighbor_(facet) - qh_fprintf(fp, 9024, " %d", - neighbor->visitid ? neighbor->visitid - 1: 0 - neighbor->id); - qh_fprintf(fp, 9025, "\n"); - break; - case qh_PRINTpointintersect: - if (!qh feasible_point) { - qh_fprintf(qh ferr, 6067, "qhull input error (qh_printafacet): option 'Fp' needs qh feasible_point\n"); - qh_errexit( qh_ERRinput, NULL, NULL); - } - if (facet->offset > 0) - goto LABELprintinfinite; - point= coordp= (coordT*)qh_memalloc(qh normal_size); - normp= facet->normal; - feasiblep= qh feasible_point; - if (facet->offset < -qh MINdenom) { - for (k=qh hull_dim; k--; ) - *(coordp++)= (*(normp++) / - facet->offset) + *(feasiblep++); - }else { - for (k=qh hull_dim; k--; ) { - *(coordp++)= qh_divzero(*(normp++), facet->offset, qh MINdenom_1, - &zerodiv) + *(feasiblep++); - if (zerodiv) { - qh_memfree(point, qh normal_size); - goto LABELprintinfinite; - } - } - } - qh_printpoint(fp, NULL, point); - qh_memfree(point, qh normal_size); - break; - LABELprintinfinite: - for (k=qh hull_dim; k--; ) - qh_fprintf(fp, 9026, qh_REAL_1, qh_INFINITE); - qh_fprintf(fp, 9027, "\n"); - break; - case qh_PRINTpointnearest: - FOREACHpoint_(facet->coplanarset) { - int id, id2; - vertex= qh_nearvertex(facet, point, &dist); - id= qh_pointid(vertex->point); - id2= qh_pointid(point); - qh_fprintf(fp, 9028, "%d %d %d " qh_REAL_1 "\n", id, id2, facet->id, dist); - } - break; - case qh_PRINTpoints: /* VORONOI only by qh_printbegin */ - if (qh CDDoutput) - qh_fprintf(fp, 9029, "1 "); - qh_printcenter(fp, format, NULL, facet); - break; - case qh_PRINTvertices: - qh_fprintf(fp, 9030, "%d", qh_setsize(facet->vertices)); - FOREACHvertex_(facet->vertices) - qh_fprintf(fp, 9031, " %d", qh_pointid(vertex->point)); - qh_fprintf(fp, 9032, "\n"); - break; - default: - break; - } -} /* printafacet */ - -/*-<a href="qh-io.htm#TOC" - >-------------------------------</a><a name="printbegin">-</a> - - qh_printbegin( ) - prints header for all output formats - - returns: - checks for valid format - - notes: - uses qh.visit_id for 3/4off - changes qh.interior_point if printing centrums - qh_countfacets clears facet->visitid for non-good facets - - see - qh_printend() and qh_printafacet() - - design: - count facets and related statistics - print header for format -*/ -void qh_printbegin(FILE *fp, qh_PRINT format, facetT *facetlist, setT *facets, boolT printall) { - int numfacets, numsimplicial, numridges, totneighbors, numcoplanars, numtricoplanars; - int i, num; - facetT *facet, **facetp; - vertexT *vertex, **vertexp; - setT *vertices; - pointT *point, **pointp, *pointtemp; - - qh printoutnum= 0; - qh_countfacets(facetlist, facets, printall, &numfacets, &numsimplicial, - &totneighbors, &numridges, &numcoplanars, &numtricoplanars); - switch (format) { - case qh_PRINTnone: - break; - case qh_PRINTarea: - qh_fprintf(fp, 9033, "%d\n", numfacets); - break; - case qh_PRINTcoplanars: - qh_fprintf(fp, 9034, "%d\n", numfacets); - break; - case qh_PRINTcentrums: - if (qh CENTERtype == qh_ASnone) - qh_clearcenters(qh_AScentrum); - qh_fprintf(fp, 9035, "%d\n%d\n", qh hull_dim, numfacets); - break; - case qh_PRINTfacets: - case qh_PRINTfacets_xridge: - if (facetlist) - qh_printvertexlist(fp, "Vertices and facets:\n", facetlist, facets, printall); - break; - case qh_PRINTgeom: - if (qh hull_dim > 4) /* qh_initqhull_globals also checks */ - goto LABELnoformat; - if (qh VORONOI && qh hull_dim > 3) /* PRINTdim == DROPdim == hull_dim-1 */ - goto LABELnoformat; - if (qh hull_dim == 2 && (qh PRINTridges || qh DOintersections)) - qh_fprintf(qh ferr, 7049, "qhull warning: output for ridges and intersections not implemented in 2-d\n"); - if (qh hull_dim == 4 && (qh PRINTinner || qh PRINTouter || - (qh PRINTdim == 4 && qh PRINTcentrums))) - qh_fprintf(qh ferr, 7050, "qhull warning: output for outer/inner planes and centrums not implemented in 4-d\n"); - if (qh PRINTdim == 4 && (qh PRINTspheres)) - qh_fprintf(qh ferr, 7051, "qhull warning: output for vertices not implemented in 4-d\n"); - if (qh PRINTdim == 4 && qh DOintersections && qh PRINTnoplanes) - qh_fprintf(qh ferr, 7052, "qhull warning: 'Gnh' generates no output in 4-d\n"); - if (qh PRINTdim == 2) { - qh_fprintf(fp, 9036, "{appearance {linewidth 3} LIST # %s | %s\n", - qh rbox_command, qh qhull_command); - }else if (qh PRINTdim == 3) { - qh_fprintf(fp, 9037, "{appearance {+edge -evert linewidth 2} LIST # %s | %s\n", - qh rbox_command, qh qhull_command); - }else if (qh PRINTdim == 4) { - qh visit_id++; - num= 0; - FORALLfacet_(facetlist) /* get number of ridges to be printed */ - qh_printend4geom(NULL, facet, &num, printall); - FOREACHfacet_(facets) - qh_printend4geom(NULL, facet, &num, printall); - qh ridgeoutnum= num; - qh printoutvar= 0; /* counts number of ridges in output */ - qh_fprintf(fp, 9038, "LIST # %s | %s\n", qh rbox_command, qh qhull_command); - } - - if (qh PRINTdots) { - qh printoutnum++; - num= qh num_points + qh_setsize(qh other_points); - if (qh DELAUNAY && qh ATinfinity) - num--; - if (qh PRINTdim == 4) - qh_fprintf(fp, 9039, "4VECT %d %d 1\n", num, num); - else - qh_fprintf(fp, 9040, "VECT %d %d 1\n", num, num); - - for (i=num; i--; ) { - if (i % 20 == 0) - qh_fprintf(fp, 9041, "\n"); - qh_fprintf(fp, 9042, "1 "); - } - qh_fprintf(fp, 9043, "# 1 point per line\n1 "); - for (i=num-1; i--; ) { /* num at least 3 for D2 */ - if (i % 20 == 0) - qh_fprintf(fp, 9044, "\n"); - qh_fprintf(fp, 9045, "0 "); - } - qh_fprintf(fp, 9046, "# 1 color for all\n"); - FORALLpoints { - if (!qh DELAUNAY || !qh ATinfinity || qh_pointid(point) != qh num_points-1) { - if (qh PRINTdim == 4) - qh_printpoint(fp, NULL, point); - else - qh_printpoint3 (fp, point); - } - } - FOREACHpoint_(qh other_points) { - if (qh PRINTdim == 4) - qh_printpoint(fp, NULL, point); - else - qh_printpoint3 (fp, point); - } - qh_fprintf(fp, 9047, "0 1 1 1 # color of points\n"); - } - - if (qh PRINTdim == 4 && !qh PRINTnoplanes) - /* 4dview loads up multiple 4OFF objects slowly */ - qh_fprintf(fp, 9048, "4OFF %d %d 1\n", 3*qh ridgeoutnum, qh ridgeoutnum); - qh PRINTcradius= 2 * qh DISTround; /* include test DISTround */ - if (qh PREmerge) { - maximize_(qh PRINTcradius, qh premerge_centrum + qh DISTround); - }else if (qh POSTmerge) - maximize_(qh PRINTcradius, qh postmerge_centrum + qh DISTround); - qh PRINTradius= qh PRINTcradius; - if (qh PRINTspheres + qh PRINTcoplanar) - maximize_(qh PRINTradius, qh MAXabs_coord * qh_MINradius); - if (qh premerge_cos < REALmax/2) { - maximize_(qh PRINTradius, (1- qh premerge_cos) * qh MAXabs_coord); - }else if (!qh PREmerge && qh POSTmerge && qh postmerge_cos < REALmax/2) { - maximize_(qh PRINTradius, (1- qh postmerge_cos) * qh MAXabs_coord); - } - maximize_(qh PRINTradius, qh MINvisible); - if (qh JOGGLEmax < REALmax/2) - qh PRINTradius += qh JOGGLEmax * sqrt((realT)qh hull_dim); - if (qh PRINTdim != 4 && - (qh PRINTcoplanar || qh PRINTspheres || qh PRINTcentrums)) { - vertices= qh_facetvertices(facetlist, facets, printall); - if (qh PRINTspheres && qh PRINTdim <= 3) - qh_printspheres(fp, vertices, qh PRINTradius); - if (qh PRINTcoplanar || qh PRINTcentrums) { - qh firstcentrum= True; - if (qh PRINTcoplanar&& !qh PRINTspheres) { - FOREACHvertex_(vertices) - qh_printpointvect2 (fp, vertex->point, NULL, qh interior_point, qh PRINTradius); - } - FORALLfacet_(facetlist) { - if (!printall && qh_skipfacet(facet)) - continue; - if (!facet->normal) - continue; - if (qh PRINTcentrums && qh PRINTdim <= 3) - qh_printcentrum(fp, facet, qh PRINTcradius); - if (!qh PRINTcoplanar) - continue; - FOREACHpoint_(facet->coplanarset) - qh_printpointvect2 (fp, point, facet->normal, NULL, qh PRINTradius); - FOREACHpoint_(facet->outsideset) - qh_printpointvect2 (fp, point, facet->normal, NULL, qh PRINTradius); - } - FOREACHfacet_(facets) { - if (!printall && qh_skipfacet(facet)) - continue; - if (!facet->normal) - continue; - if (qh PRINTcentrums && qh PRINTdim <= 3) - qh_printcentrum(fp, facet, qh PRINTcradius); - if (!qh PRINTcoplanar) - continue; - FOREACHpoint_(facet->coplanarset) - qh_printpointvect2 (fp, point, facet->normal, NULL, qh PRINTradius); - FOREACHpoint_(facet->outsideset) - qh_printpointvect2 (fp, point, facet->normal, NULL, qh PRINTradius); - } - } - qh_settempfree(&vertices); - } - qh visit_id++; /* for printing hyperplane intersections */ - break; - case qh_PRINTids: - qh_fprintf(fp, 9049, "%d\n", numfacets); - break; - case qh_PRINTincidences: - if (qh VORONOI && qh PRINTprecision) - qh_fprintf(qh ferr, 7053, "qhull warning: writing Delaunay. Use 'p' or 'o' for Voronoi centers\n"); - qh printoutvar= qh vertex_id; /* centrum id for non-simplicial facets */ - if (qh hull_dim <= 3) - qh_fprintf(fp, 9050, "%d\n", numfacets); - else - qh_fprintf(fp, 9051, "%d\n", numsimplicial+numridges); - break; - case qh_PRINTinner: - case qh_PRINTnormals: - case qh_PRINTouter: - if (qh CDDoutput) - qh_fprintf(fp, 9052, "%s | %s\nbegin\n %d %d real\n", qh rbox_command, - qh qhull_command, numfacets, qh hull_dim+1); - else - qh_fprintf(fp, 9053, "%d\n%d\n", qh hull_dim+1, numfacets); - break; - case qh_PRINTmathematica: - case qh_PRINTmaple: - if (qh hull_dim > 3) /* qh_initbuffers also checks */ - goto LABELnoformat; - if (qh VORONOI) - qh_fprintf(qh ferr, 7054, "qhull warning: output is the Delaunay triangulation\n"); - if (format == qh_PRINTmaple) { - if (qh hull_dim == 2) - qh_fprintf(fp, 9054, "PLOT(CURVES(\n"); - else - qh_fprintf(fp, 9055, "PLOT3D(POLYGONS(\n"); - }else - qh_fprintf(fp, 9056, "{\n"); - qh printoutvar= 0; /* counts number of facets for notfirst */ - break; - case qh_PRINTmerges: - qh_fprintf(fp, 9057, "%d\n", numfacets); - break; - case qh_PRINTpointintersect: - qh_fprintf(fp, 9058, "%d\n%d\n", qh hull_dim, numfacets); - break; - case qh_PRINTneighbors: - qh_fprintf(fp, 9059, "%d\n", numfacets); - break; - case qh_PRINToff: - case qh_PRINTtriangles: - if (qh VORONOI) - goto LABELnoformat; - num = qh hull_dim; - if (format == qh_PRINToff || qh hull_dim == 2) - qh_fprintf(fp, 9060, "%d\n%d %d %d\n", num, - qh num_points+qh_setsize(qh other_points), numfacets, totneighbors/2); - else { /* qh_PRINTtriangles */ - qh printoutvar= qh num_points+qh_setsize(qh other_points); /* first centrum */ - if (qh DELAUNAY) - num--; /* drop last dimension */ - qh_fprintf(fp, 9061, "%d\n%d %d %d\n", num, qh printoutvar - + numfacets - numsimplicial, numsimplicial + numridges, totneighbors/2); - } - FORALLpoints - qh_printpointid(qh fout, NULL, num, point, -1); - FOREACHpoint_(qh other_points) - qh_printpointid(qh fout, NULL, num, point, -1); - if (format == qh_PRINTtriangles && qh hull_dim > 2) { - FORALLfacets { - if (!facet->simplicial && facet->visitid) - qh_printcenter(qh fout, format, NULL, facet); - } - } - break; - case qh_PRINTpointnearest: - qh_fprintf(fp, 9062, "%d\n", numcoplanars); - break; - case qh_PRINTpoints: - if (!qh VORONOI) - goto LABELnoformat; - if (qh CDDoutput) - qh_fprintf(fp, 9063, "%s | %s\nbegin\n%d %d real\n", qh rbox_command, - qh qhull_command, numfacets, qh hull_dim); - else - qh_fprintf(fp, 9064, "%d\n%d\n", qh hull_dim-1, numfacets); - break; - case qh_PRINTvertices: - qh_fprintf(fp, 9065, "%d\n", numfacets); - break; - case qh_PRINTsummary: - default: - LABELnoformat: - qh_fprintf(qh ferr, 6068, "qhull internal error (qh_printbegin): can not use this format for dimension %d\n", - qh hull_dim); - qh_errexit(qh_ERRqhull, NULL, NULL); - } -} /* printbegin */ - -/*-<a href="qh-io.htm#TOC" - >-------------------------------</a><a name="printcenter">-</a> - - qh_printcenter( fp, string, facet ) - print facet->center as centrum or Voronoi center - string may be NULL. Don't include '%' codes. - nop if qh CENTERtype neither CENTERvoronoi nor CENTERcentrum - if upper envelope of Delaunay triangulation and point at-infinity - prints qh_INFINITE instead; - - notes: - defines facet->center if needed - if format=PRINTgeom, adds a 0 if would otherwise be 2-d - Same as QhullFacet::printCenter -*/ -void qh_printcenter(FILE *fp, qh_PRINT format, const char *string, facetT *facet) { - int k, num; - - if (qh CENTERtype != qh_ASvoronoi && qh CENTERtype != qh_AScentrum) - return; - if (string) - qh_fprintf(fp, 9066, string); - if (qh CENTERtype == qh_ASvoronoi) { - num= qh hull_dim-1; - if (!facet->normal || !facet->upperdelaunay || !qh ATinfinity) { - if (!facet->center) - facet->center= qh_facetcenter(facet->vertices); - for (k=0; k < num; k++) - qh_fprintf(fp, 9067, qh_REAL_1, facet->center[k]); - }else { - for (k=0; k < num; k++) - qh_fprintf(fp, 9068, qh_REAL_1, qh_INFINITE); - } - }else /* qh CENTERtype == qh_AScentrum */ { - num= qh hull_dim; - if (format == qh_PRINTtriangles && qh DELAUNAY) - num--; - if (!facet->center) - facet->center= qh_getcentrum(facet); - for (k=0; k < num; k++) - qh_fprintf(fp, 9069, qh_REAL_1, facet->center[k]); - } - if (format == qh_PRINTgeom && num == 2) - qh_fprintf(fp, 9070, " 0\n"); - else - qh_fprintf(fp, 9071, "\n"); -} /* printcenter */ - -/*-<a href="qh-io.htm#TOC" - >-------------------------------</a><a name="printcentrum">-</a> - - qh_printcentrum( fp, facet, radius ) - print centrum for a facet in OOGL format - radius defines size of centrum - 2-d or 3-d only - - returns: - defines facet->center if needed -*/ -void qh_printcentrum(FILE *fp, facetT *facet, realT radius) { - pointT *centrum, *projpt; - boolT tempcentrum= False; - realT xaxis[4], yaxis[4], normal[4], dist; - realT green[3]={0, 1, 0}; - vertexT *apex; - int k; - - if (qh CENTERtype == qh_AScentrum) { - if (!facet->center) - facet->center= qh_getcentrum(facet); - centrum= facet->center; - }else { - centrum= qh_getcentrum(facet); - tempcentrum= True; - } - qh_fprintf(fp, 9072, "{appearance {-normal -edge normscale 0} "); - if (qh firstcentrum) { - qh firstcentrum= False; - qh_fprintf(fp, 9073, "{INST geom { define centrum CQUAD # f%d\n\ --0.3 -0.3 0.0001 0 0 1 1\n\ - 0.3 -0.3 0.0001 0 0 1 1\n\ - 0.3 0.3 0.0001 0 0 1 1\n\ --0.3 0.3 0.0001 0 0 1 1 } transform { \n", facet->id); - }else - qh_fprintf(fp, 9074, "{INST geom { : centrum } transform { # f%d\n", facet->id); - apex= SETfirstt_(facet->vertices, vertexT); - qh_distplane(apex->point, facet, &dist); - projpt= qh_projectpoint(apex->point, facet, dist); - for (k=qh hull_dim; k--; ) { - xaxis[k]= projpt[k] - centrum[k]; - normal[k]= facet->normal[k]; - } - if (qh hull_dim == 2) { - xaxis[2]= 0; - normal[2]= 0; - }else if (qh hull_dim == 4) { - qh_projectdim3 (xaxis, xaxis); - qh_projectdim3 (normal, normal); - qh_normalize2 (normal, qh PRINTdim, True, NULL, NULL); - } - qh_crossproduct(3, xaxis, normal, yaxis); - qh_fprintf(fp, 9075, "%8.4g %8.4g %8.4g 0\n", xaxis[0], xaxis[1], xaxis[2]); - qh_fprintf(fp, 9076, "%8.4g %8.4g %8.4g 0\n", yaxis[0], yaxis[1], yaxis[2]); - qh_fprintf(fp, 9077, "%8.4g %8.4g %8.4g 0\n", normal[0], normal[1], normal[2]); - qh_printpoint3 (fp, centrum); - qh_fprintf(fp, 9078, "1 }}}\n"); - qh_memfree(projpt, qh normal_size); - qh_printpointvect(fp, centrum, facet->normal, NULL, radius, green); - if (tempcentrum) - qh_memfree(centrum, qh normal_size); -} /* printcentrum */ - -/*-<a href="qh-io.htm#TOC" - >-------------------------------</a><a name="printend">-</a> - - qh_printend( fp, format ) - prints trailer for all output formats - - see: - qh_printbegin() and qh_printafacet() - -*/ -void qh_printend(FILE *fp, qh_PRINT format, facetT *facetlist, setT *facets, boolT printall) { - int num; - facetT *facet, **facetp; - - if (!qh printoutnum) - qh_fprintf(qh ferr, 7055, "qhull warning: no facets printed\n"); - switch (format) { - case qh_PRINTgeom: - if (qh hull_dim == 4 && qh DROPdim < 0 && !qh PRINTnoplanes) { - qh visit_id++; - num= 0; - FORALLfacet_(facetlist) - qh_printend4geom(fp, facet,&num, printall); - FOREACHfacet_(facets) - qh_printend4geom(fp, facet, &num, printall); - if (num != qh ridgeoutnum || qh printoutvar != qh ridgeoutnum) { - qh_fprintf(qh ferr, 6069, "qhull internal error (qh_printend): number of ridges %d != number printed %d and at end %d\n", qh ridgeoutnum, qh printoutvar, num); - qh_errexit(qh_ERRqhull, NULL, NULL); - } - }else - qh_fprintf(fp, 9079, "}\n"); - break; - case qh_PRINTinner: - case qh_PRINTnormals: - case qh_PRINTouter: - if (qh CDDoutput) - qh_fprintf(fp, 9080, "end\n"); - break; - case qh_PRINTmaple: - qh_fprintf(fp, 9081, "));\n"); - break; - case qh_PRINTmathematica: - qh_fprintf(fp, 9082, "}\n"); - break; - case qh_PRINTpoints: - if (qh CDDoutput) - qh_fprintf(fp, 9083, "end\n"); - break; - default: - break; - } -} /* printend */ - -/*-<a href="qh-io.htm#TOC" - >-------------------------------</a><a name="printend4geom">-</a> - - qh_printend4geom( fp, facet, numridges, printall ) - helper function for qh_printbegin/printend - - returns: - number of printed ridges - - notes: - just counts printed ridges if fp=NULL - uses facet->visitid - must agree with qh_printfacet4geom... - - design: - computes color for facet from its normal - prints each ridge of facet -*/ -void qh_printend4geom(FILE *fp, facetT *facet, int *nump, boolT printall) { - realT color[3]; - int i, num= *nump; - facetT *neighbor, **neighborp; - ridgeT *ridge, **ridgep; - - if (!printall && qh_skipfacet(facet)) - return; - if (qh PRINTnoplanes || (facet->visible && qh NEWfacets)) - return; - if (!facet->normal) - return; - if (fp) { - for (i=0; i < 3; i++) { - color[i]= (facet->normal[i]+1.0)/2.0; - maximize_(color[i], -1.0); - minimize_(color[i], +1.0); - } - } - facet->visitid= qh visit_id; - if (facet->simplicial) { - FOREACHneighbor_(facet) { - if (neighbor->visitid != qh visit_id) { - if (fp) - qh_fprintf(fp, 9084, "3 %d %d %d %8.4g %8.4g %8.4g 1 # f%d f%d\n", - 3*num, 3*num+1, 3*num+2, color[0], color[1], color[2], - facet->id, neighbor->id); - num++; - } - } - }else { - FOREACHridge_(facet->ridges) { - neighbor= otherfacet_(ridge, facet); - if (neighbor->visitid != qh visit_id) { - if (fp) - qh_fprintf(fp, 9085, "3 %d %d %d %8.4g %8.4g %8.4g 1 #r%d f%d f%d\n", - 3*num, 3*num+1, 3*num+2, color[0], color[1], color[2], - ridge->id, facet->id, neighbor->id); - num++; - } - } - } - *nump= num; -} /* printend4geom */ - -/*-<a href="qh-io.htm#TOC" - >-------------------------------</a><a name="printextremes">-</a> - - qh_printextremes( fp, facetlist, facets, printall ) - print extreme points for convex hulls or halfspace intersections - - notes: - #points, followed by ids, one per line - - sorted by id - same order as qh_printpoints_out if no coplanar/interior points -*/ -void qh_printextremes(FILE *fp, facetT *facetlist, setT *facets, boolT printall) { - setT *vertices, *points; - pointT *point; - vertexT *vertex, **vertexp; - int id; - int numpoints=0, point_i, point_n; - int allpoints= qh num_points + qh_setsize(qh other_points); - - points= qh_settemp(allpoints); - qh_setzero(points, 0, allpoints); - vertices= qh_facetvertices(facetlist, facets, printall); - FOREACHvertex_(vertices) { - id= qh_pointid(vertex->point); - if (id >= 0) { - SETelem_(points, id)= vertex->point; - numpoints++; - } - } - qh_settempfree(&vertices); - qh_fprintf(fp, 9086, "%d\n", numpoints); - FOREACHpoint_i_(points) { - if (point) - qh_fprintf(fp, 9087, "%d\n", point_i); - } - qh_settempfree(&points); -} /* printextremes */ - -/*-<a href="qh-io.htm#TOC" - >-------------------------------</a><a name="printextremes_2d">-</a> - - qh_printextremes_2d( fp, facetlist, facets, printall ) - prints point ids for facets in qh_ORIENTclock order - - notes: - #points, followed by ids, one per line - if facetlist/facets are disjoint than the output includes skips - errors if facets form a loop - does not print coplanar points -*/ -void qh_printextremes_2d(FILE *fp, facetT *facetlist, setT *facets, boolT printall) { - int numfacets, numridges, totneighbors, numcoplanars, numsimplicial, numtricoplanars; - setT *vertices; - facetT *facet, *startfacet, *nextfacet; - vertexT *vertexA, *vertexB; - - qh_countfacets(facetlist, facets, printall, &numfacets, &numsimplicial, - &totneighbors, &numridges, &numcoplanars, &numtricoplanars); /* marks qh visit_id */ - vertices= qh_facetvertices(facetlist, facets, printall); - qh_fprintf(fp, 9088, "%d\n", qh_setsize(vertices)); - qh_settempfree(&vertices); - if (!numfacets) - return; - facet= startfacet= facetlist ? facetlist : SETfirstt_(facets, facetT); - qh vertex_visit++; - qh visit_id++; - do { - if (facet->toporient ^ qh_ORIENTclock) { - vertexA= SETfirstt_(facet->vertices, vertexT); - vertexB= SETsecondt_(facet->vertices, vertexT); - nextfacet= SETfirstt_(facet->neighbors, facetT); - }else { - vertexA= SETsecondt_(facet->vertices, vertexT); - vertexB= SETfirstt_(facet->vertices, vertexT); - nextfacet= SETsecondt_(facet->neighbors, facetT); - } - if (facet->visitid == qh visit_id) { - qh_fprintf(qh ferr, 6218, "Qhull internal error (qh_printextremes_2d): loop in facet list. facet %d nextfacet %d\n", - facet->id, nextfacet->id); - qh_errexit2 (qh_ERRqhull, facet, nextfacet); - } - if (facet->visitid) { - if (vertexA->visitid != qh vertex_visit) { - vertexA->visitid= qh vertex_visit; - qh_fprintf(fp, 9089, "%d\n", qh_pointid(vertexA->point)); - } - if (vertexB->visitid != qh vertex_visit) { - vertexB->visitid= qh vertex_visit; - qh_fprintf(fp, 9090, "%d\n", qh_pointid(vertexB->point)); - } - } - facet->visitid= qh visit_id; - facet= nextfacet; - }while (facet && facet != startfacet); -} /* printextremes_2d */ - -/*-<a href="qh-io.htm#TOC" - >-------------------------------</a><a name="printextremes_d">-</a> - - qh_printextremes_d( fp, facetlist, facets, printall ) - print extreme points of input sites for Delaunay triangulations - - notes: - #points, followed by ids, one per line - - unordered -*/ -void qh_printextremes_d(FILE *fp, facetT *facetlist, setT *facets, boolT printall) { - setT *vertices; - vertexT *vertex, **vertexp; - boolT upperseen, lowerseen; - facetT *neighbor, **neighborp; - int numpoints=0; - - vertices= qh_facetvertices(facetlist, facets, printall); - qh_vertexneighbors(); - FOREACHvertex_(vertices) { - upperseen= lowerseen= False; - FOREACHneighbor_(vertex) { - if (neighbor->upperdelaunay) - upperseen= True; - else - lowerseen= True; - } - if (upperseen && lowerseen) { - vertex->seen= True; - numpoints++; - }else - vertex->seen= False; - } - qh_fprintf(fp, 9091, "%d\n", numpoints); - FOREACHvertex_(vertices) { - if (vertex->seen) - qh_fprintf(fp, 9092, "%d\n", qh_pointid(vertex->point)); - } - qh_settempfree(&vertices); -} /* printextremes_d */ - -/*-<a href="qh-io.htm#TOC" - >-------------------------------</a><a name="printfacet">-</a> - - qh_printfacet( fp, facet ) - prints all fields of a facet to fp - - notes: - ridges printed in neighbor order -*/ -void qh_printfacet(FILE *fp, facetT *facet) { - - qh_printfacetheader(fp, facet); - if (facet->ridges) - qh_printfacetridges(fp, facet); -} /* printfacet */ - - -/*-<a href="qh-io.htm#TOC" - >-------------------------------</a><a name="printfacet2geom">-</a> - - qh_printfacet2geom( fp, facet, color ) - print facet as part of a 2-d VECT for Geomview - - notes: - assume precise calculations in io.c with roundoff covered by qh_GEOMepsilon - mindist is calculated within io.c. maxoutside is calculated elsewhere - so a DISTround error may have occured. -*/ -void qh_printfacet2geom(FILE *fp, facetT *facet, realT color[3]) { - pointT *point0, *point1; - realT mindist, innerplane, outerplane; - int k; - - qh_facet2point(facet, &point0, &point1, &mindist); - qh_geomplanes(facet, &outerplane, &innerplane); - if (qh PRINTouter || (!qh PRINTnoplanes && !qh PRINTinner)) - qh_printfacet2geom_points(fp, point0, point1, facet, outerplane, color); - if (qh PRINTinner || (!qh PRINTnoplanes && !qh PRINTouter && - outerplane - innerplane > 2 * qh MAXabs_coord * qh_GEOMepsilon)) { - for (k=3; k--; ) - color[k]= 1.0 - color[k]; - qh_printfacet2geom_points(fp, point0, point1, facet, innerplane, color); - } - qh_memfree(point1, qh normal_size); - qh_memfree(point0, qh normal_size); -} /* printfacet2geom */ - -/*-<a href="qh-io.htm#TOC" - >-------------------------------</a><a name="printfacet2geom_points">-</a> - - qh_printfacet2geom_points( fp, point1, point2, facet, offset, color ) - prints a 2-d facet as a VECT with 2 points at some offset. - The points are on the facet's plane. -*/ -void qh_printfacet2geom_points(FILE *fp, pointT *point1, pointT *point2, - facetT *facet, realT offset, realT color[3]) { - pointT *p1= point1, *p2= point2; - - qh_fprintf(fp, 9093, "VECT 1 2 1 2 1 # f%d\n", facet->id); - if (offset != 0.0) { - p1= qh_projectpoint(p1, facet, -offset); - p2= qh_projectpoint(p2, facet, -offset); - } - qh_fprintf(fp, 9094, "%8.4g %8.4g %8.4g\n%8.4g %8.4g %8.4g\n", - p1[0], p1[1], 0.0, p2[0], p2[1], 0.0); - if (offset != 0.0) { - qh_memfree(p1, qh normal_size); - qh_memfree(p2, qh normal_size); - } - qh_fprintf(fp, 9095, "%8.4g %8.4g %8.4g 1.0\n", color[0], color[1], color[2]); -} /* printfacet2geom_points */ - - -/*-<a href="qh-io.htm#TOC" - >-------------------------------</a><a name="printfacet2math">-</a> - - qh_printfacet2math( fp, facet, format, notfirst ) - print 2-d Maple or Mathematica output for a facet - may be non-simplicial - - notes: - use %16.8f since Mathematica 2.2 does not handle exponential format - see qh_printfacet3math -*/ -void qh_printfacet2math(FILE *fp, facetT *facet, qh_PRINT format, int notfirst) { - pointT *point0, *point1; - realT mindist; - const char *pointfmt; - - qh_facet2point(facet, &point0, &point1, &mindist); - if (notfirst) - qh_fprintf(fp, 9096, ","); - if (format == qh_PRINTmaple) - pointfmt= "[[%16.8f, %16.8f], [%16.8f, %16.8f]]\n"; - else - pointfmt= "Line[{{%16.8f, %16.8f}, {%16.8f, %16.8f}}]\n"; - qh_fprintf(fp, 9097, pointfmt, point0[0], point0[1], point1[0], point1[1]); - qh_memfree(point1, qh normal_size); - qh_memfree(point0, qh normal_size); -} /* printfacet2math */ - - -/*-<a href="qh-io.htm#TOC" - >-------------------------------</a><a name="printfacet3geom_nonsimplicial">-</a> - - qh_printfacet3geom_nonsimplicial( fp, facet, color ) - print Geomview OFF for a 3-d nonsimplicial facet. - if DOintersections, prints ridges to unvisited neighbors(qh visit_id) - - notes - uses facet->visitid for intersections and ridges -*/ -void qh_printfacet3geom_nonsimplicial(FILE *fp, facetT *facet, realT color[3]) { - ridgeT *ridge, **ridgep; - setT *projectedpoints, *vertices; - vertexT *vertex, **vertexp, *vertexA, *vertexB; - pointT *projpt, *point, **pointp; - facetT *neighbor; - realT dist, outerplane, innerplane; - int cntvertices, k; - realT black[3]={0, 0, 0}, green[3]={0, 1, 0}; - - qh_geomplanes(facet, &outerplane, &innerplane); - vertices= qh_facet3vertex(facet); /* oriented */ - cntvertices= qh_setsize(vertices); - projectedpoints= qh_settemp(cntvertices); - FOREACHvertex_(vertices) { - zinc_(Zdistio); - qh_distplane(vertex->point, facet, &dist); - projpt= qh_projectpoint(vertex->point, facet, dist); - qh_setappend(&projectedpoints, projpt); - } - if (qh PRINTouter || (!qh PRINTnoplanes && !qh PRINTinner)) - qh_printfacet3geom_points(fp, projectedpoints, facet, outerplane, color); - if (qh PRINTinner || (!qh PRINTnoplanes && !qh PRINTouter && - outerplane - innerplane > 2 * qh MAXabs_coord * qh_GEOMepsilon)) { - for (k=3; k--; ) - color[k]= 1.0 - color[k]; - qh_printfacet3geom_points(fp, projectedpoints, facet, innerplane, color); - } - FOREACHpoint_(projectedpoints) - qh_memfree(point, qh normal_size); - qh_settempfree(&projectedpoints); - qh_settempfree(&vertices); - if ((qh DOintersections || qh PRINTridges) - && (!facet->visible || !qh NEWfacets)) { - facet->visitid= qh visit_id; - FOREACHridge_(facet->ridges) { - neighbor= otherfacet_(ridge, facet); - if (neighbor->visitid != qh visit_id) { - if (qh DOintersections) - qh_printhyperplaneintersection(fp, facet, neighbor, ridge->vertices, black); - if (qh PRINTridges) { - vertexA= SETfirstt_(ridge->vertices, vertexT); - vertexB= SETsecondt_(ridge->vertices, vertexT); - qh_printline3geom(fp, vertexA->point, vertexB->point, green); - } - } - } - } -} /* printfacet3geom_nonsimplicial */ - -/*-<a href="qh-io.htm#TOC" - >-------------------------------</a><a name="printfacet3geom_points">-</a> - - qh_printfacet3geom_points( fp, points, facet, offset ) - prints a 3-d facet as OFF Geomview object. - offset is relative to the facet's hyperplane - Facet is determined as a list of points -*/ -void qh_printfacet3geom_points(FILE *fp, setT *points, facetT *facet, realT offset, realT color[3]) { - int k, n= qh_setsize(points), i; - pointT *point, **pointp; - setT *printpoints; - - qh_fprintf(fp, 9098, "{ OFF %d 1 1 # f%d\n", n, facet->id); - if (offset != 0.0) { - printpoints= qh_settemp(n); - FOREACHpoint_(points) - qh_setappend(&printpoints, qh_projectpoint(point, facet, -offset)); - }else - printpoints= points; - FOREACHpoint_(printpoints) { - for (k=0; k < qh hull_dim; k++) { - if (k == qh DROPdim) - qh_fprintf(fp, 9099, "0 "); - else - qh_fprintf(fp, 9100, "%8.4g ", point[k]); - } - if (printpoints != points) - qh_memfree(point, qh normal_size); - qh_fprintf(fp, 9101, "\n"); - } - if (printpoints != points) - qh_settempfree(&printpoints); - qh_fprintf(fp, 9102, "%d ", n); - for (i=0; i < n; i++) - qh_fprintf(fp, 9103, "%d ", i); - qh_fprintf(fp, 9104, "%8.4g %8.4g %8.4g 1.0 }\n", color[0], color[1], color[2]); -} /* printfacet3geom_points */ - - -/*-<a href="qh-io.htm#TOC" - >-------------------------------</a><a name="printfacet3geom_simplicial">-</a> - - qh_printfacet3geom_simplicial( ) - print Geomview OFF for a 3-d simplicial facet. - - notes: - may flip color - uses facet->visitid for intersections and ridges - - assume precise calculations in io.c with roundoff covered by qh_GEOMepsilon - innerplane may be off by qh DISTround. Maxoutside is calculated elsewhere - so a DISTround error may have occured. -*/ -void qh_printfacet3geom_simplicial(FILE *fp, facetT *facet, realT color[3]) { - setT *points, *vertices; - vertexT *vertex, **vertexp, *vertexA, *vertexB; - facetT *neighbor, **neighborp; - realT outerplane, innerplane; - realT black[3]={0, 0, 0}, green[3]={0, 1, 0}; - int k; - - qh_geomplanes(facet, &outerplane, &innerplane); - vertices= qh_facet3vertex(facet); - points= qh_settemp(qh TEMPsize); - FOREACHvertex_(vertices) - qh_setappend(&points, vertex->point); - if (qh PRINTouter || (!qh PRINTnoplanes && !qh PRINTinner)) - qh_printfacet3geom_points(fp, points, facet, outerplane, color); - if (qh PRINTinner || (!qh PRINTnoplanes && !qh PRINTouter && - outerplane - innerplane > 2 * qh MAXabs_coord * qh_GEOMepsilon)) { - for (k=3; k--; ) - color[k]= 1.0 - color[k]; - qh_printfacet3geom_points(fp, points, facet, innerplane, color); - } - qh_settempfree(&points); - qh_settempfree(&vertices); - if ((qh DOintersections || qh PRINTridges) - && (!facet->visible || !qh NEWfacets)) { - facet->visitid= qh visit_id; - FOREACHneighbor_(facet) { - if (neighbor->visitid != qh visit_id) { - vertices= qh_setnew_delnthsorted(facet->vertices, qh hull_dim, - SETindex_(facet->neighbors, neighbor), 0); - if (qh DOintersections) - qh_printhyperplaneintersection(fp, facet, neighbor, vertices, black); - if (qh PRINTridges) { - vertexA= SETfirstt_(vertices, vertexT); - vertexB= SETsecondt_(vertices, vertexT); - qh_printline3geom(fp, vertexA->point, vertexB->point, green); - } - qh_setfree(&vertices); - } - } - } -} /* printfacet3geom_simplicial */ - -/*-<a href="qh-io.htm#TOC" - >-------------------------------</a><a name="printfacet3math">-</a> - - qh_printfacet3math( fp, facet, notfirst ) - print 3-d Maple or Mathematica output for a facet - - notes: - may be non-simplicial - use %16.8f since Mathematica 2.2 does not handle exponential format - see qh_printfacet2math -*/ -void qh_printfacet3math(FILE *fp, facetT *facet, qh_PRINT format, int notfirst) { - vertexT *vertex, **vertexp; - setT *points, *vertices; - pointT *point, **pointp; - boolT firstpoint= True; - realT dist; - const char *pointfmt, *endfmt; - - if (notfirst) - qh_fprintf(fp, 9105, ",\n"); - vertices= qh_facet3vertex(facet); - points= qh_settemp(qh_setsize(vertices)); - FOREACHvertex_(vertices) { - zinc_(Zdistio); - qh_distplane(vertex->point, facet, &dist); - point= qh_projectpoint(vertex->point, facet, dist); - qh_setappend(&points, point); - } - if (format == qh_PRINTmaple) { - qh_fprintf(fp, 9106, "["); - pointfmt= "[%16.8f, %16.8f, %16.8f]"; - endfmt= "]"; - }else { - qh_fprintf(fp, 9107, "Polygon[{"); - pointfmt= "{%16.8f, %16.8f, %16.8f}"; - endfmt= "}]"; - } - FOREACHpoint_(points) { - if (firstpoint) - firstpoint= False; - else - qh_fprintf(fp, 9108, ",\n"); - qh_fprintf(fp, 9109, pointfmt, point[0], point[1], point[2]); - } - FOREACHpoint_(points) - qh_memfree(point, qh normal_size); - qh_settempfree(&points); - qh_settempfree(&vertices); - qh_fprintf(fp, 9110, endfmt); -} /* printfacet3math */ - - -/*-<a href="qh-io.htm#TOC" - >-------------------------------</a><a name="printfacet3vertex">-</a> - - qh_printfacet3vertex( fp, facet, format ) - print vertices in a 3-d facet as point ids - - notes: - prints number of vertices first if format == qh_PRINToff - the facet may be non-simplicial -*/ -void qh_printfacet3vertex(FILE *fp, facetT *facet, qh_PRINT format) { - vertexT *vertex, **vertexp; - setT *vertices; - - vertices= qh_facet3vertex(facet); - if (format == qh_PRINToff) - qh_fprintf(fp, 9111, "%d ", qh_setsize(vertices)); - FOREACHvertex_(vertices) - qh_fprintf(fp, 9112, "%d ", qh_pointid(vertex->point)); - qh_fprintf(fp, 9113, "\n"); - qh_settempfree(&vertices); -} /* printfacet3vertex */ - - -/*-<a href="qh-io.htm#TOC" - >-------------------------------</a><a name="printfacet4geom_nonsimplicial">-</a> - - qh_printfacet4geom_nonsimplicial( ) - print Geomview 4OFF file for a 4d nonsimplicial facet - prints all ridges to unvisited neighbors (qh.visit_id) - if qh.DROPdim - prints in OFF format - - notes: - must agree with printend4geom() -*/ -void qh_printfacet4geom_nonsimplicial(FILE *fp, facetT *facet, realT color[3]) { - facetT *neighbor; - ridgeT *ridge, **ridgep; - vertexT *vertex, **vertexp; - pointT *point; - int k; - realT dist; - - facet->visitid= qh visit_id; - if (qh PRINTnoplanes || (facet->visible && qh NEWfacets)) - return; - FOREACHridge_(facet->ridges) { - neighbor= otherfacet_(ridge, facet); - if (neighbor->visitid == qh visit_id) - continue; - if (qh PRINTtransparent && !neighbor->good) - continue; - if (qh DOintersections) - qh_printhyperplaneintersection(fp, facet, neighbor, ridge->vertices, color); - else { - if (qh DROPdim >= 0) - qh_fprintf(fp, 9114, "OFF 3 1 1 # f%d\n", facet->id); - else { - qh printoutvar++; - qh_fprintf(fp, 9115, "# r%d between f%d f%d\n", ridge->id, facet->id, neighbor->id); - } - FOREACHvertex_(ridge->vertices) { - zinc_(Zdistio); - qh_distplane(vertex->point,facet, &dist); - point=qh_projectpoint(vertex->point,facet, dist); - for (k=0; k < qh hull_dim; k++) { - if (k != qh DROPdim) - qh_fprintf(fp, 9116, "%8.4g ", point[k]); - } - qh_fprintf(fp, 9117, "\n"); - qh_memfree(point, qh normal_size); - } - if (qh DROPdim >= 0) - qh_fprintf(fp, 9118, "3 0 1 2 %8.4g %8.4g %8.4g\n", color[0], color[1], color[2]); - } - } -} /* printfacet4geom_nonsimplicial */ - - -/*-<a href="qh-io.htm#TOC" - >-------------------------------</a><a name="printfacet4geom_simplicial">-</a> - - qh_printfacet4geom_simplicial( fp, facet, color ) - print Geomview 4OFF file for a 4d simplicial facet - prints triangles for unvisited neighbors (qh.visit_id) - - notes: - must agree with printend4geom() -*/ -void qh_printfacet4geom_simplicial(FILE *fp, facetT *facet, realT color[3]) { - setT *vertices; - facetT *neighbor, **neighborp; - vertexT *vertex, **vertexp; - int k; - - facet->visitid= qh visit_id; - if (qh PRINTnoplanes || (facet->visible && qh NEWfacets)) - return; - FOREACHneighbor_(facet) { - if (neighbor->visitid == qh visit_id) - continue; - if (qh PRINTtransparent && !neighbor->good) - continue; - vertices= qh_setnew_delnthsorted(facet->vertices, qh hull_dim, - SETindex_(facet->neighbors, neighbor), 0); - if (qh DOintersections) - qh_printhyperplaneintersection(fp, facet, neighbor, vertices, color); - else { - if (qh DROPdim >= 0) - qh_fprintf(fp, 9119, "OFF 3 1 1 # ridge between f%d f%d\n", - facet->id, neighbor->id); - else { - qh printoutvar++; - qh_fprintf(fp, 9120, "# ridge between f%d f%d\n", facet->id, neighbor->id); - } - FOREACHvertex_(vertices) { - for (k=0; k < qh hull_dim; k++) { - if (k != qh DROPdim) - qh_fprintf(fp, 9121, "%8.4g ", vertex->point[k]); - } - qh_fprintf(fp, 9122, "\n"); - } - if (qh DROPdim >= 0) - qh_fprintf(fp, 9123, "3 0 1 2 %8.4g %8.4g %8.4g\n", color[0], color[1], color[2]); - } - qh_setfree(&vertices); - } -} /* printfacet4geom_simplicial */ - - -/*-<a href="qh-io.htm#TOC" - >-------------------------------</a><a name="printfacetNvertex_nonsimplicial">-</a> - - qh_printfacetNvertex_nonsimplicial( fp, facet, id, format ) - print vertices for an N-d non-simplicial facet - triangulates each ridge to the id -*/ -void qh_printfacetNvertex_nonsimplicial(FILE *fp, facetT *facet, int id, qh_PRINT format) { - vertexT *vertex, **vertexp; - ridgeT *ridge, **ridgep; - - if (facet->visible && qh NEWfacets) - return; - FOREACHridge_(facet->ridges) { - if (format == qh_PRINTtriangles) - qh_fprintf(fp, 9124, "%d ", qh hull_dim); - qh_fprintf(fp, 9125, "%d ", id); - if ((ridge->top == facet) ^ qh_ORIENTclock) { - FOREACHvertex_(ridge->vertices) - qh_fprintf(fp, 9126, "%d ", qh_pointid(vertex->point)); - }else { - FOREACHvertexreverse12_(ridge->vertices) - qh_fprintf(fp, 9127, "%d ", qh_pointid(vertex->point)); - } - qh_fprintf(fp, 9128, "\n"); - } -} /* printfacetNvertex_nonsimplicial */ - - -/*-<a href="qh-io.htm#TOC" - >-------------------------------</a><a name="printfacetNvertex_simplicial">-</a> - - qh_printfacetNvertex_simplicial( fp, facet, format ) - print vertices for an N-d simplicial facet - prints vertices for non-simplicial facets - 2-d facets (orientation preserved by qh_mergefacet2d) - PRINToff ('o') for 4-d and higher -*/ -void qh_printfacetNvertex_simplicial(FILE *fp, facetT *facet, qh_PRINT format) { - vertexT *vertex, **vertexp; - - if (format == qh_PRINToff || format == qh_PRINTtriangles) - qh_fprintf(fp, 9129, "%d ", qh_setsize(facet->vertices)); - if ((facet->toporient ^ qh_ORIENTclock) - || (qh hull_dim > 2 && !facet->simplicial)) { - FOREACHvertex_(facet->vertices) - qh_fprintf(fp, 9130, "%d ", qh_pointid(vertex->point)); - }else { - FOREACHvertexreverse12_(facet->vertices) - qh_fprintf(fp, 9131, "%d ", qh_pointid(vertex->point)); - } - qh_fprintf(fp, 9132, "\n"); -} /* printfacetNvertex_simplicial */ - - -/*-<a href="qh-io.htm#TOC" - >-------------------------------</a><a name="printfacetheader">-</a> - - qh_printfacetheader( fp, facet ) - prints header fields of a facet to fp - - notes: - for 'f' output and debugging - Same as QhullFacet::printHeader() -*/ -void qh_printfacetheader(FILE *fp, facetT *facet) { - pointT *point, **pointp, *furthest; - facetT *neighbor, **neighborp; - realT dist; - - if (facet == qh_MERGEridge) { - qh_fprintf(fp, 9133, " MERGEridge\n"); - return; - }else if (facet == qh_DUPLICATEridge) { - qh_fprintf(fp, 9134, " DUPLICATEridge\n"); - return; - }else if (!facet) { - qh_fprintf(fp, 9135, " NULLfacet\n"); - return; - } - qh old_randomdist= qh RANDOMdist; - qh RANDOMdist= False; - qh_fprintf(fp, 9136, "- f%d\n", facet->id); - qh_fprintf(fp, 9137, " - flags:"); - if (facet->toporient) - qh_fprintf(fp, 9138, " top"); - else - qh_fprintf(fp, 9139, " bottom"); - if (facet->simplicial) - qh_fprintf(fp, 9140, " simplicial"); - if (facet->tricoplanar) - qh_fprintf(fp, 9141, " tricoplanar"); - if (facet->upperdelaunay) - qh_fprintf(fp, 9142, " upperDelaunay"); - if (facet->visible) - qh_fprintf(fp, 9143, " visible"); - if (facet->newfacet) - qh_fprintf(fp, 9144, " new"); - if (facet->tested) - qh_fprintf(fp, 9145, " tested"); - if (!facet->good) - qh_fprintf(fp, 9146, " notG"); - if (facet->seen) - qh_fprintf(fp, 9147, " seen"); - if (facet->coplanar) - qh_fprintf(fp, 9148, " coplanar"); - if (facet->mergehorizon) - qh_fprintf(fp, 9149, " mergehorizon"); - if (facet->keepcentrum) - qh_fprintf(fp, 9150, " keepcentrum"); - if (facet->dupridge) - qh_fprintf(fp, 9151, " dupridge"); - if (facet->mergeridge && !facet->mergeridge2) - qh_fprintf(fp, 9152, " mergeridge1"); - if (facet->mergeridge2) - qh_fprintf(fp, 9153, " mergeridge2"); - if (facet->newmerge) - qh_fprintf(fp, 9154, " newmerge"); - if (facet->flipped) - qh_fprintf(fp, 9155, " flipped"); - if (facet->notfurthest) - qh_fprintf(fp, 9156, " notfurthest"); - if (facet->degenerate) - qh_fprintf(fp, 9157, " degenerate"); - if (facet->redundant) - qh_fprintf(fp, 9158, " redundant"); - qh_fprintf(fp, 9159, "\n"); - if (facet->isarea) - qh_fprintf(fp, 9160, " - area: %2.2g\n", facet->f.area); - else if (qh NEWfacets && facet->visible && facet->f.replace) - qh_fprintf(fp, 9161, " - replacement: f%d\n", facet->f.replace->id); - else if (facet->newfacet) { - if (facet->f.samecycle && facet->f.samecycle != facet) - qh_fprintf(fp, 9162, " - shares same visible/horizon as f%d\n", facet->f.samecycle->id); - }else if (facet->tricoplanar /* !isarea */) { - if (facet->f.triowner) - qh_fprintf(fp, 9163, " - owner of normal & centrum is facet f%d\n", facet->f.triowner->id); - }else if (facet->f.newcycle) - qh_fprintf(fp, 9164, " - was horizon to f%d\n", facet->f.newcycle->id); - if (facet->nummerge) - qh_fprintf(fp, 9165, " - merges: %d\n", facet->nummerge); - qh_printpointid(fp, " - normal: ", qh hull_dim, facet->normal, -1); - qh_fprintf(fp, 9166, " - offset: %10.7g\n", facet->offset); - if (qh CENTERtype == qh_ASvoronoi || facet->center) - qh_printcenter(fp, qh_PRINTfacets, " - center: ", facet); -#if qh_MAXoutside - if (facet->maxoutside > qh DISTround) - qh_fprintf(fp, 9167, " - maxoutside: %10.7g\n", facet->maxoutside); -#endif - if (!SETempty_(facet->outsideset)) { - furthest= (pointT*)qh_setlast(facet->outsideset); - if (qh_setsize(facet->outsideset) < 6) { - qh_fprintf(fp, 9168, " - outside set(furthest p%d):\n", qh_pointid(furthest)); - FOREACHpoint_(facet->outsideset) - qh_printpoint(fp, " ", point); - }else if (qh_setsize(facet->outsideset) < 21) { - qh_printpoints(fp, " - outside set:", facet->outsideset); - }else { - qh_fprintf(fp, 9169, " - outside set: %d points.", qh_setsize(facet->outsideset)); - qh_printpoint(fp, " Furthest", furthest); - } -#if !qh_COMPUTEfurthest - qh_fprintf(fp, 9170, " - furthest distance= %2.2g\n", facet->furthestdist); -#endif - } - if (!SETempty_(facet->coplanarset)) { - furthest= (pointT*)qh_setlast(facet->coplanarset); - if (qh_setsize(facet->coplanarset) < 6) { - qh_fprintf(fp, 9171, " - coplanar set(furthest p%d):\n", qh_pointid(furthest)); - FOREACHpoint_(facet->coplanarset) - qh_printpoint(fp, " ", point); - }else if (qh_setsize(facet->coplanarset) < 21) { - qh_printpoints(fp, " - coplanar set:", facet->coplanarset); - }else { - qh_fprintf(fp, 9172, " - coplanar set: %d points.", qh_setsize(facet->coplanarset)); - qh_printpoint(fp, " Furthest", furthest); - } - zinc_(Zdistio); - qh_distplane(furthest, facet, &dist); - qh_fprintf(fp, 9173, " furthest distance= %2.2g\n", dist); - } - qh_printvertices(fp, " - vertices:", facet->vertices); - qh_fprintf(fp, 9174, " - neighboring facets:"); - FOREACHneighbor_(facet) { - if (neighbor == qh_MERGEridge) - qh_fprintf(fp, 9175, " MERGE"); - else if (neighbor == qh_DUPLICATEridge) - qh_fprintf(fp, 9176, " DUP"); - else - qh_fprintf(fp, 9177, " f%d", neighbor->id); - } - qh_fprintf(fp, 9178, "\n"); - qh RANDOMdist= qh old_randomdist; -} /* printfacetheader */ - - -/*-<a href="qh-io.htm#TOC" - >-------------------------------</a><a name="printfacetridges">-</a> - - qh_printfacetridges( fp, facet ) - prints ridges of a facet to fp - - notes: - ridges printed in neighbor order - assumes the ridges exist - for 'f' output - same as QhullFacet::printRidges -*/ -void qh_printfacetridges(FILE *fp, facetT *facet) { - facetT *neighbor, **neighborp; - ridgeT *ridge, **ridgep; - int numridges= 0; - - - if (facet->visible && qh NEWfacets) { - qh_fprintf(fp, 9179, " - ridges(ids may be garbage):"); - FOREACHridge_(facet->ridges) - qh_fprintf(fp, 9180, " r%d", ridge->id); - qh_fprintf(fp, 9181, "\n"); - }else { - qh_fprintf(fp, 9182, " - ridges:\n"); - FOREACHridge_(facet->ridges) - ridge->seen= False; - if (qh hull_dim == 3) { - ridge= SETfirstt_(facet->ridges, ridgeT); - while (ridge && !ridge->seen) { - ridge->seen= True; - qh_printridge(fp, ridge); - numridges++; - ridge= qh_nextridge3d(ridge, facet, NULL); - } - }else { - FOREACHneighbor_(facet) { - FOREACHridge_(facet->ridges) { - if (otherfacet_(ridge,facet) == neighbor) { - ridge->seen= True; - qh_printridge(fp, ridge); - numridges++; - } - } - } - } - if (numridges != qh_setsize(facet->ridges)) { - qh_fprintf(fp, 9183, " - all ridges:"); - FOREACHridge_(facet->ridges) - qh_fprintf(fp, 9184, " r%d", ridge->id); - qh_fprintf(fp, 9185, "\n"); - } - FOREACHridge_(facet->ridges) { - if (!ridge->seen) - qh_printridge(fp, ridge); - } - } -} /* printfacetridges */ - -/*-<a href="qh-io.htm#TOC" - >-------------------------------</a><a name="printfacets">-</a> - - qh_printfacets( fp, format, facetlist, facets, printall ) - prints facetlist and/or facet set in output format - - notes: - also used for specialized formats ('FO' and summary) - turns off 'Rn' option since want actual numbers -*/ -void qh_printfacets(FILE *fp, qh_PRINT format, facetT *facetlist, setT *facets, boolT printall) { - int numfacets, numsimplicial, numridges, totneighbors, numcoplanars, numtricoplanars; - facetT *facet, **facetp; - setT *vertices; - coordT *center; - realT outerplane, innerplane; - - qh old_randomdist= qh RANDOMdist; - qh RANDOMdist= False; - if (qh CDDoutput && (format == qh_PRINTcentrums || format == qh_PRINTpointintersect || format == qh_PRINToff)) - qh_fprintf(qh ferr, 7056, "qhull warning: CDD format is not available for centrums, halfspace\nintersections, and OFF file format.\n"); - if (format == qh_PRINTnone) - ; /* print nothing */ - else if (format == qh_PRINTaverage) { - vertices= qh_facetvertices(facetlist, facets, printall); - center= qh_getcenter(vertices); - qh_fprintf(fp, 9186, "%d 1\n", qh hull_dim); - qh_printpointid(fp, NULL, qh hull_dim, center, -1); - qh_memfree(center, qh normal_size); - qh_settempfree(&vertices); - }else if (format == qh_PRINTextremes) { - if (qh DELAUNAY) - qh_printextremes_d(fp, facetlist, facets, printall); - else if (qh hull_dim == 2) - qh_printextremes_2d(fp, facetlist, facets, printall); - else - qh_printextremes(fp, facetlist, facets, printall); - }else if (format == qh_PRINToptions) - qh_fprintf(fp, 9187, "Options selected for Qhull %s:\n%s\n", qh_version, qh qhull_options); - else if (format == qh_PRINTpoints && !qh VORONOI) - qh_printpoints_out(fp, facetlist, facets, printall); - else if (format == qh_PRINTqhull) - qh_fprintf(fp, 9188, "%s | %s\n", qh rbox_command, qh qhull_command); - else if (format == qh_PRINTsize) { - qh_fprintf(fp, 9189, "0\n2 "); - qh_fprintf(fp, 9190, qh_REAL_1, qh totarea); - qh_fprintf(fp, 9191, qh_REAL_1, qh totvol); - qh_fprintf(fp, 9192, "\n"); - }else if (format == qh_PRINTsummary) { - qh_countfacets(facetlist, facets, printall, &numfacets, &numsimplicial, - &totneighbors, &numridges, &numcoplanars, &numtricoplanars); - vertices= qh_facetvertices(facetlist, facets, printall); - qh_fprintf(fp, 9193, "10 %d %d %d %d %d %d %d %d %d %d\n2 ", qh hull_dim, - qh num_points + qh_setsize(qh other_points), - qh num_vertices, qh num_facets - qh num_visible, - qh_setsize(vertices), numfacets, numcoplanars, - numfacets - numsimplicial, zzval_(Zdelvertextot), - numtricoplanars); - qh_settempfree(&vertices); - qh_outerinner(NULL, &outerplane, &innerplane); - qh_fprintf(fp, 9194, qh_REAL_2n, outerplane, innerplane); - }else if (format == qh_PRINTvneighbors) - qh_printvneighbors(fp, facetlist, facets, printall); - else if (qh VORONOI && format == qh_PRINToff) - qh_printvoronoi(fp, format, facetlist, facets, printall); - else if (qh VORONOI && format == qh_PRINTgeom) { - qh_printbegin(fp, format, facetlist, facets, printall); - qh_printvoronoi(fp, format, facetlist, facets, printall); - qh_printend(fp, format, facetlist, facets, printall); - }else if (qh VORONOI - && (format == qh_PRINTvertices || format == qh_PRINTinner || format == qh_PRINTouter)) - qh_printvdiagram(fp, format, facetlist, facets, printall); - else { - qh_printbegin(fp, format, facetlist, facets, printall); - FORALLfacet_(facetlist) - qh_printafacet(fp, format, facet, printall); - FOREACHfacet_(facets) - qh_printafacet(fp, format, facet, printall); - qh_printend(fp, format, facetlist, facets, printall); - } - qh RANDOMdist= qh old_randomdist; -} /* printfacets */ - - -/*-<a href="qh-io.htm#TOC" - >-------------------------------</a><a name="printhyperplaneintersection">-</a> - - qh_printhyperplaneintersection( fp, facet1, facet2, vertices, color ) - print Geomview OFF or 4OFF for the intersection of two hyperplanes in 3-d or 4-d -*/ -void qh_printhyperplaneintersection(FILE *fp, facetT *facet1, facetT *facet2, - setT *vertices, realT color[3]) { - realT costheta, denominator, dist1, dist2, s, t, mindenom, p[4]; - vertexT *vertex, **vertexp; - int i, k; - boolT nearzero1, nearzero2; - - costheta= qh_getangle(facet1->normal, facet2->normal); - denominator= 1 - costheta * costheta; - i= qh_setsize(vertices); - if (qh hull_dim == 3) - qh_fprintf(fp, 9195, "VECT 1 %d 1 %d 1 ", i, i); - else if (qh hull_dim == 4 && qh DROPdim >= 0) - qh_fprintf(fp, 9196, "OFF 3 1 1 "); - else - qh printoutvar++; - qh_fprintf(fp, 9197, "# intersect f%d f%d\n", facet1->id, facet2->id); - mindenom= 1 / (10.0 * qh MAXabs_coord); - FOREACHvertex_(vertices) { - zadd_(Zdistio, 2); - qh_distplane(vertex->point, facet1, &dist1); - qh_distplane(vertex->point, facet2, &dist2); - s= qh_divzero(-dist1 + costheta * dist2, denominator,mindenom,&nearzero1); - t= qh_divzero(-dist2 + costheta * dist1, denominator,mindenom,&nearzero2); - if (nearzero1 || nearzero2) - s= t= 0.0; - for (k=qh hull_dim; k--; ) - p[k]= vertex->point[k] + facet1->normal[k] * s + facet2->normal[k] * t; - if (qh PRINTdim <= 3) { - qh_projectdim3 (p, p); - qh_fprintf(fp, 9198, "%8.4g %8.4g %8.4g # ", p[0], p[1], p[2]); - }else - qh_fprintf(fp, 9199, "%8.4g %8.4g %8.4g %8.4g # ", p[0], p[1], p[2], p[3]); - if (nearzero1+nearzero2) - qh_fprintf(fp, 9200, "p%d(coplanar facets)\n", qh_pointid(vertex->point)); - else - qh_fprintf(fp, 9201, "projected p%d\n", qh_pointid(vertex->point)); - } - if (qh hull_dim == 3) - qh_fprintf(fp, 9202, "%8.4g %8.4g %8.4g 1.0\n", color[0], color[1], color[2]); - else if (qh hull_dim == 4 && qh DROPdim >= 0) - qh_fprintf(fp, 9203, "3 0 1 2 %8.4g %8.4g %8.4g 1.0\n", color[0], color[1], color[2]); -} /* printhyperplaneintersection */ - -/*-<a href="qh-io.htm#TOC" - >-------------------------------</a><a name="printline3geom">-</a> - - qh_printline3geom( fp, pointA, pointB, color ) - prints a line as a VECT - prints 0's for qh.DROPdim - - notes: - if pointA == pointB, - it's a 1 point VECT -*/ -void qh_printline3geom(FILE *fp, pointT *pointA, pointT *pointB, realT color[3]) { - int k; - realT pA[4], pB[4]; - - qh_projectdim3(pointA, pA); - qh_projectdim3(pointB, pB); - if ((fabs(pA[0] - pB[0]) > 1e-3) || - (fabs(pA[1] - pB[1]) > 1e-3) || - (fabs(pA[2] - pB[2]) > 1e-3)) { - qh_fprintf(fp, 9204, "VECT 1 2 1 2 1\n"); - for (k=0; k < 3; k++) - qh_fprintf(fp, 9205, "%8.4g ", pB[k]); - qh_fprintf(fp, 9206, " # p%d\n", qh_pointid(pointB)); - }else - qh_fprintf(fp, 9207, "VECT 1 1 1 1 1\n"); - for (k=0; k < 3; k++) - qh_fprintf(fp, 9208, "%8.4g ", pA[k]); - qh_fprintf(fp, 9209, " # p%d\n", qh_pointid(pointA)); - qh_fprintf(fp, 9210, "%8.4g %8.4g %8.4g 1\n", color[0], color[1], color[2]); -} - -/*-<a href="qh-io.htm#TOC" - >-------------------------------</a><a name="printneighborhood">-</a> - - qh_printneighborhood( fp, format, facetA, facetB, printall ) - print neighborhood of one or two facets - - notes: - calls qh_findgood_all() - bumps qh.visit_id -*/ -void qh_printneighborhood(FILE *fp, qh_PRINT format, facetT *facetA, facetT *facetB, boolT printall) { - facetT *neighbor, **neighborp, *facet; - setT *facets; - - if (format == qh_PRINTnone) - return; - qh_findgood_all(qh facet_list); - if (facetA == facetB) - facetB= NULL; - facets= qh_settemp(2*(qh_setsize(facetA->neighbors)+1)); - qh visit_id++; - for (facet= facetA; facet; facet= ((facet == facetA) ? facetB : NULL)) { - if (facet->visitid != qh visit_id) { - facet->visitid= qh visit_id; - qh_setappend(&facets, facet); - } - FOREACHneighbor_(facet) { - if (neighbor->visitid == qh visit_id) - continue; - neighbor->visitid= qh visit_id; - if (printall || !qh_skipfacet(neighbor)) - qh_setappend(&facets, neighbor); - } - } - qh_printfacets(fp, format, NULL, facets, printall); - qh_settempfree(&facets); -} /* printneighborhood */ - -/*-<a href="qh-io.htm#TOC" - >-------------------------------</a><a name="printpoint">-</a> - - qh_printpoint( fp, string, point ) - qh_printpointid( fp, string, dim, point, id ) - prints the coordinates of a point - - returns: - if string is defined - prints 'string p%d' (skips p%d if id=-1) - - notes: - nop if point is NULL - prints id unless it is undefined (-1) - Same as QhullPoint's printPoint -*/ -void qh_printpoint(FILE *fp, const char *string, pointT *point) { - int id= qh_pointid( point); - - qh_printpointid( fp, string, qh hull_dim, point, id); -} /* printpoint */ - -void qh_printpointid(FILE *fp, const char *string, int dim, pointT *point, int id) { - int k; - realT r; /*bug fix*/ - - if (!point) - return; - if (string) { - qh_fprintf(fp, 9211, "%s", string); - if (id != -1) - qh_fprintf(fp, 9212, " p%d: ", id); - } - for (k=dim; k--; ) { - r= *point++; - if (string) - qh_fprintf(fp, 9213, " %8.4g", r); - else - qh_fprintf(fp, 9214, qh_REAL_1, r); - } - qh_fprintf(fp, 9215, "\n"); -} /* printpointid */ - -/*-<a href="qh-io.htm#TOC" - >-------------------------------</a><a name="printpoint3">-</a> - - qh_printpoint3( fp, point ) - prints 2-d, 3-d, or 4-d point as Geomview 3-d coordinates -*/ -void qh_printpoint3 (FILE *fp, pointT *point) { - int k; - realT p[4]; - - qh_projectdim3 (point, p); - for (k=0; k < 3; k++) - qh_fprintf(fp, 9216, "%8.4g ", p[k]); - qh_fprintf(fp, 9217, " # p%d\n", qh_pointid(point)); -} /* printpoint3 */ - -/*---------------------------------------- --printpoints- print pointids for a set of points starting at index - see geom.c -*/ - -/*-<a href="qh-io.htm#TOC" - >-------------------------------</a><a name="printpoints_out">-</a> - - qh_printpoints_out( fp, facetlist, facets, printall ) - prints vertices, coplanar/inside points, for facets by their point coordinates - allows qh.CDDoutput - - notes: - same format as qhull input - if no coplanar/interior points, - same order as qh_printextremes -*/ -void qh_printpoints_out(FILE *fp, facetT *facetlist, setT *facets, boolT printall) { - int allpoints= qh num_points + qh_setsize(qh other_points); - int numpoints=0, point_i, point_n; - setT *vertices, *points; - facetT *facet, **facetp; - pointT *point, **pointp; - vertexT *vertex, **vertexp; - int id; - - points= qh_settemp(allpoints); - qh_setzero(points, 0, allpoints); - vertices= qh_facetvertices(facetlist, facets, printall); - FOREACHvertex_(vertices) { - id= qh_pointid(vertex->point); - if (id >= 0) - SETelem_(points, id)= vertex->point; - } - if (qh KEEPinside || qh KEEPcoplanar || qh KEEPnearinside) { - FORALLfacet_(facetlist) { - if (!printall && qh_skipfacet(facet)) - continue; - FOREACHpoint_(facet->coplanarset) { - id= qh_pointid(point); - if (id >= 0) - SETelem_(points, id)= point; - } - } - FOREACHfacet_(facets) { - if (!printall && qh_skipfacet(facet)) - continue; - FOREACHpoint_(facet->coplanarset) { - id= qh_pointid(point); - if (id >= 0) - SETelem_(points, id)= point; - } - } - } - qh_settempfree(&vertices); - FOREACHpoint_i_(points) { - if (point) - numpoints++; - } - if (qh CDDoutput) - qh_fprintf(fp, 9218, "%s | %s\nbegin\n%d %d real\n", qh rbox_command, - qh qhull_command, numpoints, qh hull_dim + 1); - else - qh_fprintf(fp, 9219, "%d\n%d\n", qh hull_dim, numpoints); - FOREACHpoint_i_(points) { - if (point) { - if (qh CDDoutput) - qh_fprintf(fp, 9220, "1 "); - qh_printpoint(fp, NULL, point); - } - } - if (qh CDDoutput) - qh_fprintf(fp, 9221, "end\n"); - qh_settempfree(&points); -} /* printpoints_out */ - - -/*-<a href="qh-io.htm#TOC" - >-------------------------------</a><a name="printpointvect">-</a> - - qh_printpointvect( fp, point, normal, center, radius, color ) - prints a 2-d, 3-d, or 4-d point as 3-d VECT's relative to normal or to center point -*/ -void qh_printpointvect(FILE *fp, pointT *point, coordT *normal, pointT *center, realT radius, realT color[3]) { - realT diff[4], pointA[4]; - int k; - - for (k=qh hull_dim; k--; ) { - if (center) - diff[k]= point[k]-center[k]; - else if (normal) - diff[k]= normal[k]; - else - diff[k]= 0; - } - if (center) - qh_normalize2 (diff, qh hull_dim, True, NULL, NULL); - for (k=qh hull_dim; k--; ) - pointA[k]= point[k]+diff[k] * radius; - qh_printline3geom(fp, point, pointA, color); -} /* printpointvect */ - -/*-<a href="qh-io.htm#TOC" - >-------------------------------</a><a name="printpointvect2">-</a> - - qh_printpointvect2( fp, point, normal, center, radius ) - prints a 2-d, 3-d, or 4-d point as 2 3-d VECT's for an imprecise point -*/ -void qh_printpointvect2 (FILE *fp, pointT *point, coordT *normal, pointT *center, realT radius) { - realT red[3]={1, 0, 0}, yellow[3]={1, 1, 0}; - - qh_printpointvect(fp, point, normal, center, radius, red); - qh_printpointvect(fp, point, normal, center, -radius, yellow); -} /* printpointvect2 */ - -/*-<a href="qh-io.htm#TOC" - >-------------------------------</a><a name="printridge">-</a> - - qh_printridge( fp, ridge ) - prints the information in a ridge - - notes: - for qh_printfacetridges() - same as operator<< [QhullRidge.cpp] -*/ -void qh_printridge(FILE *fp, ridgeT *ridge) { - - qh_fprintf(fp, 9222, " - r%d", ridge->id); - if (ridge->tested) - qh_fprintf(fp, 9223, " tested"); - if (ridge->nonconvex) - qh_fprintf(fp, 9224, " nonconvex"); - qh_fprintf(fp, 9225, "\n"); - qh_printvertices(fp, " vertices:", ridge->vertices); - if (ridge->top && ridge->bottom) - qh_fprintf(fp, 9226, " between f%d and f%d\n", - ridge->top->id, ridge->bottom->id); -} /* printridge */ - -/*-<a href="qh-io.htm#TOC" - >-------------------------------</a><a name="printspheres">-</a> - - qh_printspheres( fp, vertices, radius ) - prints 3-d vertices as OFF spheres - - notes: - inflated octahedron from Stuart Levy earth/mksphere2 -*/ -void qh_printspheres(FILE *fp, setT *vertices, realT radius) { - vertexT *vertex, **vertexp; - - qh printoutnum++; - qh_fprintf(fp, 9227, "{appearance {-edge -normal normscale 0} {\n\ -INST geom {define vsphere OFF\n\ -18 32 48\n\ -\n\ -0 0 1\n\ -1 0 0\n\ -0 1 0\n\ --1 0 0\n\ -0 -1 0\n\ -0 0 -1\n\ -0.707107 0 0.707107\n\ -0 -0.707107 0.707107\n\ -0.707107 -0.707107 0\n\ --0.707107 0 0.707107\n\ --0.707107 -0.707107 0\n\ -0 0.707107 0.707107\n\ --0.707107 0.707107 0\n\ -0.707107 0.707107 0\n\ -0.707107 0 -0.707107\n\ -0 0.707107 -0.707107\n\ --0.707107 0 -0.707107\n\ -0 -0.707107 -0.707107\n\ -\n\ -3 0 6 11\n\ -3 0 7 6 \n\ -3 0 9 7 \n\ -3 0 11 9\n\ -3 1 6 8 \n\ -3 1 8 14\n\ -3 1 13 6\n\ -3 1 14 13\n\ -3 2 11 13\n\ -3 2 12 11\n\ -3 2 13 15\n\ -3 2 15 12\n\ -3 3 9 12\n\ -3 3 10 9\n\ -3 3 12 16\n\ -3 3 16 10\n\ -3 4 7 10\n\ -3 4 8 7\n\ -3 4 10 17\n\ -3 4 17 8\n\ -3 5 14 17\n\ -3 5 15 14\n\ -3 5 16 15\n\ -3 5 17 16\n\ -3 6 13 11\n\ -3 7 8 6\n\ -3 9 10 7\n\ -3 11 12 9\n\ -3 14 8 17\n\ -3 15 13 14\n\ -3 16 12 15\n\ -3 17 10 16\n} transforms { TLIST\n"); - FOREACHvertex_(vertices) { - qh_fprintf(fp, 9228, "%8.4g 0 0 0 # v%d\n 0 %8.4g 0 0\n0 0 %8.4g 0\n", - radius, vertex->id, radius, radius); - qh_printpoint3 (fp, vertex->point); - qh_fprintf(fp, 9229, "1\n"); - } - qh_fprintf(fp, 9230, "}}}\n"); -} /* printspheres */ - - -/*---------------------------------------------- --printsummary- - see libqhull.c -*/ - -/*-<a href="qh-io.htm#TOC" - >-------------------------------</a><a name="printvdiagram">-</a> - - qh_printvdiagram( fp, format, facetlist, facets, printall ) - print voronoi diagram - # of pairs of input sites - #indices site1 site2 vertex1 ... - - sites indexed by input point id - point 0 is the first input point - vertices indexed by 'o' and 'p' order - vertex 0 is the 'vertex-at-infinity' - vertex 1 is the first Voronoi vertex - - see: - qh_printvoronoi() - qh_eachvoronoi_all() - - notes: - if all facets are upperdelaunay, - prints upper hull (furthest-site Voronoi diagram) -*/ -void qh_printvdiagram(FILE *fp, qh_PRINT format, facetT *facetlist, setT *facets, boolT printall) { - setT *vertices; - int totcount, numcenters; - boolT isLower; - qh_RIDGE innerouter= qh_RIDGEall; - printvridgeT printvridge= NULL; - - if (format == qh_PRINTvertices) { - innerouter= qh_RIDGEall; - printvridge= qh_printvridge; - }else if (format == qh_PRINTinner) { - innerouter= qh_RIDGEinner; - printvridge= qh_printvnorm; - }else if (format == qh_PRINTouter) { - innerouter= qh_RIDGEouter; - printvridge= qh_printvnorm; - }else { - qh_fprintf(qh ferr, 6219, "Qhull internal error (qh_printvdiagram): unknown print format %d.\n", format); - qh_errexit(qh_ERRinput, NULL, NULL); - } - vertices= qh_markvoronoi(facetlist, facets, printall, &isLower, &numcenters); - totcount= qh_printvdiagram2 (NULL, NULL, vertices, innerouter, False); - qh_fprintf(fp, 9231, "%d\n", totcount); - totcount= qh_printvdiagram2 (fp, printvridge, vertices, innerouter, True /* inorder*/); - qh_settempfree(&vertices); -#if 0 /* for testing qh_eachvoronoi_all */ - qh_fprintf(fp, 9232, "\n"); - totcount= qh_eachvoronoi_all(fp, printvridge, qh UPPERdelaunay, innerouter, True /* inorder*/); - qh_fprintf(fp, 9233, "%d\n", totcount); -#endif -} /* printvdiagram */ - -/*-<a href="qh-io.htm#TOC" - >-------------------------------</a><a name="printvdiagram2">-</a> - - qh_printvdiagram2( fp, printvridge, vertices, innerouter, inorder ) - visit all pairs of input sites (vertices) for selected Voronoi vertices - vertices may include NULLs - - innerouter: - qh_RIDGEall print inner ridges(bounded) and outer ridges(unbounded) - qh_RIDGEinner print only inner ridges - qh_RIDGEouter print only outer ridges - - inorder: - print 3-d Voronoi vertices in order - - assumes: - qh_markvoronoi marked facet->visitid for Voronoi vertices - all facet->seen= False - all facet->seen2= True - - returns: - total number of Voronoi ridges - if printvridge, - calls printvridge( fp, vertex, vertexA, centers) for each ridge - [see qh_eachvoronoi()] - - see: - qh_eachvoronoi_all() -*/ -int qh_printvdiagram2 (FILE *fp, printvridgeT printvridge, setT *vertices, qh_RIDGE innerouter, boolT inorder) { - int totcount= 0; - int vertex_i, vertex_n; - vertexT *vertex; - - FORALLvertices - vertex->seen= False; - FOREACHvertex_i_(vertices) { - if (vertex) { - if (qh GOODvertex > 0 && qh_pointid(vertex->point)+1 != qh GOODvertex) - continue; - totcount += qh_eachvoronoi(fp, printvridge, vertex, !qh_ALL, innerouter, inorder); - } - } - return totcount; -} /* printvdiagram2 */ - -/*-<a href="qh-io.htm#TOC" - >-------------------------------</a><a name="printvertex">-</a> - - qh_printvertex( fp, vertex ) - prints the information in a vertex - Duplicated as operator<< [QhullVertex.cpp] -*/ -void qh_printvertex(FILE *fp, vertexT *vertex) { - pointT *point; - int k, count= 0; - facetT *neighbor, **neighborp; - realT r; /*bug fix*/ - - if (!vertex) { - qh_fprintf(fp, 9234, " NULLvertex\n"); - return; - } - qh_fprintf(fp, 9235, "- p%d(v%d):", qh_pointid(vertex->point), vertex->id); - point= vertex->point; - if (point) { - for (k=qh hull_dim; k--; ) { - r= *point++; - qh_fprintf(fp, 9236, " %5.2g", r); - } - } - if (vertex->deleted) - qh_fprintf(fp, 9237, " deleted"); - if (vertex->delridge) - qh_fprintf(fp, 9238, " ridgedeleted"); - qh_fprintf(fp, 9239, "\n"); - if (vertex->neighbors) { - qh_fprintf(fp, 9240, " neighbors:"); - FOREACHneighbor_(vertex) { - if (++count % 100 == 0) - qh_fprintf(fp, 9241, "\n "); - qh_fprintf(fp, 9242, " f%d", neighbor->id); - } - qh_fprintf(fp, 9243, "\n"); - } -} /* printvertex */ - - -/*-<a href="qh-io.htm#TOC" - >-------------------------------</a><a name="printvertexlist">-</a> - - qh_printvertexlist( fp, string, facetlist, facets, printall ) - prints vertices used by a facetlist or facet set - tests qh_skipfacet() if !printall -*/ -void qh_printvertexlist(FILE *fp, const char* string, facetT *facetlist, - setT *facets, boolT printall) { - vertexT *vertex, **vertexp; - setT *vertices; - - vertices= qh_facetvertices(facetlist, facets, printall); - qh_fprintf(fp, 9244, "%s", string); - FOREACHvertex_(vertices) - qh_printvertex(fp, vertex); - qh_settempfree(&vertices); -} /* printvertexlist */ - - -/*-<a href="qh-io.htm#TOC" - >-------------------------------</a><a name="printvertices">-</a> - - qh_printvertices( fp, string, vertices ) - prints vertices in a set - duplicated as printVertexSet [QhullVertex.cpp] -*/ -void qh_printvertices(FILE *fp, const char* string, setT *vertices) { - vertexT *vertex, **vertexp; - - qh_fprintf(fp, 9245, "%s", string); - FOREACHvertex_(vertices) - qh_fprintf(fp, 9246, " p%d(v%d)", qh_pointid(vertex->point), vertex->id); - qh_fprintf(fp, 9247, "\n"); -} /* printvertices */ - -/*-<a href="qh-io.htm#TOC" - >-------------------------------</a><a name="printvneighbors">-</a> - - qh_printvneighbors( fp, facetlist, facets, printall ) - print vertex neighbors of vertices in facetlist and facets ('FN') - - notes: - qh_countfacets clears facet->visitid for non-printed facets - - design: - collect facet count and related statistics - if necessary, build neighbor sets for each vertex - collect vertices in facetlist and facets - build a point array for point->vertex and point->coplanar facet - for each point - list vertex neighbors or coplanar facet -*/ -void qh_printvneighbors(FILE *fp, facetT* facetlist, setT *facets, boolT printall) { - int numfacets, numsimplicial, numridges, totneighbors, numneighbors, numcoplanars, numtricoplanars; - setT *vertices, *vertex_points, *coplanar_points; - int numpoints= qh num_points + qh_setsize(qh other_points); - vertexT *vertex, **vertexp; - int vertex_i, vertex_n; - facetT *facet, **facetp, *neighbor, **neighborp; - pointT *point, **pointp; - - qh_countfacets(facetlist, facets, printall, &numfacets, &numsimplicial, - &totneighbors, &numridges, &numcoplanars, &numtricoplanars); /* sets facet->visitid */ - qh_fprintf(fp, 9248, "%d\n", numpoints); - qh_vertexneighbors(); - vertices= qh_facetvertices(facetlist, facets, printall); - vertex_points= qh_settemp(numpoints); - coplanar_points= qh_settemp(numpoints); - qh_setzero(vertex_points, 0, numpoints); - qh_setzero(coplanar_points, 0, numpoints); - FOREACHvertex_(vertices) - qh_point_add(vertex_points, vertex->point, vertex); - FORALLfacet_(facetlist) { - FOREACHpoint_(facet->coplanarset) - qh_point_add(coplanar_points, point, facet); - } - FOREACHfacet_(facets) { - FOREACHpoint_(facet->coplanarset) - qh_point_add(coplanar_points, point, facet); - } - FOREACHvertex_i_(vertex_points) { - if (vertex) { - numneighbors= qh_setsize(vertex->neighbors); - qh_fprintf(fp, 9249, "%d", numneighbors); - if (qh hull_dim == 3) - qh_order_vertexneighbors(vertex); - else if (qh hull_dim >= 4) - qsort(SETaddr_(vertex->neighbors, facetT), (size_t)numneighbors, - sizeof(facetT *), qh_compare_facetvisit); - FOREACHneighbor_(vertex) - qh_fprintf(fp, 9250, " %d", - neighbor->visitid ? neighbor->visitid - 1 : 0 - neighbor->id); - qh_fprintf(fp, 9251, "\n"); - }else if ((facet= SETelemt_(coplanar_points, vertex_i, facetT))) - qh_fprintf(fp, 9252, "1 %d\n", - facet->visitid ? facet->visitid - 1 : 0 - facet->id); - else - qh_fprintf(fp, 9253, "0\n"); - } - qh_settempfree(&coplanar_points); - qh_settempfree(&vertex_points); - qh_settempfree(&vertices); -} /* printvneighbors */ - -/*-<a href="qh-io.htm#TOC" - >-------------------------------</a><a name="printvoronoi">-</a> - - qh_printvoronoi( fp, format, facetlist, facets, printall ) - print voronoi diagram in 'o' or 'G' format - for 'o' format - prints voronoi centers for each facet and for infinity - for each vertex, lists ids of printed facets or infinity - assumes facetlist and facets are disjoint - for 'G' format - prints an OFF object - adds a 0 coordinate to center - prints infinity but does not list in vertices - - see: - qh_printvdiagram() - - notes: - if 'o', - prints a line for each point except "at-infinity" - if all facets are upperdelaunay, - reverses lower and upper hull -*/ -void qh_printvoronoi(FILE *fp, qh_PRINT format, facetT *facetlist, setT *facets, boolT printall) { - int k, numcenters, numvertices= 0, numneighbors, numinf, vid=1, vertex_i, vertex_n; - facetT *facet, **facetp, *neighbor, **neighborp; - setT *vertices; - vertexT *vertex; - boolT isLower; - unsigned int numfacets= (unsigned int) qh num_facets; - - vertices= qh_markvoronoi(facetlist, facets, printall, &isLower, &numcenters); - FOREACHvertex_i_(vertices) { - if (vertex) { - numvertices++; - numneighbors = numinf = 0; - FOREACHneighbor_(vertex) { - if (neighbor->visitid == 0) - numinf= 1; - else if (neighbor->visitid < numfacets) - numneighbors++; - } - if (numinf && !numneighbors) { - SETelem_(vertices, vertex_i)= NULL; - numvertices--; - } - } - } - if (format == qh_PRINTgeom) - qh_fprintf(fp, 9254, "{appearance {+edge -face} OFF %d %d 1 # Voronoi centers and cells\n", - numcenters, numvertices); - else - qh_fprintf(fp, 9255, "%d\n%d %d 1\n", qh hull_dim-1, numcenters, qh_setsize(vertices)); - if (format == qh_PRINTgeom) { - for (k=qh hull_dim-1; k--; ) - qh_fprintf(fp, 9256, qh_REAL_1, 0.0); - qh_fprintf(fp, 9257, " 0 # infinity not used\n"); - }else { - for (k=qh hull_dim-1; k--; ) - qh_fprintf(fp, 9258, qh_REAL_1, qh_INFINITE); - qh_fprintf(fp, 9259, "\n"); - } - FORALLfacet_(facetlist) { - if (facet->visitid && facet->visitid < numfacets) { - if (format == qh_PRINTgeom) - qh_fprintf(fp, 9260, "# %d f%d\n", vid++, facet->id); - qh_printcenter(fp, format, NULL, facet); - } - } - FOREACHfacet_(facets) { - if (facet->visitid && facet->visitid < numfacets) { - if (format == qh_PRINTgeom) - qh_fprintf(fp, 9261, "# %d f%d\n", vid++, facet->id); - qh_printcenter(fp, format, NULL, facet); - } - } - FOREACHvertex_i_(vertices) { - numneighbors= 0; - numinf=0; - if (vertex) { - if (qh hull_dim == 3) - qh_order_vertexneighbors(vertex); - else if (qh hull_dim >= 4) - qsort(SETaddr_(vertex->neighbors, facetT), - (size_t)qh_setsize(vertex->neighbors), - sizeof(facetT *), qh_compare_facetvisit); - FOREACHneighbor_(vertex) { - if (neighbor->visitid == 0) - numinf= 1; - else if (neighbor->visitid < numfacets) - numneighbors++; - } - } - if (format == qh_PRINTgeom) { - if (vertex) { - qh_fprintf(fp, 9262, "%d", numneighbors); - FOREACHneighbor_(vertex) { - if (neighbor->visitid && neighbor->visitid < numfacets) - qh_fprintf(fp, 9263, " %d", neighbor->visitid); - } - qh_fprintf(fp, 9264, " # p%d(v%d)\n", vertex_i, vertex->id); - }else - qh_fprintf(fp, 9265, " # p%d is coplanar or isolated\n", vertex_i); - }else { - if (numinf) - numneighbors++; - qh_fprintf(fp, 9266, "%d", numneighbors); - if (vertex) { - FOREACHneighbor_(vertex) { - if (neighbor->visitid == 0) { - if (numinf) { - numinf= 0; - qh_fprintf(fp, 9267, " %d", neighbor->visitid); - } - }else if (neighbor->visitid < numfacets) - qh_fprintf(fp, 9268, " %d", neighbor->visitid); - } - } - qh_fprintf(fp, 9269, "\n"); - } - } - if (format == qh_PRINTgeom) - qh_fprintf(fp, 9270, "}\n"); - qh_settempfree(&vertices); -} /* printvoronoi */ - -/*-<a href="qh-io.htm#TOC" - >-------------------------------</a><a name="printvnorm">-</a> - - qh_printvnorm( fp, vertex, vertexA, centers, unbounded ) - print one separating plane of the Voronoi diagram for a pair of input sites - unbounded==True if centers includes vertex-at-infinity - - assumes: - qh_ASvoronoi and qh_vertexneighbors() already set - - note: - parameter unbounded is UNUSED by this callback - - see: - qh_printvdiagram() - qh_eachvoronoi() -*/ -void qh_printvnorm(FILE *fp, vertexT *vertex, vertexT *vertexA, setT *centers, boolT unbounded) { - pointT *normal; - realT offset; - int k; - QHULL_UNUSED(unbounded); - - normal= qh_detvnorm(vertex, vertexA, centers, &offset); - qh_fprintf(fp, 9271, "%d %d %d ", - 2+qh hull_dim, qh_pointid(vertex->point), qh_pointid(vertexA->point)); - for (k=0; k< qh hull_dim-1; k++) - qh_fprintf(fp, 9272, qh_REAL_1, normal[k]); - qh_fprintf(fp, 9273, qh_REAL_1, offset); - qh_fprintf(fp, 9274, "\n"); -} /* printvnorm */ - -/*-<a href="qh-io.htm#TOC" - >-------------------------------</a><a name="printvridge">-</a> - - qh_printvridge( fp, vertex, vertexA, centers, unbounded ) - print one ridge of the Voronoi diagram for a pair of input sites - unbounded==True if centers includes vertex-at-infinity - - see: - qh_printvdiagram() - - notes: - the user may use a different function - parameter unbounded is UNUSED -*/ -void qh_printvridge(FILE *fp, vertexT *vertex, vertexT *vertexA, setT *centers, boolT unbounded) { - facetT *facet, **facetp; - QHULL_UNUSED(unbounded); - - qh_fprintf(fp, 9275, "%d %d %d", qh_setsize(centers)+2, - qh_pointid(vertex->point), qh_pointid(vertexA->point)); - FOREACHfacet_(centers) - qh_fprintf(fp, 9276, " %d", facet->visitid); - qh_fprintf(fp, 9277, "\n"); -} /* printvridge */ - -/*-<a href="qh-io.htm#TOC" - >-------------------------------</a><a name="projectdim3">-</a> - - qh_projectdim3( source, destination ) - project 2-d 3-d or 4-d point to a 3-d point - uses qh.DROPdim and qh.hull_dim - source and destination may be the same - - notes: - allocate 4 elements to destination just in case -*/ -void qh_projectdim3 (pointT *source, pointT *destination) { - int i,k; - - for (k=0, i=0; k < qh hull_dim; k++) { - if (qh hull_dim == 4) { - if (k != qh DROPdim) - destination[i++]= source[k]; - }else if (k == qh DROPdim) - destination[i++]= 0; - else - destination[i++]= source[k]; - } - while (i < 3) - destination[i++]= 0.0; -} /* projectdim3 */ - -/*-<a href="qh-io.htm#TOC" - >-------------------------------</a><a name="readfeasible">-</a> - - qh_readfeasible( dim, curline ) - read feasible point from current line and qh.fin - - returns: - number of lines read from qh.fin - sets qh.FEASIBLEpoint with malloc'd coordinates - - notes: - checks for qh.HALFspace - assumes dim > 1 - - see: - qh_setfeasible -*/ -int qh_readfeasible(int dim, const char *curline) { - boolT isfirst= True; - int linecount= 0, tokcount= 0; - const char *s; - char *t, firstline[qh_MAXfirst+1]; - coordT *coords, value; - - if (!qh HALFspace) { - qh_fprintf(qh ferr, 6070, "qhull input error: feasible point(dim 1 coords) is only valid for halfspace intersection\n"); - qh_errexit(qh_ERRinput, NULL, NULL); - } - if (qh feasible_string) - qh_fprintf(qh ferr, 7057, "qhull input warning: feasible point(dim 1 coords) overrides 'Hn,n,n' feasible point for halfspace intersection\n"); - if (!(qh feasible_point= (coordT*)qh_malloc(dim* sizeof(coordT)))) { - qh_fprintf(qh ferr, 6071, "qhull error: insufficient memory for feasible point\n"); - qh_errexit(qh_ERRmem, NULL, NULL); - } - coords= qh feasible_point; - while ((s= (isfirst ? curline : fgets(firstline, qh_MAXfirst, qh fin)))) { - if (isfirst) - isfirst= False; - else - linecount++; - while (*s) { - while (isspace(*s)) - s++; - value= qh_strtod(s, &t); - if (s == t) - break; - s= t; - *(coords++)= value; - if (++tokcount == dim) { - while (isspace(*s)) - s++; - qh_strtod(s, &t); - if (s != t) { - qh_fprintf(qh ferr, 6072, "qhull input error: coordinates for feasible point do not finish out the line: %s\n", - s); - qh_errexit(qh_ERRinput, NULL, NULL); - } - return linecount; - } - } - } - qh_fprintf(qh ferr, 6073, "qhull input error: only %d coordinates. Could not read %d-d feasible point.\n", - tokcount, dim); - qh_errexit(qh_ERRinput, NULL, NULL); - return 0; -} /* readfeasible */ - -/*-<a href="qh-io.htm#TOC" - >-------------------------------</a><a name="readpoints">-</a> - - qh_readpoints( numpoints, dimension, ismalloc ) - read points from qh.fin into qh.first_point, qh.num_points - qh.fin is lines of coordinates, one per vertex, first line number of points - if 'rbox D4', - gives message - if qh.ATinfinity, - adds point-at-infinity for Delaunay triangulations - - returns: - number of points, array of point coordinates, dimension, ismalloc True - if qh.DELAUNAY & !qh.PROJECTinput, projects points to paraboloid - and clears qh.PROJECTdelaunay - if qh.HALFspace, reads optional feasible point, reads halfspaces, - converts to dual. - - for feasible point in "cdd format" in 3-d: - 3 1 - coordinates - comments - begin - n 4 real/integer - ... - end - - notes: - dimension will change in qh_initqhull_globals if qh.PROJECTinput - uses malloc() since qh_mem not initialized - FIXUP QH11012: qh_readpoints needs rewriting, too long -*/ -coordT *qh_readpoints(int *numpoints, int *dimension, boolT *ismalloc) { - coordT *points, *coords, *infinity= NULL; - realT paraboloid, maxboloid= -REALmax, value; - realT *coordp= NULL, *offsetp= NULL, *normalp= NULL; - char *s= 0, *t, firstline[qh_MAXfirst+1]; - int diminput=0, numinput=0, dimfeasible= 0, newnum, k, tempi; - int firsttext=0, firstshort=0, firstlong=0, firstpoint=0; - int tokcount= 0, linecount=0, maxcount, coordcount=0; - boolT islong, isfirst= True, wasbegin= False; - boolT isdelaunay= qh DELAUNAY && !qh PROJECTinput; - - if (qh CDDinput) { - while ((s= fgets(firstline, qh_MAXfirst, qh fin))) { - linecount++; - if (qh HALFspace && linecount == 1 && isdigit(*s)) { - dimfeasible= qh_strtol(s, &s); - while (isspace(*s)) - s++; - if (qh_strtol(s, &s) == 1) - linecount += qh_readfeasible(dimfeasible, s); - else - dimfeasible= 0; - }else if (!memcmp(firstline, "begin", (size_t)5) || !memcmp(firstline, "BEGIN", (size_t)5)) - break; - else if (!*qh rbox_command) - strncat(qh rbox_command, s, sizeof(qh rbox_command)-1); - } - if (!s) { - qh_fprintf(qh ferr, 6074, "qhull input error: missing \"begin\" for cdd-formated input\n"); - qh_errexit(qh_ERRinput, NULL, NULL); - } - } - while (!numinput && (s= fgets(firstline, qh_MAXfirst, qh fin))) { - linecount++; - if (!memcmp(s, "begin", (size_t)5) || !memcmp(s, "BEGIN", (size_t)5)) - wasbegin= True; - while (*s) { - while (isspace(*s)) - s++; - if (!*s) - break; - if (!isdigit(*s)) { - if (!*qh rbox_command) { - strncat(qh rbox_command, s, sizeof(qh rbox_command)-1); - firsttext= linecount; - } - break; - } - if (!diminput) - diminput= qh_strtol(s, &s); - else { - numinput= qh_strtol(s, &s); - if (numinput == 1 && diminput >= 2 && qh HALFspace && !qh CDDinput) { - linecount += qh_readfeasible(diminput, s); /* checks if ok */ - dimfeasible= diminput; - diminput= numinput= 0; - }else - break; - } - } - } - if (!s) { - qh_fprintf(qh ferr, 6075, "qhull input error: short input file. Did not find dimension and number of points\n"); - qh_errexit(qh_ERRinput, NULL, NULL); - } - if (diminput > numinput) { - tempi= diminput; /* exchange dim and n, e.g., for cdd input format */ - diminput= numinput; - numinput= tempi; - } - if (diminput < 2) { - qh_fprintf(qh ferr, 6220,"qhull input error: dimension %d(first number) should be at least 2\n", - diminput); - qh_errexit(qh_ERRinput, NULL, NULL); - } - if (isdelaunay) { - qh PROJECTdelaunay= False; - if (qh CDDinput) - *dimension= diminput; - else - *dimension= diminput+1; - *numpoints= numinput; - if (qh ATinfinity) - (*numpoints)++; - }else if (qh HALFspace) { - *dimension= diminput - 1; - *numpoints= numinput; - if (diminput < 3) { - qh_fprintf(qh ferr, 6221,"qhull input error: dimension %d(first number, includes offset) should be at least 3 for halfspaces\n", - diminput); - qh_errexit(qh_ERRinput, NULL, NULL); - } - if (dimfeasible) { - if (dimfeasible != *dimension) { - qh_fprintf(qh ferr, 6222,"qhull input error: dimension %d of feasible point is not one less than dimension %d for halfspaces\n", - dimfeasible, diminput); - qh_errexit(qh_ERRinput, NULL, NULL); - } - }else - qh_setfeasible(*dimension); - }else { - if (qh CDDinput) - *dimension= diminput-1; - else - *dimension= diminput; - *numpoints= numinput; - } - qh normal_size= *dimension * sizeof(coordT); /* for tracing with qh_printpoint */ - if (qh HALFspace) { - qh half_space= coordp= (coordT*)qh_malloc(qh normal_size + sizeof(coordT)); - if (qh CDDinput) { - offsetp= qh half_space; - normalp= offsetp + 1; - }else { - normalp= qh half_space; - offsetp= normalp + *dimension; - } - } - qh maxline= diminput * (qh_REALdigits + 5); - maximize_(qh maxline, 500); - qh line= (char*)qh_malloc((qh maxline+1) * sizeof(char)); - *ismalloc= True; /* use malloc since memory not setup */ - coords= points= qh temp_malloc= - (coordT*)qh_malloc((*numpoints)*(*dimension)*sizeof(coordT)); - if (!coords || !qh line || (qh HALFspace && !qh half_space)) { - qh_fprintf(qh ferr, 6076, "qhull error: insufficient memory to read %d points\n", - numinput); - qh_errexit(qh_ERRmem, NULL, NULL); - } - if (isdelaunay && qh ATinfinity) { - infinity= points + numinput * (*dimension); - for (k= (*dimension) - 1; k--; ) - infinity[k]= 0.0; - } - maxcount= numinput * diminput; - paraboloid= 0.0; - while ((s= (isfirst ? s : fgets(qh line, qh maxline, qh fin)))) { - if (!isfirst) { - linecount++; - if (*s == 'e' || *s == 'E') { - if (!memcmp(s, "end", (size_t)3) || !memcmp(s, "END", (size_t)3)) { - if (qh CDDinput ) - break; - else if (wasbegin) - qh_fprintf(qh ferr, 7058, "qhull input warning: the input appears to be in cdd format. If so, use 'Fd'\n"); - } - } - } - islong= False; - while (*s) { - while (isspace(*s)) - s++; - value= qh_strtod(s, &t); - if (s == t) { - if (!*qh rbox_command) - strncat(qh rbox_command, s, sizeof(qh rbox_command)-1); - if (*s && !firsttext) - firsttext= linecount; - if (!islong && !firstshort && coordcount) - firstshort= linecount; - break; - } - if (!firstpoint) - firstpoint= linecount; - s= t; - if (++tokcount > maxcount) - continue; - if (qh HALFspace) { - if (qh CDDinput) - *(coordp++)= -value; /* both coefficients and offset */ - else - *(coordp++)= value; - }else { - *(coords++)= value; - if (qh CDDinput && !coordcount) { - if (value != 1.0) { - qh_fprintf(qh ferr, 6077, "qhull input error: for cdd format, point at line %d does not start with '1'\n", - linecount); - qh_errexit(qh_ERRinput, NULL, NULL); - } - coords--; - }else if (isdelaunay) { - paraboloid += value * value; - if (qh ATinfinity) { - if (qh CDDinput) - infinity[coordcount-1] += value; - else - infinity[coordcount] += value; - } - } - } - if (++coordcount == diminput) { - coordcount= 0; - if (isdelaunay) { - *(coords++)= paraboloid; - maximize_(maxboloid, paraboloid); - paraboloid= 0.0; - }else if (qh HALFspace) { - if (!qh_sethalfspace(*dimension, coords, &coords, normalp, offsetp, qh feasible_point)) { - qh_fprintf(qh ferr, 8048, "The halfspace was on line %d\n", linecount); - if (wasbegin) - qh_fprintf(qh ferr, 8049, "The input appears to be in cdd format. If so, you should use option 'Fd'\n"); - qh_errexit(qh_ERRinput, NULL, NULL); - } - coordp= qh half_space; - } - while (isspace(*s)) - s++; - if (*s) { - islong= True; - if (!firstlong) - firstlong= linecount; - } - } - } - if (!islong && !firstshort && coordcount) - firstshort= linecount; - if (!isfirst && s - qh line >= qh maxline) { - qh_fprintf(qh ferr, 6078, "qhull input error: line %d contained more than %d characters\n", - linecount, (int) (s - qh line)); /* WARN64 */ - qh_errexit(qh_ERRinput, NULL, NULL); - } - isfirst= False; - } - if (tokcount != maxcount) { - newnum= fmin_(numinput, tokcount/diminput); - qh_fprintf(qh ferr, 7073,"\ -qhull warning: instead of %d %d-dimensional points, input contains\n\ -%d points and %d extra coordinates. Line %d is the first\npoint", - numinput, diminput, tokcount/diminput, tokcount % diminput, firstpoint); - if (firsttext) - qh_fprintf(qh ferr, 8051, ", line %d is the first comment", firsttext); - if (firstshort) - qh_fprintf(qh ferr, 8052, ", line %d is the first short\nline", firstshort); - if (firstlong) - qh_fprintf(qh ferr, 8053, ", line %d is the first long line", firstlong); - qh_fprintf(qh ferr, 8054, ". Continue with %d points.\n", newnum); - numinput= newnum; - if (isdelaunay && qh ATinfinity) { - for (k= tokcount % diminput; k--; ) - infinity[k] -= *(--coords); - *numpoints= newnum+1; - }else { - coords -= tokcount % diminput; - *numpoints= newnum; - } - } - if (isdelaunay && qh ATinfinity) { - for (k= (*dimension) -1; k--; ) - infinity[k] /= numinput; - if (coords == infinity) - coords += (*dimension) -1; - else { - for (k=0; k < (*dimension) -1; k++) - *(coords++)= infinity[k]; - } - *(coords++)= maxboloid * 1.1; - } - if (qh rbox_command[0]) { - qh rbox_command[strlen(qh rbox_command)-1]= '\0'; - if (!strcmp(qh rbox_command, "./rbox D4")) - qh_fprintf(qh ferr, 8055, "\n\ -This is the qhull test case. If any errors or core dumps occur,\n\ -recompile qhull with 'make new'. If errors still occur, there is\n\ -an incompatibility. You should try a different compiler. You can also\n\ -change the choices in user.h. If you discover the source of the problem,\n\ -please send mail to qhull_bug@qhull.org.\n\ -\n\ -Type 'qhull' for a short list of options.\n"); - } - qh_free(qh line); - qh line= NULL; - if (qh half_space) { - qh_free(qh half_space); - qh half_space= NULL; - } - qh temp_malloc= NULL; - trace1((qh ferr, 1008,"qh_readpoints: read in %d %d-dimensional points\n", - numinput, diminput)); - return(points); -} /* readpoints */ - - -/*-<a href="qh-io.htm#TOC" - >-------------------------------</a><a name="setfeasible">-</a> - - qh_setfeasible( dim ) - set qh.FEASIBLEpoint from qh.feasible_string in "n,n,n" or "n n n" format - - notes: - "n,n,n" already checked by qh_initflags() - see qh_readfeasible() -*/ -void qh_setfeasible(int dim) { - int tokcount= 0; - char *s; - coordT *coords, value; - - if (!(s= qh feasible_string)) { - qh_fprintf(qh ferr, 6223, "\ -qhull input error: halfspace intersection needs a feasible point.\n\ -Either prepend the input with 1 point or use 'Hn,n,n'. See manual.\n"); - qh_errexit(qh_ERRinput, NULL, NULL); - } - if (!(qh feasible_point= (pointT*)qh_malloc(dim * sizeof(coordT)))) { - qh_fprintf(qh ferr, 6079, "qhull error: insufficient memory for 'Hn,n,n'\n"); - qh_errexit(qh_ERRmem, NULL, NULL); - } - coords= qh feasible_point; - while (*s) { - value= qh_strtod(s, &s); - if (++tokcount > dim) { - qh_fprintf(qh ferr, 7059, "qhull input warning: more coordinates for 'H%s' than dimension %d\n", - qh feasible_string, dim); - break; - } - *(coords++)= value; - if (*s) - s++; - } - while (++tokcount <= dim) - *(coords++)= 0.0; -} /* setfeasible */ - -/*-<a href="qh-io.htm#TOC" - >-------------------------------</a><a name="skipfacet">-</a> - - qh_skipfacet( facet ) - returns 'True' if this facet is not to be printed - - notes: - based on the user provided slice thresholds and 'good' specifications -*/ -boolT qh_skipfacet(facetT *facet) { - facetT *neighbor, **neighborp; - - if (qh PRINTneighbors) { - if (facet->good) - return !qh PRINTgood; - FOREACHneighbor_(facet) { - if (neighbor->good) - return False; - } - return True; - }else if (qh PRINTgood) - return !facet->good; - else if (!facet->normal) - return True; - return(!qh_inthresholds(facet->normal, NULL)); -} /* skipfacet */ - -/*-<a href="qh-io.htm#TOC" - >-------------------------------</a><a name="skipfilename">-</a> - - qh_skipfilename( string ) - returns pointer to character after filename - - notes: - skips leading spaces - ends with spacing or eol - if starts with ' or " ends with the same, skipping \' or \" - For qhull, qh_argv_to_command() only uses double quotes -*/ -char *qh_skipfilename(char *filename) { - char *s= filename; /* non-const due to return */ - char c; - - while (*s && isspace(*s)) - s++; - c= *s++; - if (c == '\0') { - qh_fprintf(qh ferr, 6204, "qhull input error: filename expected, none found.\n"); - qh_errexit(qh_ERRinput, NULL, NULL); - } - if (c == '\'' || c == '"') { - while (*s !=c || s[-1] == '\\') { - if (!*s) { - qh_fprintf(qh ferr, 6203, "qhull input error: missing quote after filename -- %s\n", filename); - qh_errexit(qh_ERRinput, NULL, NULL); - } - s++; - } - s++; - } - else while (*s && !isspace(*s)) - s++; - return s; -} /* skipfilename */ - diff --git a/PyMca/Object3D/Object3DQhull/src/io.h b/PyMca/Object3D/Object3DQhull/src/io.h deleted file mode 100644 index 580d51b..0000000 --- a/PyMca/Object3D/Object3DQhull/src/io.h +++ /dev/null @@ -1,159 +0,0 @@ -/*<html><pre> -<a href="qh-io.htm" - >-------------------------------</a><a name="TOP">-</a> - - io.h - declarations of Input/Output functions - - see README, libqhull.h and io.c - - Copyright (c) 1993-2012 The Geometry Center. - $Id: //main/2011/qhull/src/libqhull/io.h#3 $$Change: 1464 $ - $DateTime: 2012/01/25 22:58:41 $$Author: bbarber $ -*/ - -#ifndef qhDEFio -#define qhDEFio 1 - -#include "libqhull.h" - -/*============ constants and flags ==================*/ - -/*-<a href="qh-io.htm#TOC" - >--------------------------------</a><a name="qh_MAXfirst">-</a> - - qh_MAXfirst - maximum length of first two lines of stdin -*/ -#define qh_MAXfirst 200 - -/*-<a href="qh-io.htm#TOC" - >--------------------------------</a><a name="qh_MINradius">-</a> - - qh_MINradius - min radius for Gp and Gv, fraction of maxcoord -*/ -#define qh_MINradius 0.02 - -/*-<a href="qh-io.htm#TOC" - >--------------------------------</a><a name="qh_GEOMepsilon">-</a> - - qh_GEOMepsilon - adjust outer planes for 'lines closer' and geomview roundoff. - This prevents bleed through. -*/ -#define qh_GEOMepsilon 2e-3 - -/*-<a href="qh-io.htm#TOC" - >--------------------------------</a><a name="qh_WHITESPACE">-</a> - - qh_WHITESPACE - possible values of white space -*/ -#define qh_WHITESPACE " \n\t\v\r\f" - - -/*-<a href="qh-io.htm#TOC" - >--------------------------------</a><a name="RIDGE">-</a> - - qh_RIDGE - to select which ridges to print in qh_eachvoronoi -*/ -typedef enum -{ - qh_RIDGEall = 0, qh_RIDGEinner, qh_RIDGEouter -} -qh_RIDGE; - -/*-<a href="qh-io.htm#TOC" - >--------------------------------</a><a name="printvridgeT">-</a> - - printvridgeT - prints results of qh_printvdiagram - - see: - <a href="io.c#printvridge">qh_printvridge</a> for an example -*/ -typedef void (*printvridgeT)(FILE *fp, vertexT *vertex, vertexT *vertexA, setT *centers, boolT unbounded); - -/*============== -prototypes in alphabetical order =========*/ - -void dfacet(unsigned id); -void dvertex(unsigned id); -int qh_compare_facetarea(const void *p1, const void *p2); -int qh_compare_facetmerge(const void *p1, const void *p2); -int qh_compare_facetvisit(const void *p1, const void *p2); -int qh_compare_vertexpoint(const void *p1, const void *p2); /* not used */ -void qh_copyfilename(char *filename, int size, const char* source, int length); -void qh_countfacets(facetT *facetlist, setT *facets, boolT printall, - int *numfacetsp, int *numsimplicialp, int *totneighborsp, - int *numridgesp, int *numcoplanarsp, int *numnumtricoplanarsp); -pointT *qh_detvnorm(vertexT *vertex, vertexT *vertexA, setT *centers, realT *offsetp); -setT *qh_detvridge(vertexT *vertex); -setT *qh_detvridge3 (vertexT *atvertex, vertexT *vertex); -int qh_eachvoronoi(FILE *fp, printvridgeT printvridge, vertexT *atvertex, boolT visitall, qh_RIDGE innerouter, boolT inorder); -int qh_eachvoronoi_all(FILE *fp, printvridgeT printvridge, boolT isUpper, qh_RIDGE innerouter, boolT inorder); -void qh_facet2point(facetT *facet, pointT **point0, pointT **point1, realT *mindist); -setT *qh_facetvertices(facetT *facetlist, setT *facets, boolT allfacets); -void qh_geomplanes(facetT *facet, realT *outerplane, realT *innerplane); -void qh_markkeep(facetT *facetlist); -setT *qh_markvoronoi(facetT *facetlist, setT *facets, boolT printall, boolT *isLowerp, int *numcentersp); -void qh_order_vertexneighbors(vertexT *vertex); -void qh_prepare_output(void); -void qh_printafacet(FILE *fp, qh_PRINT format, facetT *facet, boolT printall); -void qh_printbegin(FILE *fp, qh_PRINT format, facetT *facetlist, setT *facets, boolT printall); -void qh_printcenter(FILE *fp, qh_PRINT format, const char *string, facetT *facet); -void qh_printcentrum(FILE *fp, facetT *facet, realT radius); -void qh_printend(FILE *fp, qh_PRINT format, facetT *facetlist, setT *facets, boolT printall); -void qh_printend4geom(FILE *fp, facetT *facet, int *num, boolT printall); -void qh_printextremes(FILE *fp, facetT *facetlist, setT *facets, boolT printall); -void qh_printextremes_2d(FILE *fp, facetT *facetlist, setT *facets, boolT printall); -void qh_printextremes_d(FILE *fp, facetT *facetlist, setT *facets, boolT printall); -void qh_printfacet(FILE *fp, facetT *facet); -void qh_printfacet2math(FILE *fp, facetT *facet, qh_PRINT format, int notfirst); -void qh_printfacet2geom(FILE *fp, facetT *facet, realT color[3]); -void qh_printfacet2geom_points(FILE *fp, pointT *point1, pointT *point2, - facetT *facet, realT offset, realT color[3]); -void qh_printfacet3math(FILE *fp, facetT *facet, qh_PRINT format, int notfirst); -void qh_printfacet3geom_nonsimplicial(FILE *fp, facetT *facet, realT color[3]); -void qh_printfacet3geom_points(FILE *fp, setT *points, facetT *facet, realT offset, realT color[3]); -void qh_printfacet3geom_simplicial(FILE *fp, facetT *facet, realT color[3]); -void qh_printfacet3vertex(FILE *fp, facetT *facet, qh_PRINT format); -void qh_printfacet4geom_nonsimplicial(FILE *fp, facetT *facet, realT color[3]); -void qh_printfacet4geom_simplicial(FILE *fp, facetT *facet, realT color[3]); -void qh_printfacetNvertex_nonsimplicial(FILE *fp, facetT *facet, int id, qh_PRINT format); -void qh_printfacetNvertex_simplicial(FILE *fp, facetT *facet, qh_PRINT format); -void qh_printfacetheader(FILE *fp, facetT *facet); -void qh_printfacetridges(FILE *fp, facetT *facet); -void qh_printfacets(FILE *fp, qh_PRINT format, facetT *facetlist, setT *facets, boolT printall); -void qh_printhyperplaneintersection(FILE *fp, facetT *facet1, facetT *facet2, - setT *vertices, realT color[3]); -void qh_printneighborhood(FILE *fp, qh_PRINT format, facetT *facetA, facetT *facetB, boolT printall); -void qh_printline3geom(FILE *fp, pointT *pointA, pointT *pointB, realT color[3]); -void qh_printpoint(FILE *fp, const char *string, pointT *point); -void qh_printpointid(FILE *fp, const char *string, int dim, pointT *point, int id); -void qh_printpoint3 (FILE *fp, pointT *point); -void qh_printpoints_out(FILE *fp, facetT *facetlist, setT *facets, boolT printall); -void qh_printpointvect(FILE *fp, pointT *point, coordT *normal, pointT *center, realT radius, realT color[3]); -void qh_printpointvect2 (FILE *fp, pointT *point, coordT *normal, pointT *center, realT radius); -void qh_printridge(FILE *fp, ridgeT *ridge); -void qh_printspheres(FILE *fp, setT *vertices, realT radius); -void qh_printvdiagram(FILE *fp, qh_PRINT format, facetT *facetlist, setT *facets, boolT printall); -int qh_printvdiagram2 (FILE *fp, printvridgeT printvridge, setT *vertices, qh_RIDGE innerouter, boolT inorder); -void qh_printvertex(FILE *fp, vertexT *vertex); -void qh_printvertexlist(FILE *fp, const char* string, facetT *facetlist, - setT *facets, boolT printall); -void qh_printvertices(FILE *fp, const char* string, setT *vertices); -void qh_printvneighbors(FILE *fp, facetT* facetlist, setT *facets, boolT printall); -void qh_printvoronoi(FILE *fp, qh_PRINT format, facetT *facetlist, setT *facets, boolT printall); -void qh_printvnorm(FILE *fp, vertexT *vertex, vertexT *vertexA, setT *centers, boolT unbounded); -void qh_printvridge(FILE *fp, vertexT *vertex, vertexT *vertexA, setT *centers, boolT unbounded); -void qh_produce_output(void); -void qh_produce_output2(void); -void qh_projectdim3 (pointT *source, pointT *destination); -int qh_readfeasible(int dim, const char *curline); -coordT *qh_readpoints(int *numpoints, int *dimension, boolT *ismalloc); -void qh_setfeasible(int dim); -boolT qh_skipfacet(facetT *facet); -char *qh_skipfilename(char *filename); - -#endif /* qhDEFio */ diff --git a/PyMca/Object3D/Object3DQhull/src/libqhull.c b/PyMca/Object3D/Object3DQhull/src/libqhull.c deleted file mode 100644 index a7d86ce..0000000 --- a/PyMca/Object3D/Object3DQhull/src/libqhull.c +++ /dev/null @@ -1,1401 +0,0 @@ -/*<html><pre> -<a href="qh-qhull.htm" - >-------------------------------</a><a name="TOP">-</a> - - libqhull.c - Quickhull algorithm for convex hulls - - qhull() and top-level routines - - see qh-qhull.htm, libqhull.h, unix.c - - see qhull_a.h for internal functions - - Copyright (c) 1993-2012 The Geometry Center. - $Id: //main/2011/qhull/src/libqhull/libqhull.c#4 $$Change: 1464 $ - $DateTime: 2012/01/25 22:58:41 $$Author: bbarber $ -*/ - -#include "qhull_a.h" - -/*============= functions in alphabetic order after qhull() =======*/ - -/*-<a href="qh-qhull.htm#TOC" - >-------------------------------</a><a name="qhull">-</a> - - qh_qhull() - compute DIM3 convex hull of qh.num_points starting at qh.first_point - qh contains all global options and variables - - returns: - returns polyhedron - qh.facet_list, qh.num_facets, qh.vertex_list, qh.num_vertices, - - returns global variables - qh.hulltime, qh.max_outside, qh.interior_point, qh.max_vertex, qh.min_vertex - - returns precision constants - qh.ANGLEround, centrum_radius, cos_max, DISTround, MAXabs_coord, ONEmerge - - notes: - unless needed for output - qh.max_vertex and qh.min_vertex are max/min due to merges - - see: - to add individual points to either qh.num_points - use qh_addpoint() - - if qh.GETarea - qh_produceoutput() returns qh.totarea and qh.totvol via qh_getarea() - - design: - record starting time - initialize hull and partition points - build convex hull - unless early termination - update facet->maxoutside for vertices, coplanar, and near-inside points - error if temporary sets exist - record end time -*/ - -void qh_qhull(void) { - int numoutside; - - qh hulltime= qh_CPUclock; - if (qh RERUN || qh JOGGLEmax < REALmax/2) - qh_build_withrestart(); - else { - qh_initbuild(); - qh_buildhull(); - } - if (!qh STOPpoint && !qh STOPcone) { - if (qh ZEROall_ok && !qh TESTvneighbors && qh MERGEexact) - qh_checkzero( qh_ALL); - if (qh ZEROall_ok && !qh TESTvneighbors && !qh WAScoplanar) { - trace2((qh ferr, 2055, "qh_qhull: all facets are clearly convex and no coplanar points. Post-merging and check of maxout not needed.\n")); - qh DOcheckmax= False; - }else { - if (qh MERGEexact || (qh hull_dim > qh_DIMreduceBuild && qh PREmerge)) - qh_postmerge("First post-merge", qh premerge_centrum, qh premerge_cos, - (qh POSTmerge ? False : qh TESTvneighbors)); - else if (!qh POSTmerge && qh TESTvneighbors) - qh_postmerge("For testing vertex neighbors", qh premerge_centrum, - qh premerge_cos, True); - if (qh POSTmerge) - qh_postmerge("For post-merging", qh postmerge_centrum, - qh postmerge_cos, qh TESTvneighbors); - if (qh visible_list == qh facet_list) { /* i.e., merging done */ - qh findbestnew= True; - qh_partitionvisible(/*visible_list, newfacet_list*/ !qh_ALL, &numoutside); - qh findbestnew= False; - qh_deletevisible(/*qh visible_list*/); - qh_resetlists(False, qh_RESETvisible /*qh visible_list newvertex_list newfacet_list */); - } - } - if (qh DOcheckmax){ - if (qh REPORTfreq) { - qh_buildtracing(NULL, NULL); - qh_fprintf(qh ferr, 8115, "\nTesting all coplanar points.\n"); - } - qh_check_maxout(); - } - if (qh KEEPnearinside && !qh maxoutdone) - qh_nearcoplanar(); - } - if (qh_setsize(qhmem.tempstack) != 0) { - qh_fprintf(qh ferr, 6164, "qhull internal error (qh_qhull): temporary sets not empty(%d)\n", - qh_setsize(qhmem.tempstack)); - qh_errexit(qh_ERRqhull, NULL, NULL); - } - qh hulltime= qh_CPUclock - qh hulltime; - qh QHULLfinished= True; - trace1((qh ferr, 1036, "Qhull: algorithm completed\n")); -} /* qhull */ - -/*-<a href="qh-qhull.htm#TOC" - >-------------------------------</a><a name="addpoint">-</a> - - qh_addpoint( furthest, facet, checkdist ) - add point (usually furthest point) above facet to hull - if checkdist, - check that point is above facet. - if point is not outside of the hull, uses qh_partitioncoplanar() - assumes that facet is defined by qh_findbestfacet() - else if facet specified, - assumes that point is above facet (major damage if below) - for Delaunay triangulations, - Use qh_setdelaunay() to lift point to paraboloid and scale by 'Qbb' if needed - Do not use options 'Qbk', 'QBk', or 'QbB' since they scale the coordinates. - - returns: - returns False if user requested an early termination - qh.visible_list, newfacet_list, delvertex_list, NEWfacets may be defined - updates qh.facet_list, qh.num_facets, qh.vertex_list, qh.num_vertices - clear qh.maxoutdone (will need to call qh_check_maxout() for facet->maxoutside) - if unknown point, adds a pointer to qh.other_points - do not deallocate the point's coordinates - - notes: - assumes point is near its best facet and not at a local minimum of a lens - distributions. Use qh_findbestfacet to avoid this case. - uses qh.visible_list, qh.newfacet_list, qh.delvertex_list, qh.NEWfacets - - see also: - qh_triangulate() -- triangulate non-simplicial facets - - design: - add point to other_points if needed - if checkdist - if point not above facet - partition coplanar point - exit - exit if pre STOPpoint requested - find horizon and visible facets for point - make new facets for point to horizon - make hyperplanes for point - compute balance statistics - match neighboring new facets - update vertex neighbors and delete interior vertices - exit if STOPcone requested - merge non-convex new facets - if merge found, many merges, or 'Qf' - use qh_findbestnew() instead of qh_findbest() - partition outside points from visible facets - delete visible facets - check polyhedron if requested - exit if post STOPpoint requested - reset working lists of facets and vertices -*/ -boolT qh_addpoint(pointT *furthest, facetT *facet, boolT checkdist) { - int goodvisible, goodhorizon; - vertexT *vertex; - facetT *newfacet; - realT dist, newbalance, pbalance; - boolT isoutside= False; - int numpart, numpoints, numnew, firstnew; - - qh maxoutdone= False; - if (qh_pointid(furthest) == -1) - qh_setappend(&qh other_points, furthest); - if (!facet) { - qh_fprintf(qh ferr, 6213, "qhull internal error (qh_addpoint): NULL facet. Need to call qh_findbestfacet first\n"); - qh_errexit(qh_ERRqhull, NULL, NULL); - } - if (checkdist) { - facet= qh_findbest(furthest, facet, !qh_ALL, !qh_ISnewfacets, !qh_NOupper, - &dist, &isoutside, &numpart); - zzadd_(Zpartition, numpart); - if (!isoutside) { - zinc_(Znotmax); /* last point of outsideset is no longer furthest. */ - facet->notfurthest= True; - qh_partitioncoplanar(furthest, facet, &dist); - return True; - } - } - qh_buildtracing(furthest, facet); - if (qh STOPpoint < 0 && qh furthest_id == -qh STOPpoint-1) { - facet->notfurthest= True; - return False; - } - qh_findhorizon(furthest, facet, &goodvisible, &goodhorizon); - if (qh ONLYgood && !(goodvisible+goodhorizon) && !qh GOODclosest) { - zinc_(Znotgood); - facet->notfurthest= True; - /* last point of outsideset is no longer furthest. This is ok - since all points of the outside are likely to be bad */ - qh_resetlists(False, qh_RESETvisible /*qh visible_list newvertex_list newfacet_list */); - return True; - } - zzinc_(Zprocessed); - firstnew= qh facet_id; - vertex= qh_makenewfacets(furthest /*visible_list, attaches if !ONLYgood */); - qh_makenewplanes(/* newfacet_list */); - numnew= qh facet_id - firstnew; - newbalance= numnew - (realT) (qh num_facets-qh num_visible) - * qh hull_dim/qh num_vertices; - wadd_(Wnewbalance, newbalance); - wadd_(Wnewbalance2, newbalance * newbalance); - if (qh ONLYgood - && !qh_findgood(qh newfacet_list, goodhorizon) && !qh GOODclosest) { - FORALLnew_facets - qh_delfacet(newfacet); - qh_delvertex(vertex); - qh_resetlists(True, qh_RESETvisible /*qh visible_list newvertex_list newfacet_list */); - zinc_(Znotgoodnew); - facet->notfurthest= True; - return True; - } - if (qh ONLYgood) - qh_attachnewfacets(/*visible_list*/); - qh_matchnewfacets(); - qh_updatevertices(); - if (qh STOPcone && qh furthest_id == qh STOPcone-1) { - facet->notfurthest= True; - return False; /* visible_list etc. still defined */ - } - qh findbestnew= False; - if (qh PREmerge || qh MERGEexact) { - qh_premerge(vertex, qh premerge_centrum, qh premerge_cos); - if (qh_USEfindbestnew) - qh findbestnew= True; - else { - FORALLnew_facets { - if (!newfacet->simplicial) { - qh findbestnew= True; /* use qh_findbestnew instead of qh_findbest*/ - break; - } - } - } - }else if (qh BESToutside) - qh findbestnew= True; - qh_partitionvisible(/*visible_list, newfacet_list*/ !qh_ALL, &numpoints); - qh findbestnew= False; - qh findbest_notsharp= False; - zinc_(Zpbalance); - pbalance= numpoints - (realT) qh hull_dim /* assumes all points extreme */ - * (qh num_points - qh num_vertices)/qh num_vertices; - wadd_(Wpbalance, pbalance); - wadd_(Wpbalance2, pbalance * pbalance); - qh_deletevisible(/*qh visible_list*/); - zmax_(Zmaxvertex, qh num_vertices); - qh NEWfacets= False; - if (qh IStracing >= 4) { - if (qh num_facets < 2000) - qh_printlists(); - qh_printfacetlist(qh newfacet_list, NULL, True); - qh_checkpolygon(qh facet_list); - }else if (qh CHECKfrequently) { - if (qh num_facets < 50) - qh_checkpolygon(qh facet_list); - else - qh_checkpolygon(qh newfacet_list); - } - if (qh STOPpoint > 0 && qh furthest_id == qh STOPpoint-1) - return False; - qh_resetlists(True, qh_RESETvisible /*qh visible_list newvertex_list newfacet_list */); - /* qh_triangulate(); to test qh.TRInormals */ - trace2((qh ferr, 2056, "qh_addpoint: added p%d new facets %d new balance %2.2g point balance %2.2g\n", - qh_pointid(furthest), numnew, newbalance, pbalance)); - return True; -} /* addpoint */ - -/*-<a href="qh-qhull.htm#TOC" - >-------------------------------</a><a name="build_withrestart">-</a> - - qh_build_withrestart() - allow restarts due to qh.JOGGLEmax while calling qh_buildhull() - qh.FIRSTpoint/qh.NUMpoints is point array - it may be moved by qh_joggleinput() -*/ -void qh_build_withrestart(void) { - int restart; - - qh ALLOWrestart= True; - while (True) { - restart= setjmp(qh restartexit); /* simple statement for CRAY J916 */ - if (restart) { /* only from qh_precision() */ - zzinc_(Zretry); - wmax_(Wretrymax, qh JOGGLEmax); - /* QH7078 warns about using 'TCn' with 'QJn' */ - qh STOPcone= -1; /* if break from joggle, prevents normal output */ - } - if (!qh RERUN && qh JOGGLEmax < REALmax/2) { - if (qh build_cnt > qh_JOGGLEmaxretry) { - qh_fprintf(qh ferr, 6229, "qhull precision error: %d attempts to construct a convex hull\n\ - with joggled input. Increase joggle above 'QJ%2.2g'\n\ - or modify qh_JOGGLE... parameters in user.h\n", - qh build_cnt, qh JOGGLEmax); - qh_errexit(qh_ERRqhull, NULL, NULL); - } - if (qh build_cnt && !restart) - break; - }else if (qh build_cnt && qh build_cnt >= qh RERUN) - break; - qh STOPcone= 0; - qh_freebuild(True); /* first call is a nop */ - qh build_cnt++; - if (!qh qhull_optionsiz) - qh qhull_optionsiz= (int)strlen(qh qhull_options); /* WARN64 */ - else { - qh qhull_options [qh qhull_optionsiz]= '\0'; - qh qhull_optionlen= qh_OPTIONline; /* starts a new line */ - } - qh_option("_run", &qh build_cnt, NULL); - if (qh build_cnt == qh RERUN) { - qh IStracing= qh TRACElastrun; /* duplicated from qh_initqhull_globals */ - if (qh TRACEpoint != -1 || qh TRACEdist < REALmax/2 || qh TRACEmerge) { - qh TRACElevel= (qh IStracing? qh IStracing : 3); - qh IStracing= 0; - } - qhmem.IStracing= qh IStracing; - } - if (qh JOGGLEmax < REALmax/2) - qh_joggleinput(); - qh_initbuild(); - qh_buildhull(); - if (qh JOGGLEmax < REALmax/2 && !qh MERGING) - qh_checkconvex(qh facet_list, qh_ALGORITHMfault); - } - qh ALLOWrestart= False; -} /* qh_build_withrestart */ - -/*-<a href="qh-qhull.htm#TOC" - >-------------------------------</a><a name="buildhull">-</a> - - qh_buildhull() - construct a convex hull by adding outside points one at a time - - returns: - - notes: - may be called multiple times - checks facet and vertex lists for incorrect flags - to recover from STOPcone, call qh_deletevisible and qh_resetlists - - design: - check visible facet and newfacet flags - check newlist vertex flags and qh.STOPcone/STOPpoint - for each facet with a furthest outside point - add point to facet - exit if qh.STOPcone or qh.STOPpoint requested - if qh.NARROWhull for initial simplex - partition remaining outside points to coplanar sets -*/ -void qh_buildhull(void) { - facetT *facet; - pointT *furthest; - vertexT *vertex; - int id; - - trace1((qh ferr, 1037, "qh_buildhull: start build hull\n")); - FORALLfacets { - if (facet->visible || facet->newfacet) { - qh_fprintf(qh ferr, 6165, "qhull internal error (qh_buildhull): visible or new facet f%d in facet list\n", - facet->id); - qh_errexit(qh_ERRqhull, facet, NULL); - } - } - FORALLvertices { - if (vertex->newlist) { - qh_fprintf(qh ferr, 6166, "qhull internal error (qh_buildhull): new vertex f%d in vertex list\n", - vertex->id); - qh_errprint("ERRONEOUS", NULL, NULL, NULL, vertex); - qh_errexit(qh_ERRqhull, NULL, NULL); - } - id= qh_pointid(vertex->point); - if ((qh STOPpoint>0 && id == qh STOPpoint-1) || - (qh STOPpoint<0 && id == -qh STOPpoint-1) || - (qh STOPcone>0 && id == qh STOPcone-1)) { - trace1((qh ferr, 1038,"qh_buildhull: stop point or cone P%d in initial hull\n", id)); - return; - } - } - qh facet_next= qh facet_list; /* advance facet when processed */ - while ((furthest= qh_nextfurthest(&facet))) { - qh num_outside--; /* if ONLYmax, furthest may not be outside */ - if (!qh_addpoint(furthest, facet, qh ONLYmax)) - break; - } - if (qh NARROWhull) /* move points from outsideset to coplanarset */ - qh_outcoplanar( /* facet_list */ ); - if (qh num_outside && !furthest) { - qh_fprintf(qh ferr, 6167, "qhull internal error (qh_buildhull): %d outside points were never processed.\n", qh num_outside); - qh_errexit(qh_ERRqhull, NULL, NULL); - } - trace1((qh ferr, 1039, "qh_buildhull: completed the hull construction\n")); -} /* buildhull */ - - -/*-<a href="qh-qhull.htm#TOC" - >-------------------------------</a><a name="buildtracing">-</a> - - qh_buildtracing( furthest, facet ) - trace an iteration of qh_buildhull() for furthest point and facet - if !furthest, prints progress message - - returns: - tracks progress with qh.lastreport - updates qh.furthest_id (-3 if furthest is NULL) - also resets visit_id, vertext_visit on wrap around - - see: - qh_tracemerging() - - design: - if !furthest - print progress message - exit - if 'TFn' iteration - print progress message - else if tracing - trace furthest point and facet - reset qh.visit_id and qh.vertex_visit if overflow may occur - set qh.furthest_id for tracing -*/ -void qh_buildtracing(pointT *furthest, facetT *facet) { - realT dist= 0; - float cpu; - int total, furthestid; - time_t timedata; - struct tm *tp; - vertexT *vertex; - - qh old_randomdist= qh RANDOMdist; - qh RANDOMdist= False; - if (!furthest) { - time(&timedata); - tp= localtime(&timedata); - cpu= (float)qh_CPUclock - (float)qh hulltime; - cpu /= (float)qh_SECticks; - total= zzval_(Ztotmerge) - zzval_(Zcyclehorizon) + zzval_(Zcyclefacettot); - qh_fprintf(qh ferr, 8118, "\n\ -At %02d:%02d:%02d & %2.5g CPU secs, qhull has created %d facets and merged %d.\n\ - The current hull contains %d facets and %d vertices. Last point was p%d\n", - tp->tm_hour, tp->tm_min, tp->tm_sec, cpu, qh facet_id -1, - total, qh num_facets, qh num_vertices, qh furthest_id); - return; - } - furthestid= qh_pointid(furthest); - if (qh TRACEpoint == furthestid) { - qh IStracing= qh TRACElevel; - qhmem.IStracing= qh TRACElevel; - }else if (qh TRACEpoint != -1 && qh TRACEdist < REALmax/2) { - qh IStracing= 0; - qhmem.IStracing= 0; - } - if (qh REPORTfreq && (qh facet_id-1 > qh lastreport+qh REPORTfreq)) { - qh lastreport= qh facet_id-1; - time(&timedata); - tp= localtime(&timedata); - cpu= (float)qh_CPUclock - (float)qh hulltime; - cpu /= (float)qh_SECticks; - total= zzval_(Ztotmerge) - zzval_(Zcyclehorizon) + zzval_(Zcyclefacettot); - zinc_(Zdistio); - qh_distplane(furthest, facet, &dist); - qh_fprintf(qh ferr, 8119, "\n\ -At %02d:%02d:%02d & %2.5g CPU secs, qhull has created %d facets and merged %d.\n\ - The current hull contains %d facets and %d vertices. There are %d\n\ - outside points. Next is point p%d(v%d), %2.2g above f%d.\n", - tp->tm_hour, tp->tm_min, tp->tm_sec, cpu, qh facet_id -1, - total, qh num_facets, qh num_vertices, qh num_outside+1, - furthestid, qh vertex_id, dist, getid_(facet)); - }else if (qh IStracing >=1) { - cpu= (float)qh_CPUclock - (float)qh hulltime; - cpu /= (float)qh_SECticks; - qh_distplane(furthest, facet, &dist); - qh_fprintf(qh ferr, 8120, "qh_addpoint: add p%d(v%d) to hull of %d facets(%2.2g above f%d) and %d outside at %4.4g CPU secs. Previous was p%d.\n", - furthestid, qh vertex_id, qh num_facets, dist, - getid_(facet), qh num_outside+1, cpu, qh furthest_id); - } - zmax_(Zvisit2max, (int)qh visit_id/2); - if (qh visit_id > (unsigned) INT_MAX) { - zinc_(Zvisit); - qh visit_id= 0; - FORALLfacets - facet->visitid= 0; - } - zmax_(Zvvisit2max, (int)qh vertex_visit/2); - if (qh vertex_visit > (unsigned) INT_MAX/2) { /* 31 bits */ - zinc_(Zvvisit); - qh vertex_visit= 0; - FORALLvertices - vertex->visitid= 0; - } - qh furthest_id= furthestid; - qh RANDOMdist= qh old_randomdist; -} /* buildtracing */ - -/*-<a href="qh-qhull.htm#TOC" - >-------------------------------</a><a name="errexit2">-</a> - - qh_errexit2( exitcode, facet, otherfacet ) - return exitcode to system after an error - report two facets - - returns: - assumes exitcode non-zero - - see: - normally use qh_errexit() in user.c(reports a facet and a ridge) -*/ -void qh_errexit2(int exitcode, facetT *facet, facetT *otherfacet) { - - qh_errprint("ERRONEOUS", facet, otherfacet, NULL, NULL); - qh_errexit(exitcode, NULL, NULL); -} /* errexit2 */ - - -/*-<a href="qh-qhull.htm#TOC" - >-------------------------------</a><a name="findhorizon">-</a> - - qh_findhorizon( point, facet, goodvisible, goodhorizon ) - given a visible facet, find the point's horizon and visible facets - for all facets, !facet-visible - - returns: - returns qh.visible_list/num_visible with all visible facets - marks visible facets with ->visible - updates count of good visible and good horizon facets - updates qh.max_outside, qh.max_vertex, facet->maxoutside - - see: - similar to qh_delpoint() - - design: - move facet to qh.visible_list at end of qh.facet_list - for all visible facets - for each unvisited neighbor of a visible facet - compute distance of point to neighbor - if point above neighbor - move neighbor to end of qh.visible_list - else if point is coplanar with neighbor - update qh.max_outside, qh.max_vertex, neighbor->maxoutside - mark neighbor coplanar (will create a samecycle later) - update horizon statistics -*/ -void qh_findhorizon(pointT *point, facetT *facet, int *goodvisible, int *goodhorizon) { - facetT *neighbor, **neighborp, *visible; - int numhorizon= 0, coplanar= 0; - realT dist; - - trace1((qh ferr, 1040,"qh_findhorizon: find horizon for point p%d facet f%d\n",qh_pointid(point),facet->id)); - *goodvisible= *goodhorizon= 0; - zinc_(Ztotvisible); - qh_removefacet(facet); /* visible_list at end of qh facet_list */ - qh_appendfacet(facet); - qh num_visible= 1; - if (facet->good) - (*goodvisible)++; - qh visible_list= facet; - facet->visible= True; - facet->f.replace= NULL; - if (qh IStracing >=4) - qh_errprint("visible", facet, NULL, NULL, NULL); - qh visit_id++; - FORALLvisible_facets { - if (visible->tricoplanar && !qh TRInormals) { - qh_fprintf(qh ferr, 6230, "Qhull internal error (qh_findhorizon): does not work for tricoplanar facets. Use option 'Q11'\n"); - qh_errexit(qh_ERRqhull, visible, NULL); - } - visible->visitid= qh visit_id; - FOREACHneighbor_(visible) { - if (neighbor->visitid == qh visit_id) - continue; - neighbor->visitid= qh visit_id; - zzinc_(Znumvisibility); - qh_distplane(point, neighbor, &dist); - if (dist > qh MINvisible) { - zinc_(Ztotvisible); - qh_removefacet(neighbor); /* append to end of qh visible_list */ - qh_appendfacet(neighbor); - neighbor->visible= True; - neighbor->f.replace= NULL; - qh num_visible++; - if (neighbor->good) - (*goodvisible)++; - if (qh IStracing >=4) - qh_errprint("visible", neighbor, NULL, NULL, NULL); - }else { - if (dist > - qh MAXcoplanar) { - neighbor->coplanar= True; - zzinc_(Zcoplanarhorizon); - qh_precision("coplanar horizon"); - coplanar++; - if (qh MERGING) { - if (dist > 0) { - maximize_(qh max_outside, dist); - maximize_(qh max_vertex, dist); -#if qh_MAXoutside - maximize_(neighbor->maxoutside, dist); -#endif - }else - minimize_(qh min_vertex, dist); /* due to merge later */ - } - trace2((qh ferr, 2057, "qh_findhorizon: point p%d is coplanar to horizon f%d, dist=%2.7g < qh MINvisible(%2.7g)\n", - qh_pointid(point), neighbor->id, dist, qh MINvisible)); - }else - neighbor->coplanar= False; - zinc_(Ztothorizon); - numhorizon++; - if (neighbor->good) - (*goodhorizon)++; - if (qh IStracing >=4) - qh_errprint("horizon", neighbor, NULL, NULL, NULL); - } - } - } - if (!numhorizon) { - qh_precision("empty horizon"); - qh_fprintf(qh ferr, 6168, "qhull precision error (qh_findhorizon): empty horizon\n\ -QhullPoint p%d was above all facets.\n", qh_pointid(point)); - qh_printfacetlist(qh facet_list, NULL, True); - qh_errexit(qh_ERRprec, NULL, NULL); - } - trace1((qh ferr, 1041, "qh_findhorizon: %d horizon facets(good %d), %d visible(good %d), %d coplanar\n", - numhorizon, *goodhorizon, qh num_visible, *goodvisible, coplanar)); - if (qh IStracing >= 4 && qh num_facets < 50) - qh_printlists(); -} /* findhorizon */ - -/*-<a href="qh-qhull.htm#TOC" - >-------------------------------</a><a name="nextfurthest">-</a> - - qh_nextfurthest( visible ) - returns next furthest point and visible facet for qh_addpoint() - starts search at qh.facet_next - - returns: - removes furthest point from outside set - NULL if none available - advances qh.facet_next over facets with empty outside sets - - design: - for each facet from qh.facet_next - if empty outside set - advance qh.facet_next - else if qh.NARROWhull - determine furthest outside point - if furthest point is not outside - advance qh.facet_next(point will be coplanar) - remove furthest point from outside set -*/ -pointT *qh_nextfurthest(facetT **visible) { - facetT *facet; - int size, idx; - realT randr, dist; - pointT *furthest; - - while ((facet= qh facet_next) != qh facet_tail) { - if (!facet->outsideset) { - qh facet_next= facet->next; - continue; - } - SETreturnsize_(facet->outsideset, size); - if (!size) { - qh_setfree(&facet->outsideset); - qh facet_next= facet->next; - continue; - } - if (qh NARROWhull) { - if (facet->notfurthest) - qh_furthestout(facet); - furthest= (pointT*)qh_setlast(facet->outsideset); -#if qh_COMPUTEfurthest - qh_distplane(furthest, facet, &dist); - zinc_(Zcomputefurthest); -#else - dist= facet->furthestdist; -#endif - if (dist < qh MINoutside) { /* remainder of outside set is coplanar for qh_outcoplanar */ - qh facet_next= facet->next; - continue; - } - } - if (!qh RANDOMoutside && !qh VIRTUALmemory) { - if (qh PICKfurthest) { - qh_furthestnext(/* qh facet_list */); - facet= qh facet_next; - } - *visible= facet; - return((pointT*)qh_setdellast(facet->outsideset)); - } - if (qh RANDOMoutside) { - int outcoplanar = 0; - if (qh NARROWhull) { - FORALLfacets { - if (facet == qh facet_next) - break; - if (facet->outsideset) - outcoplanar += qh_setsize( facet->outsideset); - } - } - randr= qh_RANDOMint; - randr= randr/(qh_RANDOMmax+1); - idx= (int)floor((qh num_outside - outcoplanar) * randr); - FORALLfacet_(qh facet_next) { - if (facet->outsideset) { - SETreturnsize_(facet->outsideset, size); - if (!size) - qh_setfree(&facet->outsideset); - else if (size > idx) { - *visible= facet; - return((pointT*)qh_setdelnth(facet->outsideset, idx)); - }else - idx -= size; - } - } - qh_fprintf(qh ferr, 6169, "qhull internal error (qh_nextfurthest): num_outside %d is too low\nby at least %d, or a random real %g >= 1.0\n", - qh num_outside, idx+1, randr); - qh_errexit(qh_ERRqhull, NULL, NULL); - }else { /* VIRTUALmemory */ - facet= qh facet_tail->previous; - if (!(furthest= (pointT*)qh_setdellast(facet->outsideset))) { - if (facet->outsideset) - qh_setfree(&facet->outsideset); - qh_removefacet(facet); - qh_prependfacet(facet, &qh facet_list); - continue; - } - *visible= facet; - return furthest; - } - } - return NULL; -} /* nextfurthest */ - -/*-<a href="qh-qhull.htm#TOC" - >-------------------------------</a><a name="partitionall">-</a> - - qh_partitionall( vertices, points, numpoints ) - partitions all points in points/numpoints to the outsidesets of facets - vertices= vertices in qh.facet_list(!partitioned) - - returns: - builds facet->outsideset - does not partition qh.GOODpoint - if qh.ONLYgood && !qh.MERGING, - does not partition qh.GOODvertex - - notes: - faster if qh.facet_list sorted by anticipated size of outside set - - design: - initialize pointset with all points - remove vertices from pointset - remove qh.GOODpointp from pointset (unless it's qh.STOPcone or qh.STOPpoint) - for all facets - for all remaining points in pointset - compute distance from point to facet - if point is outside facet - remove point from pointset (by not reappending) - update bestpoint - append point or old bestpoint to facet's outside set - append bestpoint to facet's outside set (furthest) - for all points remaining in pointset - partition point into facets' outside sets and coplanar sets -*/ -void qh_partitionall(setT *vertices, pointT *points, int numpoints){ - setT *pointset; - vertexT *vertex, **vertexp; - pointT *point, **pointp, *bestpoint; - int size, point_i, point_n, point_end, remaining, i, id; - facetT *facet; - realT bestdist= -REALmax, dist, distoutside; - - trace1((qh ferr, 1042, "qh_partitionall: partition all points into outside sets\n")); - pointset= qh_settemp(numpoints); - qh num_outside= 0; - pointp= SETaddr_(pointset, pointT); - for (i=numpoints, point= points; i--; point += qh hull_dim) - *(pointp++)= point; - qh_settruncate(pointset, numpoints); - FOREACHvertex_(vertices) { - if ((id= qh_pointid(vertex->point)) >= 0) - SETelem_(pointset, id)= NULL; - } - id= qh_pointid(qh GOODpointp); - if (id >=0 && qh STOPcone-1 != id && -qh STOPpoint-1 != id) - SETelem_(pointset, id)= NULL; - if (qh GOODvertexp && qh ONLYgood && !qh MERGING) { /* matches qhull()*/ - if ((id= qh_pointid(qh GOODvertexp)) >= 0) - SETelem_(pointset, id)= NULL; - } - if (!qh BESToutside) { /* matches conditional for qh_partitionpoint below */ - distoutside= qh_DISToutside; /* multiple of qh.MINoutside & qh.max_outside, see user.h */ - zval_(Ztotpartition)= qh num_points - qh hull_dim - 1; /*misses GOOD... */ - remaining= qh num_facets; - point_end= numpoints; - FORALLfacets { - size= point_end/(remaining--) + 100; - facet->outsideset= qh_setnew(size); - bestpoint= NULL; - point_end= 0; - FOREACHpoint_i_(pointset) { - if (point) { - zzinc_(Zpartitionall); - qh_distplane(point, facet, &dist); - if (dist < distoutside) - SETelem_(pointset, point_end++)= point; - else { - qh num_outside++; - if (!bestpoint) { - bestpoint= point; - bestdist= dist; - }else if (dist > bestdist) { - qh_setappend(&facet->outsideset, bestpoint); - bestpoint= point; - bestdist= dist; - }else - qh_setappend(&facet->outsideset, point); - } - } - } - if (bestpoint) { - qh_setappend(&facet->outsideset, bestpoint); -#if !qh_COMPUTEfurthest - facet->furthestdist= bestdist; -#endif - }else - qh_setfree(&facet->outsideset); - qh_settruncate(pointset, point_end); - } - } - /* if !qh BESToutside, pointset contains points not assigned to outsideset */ - if (qh BESToutside || qh MERGING || qh KEEPcoplanar || qh KEEPinside) { - qh findbestnew= True; - FOREACHpoint_i_(pointset) { - if (point) - qh_partitionpoint(point, qh facet_list); - } - qh findbestnew= False; - } - zzadd_(Zpartitionall, zzval_(Zpartition)); - zzval_(Zpartition)= 0; - qh_settempfree(&pointset); - if (qh IStracing >= 4) - qh_printfacetlist(qh facet_list, NULL, True); -} /* partitionall */ - - -/*-<a href="qh-qhull.htm#TOC" - >-------------------------------</a><a name="partitioncoplanar">-</a> - - qh_partitioncoplanar( point, facet, dist ) - partition coplanar point to a facet - dist is distance from point to facet - if dist NULL, - searches for bestfacet and does nothing if inside - if qh.findbestnew set, - searches new facets instead of using qh_findbest() - - returns: - qh.max_ouside updated - if qh.KEEPcoplanar or qh.KEEPinside - point assigned to best coplanarset - - notes: - facet->maxoutside is updated at end by qh_check_maxout - - design: - if dist undefined - find best facet for point - if point sufficiently below facet (depends on qh.NEARinside and qh.KEEPinside) - exit - if keeping coplanar/nearinside/inside points - if point is above furthest coplanar point - append point to coplanar set (it is the new furthest) - update qh.max_outside - else - append point one before end of coplanar set - else if point is clearly outside of qh.max_outside and bestfacet->coplanarset - and bestfacet is more than perpendicular to facet - repartition the point using qh_findbest() -- it may be put on an outsideset - else - update qh.max_outside -*/ -void qh_partitioncoplanar(pointT *point, facetT *facet, realT *dist) { - facetT *bestfacet; - pointT *oldfurthest; - realT bestdist, dist2= 0, angle; - int numpart= 0, oldfindbest; - boolT isoutside; - - qh WAScoplanar= True; - if (!dist) { - if (qh findbestnew) - bestfacet= qh_findbestnew(point, facet, &bestdist, qh_ALL, &isoutside, &numpart); - else - bestfacet= qh_findbest(point, facet, qh_ALL, !qh_ISnewfacets, qh DELAUNAY, - &bestdist, &isoutside, &numpart); - zinc_(Ztotpartcoplanar); - zzadd_(Zpartcoplanar, numpart); - if (!qh DELAUNAY && !qh KEEPinside) { /* for 'd', bestdist skips upperDelaunay facets */ - if (qh KEEPnearinside) { - if (bestdist < -qh NEARinside) { - zinc_(Zcoplanarinside); - trace4((qh ferr, 4062, "qh_partitioncoplanar: point p%d is more than near-inside facet f%d dist %2.2g findbestnew %d\n", - qh_pointid(point), bestfacet->id, bestdist, qh findbestnew)); - return; - } - }else if (bestdist < -qh MAXcoplanar) { - trace4((qh ferr, 4063, "qh_partitioncoplanar: point p%d is inside facet f%d dist %2.2g findbestnew %d\n", - qh_pointid(point), bestfacet->id, bestdist, qh findbestnew)); - zinc_(Zcoplanarinside); - return; - } - } - }else { - bestfacet= facet; - bestdist= *dist; - } - if (bestdist > qh max_outside) { - if (!dist && facet != bestfacet) { - zinc_(Zpartangle); - angle= qh_getangle(facet->normal, bestfacet->normal); - if (angle < 0) { - /* typically due to deleted vertex and coplanar facets, e.g., - RBOX 1000 s Z1 G1e-13 t1001185205 | QHULL Tv */ - zinc_(Zpartflip); - trace2((qh ferr, 2058, "qh_partitioncoplanar: repartition point p%d from f%d. It is above flipped facet f%d dist %2.2g\n", - qh_pointid(point), facet->id, bestfacet->id, bestdist)); - oldfindbest= qh findbestnew; - qh findbestnew= False; - qh_partitionpoint(point, bestfacet); - qh findbestnew= oldfindbest; - return; - } - } - qh max_outside= bestdist; - if (bestdist > qh TRACEdist) { - qh_fprintf(qh ferr, 8122, "qh_partitioncoplanar: ====== p%d from f%d increases max_outside to %2.2g of f%d last p%d\n", - qh_pointid(point), facet->id, bestdist, bestfacet->id, qh furthest_id); - qh_errprint("DISTANT", facet, bestfacet, NULL, NULL); - } - } - if (qh KEEPcoplanar + qh KEEPinside + qh KEEPnearinside) { - oldfurthest= (pointT*)qh_setlast(bestfacet->coplanarset); - if (oldfurthest) { - zinc_(Zcomputefurthest); - qh_distplane(oldfurthest, bestfacet, &dist2); - } - if (!oldfurthest || dist2 < bestdist) - qh_setappend(&bestfacet->coplanarset, point); - else - qh_setappend2ndlast(&bestfacet->coplanarset, point); - } - trace4((qh ferr, 4064, "qh_partitioncoplanar: point p%d is coplanar with facet f%d(or inside) dist %2.2g\n", - qh_pointid(point), bestfacet->id, bestdist)); -} /* partitioncoplanar */ - -/*-<a href="qh-qhull.htm#TOC" - >-------------------------------</a><a name="partitionpoint">-</a> - - qh_partitionpoint( point, facet ) - assigns point to an outside set, coplanar set, or inside set (i.e., dropt) - if qh.findbestnew - uses qh_findbestnew() to search all new facets - else - uses qh_findbest() - - notes: - after qh_distplane(), this and qh_findbest() are most expensive in 3-d - - design: - find best facet for point - (either exhaustive search of new facets or directed search from facet) - if qh.NARROWhull - retain coplanar and nearinside points as outside points - if point is outside bestfacet - if point above furthest point for bestfacet - append point to outside set (it becomes the new furthest) - if outside set was empty - move bestfacet to end of qh.facet_list (i.e., after qh.facet_next) - update bestfacet->furthestdist - else - append point one before end of outside set - else if point is coplanar to bestfacet - if keeping coplanar points or need to update qh.max_outside - partition coplanar point into bestfacet - else if near-inside point - partition as coplanar point into bestfacet - else is an inside point - if keeping inside points - partition as coplanar point into bestfacet -*/ -void qh_partitionpoint(pointT *point, facetT *facet) { - realT bestdist; - boolT isoutside; - facetT *bestfacet; - int numpart; -#if qh_COMPUTEfurthest - realT dist; -#endif - - if (qh findbestnew) - bestfacet= qh_findbestnew(point, facet, &bestdist, qh BESToutside, &isoutside, &numpart); - else - bestfacet= qh_findbest(point, facet, qh BESToutside, qh_ISnewfacets, !qh_NOupper, - &bestdist, &isoutside, &numpart); - zinc_(Ztotpartition); - zzadd_(Zpartition, numpart); - if (qh NARROWhull) { - if (qh DELAUNAY && !isoutside && bestdist >= -qh MAXcoplanar) - qh_precision("nearly incident point(narrow hull)"); - if (qh KEEPnearinside) { - if (bestdist >= -qh NEARinside) - isoutside= True; - }else if (bestdist >= -qh MAXcoplanar) - isoutside= True; - } - - if (isoutside) { - if (!bestfacet->outsideset - || !qh_setlast(bestfacet->outsideset)) { - qh_setappend(&(bestfacet->outsideset), point); - if (!bestfacet->newfacet) { - qh_removefacet(bestfacet); /* make sure it's after qh facet_next */ - qh_appendfacet(bestfacet); - } -#if !qh_COMPUTEfurthest - bestfacet->furthestdist= bestdist; -#endif - }else { -#if qh_COMPUTEfurthest - zinc_(Zcomputefurthest); - qh_distplane(oldfurthest, bestfacet, &dist); - if (dist < bestdist) - qh_setappend(&(bestfacet->outsideset), point); - else - qh_setappend2ndlast(&(bestfacet->outsideset), point); -#else - if (bestfacet->furthestdist < bestdist) { - qh_setappend(&(bestfacet->outsideset), point); - bestfacet->furthestdist= bestdist; - }else - qh_setappend2ndlast(&(bestfacet->outsideset), point); -#endif - } - qh num_outside++; - trace4((qh ferr, 4065, "qh_partitionpoint: point p%d is outside facet f%d new? %d (or narrowhull)\n", - qh_pointid(point), bestfacet->id, bestfacet->newfacet)); - }else if (qh DELAUNAY || bestdist >= -qh MAXcoplanar) { /* for 'd', bestdist skips upperDelaunay facets */ - zzinc_(Zcoplanarpart); - if (qh DELAUNAY) - qh_precision("nearly incident point"); - if ((qh KEEPcoplanar + qh KEEPnearinside) || bestdist > qh max_outside) - qh_partitioncoplanar(point, bestfacet, &bestdist); - else { - trace4((qh ferr, 4066, "qh_partitionpoint: point p%d is coplanar to facet f%d (dropped)\n", - qh_pointid(point), bestfacet->id)); - } - }else if (qh KEEPnearinside && bestdist > -qh NEARinside) { - zinc_(Zpartnear); - qh_partitioncoplanar(point, bestfacet, &bestdist); - }else { - zinc_(Zpartinside); - trace4((qh ferr, 4067, "qh_partitionpoint: point p%d is inside all facets, closest to f%d dist %2.2g\n", - qh_pointid(point), bestfacet->id, bestdist)); - if (qh KEEPinside) - qh_partitioncoplanar(point, bestfacet, &bestdist); - } -} /* partitionpoint */ - -/*-<a href="qh-qhull.htm#TOC" - >-------------------------------</a><a name="partitionvisible">-</a> - - qh_partitionvisible( allpoints, numoutside ) - partitions points in visible facets to qh.newfacet_list - qh.visible_list= visible facets - for visible facets - 1st neighbor (if any) points to a horizon facet or a new facet - if allpoints(!used), - repartitions coplanar points - - returns: - updates outside sets and coplanar sets of qh.newfacet_list - updates qh.num_outside (count of outside points) - - notes: - qh.findbest_notsharp should be clear (extra work if set) - - design: - for all visible facets with outside set or coplanar set - select a newfacet for visible facet - if outside set - partition outside set into new facets - if coplanar set and keeping coplanar/near-inside/inside points - if allpoints - partition coplanar set into new facets, may be assigned outside - else - partition coplanar set into coplanar sets of new facets - for each deleted vertex - if allpoints - partition vertex into new facets, may be assigned outside - else - partition vertex into coplanar sets of new facets -*/ -void qh_partitionvisible(/*visible_list*/ boolT allpoints, int *numoutside) { - facetT *visible, *newfacet; - pointT *point, **pointp; - int coplanar=0, size; - unsigned count; - vertexT *vertex, **vertexp; - - if (qh ONLYmax) - maximize_(qh MINoutside, qh max_vertex); - *numoutside= 0; - FORALLvisible_facets { - if (!visible->outsideset && !visible->coplanarset) - continue; - newfacet= visible->f.replace; - count= 0; - while (newfacet && newfacet->visible) { - newfacet= newfacet->f.replace; - if (count++ > qh facet_id) - qh_infiniteloop(visible); - } - if (!newfacet) - newfacet= qh newfacet_list; - if (newfacet == qh facet_tail) { - qh_fprintf(qh ferr, 6170, "qhull precision error (qh_partitionvisible): all new facets deleted as\n degenerate facets. Can not continue.\n"); - qh_errexit(qh_ERRprec, NULL, NULL); - } - if (visible->outsideset) { - size= qh_setsize(visible->outsideset); - *numoutside += size; - qh num_outside -= size; - FOREACHpoint_(visible->outsideset) - qh_partitionpoint(point, newfacet); - } - if (visible->coplanarset && (qh KEEPcoplanar + qh KEEPinside + qh KEEPnearinside)) { - size= qh_setsize(visible->coplanarset); - coplanar += size; - FOREACHpoint_(visible->coplanarset) { - if (allpoints) /* not used */ - qh_partitionpoint(point, newfacet); - else - qh_partitioncoplanar(point, newfacet, NULL); - } - } - } - FOREACHvertex_(qh del_vertices) { - if (vertex->point) { - if (allpoints) /* not used */ - qh_partitionpoint(vertex->point, qh newfacet_list); - else - qh_partitioncoplanar(vertex->point, qh newfacet_list, NULL); - } - } - trace1((qh ferr, 1043,"qh_partitionvisible: partitioned %d points from outsidesets and %d points from coplanarsets\n", *numoutside, coplanar)); -} /* partitionvisible */ - - - -/*-<a href="qh-qhull.htm#TOC" - >-------------------------------</a><a name="precision">-</a> - - qh_precision( reason ) - restart on precision errors if not merging and if 'QJn' -*/ -void qh_precision(const char *reason) { - - if (qh ALLOWrestart && !qh PREmerge && !qh MERGEexact) { - if (qh JOGGLEmax < REALmax/2) { - trace0((qh ferr, 26, "qh_precision: qhull restart because of %s\n", reason)); - longjmp(qh restartexit, qh_ERRprec); - } - } -} /* qh_precision */ - -/*-<a href="qh-qhull.htm#TOC" - >-------------------------------</a><a name="printsummary">-</a> - - qh_printsummary( fp ) - prints summary to fp - - notes: - not in io.c so that user_eg.c can prevent io.c from loading - qh_printsummary and qh_countfacets must match counts - - design: - determine number of points, vertices, and coplanar points - print summary -*/ -void qh_printsummary(FILE *fp) { - realT ratio, outerplane, innerplane; - float cpu; - int size, id, nummerged, numvertices, numcoplanars= 0, nonsimplicial=0; - int goodused; - facetT *facet; - const char *s; - int numdel= zzval_(Zdelvertextot); - int numtricoplanars= 0; - - size= qh num_points + qh_setsize(qh other_points); - numvertices= qh num_vertices - qh_setsize(qh del_vertices); - id= qh_pointid(qh GOODpointp); - FORALLfacets { - if (facet->coplanarset) - numcoplanars += qh_setsize( facet->coplanarset); - if (facet->good) { - if (facet->simplicial) { - if (facet->keepcentrum && facet->tricoplanar) - numtricoplanars++; - }else if (qh_setsize(facet->vertices) != qh hull_dim) - nonsimplicial++; - } - } - if (id >=0 && qh STOPcone-1 != id && -qh STOPpoint-1 != id) - size--; - if (qh STOPcone || qh STOPpoint) - qh_fprintf(fp, 9288, "\nAt a premature exit due to 'TVn', 'TCn', 'TRn', or precision error with 'QJn'."); - if (qh UPPERdelaunay) - goodused= qh GOODvertex + qh GOODpoint + qh SPLITthresholds; - else if (qh DELAUNAY) - goodused= qh GOODvertex + qh GOODpoint + qh GOODthreshold; - else - goodused= qh num_good; - nummerged= zzval_(Ztotmerge) - zzval_(Zcyclehorizon) + zzval_(Zcyclefacettot); - if (qh VORONOI) { - if (qh UPPERdelaunay) - qh_fprintf(fp, 9289, "\n\ -Furthest-site Voronoi vertices by the convex hull of %d points in %d-d:\n\n", size, qh hull_dim); - else - qh_fprintf(fp, 9290, "\n\ -Voronoi diagram by the convex hull of %d points in %d-d:\n\n", size, qh hull_dim); - qh_fprintf(fp, 9291, " Number of Voronoi regions%s: %d\n", - qh ATinfinity ? " and at-infinity" : "", numvertices); - if (numdel) - qh_fprintf(fp, 9292, " Total number of deleted points due to merging: %d\n", numdel); - if (numcoplanars - numdel > 0) - qh_fprintf(fp, 9293, " Number of nearly incident points: %d\n", numcoplanars - numdel); - else if (size - numvertices - numdel > 0) - qh_fprintf(fp, 9294, " Total number of nearly incident points: %d\n", size - numvertices - numdel); - qh_fprintf(fp, 9295, " Number of%s Voronoi vertices: %d\n", - goodused ? " 'good'" : "", qh num_good); - if (nonsimplicial) - qh_fprintf(fp, 9296, " Number of%s non-simplicial Voronoi vertices: %d\n", - goodused ? " 'good'" : "", nonsimplicial); - }else if (qh DELAUNAY) { - if (qh UPPERdelaunay) - qh_fprintf(fp, 9297, "\n\ -Furthest-site Delaunay triangulation by the convex hull of %d points in %d-d:\n\n", size, qh hull_dim); - else - qh_fprintf(fp, 9298, "\n\ -Delaunay triangulation by the convex hull of %d points in %d-d:\n\n", size, qh hull_dim); - qh_fprintf(fp, 9299, " Number of input sites%s: %d\n", - qh ATinfinity ? " and at-infinity" : "", numvertices); - if (numdel) - qh_fprintf(fp, 9300, " Total number of deleted points due to merging: %d\n", numdel); - if (numcoplanars - numdel > 0) - qh_fprintf(fp, 9301, " Number of nearly incident points: %d\n", numcoplanars - numdel); - else if (size - numvertices - numdel > 0) - qh_fprintf(fp, 9302, " Total number of nearly incident points: %d\n", size - numvertices - numdel); - qh_fprintf(fp, 9303, " Number of%s Delaunay regions: %d\n", - goodused ? " 'good'" : "", qh num_good); - if (nonsimplicial) - qh_fprintf(fp, 9304, " Number of%s non-simplicial Delaunay regions: %d\n", - goodused ? " 'good'" : "", nonsimplicial); - }else if (qh HALFspace) { - qh_fprintf(fp, 9305, "\n\ -Halfspace intersection by the convex hull of %d points in %d-d:\n\n", size, qh hull_dim); - qh_fprintf(fp, 9306, " Number of halfspaces: %d\n", size); - qh_fprintf(fp, 9307, " Number of non-redundant halfspaces: %d\n", numvertices); - if (numcoplanars) { - if (qh KEEPinside && qh KEEPcoplanar) - s= "similar and redundant"; - else if (qh KEEPinside) - s= "redundant"; - else - s= "similar"; - qh_fprintf(fp, 9308, " Number of %s halfspaces: %d\n", s, numcoplanars); - } - qh_fprintf(fp, 9309, " Number of intersection points: %d\n", qh num_facets - qh num_visible); - if (goodused) - qh_fprintf(fp, 9310, " Number of 'good' intersection points: %d\n", qh num_good); - if (nonsimplicial) - qh_fprintf(fp, 9311, " Number of%s non-simplicial intersection points: %d\n", - goodused ? " 'good'" : "", nonsimplicial); - }else { - qh_fprintf(fp, 9312, "\n\ -Convex hull of %d points in %d-d:\n\n", size, qh hull_dim); - qh_fprintf(fp, 9313, " Number of vertices: %d\n", numvertices); - if (numcoplanars) { - if (qh KEEPinside && qh KEEPcoplanar) - s= "coplanar and interior"; - else if (qh KEEPinside) - s= "interior"; - else - s= "coplanar"; - qh_fprintf(fp, 9314, " Number of %s points: %d\n", s, numcoplanars); - } - qh_fprintf(fp, 9315, " Number of facets: %d\n", qh num_facets - qh num_visible); - if (goodused) - qh_fprintf(fp, 9316, " Number of 'good' facets: %d\n", qh num_good); - if (nonsimplicial) - qh_fprintf(fp, 9317, " Number of%s non-simplicial facets: %d\n", - goodused ? " 'good'" : "", nonsimplicial); - } - if (numtricoplanars) - qh_fprintf(fp, 9318, " Number of triangulated facets: %d\n", numtricoplanars); - qh_fprintf(fp, 9319, "\nStatistics for: %s | %s", - qh rbox_command, qh qhull_command); - if (qh ROTATErandom != INT_MIN) - qh_fprintf(fp, 9320, " QR%d\n\n", qh ROTATErandom); - else - qh_fprintf(fp, 9321, "\n\n"); - qh_fprintf(fp, 9322, " Number of points processed: %d\n", zzval_(Zprocessed)); - qh_fprintf(fp, 9323, " Number of hyperplanes created: %d\n", zzval_(Zsetplane)); - if (qh DELAUNAY) - qh_fprintf(fp, 9324, " Number of facets in hull: %d\n", qh num_facets - qh num_visible); - qh_fprintf(fp, 9325, " Number of distance tests for qhull: %d\n", zzval_(Zpartition)+ - zzval_(Zpartitionall)+zzval_(Znumvisibility)+zzval_(Zpartcoplanar)); -#if 0 /* NOTE: must print before printstatistics() */ - {realT stddev, ave; - qh_fprintf(fp, 9326, " average new facet balance: %2.2g\n", - wval_(Wnewbalance)/zval_(Zprocessed)); - stddev= qh_stddev(zval_(Zprocessed), wval_(Wnewbalance), - wval_(Wnewbalance2), &ave); - qh_fprintf(fp, 9327, " new facet standard deviation: %2.2g\n", stddev); - qh_fprintf(fp, 9328, " average partition balance: %2.2g\n", - wval_(Wpbalance)/zval_(Zpbalance)); - stddev= qh_stddev(zval_(Zpbalance), wval_(Wpbalance), - wval_(Wpbalance2), &ave); - qh_fprintf(fp, 9329, " partition standard deviation: %2.2g\n", stddev); - } -#endif - if (nummerged) { - qh_fprintf(fp, 9330," Number of distance tests for merging: %d\n",zzval_(Zbestdist)+ - zzval_(Zcentrumtests)+zzval_(Zdistconvex)+zzval_(Zdistcheck)+ - zzval_(Zdistzero)); - qh_fprintf(fp, 9331," Number of distance tests for checking: %d\n",zzval_(Zcheckpart)); - qh_fprintf(fp, 9332," Number of merged facets: %d\n", nummerged); - } - if (!qh RANDOMoutside && qh QHULLfinished) { - cpu= (float)qh hulltime; - cpu /= (float)qh_SECticks; - wval_(Wcpu)= cpu; - qh_fprintf(fp, 9333, " CPU seconds to compute hull (after input): %2.4g\n", cpu); - } - if (qh RERUN) { - if (!qh PREmerge && !qh MERGEexact) - qh_fprintf(fp, 9334, " Percentage of runs with precision errors: %4.1f\n", - zzval_(Zretry)*100.0/qh build_cnt); /* careful of order */ - }else if (qh JOGGLEmax < REALmax/2) { - if (zzval_(Zretry)) - qh_fprintf(fp, 9335, " After %d retries, input joggled by: %2.2g\n", - zzval_(Zretry), qh JOGGLEmax); - else - qh_fprintf(fp, 9336, " Input joggled by: %2.2g\n", qh JOGGLEmax); - } - if (qh totarea != 0.0) - qh_fprintf(fp, 9337, " %s facet area: %2.8g\n", - zzval_(Ztotmerge) ? "Approximate" : "Total", qh totarea); - if (qh totvol != 0.0) - qh_fprintf(fp, 9338, " %s volume: %2.8g\n", - zzval_(Ztotmerge) ? "Approximate" : "Total", qh totvol); - if (qh MERGING) { - qh_outerinner(NULL, &outerplane, &innerplane); - if (outerplane > 2 * qh DISTround) { - qh_fprintf(fp, 9339, " Maximum distance of %spoint above facet: %2.2g", - (qh QHULLfinished ? "" : "merged "), outerplane); - ratio= outerplane/(qh ONEmerge + qh DISTround); - /* don't report ratio if MINoutside is large */ - if (ratio > 0.05 && 2* qh ONEmerge > qh MINoutside && qh JOGGLEmax > REALmax/2) - qh_fprintf(fp, 9340, " (%.1fx)\n", ratio); - else - qh_fprintf(fp, 9341, "\n"); - } - if (innerplane < -2 * qh DISTround) { - qh_fprintf(fp, 9342, " Maximum distance of %svertex below facet: %2.2g", - (qh QHULLfinished ? "" : "merged "), innerplane); - ratio= -innerplane/(qh ONEmerge+qh DISTround); - if (ratio > 0.05 && qh JOGGLEmax > REALmax/2) - qh_fprintf(fp, 9343, " (%.1fx)\n", ratio); - else - qh_fprintf(fp, 9344, "\n"); - } - } - qh_fprintf(fp, 9345, "\n"); -} /* printsummary */ - - diff --git a/PyMca/Object3D/Object3DQhull/src/libqhull.h b/PyMca/Object3D/Object3DQhull/src/libqhull.h deleted file mode 100644 index 7a13226..0000000 --- a/PyMca/Object3D/Object3DQhull/src/libqhull.h +++ /dev/null @@ -1,1100 +0,0 @@ -/*<html><pre> -<a href="qh-qhull.htm" - >-------------------------------</a><a name="TOP">-</a> - - libqhull.h - user-level header file for using qhull.a library - - see qh-qhull.htm, qhull_a.h - - Copyright (c) 1993-2012 The Geometry Center. - $Id: //main/2011/qhull/src/libqhull/libqhull.h#7 $$Change: 1464 $ - $DateTime: 2012/01/25 22:58:41 $$Author: bbarber $ - - NOTE: access to qh_qh is via the 'qh' macro. This allows - qh_qh to be either a pointer or a structure. An example - of using qh is "qh DROPdim" which accesses the DROPdim - field of qh_qh. Similarly, access to qh_qhstat is via - the 'qhstat' macro. - - includes function prototypes for libqhull.c, geom.c, global.c, io.c, user.c - - use mem.h for mem.c - use qset.h for qset.c - - see unix.c for an example of using libqhull.h - - recompile qhull if you change this file -*/ - -#ifndef qhDEFlibqhull -#define qhDEFlibqhull 1 - -/*=========================== -included files ==============*/ - -#include "user.h" /* user definable constants (e.g., qh_QHpointer) */ - -#include <setjmp.h> -#include <float.h> -#include <time.h> -#include <stdio.h> - -#if __MWERKS__ && __POWERPC__ -#include <SIOUX.h> -#include <Files.h> -#include <Desk.h> -#endif - -#ifndef __STDC__ -#ifndef __cplusplus -#if !_MSC_VER -#error Neither __STDC__ nor __cplusplus is defined. Please use strict ANSI C or C++ to compile -#error Qhull. You may need to turn off compiler extensions in your project configuration. If -#error your compiler is a standard C compiler, you can delete this warning from libqhull.h -#endif -#endif -#endif - -/*============ constants and basic types ====================*/ - -extern const char *qh_version; /* defined in global.c */ - -/*-<a href="qh-geom.htm#TOC" - >--------------------------------</a><a name="coordT">-</a> - - coordT - coordinates and coefficients are stored as realT (i.e., double) - - notes: - Qhull works well if realT is 'float'. If so joggle (QJ) is not effective. - - Could use 'float' for data and 'double' for calculations (realT vs. coordT) - This requires many type casts, and adjusted error bounds. - Also C compilers may do expressions in double anyway. -*/ -#define coordT realT - -/*-<a href="qh-geom.htm#TOC" - >--------------------------------</a><a name="pointT">-</a> - - pointT - a point is an array of coordinates, usually qh.hull_dim -*/ -#define pointT coordT - -/*-<a href="qh-qhull.htm#TOC" - >--------------------------------</a><a name="flagT">-</a> - - flagT - Boolean flag as a bit -*/ -#define flagT unsigned int - -/*-<a href="qh-qhull.htm#TOC" - >--------------------------------</a><a name="boolT">-</a> - - boolT - boolean value, either True or False - - notes: - needed for portability - Use qh_False/qh_True as synonyms -*/ -#define boolT unsigned int -#ifdef False -#undef False -#endif -#ifdef True -#undef True -#endif -#define False 0 -#define True 1 -#define qh_False 0 -#define qh_True 1 - -/*-<a href="qh-qhull.htm#TOC" - >--------------------------------</a><a name="CENTERtype">-</a> - - qh_CENTER - to distinguish facet->center -*/ -typedef enum -{ - qh_ASnone = 0, qh_ASvoronoi, qh_AScentrum -} -qh_CENTER; - -/*-<a href="qh-qhull.htm#TOC" - >--------------------------------</a><a name="qh_PRINT">-</a> - - qh_PRINT - output formats for printing (qh.PRINTout). - 'Fa' 'FV' 'Fc' 'FC' - - - notes: - some of these names are similar to qh names. The similar names are only - used in switch statements in qh_printbegin() etc. -*/ -typedef enum {qh_PRINTnone= 0, - qh_PRINTarea, qh_PRINTaverage, /* 'Fa' 'FV' 'Fc' 'FC' */ - qh_PRINTcoplanars, qh_PRINTcentrums, - qh_PRINTfacets, qh_PRINTfacets_xridge, /* 'f' 'FF' 'G' 'FI' 'Fi' 'Fn' */ - qh_PRINTgeom, qh_PRINTids, qh_PRINTinner, qh_PRINTneighbors, - qh_PRINTnormals, qh_PRINTouter, qh_PRINTmaple, /* 'n' 'Fo' 'i' 'm' 'Fm' 'FM', 'o' */ - qh_PRINTincidences, qh_PRINTmathematica, qh_PRINTmerges, qh_PRINToff, - qh_PRINToptions, qh_PRINTpointintersect, /* 'FO' 'Fp' 'FP' 'p' 'FQ' 'FS' */ - qh_PRINTpointnearest, qh_PRINTpoints, qh_PRINTqhull, qh_PRINTsize, - qh_PRINTsummary, qh_PRINTtriangles, /* 'Fs' 'Ft' 'Fv' 'FN' 'Fx' */ - qh_PRINTvertices, qh_PRINTvneighbors, qh_PRINTextremes, - qh_PRINTEND} qh_PRINT; - -/*-<a href="qh-qhull.htm#TOC" - >--------------------------------</a><a name="qh_ALL">-</a> - - qh_ALL - argument flag for selecting everything -*/ -#define qh_ALL True -#define qh_NOupper True /* argument for qh_findbest */ -#define qh_IScheckmax True /* argument for qh_findbesthorizon */ -#define qh_ISnewfacets True /* argument for qh_findbest */ -#define qh_RESETvisible True /* argument for qh_resetlists */ - -/*-<a href="qh-qhull.htm#TOC" - >--------------------------------</a><a name="qh_ERR">-</a> - - qh_ERR - Qhull exit codes, for indicating errors - See: MSG_ERROR and MSG_WARNING [user.h] -*/ -#define qh_ERRnone 0 /* no error occurred during qhull */ -#define qh_ERRinput 1 /* input inconsistency */ -#define qh_ERRsingular 2 /* singular input data */ -#define qh_ERRprec 3 /* precision error */ -#define qh_ERRmem 4 /* insufficient memory, matches mem.h */ -#define qh_ERRqhull 5 /* internal error detected, matches mem.h */ - -/*-<a href="qh-qhull.htm#TOC" ->--------------------------------</a><a name="qh_FILEstderr">-</a> - -qh_FILEstderr -Fake stderr to distinguish error output from normal output -For C++ interface. Must redefine qh_fprintf_qhull -*/ -#define qh_FILEstderr (FILE*)1 - -/* ============ -structures- ==================== - each of the following structures is defined by a typedef - all realT and coordT fields occur at the beginning of a structure - (otherwise space may be wasted due to alignment) - define all flags together and pack into 32-bit number -*/ - -typedef struct vertexT vertexT; -typedef struct ridgeT ridgeT; -typedef struct facetT facetT; -#ifndef DEFsetT -#define DEFsetT 1 -typedef struct setT setT; /* defined in qset.h */ -#endif - -#ifndef DEFqhstatT -#define DEFqhstatT 1 -typedef struct qhstatT qhstatT; /* defined in stat.h */ -#endif - -/*-<a href="qh-poly.htm#TOC" - >--------------------------------</a><a name="facetT">-</a> - - facetT - defines a facet - - notes: - qhull() generates the hull as a list of facets. - - topological information: - f.previous,next doubly-linked list of facets - f.vertices set of vertices - f.ridges set of ridges - f.neighbors set of neighbors - f.toporient True if facet has top-orientation (else bottom) - - geometric information: - f.offset,normal hyperplane equation - f.maxoutside offset to outer plane -- all points inside - f.center centrum for testing convexity - f.simplicial True if facet is simplicial - f.flipped True if facet does not include qh.interior_point - - for constructing hull: - f.visible True if facet on list of visible facets (will be deleted) - f.newfacet True if facet on list of newly created facets - f.coplanarset set of points coplanar with this facet - (includes near-inside points for later testing) - f.outsideset set of points outside of this facet - f.furthestdist distance to furthest point of outside set - f.visitid marks visited facets during a loop - f.replace replacement facet for to-be-deleted, visible facets - f.samecycle,newcycle cycle of facets for merging into horizon facet - - see below for other flags and fields -*/ -struct facetT { -#if !qh_COMPUTEfurthest - coordT furthestdist;/* distance to furthest point of outsideset */ -#endif -#if qh_MAXoutside - coordT maxoutside; /* max computed distance of point to facet - Before QHULLfinished this is an approximation - since maxdist not always set for mergefacet - Actual outer plane is +DISTround and - computed outer plane is +2*DISTround */ -#endif - coordT offset; /* exact offset of hyperplane from origin */ - coordT *normal; /* normal of hyperplane, hull_dim coefficients */ - /* if tricoplanar, shared with a neighbor */ - union { /* in order of testing */ - realT area; /* area of facet, only in io.c if ->isarea */ - facetT *replace; /* replacement facet if ->visible and NEWfacets - is NULL only if qh_mergedegen_redundant or interior */ - facetT *samecycle; /* cycle of facets from the same visible/horizon intersection, - if ->newfacet */ - facetT *newcycle; /* in horizon facet, current samecycle of new facets */ - facetT *trivisible; /* visible facet for ->tricoplanar facets during qh_triangulate() */ - facetT *triowner; /* owner facet for ->tricoplanar, !isarea facets w/ ->keepcentrum */ - }f; - coordT *center; /* centrum for convexity, qh CENTERtype == qh_AScentrum */ - /* Voronoi center, qh CENTERtype == qh_ASvoronoi */ - /* if tricoplanar, shared with a neighbor */ - facetT *previous; /* previous facet in the facet_list */ - facetT *next; /* next facet in the facet_list */ - setT *vertices; /* vertices for this facet, inverse sorted by ID - if simplicial, 1st vertex was apex/furthest */ - setT *ridges; /* explicit ridges for nonsimplicial facets. - for simplicial facets, neighbors define the ridges */ - setT *neighbors; /* neighbors of the facet. If simplicial, the kth - neighbor is opposite the kth vertex, and the first - neighbor is the horizon facet for the first vertex*/ - setT *outsideset; /* set of points outside this facet - if non-empty, last point is furthest - if NARROWhull, includes coplanars for partitioning*/ - setT *coplanarset; /* set of points coplanar with this facet - > qh.min_vertex and <= facet->max_outside - a point is assigned to the furthest facet - if non-empty, last point is furthest away */ - unsigned visitid; /* visit_id, for visiting all neighbors, - all uses are independent */ - unsigned id; /* unique identifier from qh facet_id */ - unsigned nummerge:9; /* number of merges */ -#define qh_MAXnummerge 511 /* 2^9-1, 32 flags total, see "flags:" in io.c */ - flagT tricoplanar:1; /* True if TRIangulate and simplicial and coplanar with a neighbor */ - /* all tricoplanars share the same ->center, ->normal, ->offset, ->maxoutside */ - /* all tricoplanars share the same apex */ - /* if ->degenerate, does not span facet (one logical ridge) */ - /* one tricoplanar has ->keepcentrum and ->coplanarset */ - /* during qh_triangulate, f.trivisible points to original facet */ - flagT newfacet:1; /* True if facet on qh newfacet_list (new or merged) */ - flagT visible:1; /* True if visible facet (will be deleted) */ - flagT toporient:1; /* True if created with top orientation - after merging, use ridge orientation */ - flagT simplicial:1;/* True if simplicial facet, ->ridges may be implicit */ - flagT seen:1; /* used to perform operations only once, like visitid */ - flagT seen2:1; /* used to perform operations only once, like visitid */ - flagT flipped:1; /* True if facet is flipped */ - flagT upperdelaunay:1; /* True if facet is upper envelope of Delaunay triangulation */ - flagT notfurthest:1; /* True if last point of outsideset is not furthest*/ - -/*-------- flags primarily for output ---------*/ - flagT good:1; /* True if a facet marked good for output */ - flagT isarea:1; /* True if facet->f.area is defined */ - -/*-------- flags for merging ------------------*/ - flagT dupridge:1; /* True if duplicate ridge in facet */ - flagT mergeridge:1; /* True if facet or neighbor contains a qh_MERGEridge - ->normal defined (also defined for mergeridge2) */ - flagT mergeridge2:1; /* True if neighbor contains a qh_MERGEridge (mark_dupridges */ - flagT coplanar:1; /* True if horizon facet is coplanar at last use */ - flagT mergehorizon:1; /* True if will merge into horizon (->coplanar) */ - flagT cycledone:1;/* True if mergecycle_all already done */ - flagT tested:1; /* True if facet convexity has been tested (false after merge */ - flagT keepcentrum:1; /* True if keep old centrum after a merge, or marks owner for ->tricoplanar */ - flagT newmerge:1; /* True if facet is newly merged for reducevertices */ - flagT degenerate:1; /* True if facet is degenerate (degen_mergeset or ->tricoplanar) */ - flagT redundant:1; /* True if facet is redundant (degen_mergeset) */ -}; - - -/*-<a href="qh-poly.htm#TOC" - >--------------------------------</a><a name="ridgeT">-</a> - - ridgeT - defines a ridge - - notes: - a ridge is hull_dim-1 simplex between two neighboring facets. If the - facets are non-simplicial, there may be more than one ridge between - two facets. E.G. a 4-d hypercube has two triangles between each pair - of neighboring facets. - - topological information: - vertices a set of vertices - top,bottom neighboring facets with orientation - - geometric information: - tested True if ridge is clearly convex - nonconvex True if ridge is non-convex -*/ -struct ridgeT { - setT *vertices; /* vertices belonging to this ridge, inverse sorted by ID - NULL if a degen ridge (matchsame) */ - facetT *top; /* top facet this ridge is part of */ - facetT *bottom; /* bottom facet this ridge is part of */ - unsigned id:24; /* unique identifier, =>room for 8 flags, bit field matches qh.ridge_id */ - flagT seen:1; /* used to perform operations only once */ - flagT tested:1; /* True when ridge is tested for convexity */ - flagT nonconvex:1; /* True if getmergeset detected a non-convex neighbor - only one ridge between neighbors may have nonconvex */ -}; - -/*-<a href="qh-poly.htm#TOC" - >--------------------------------</a><a name="vertexT">-</a> - - vertexT - defines a vertex - - topological information: - next,previous doubly-linked list of all vertices - neighbors set of adjacent facets (only if qh.VERTEXneighbors) - - geometric information: - point array of DIM3 coordinates -*/ -struct vertexT { - vertexT *next; /* next vertex in vertex_list */ - vertexT *previous; /* previous vertex in vertex_list */ - pointT *point; /* hull_dim coordinates (coordT) */ - setT *neighbors; /* neighboring facets of vertex, qh_vertexneighbors() - inits in io.c or after first merge */ - unsigned visitid:31; /* for use with qh vertex_visit, size must match */ - flagT seen2:1; /* another seen flag */ - unsigned id:24; /* unique identifier, bit field matches qh.vertex_id */ - unsigned dim:4; /* dimension of point if non-zero, used by cpp */ - /* =>room for 4 flags */ - flagT seen:1; /* used to perform operations only once */ - flagT delridge:1; /* vertex was part of a deleted ridge */ - flagT deleted:1; /* true if vertex on qh del_vertices */ - flagT newlist:1; /* true if vertex on qh newvertex_list */ -}; - -#define MAX_vdim 15 /* Maximum size of vertex->dim */ - -/*======= -global variables -qh ============================*/ - -/*-<a href="qh-globa.htm#TOC" - >--------------------------------</a><a name="qh">-</a> - - qh - all global variables for qhull are in qh, qhmem, and qhstat - - notes: - qhmem is defined in mem.h, qhstat is defined in stat.h, qhrbox is defined in rboxpoints.h - Access to qh_qh is via the "qh" macro. See qh_QHpointer in user.h - - All global variables for qhull are in qh, qhmem, and qhstat - qh must be unique for each instance of qhull - qhstat may be shared between qhull instances. - qhmem may be shared across multiple instances of Qhull. - Rbox uses global variables rbox_inuse and rbox, but does not persist data across calls. - - Qhull is not multithreaded. Global state could be stored in thread-local storage. -*/ - -extern int qhull_inuse; - -typedef struct qhT qhT; -#if qh_QHpointer_dllimport -#define qh qh_qh-> -__declspec(dllimport) extern qhT *qh_qh; /* allocated in global.c */ -#elif qh_QHpointer -#define qh qh_qh-> -extern qhT *qh_qh; /* allocated in global.c */ -#elif qh_dllimport -#define qh qh_qh. -__declspec(dllimport) extern qhT qh_qh; /* allocated in global.c */ -#else -#define qh qh_qh. -extern qhT qh_qh; -#endif - -struct qhT { - -/*-<a href="qh-globa.htm#TOC" - >--------------------------------</a><a name="qh-const">-</a> - - qh constants - configuration flags and constants for Qhull - - notes: - The user configures Qhull by defining flags. They are - copied into qh by qh_setflags(). qh-quick.htm#options defines the flags. -*/ - boolT ALLpoints; /* true 'Qs' if search all points for initial simplex */ - boolT ANGLEmerge; /* true 'Qa' if sort potential merges by angle */ - boolT APPROXhull; /* true 'Wn' if MINoutside set */ - realT MINoutside; /* 'Wn' min. distance for an outside point */ - boolT ANNOTATEoutput; /* true 'Ta' if annotate output with message codes */ - boolT ATinfinity; /* true 'Qz' if point num_points-1 is "at-infinity" - for improving precision in Delaunay triangulations */ - boolT AVOIDold; /* true 'Q4' if avoid old->new merges */ - boolT BESToutside; /* true 'Qf' if partition points into best outsideset */ - boolT CDDinput; /* true 'Pc' if input uses CDD format (1.0/offset first) */ - boolT CDDoutput; /* true 'PC' if print normals in CDD format (offset first) */ - boolT CHECKfrequently; /* true 'Tc' if checking frequently */ - realT premerge_cos; /* 'A-n' cos_max when pre merging */ - realT postmerge_cos; /* 'An' cos_max when post merging */ - boolT DELAUNAY; /* true 'd' if computing DELAUNAY triangulation */ - boolT DOintersections; /* true 'Gh' if print hyperplane intersections */ - int DROPdim; /* drops dim 'GDn' for 4-d -> 3-d output */ - boolT FORCEoutput; /* true 'Po' if forcing output despite degeneracies */ - int GOODpoint; /* 1+n for 'QGn', good facet if visible/not(-) from point n*/ - pointT *GOODpointp; /* the actual point */ - boolT GOODthreshold; /* true if qh lower_threshold/upper_threshold defined - false if qh SPLITthreshold */ - int GOODvertex; /* 1+n, good facet if vertex for point n */ - pointT *GOODvertexp; /* the actual point */ - boolT HALFspace; /* true 'Hn,n,n' if halfspace intersection */ - int IStracing; /* trace execution, 0=none, 1=least, 4=most, -1=events */ - int KEEParea; /* 'PAn' number of largest facets to keep */ - boolT KEEPcoplanar; /* true 'Qc' if keeping nearest facet for coplanar points */ - boolT KEEPinside; /* true 'Qi' if keeping nearest facet for inside points - set automatically if 'd Qc' */ - int KEEPmerge; /* 'PMn' number of facets to keep with most merges */ - realT KEEPminArea; /* 'PFn' minimum facet area to keep */ - realT MAXcoplanar; /* 'Un' max distance below a facet to be coplanar*/ - boolT MERGEexact; /* true 'Qx' if exact merges (coplanar, degen, dupridge, flipped) */ - boolT MERGEindependent; /* true 'Q2' if merging independent sets */ - boolT MERGING; /* true if exact-, pre- or post-merging, with angle and centrum tests */ - realT premerge_centrum; /* 'C-n' centrum_radius when pre merging. Default is round-off */ - realT postmerge_centrum; /* 'Cn' centrum_radius when post merging. Default is round-off */ - boolT MERGEvertices; /* true 'Q3' if merging redundant vertices */ - realT MINvisible; /* 'Vn' min. distance for a facet to be visible */ - boolT NOnarrow; /* true 'Q10' if no special processing for narrow distributions */ - boolT NOnearinside; /* true 'Q8' if ignore near-inside points when partitioning */ - boolT NOpremerge; /* true 'Q0' if no defaults for C-0 or Qx */ - boolT ONLYgood; /* true 'Qg' if process points with good visible or horizon facets */ - boolT ONLYmax; /* true 'Qm' if only process points that increase max_outside */ - boolT PICKfurthest; /* true 'Q9' if process furthest of furthest points*/ - boolT POSTmerge; /* true if merging after buildhull (Cn or An) */ - boolT PREmerge; /* true if merging during buildhull (C-n or A-n) */ - /* NOTE: some of these names are similar to qh_PRINT names */ - boolT PRINTcentrums; /* true 'Gc' if printing centrums */ - boolT PRINTcoplanar; /* true 'Gp' if printing coplanar points */ - int PRINTdim; /* print dimension for Geomview output */ - boolT PRINTdots; /* true 'Ga' if printing all points as dots */ - boolT PRINTgood; /* true 'Pg' if printing good facets */ - boolT PRINTinner; /* true 'Gi' if printing inner planes */ - boolT PRINTneighbors; /* true 'PG' if printing neighbors of good facets */ - boolT PRINTnoplanes; /* true 'Gn' if printing no planes */ - boolT PRINToptions1st; /* true 'FO' if printing options to stderr */ - boolT PRINTouter; /* true 'Go' if printing outer planes */ - boolT PRINTprecision; /* false 'Pp' if not reporting precision problems */ - qh_PRINT PRINTout[qh_PRINTEND]; /* list of output formats to print */ - boolT PRINTridges; /* true 'Gr' if print ridges */ - boolT PRINTspheres; /* true 'Gv' if print vertices as spheres */ - boolT PRINTstatistics; /* true 'Ts' if printing statistics to stderr */ - boolT PRINTsummary; /* true 's' if printing summary to stderr */ - boolT PRINTtransparent; /* true 'Gt' if print transparent outer ridges */ - boolT PROJECTdelaunay; /* true if DELAUNAY, no readpoints() and - need projectinput() for Delaunay in qh_init_B */ - int PROJECTinput; /* number of projected dimensions 'bn:0Bn:0' */ - boolT QUICKhelp; /* true if quick help message for degen input */ - boolT RANDOMdist; /* true if randomly change distplane and setfacetplane */ - realT RANDOMfactor; /* maximum random perturbation */ - realT RANDOMa; /* qh_randomfactor is randr * RANDOMa + RANDOMb */ - realT RANDOMb; - boolT RANDOMoutside; /* true if select a random outside point */ - int REPORTfreq; /* buildtracing reports every n facets */ - int REPORTfreq2; /* tracemerging reports every REPORTfreq/2 facets */ - int RERUN; /* 'TRn' rerun qhull n times (qh.build_cnt) */ - int ROTATErandom; /* 'QRn' seed, 0 time, >= rotate input */ - boolT SCALEinput; /* true 'Qbk' if scaling input */ - boolT SCALElast; /* true 'Qbb' if scale last coord to max prev coord */ - boolT SETroundoff; /* true 'E' if qh DISTround is predefined */ - boolT SKIPcheckmax; /* true 'Q5' if skip qh_check_maxout */ - boolT SKIPconvex; /* true 'Q6' if skip convexity testing during pre-merge */ - boolT SPLITthresholds; /* true if upper_/lower_threshold defines a region - used only for printing (!for qh ONLYgood) */ - int STOPcone; /* 'TCn' 1+n for stopping after cone for point n */ - /* also used by qh_build_withresart for err exit*/ - int STOPpoint; /* 'TVn' 'TV-n' 1+n for stopping after/before(-) - adding point n */ - int TESTpoints; /* 'QTn' num of test points after qh.num_points. Test points always coplanar. */ - boolT TESTvneighbors; /* true 'Qv' if test vertex neighbors at end */ - int TRACElevel; /* 'Tn' conditional IStracing level */ - int TRACElastrun; /* qh.TRACElevel applies to last qh.RERUN */ - int TRACEpoint; /* 'TPn' start tracing when point n is a vertex */ - realT TRACEdist; /* 'TWn' start tracing when merge distance too big */ - int TRACEmerge; /* 'TMn' start tracing before this merge */ - boolT TRIangulate; /* true 'Qt' if triangulate non-simplicial facets */ - boolT TRInormals; /* true 'Q11' if triangulate duplicates normals (sets Qt) */ - boolT UPPERdelaunay; /* true 'Qu' if computing furthest-site Delaunay */ - boolT USEstdout; /* true 'Tz' if using stdout instead of stderr */ - boolT VERIFYoutput; /* true 'Tv' if verify output at end of qhull */ - boolT VIRTUALmemory; /* true 'Q7' if depth-first processing in buildhull */ - boolT VORONOI; /* true 'v' if computing Voronoi diagram */ - - /*--------input constants ---------*/ - realT AREAfactor; /* 1/(hull_dim-1)! for converting det's to area */ - boolT DOcheckmax; /* true if calling qh_check_maxout (qh_initqhull_globals) */ - char *feasible_string; /* feasible point 'Hn,n,n' for halfspace intersection */ - coordT *feasible_point; /* as coordinates, both malloc'd */ - boolT GETarea; /* true 'Fa', 'FA', 'FS', 'PAn', 'PFn' if compute facet area/Voronoi volume in io.c */ - boolT KEEPnearinside; /* true if near-inside points in coplanarset */ - int hull_dim; /* dimension of hull, set by initbuffers */ - int input_dim; /* dimension of input, set by initbuffers */ - int num_points; /* number of input points */ - pointT *first_point; /* array of input points, see POINTSmalloc */ - boolT POINTSmalloc; /* true if qh first_point/num_points allocated */ - pointT *input_points; /* copy of original qh.first_point for input points for qh_joggleinput */ - boolT input_malloc; /* true if qh input_points malloc'd */ - char qhull_command[256];/* command line that invoked this program */ - int qhull_commandsiz2; /* size of qhull_command at qh_clear_outputflags */ - char rbox_command[256]; /* command line that produced the input points */ - char qhull_options[512];/* descriptive list of options */ - int qhull_optionlen; /* length of last line */ - int qhull_optionsiz; /* size of qhull_options at qh_build_withrestart */ - int qhull_optionsiz2; /* size of qhull_options at qh_clear_outputflags */ - int run_id; /* non-zero, random identifier for this instance of qhull */ - boolT VERTEXneighbors; /* true if maintaining vertex neighbors */ - boolT ZEROcentrum; /* true if 'C-0' or 'C-0 Qx'. sets ZEROall_ok */ - realT *upper_threshold; /* don't print if facet->normal[k]>=upper_threshold[k] - must set either GOODthreshold or SPLITthreshold - if Delaunay, default is 0.0 for upper envelope */ - realT *lower_threshold; /* don't print if facet->normal[k] <=lower_threshold[k] */ - realT *upper_bound; /* scale point[k] to new upper bound */ - realT *lower_bound; /* scale point[k] to new lower bound - project if both upper_ and lower_bound == 0 */ - -/*-<a href="qh-globa.htm#TOC" - >--------------------------------</a><a name="qh-prec">-</a> - - qh precision constants - precision constants for Qhull - - notes: - qh_detroundoff() computes the maximum roundoff error for distance - and other computations. It also sets default values for the - qh constants above. -*/ - realT ANGLEround; /* max round off error for angles */ - realT centrum_radius; /* max centrum radius for convexity (roundoff added) */ - realT cos_max; /* max cosine for convexity (roundoff added) */ - realT DISTround; /* max round off error for distances, 'E' overrides */ - realT MAXabs_coord; /* max absolute coordinate */ - realT MAXlastcoord; /* max last coordinate for qh_scalelast */ - realT MAXsumcoord; /* max sum of coordinates */ - realT MAXwidth; /* max rectilinear width of point coordinates */ - realT MINdenom_1; /* min. abs. value for 1/x */ - realT MINdenom; /* use divzero if denominator < MINdenom */ - realT MINdenom_1_2; /* min. abs. val for 1/x that allows normalization */ - realT MINdenom_2; /* use divzero if denominator < MINdenom_2 */ - realT MINlastcoord; /* min. last coordinate for qh_scalelast */ - boolT NARROWhull; /* set in qh_initialhull if angle < qh_MAXnarrow */ - realT *NEARzero; /* hull_dim array for near zero in gausselim */ - realT NEARinside; /* keep points for qh_check_maxout if close to facet */ - realT ONEmerge; /* max distance for merging simplicial facets */ - realT outside_err; /* application's epsilon for coplanar points - qh_check_bestdist() qh_check_points() reports error if point outside */ - realT WIDEfacet; /* size of wide facet for skipping ridge in - area computation and locking centrum */ - -/*-<a href="qh-globa.htm#TOC" - >--------------------------------</a><a name="qh-codetern">-</a> - - qh internal constants - internal constants for Qhull -*/ - char qhull[sizeof("qhull")]; /* "qhull" for checking ownership while debugging */ - jmp_buf errexit; /* exit label for qh_errexit, defined by setjmp() */ - char jmpXtra[40]; /* extra bytes in case jmp_buf is defined wrong by compiler */ - jmp_buf restartexit; /* restart label for qh_errexit, defined by setjmp() */ - char jmpXtra2[40]; /* extra bytes in case jmp_buf is defined wrong by compiler*/ - FILE *fin; /* pointer to input file, init by qh_meminit */ - FILE *fout; /* pointer to output file */ - FILE *ferr; /* pointer to error file */ - pointT *interior_point; /* center point of the initial simplex*/ - int normal_size; /* size in bytes for facet normals and point coords*/ - int center_size; /* size in bytes for Voronoi centers */ - int TEMPsize; /* size for small, temporary sets (in quick mem) */ - -/*-<a href="qh-globa.htm#TOC" - >--------------------------------</a><a name="qh-lists">-</a> - - qh facet and vertex lists - defines lists of facets, new facets, visible facets, vertices, and - new vertices. Includes counts, next ids, and trace ids. - see: - qh_resetlists() -*/ - facetT *facet_list; /* first facet */ - facetT *facet_tail; /* end of facet_list (dummy facet) */ - facetT *facet_next; /* next facet for buildhull() - previous facets do not have outside sets - NARROWhull: previous facets may have coplanar outside sets for qh_outcoplanar */ - facetT *newfacet_list; /* list of new facets to end of facet_list */ - facetT *visible_list; /* list of visible facets preceeding newfacet_list, - facet->visible set */ - int num_visible; /* current number of visible facets */ - unsigned tracefacet_id; /* set at init, then can print whenever */ - facetT *tracefacet; /* set in newfacet/mergefacet, undone in delfacet*/ - unsigned tracevertex_id; /* set at buildtracing, can print whenever */ - vertexT *tracevertex; /* set in newvertex, undone in delvertex*/ - vertexT *vertex_list; /* list of all vertices, to vertex_tail */ - vertexT *vertex_tail; /* end of vertex_list (dummy vertex) */ - vertexT *newvertex_list; /* list of vertices in newfacet_list, to vertex_tail - all vertices have 'newlist' set */ - int num_facets; /* number of facets in facet_list - includes visble faces (num_visible) */ - int num_vertices; /* number of vertices in facet_list */ - int num_outside; /* number of points in outsidesets (for tracing and RANDOMoutside) - includes coplanar outsideset points for NARROWhull/qh_outcoplanar() */ - int num_good; /* number of good facets (after findgood_all) */ - unsigned facet_id; /* ID of next, new facet from newfacet() */ - unsigned ridge_id:24; /* ID of next, new ridge from newridge() */ - unsigned vertex_id:24; /* ID of next, new vertex from newvertex() */ - -/*-<a href="qh-globa.htm#TOC" - >--------------------------------</a><a name="qh-var">-</a> - - qh global variables - defines minimum and maximum distances, next visit ids, several flags, - and other global variables. - initialize in qh_initbuild or qh_maxmin if used in qh_buildhull -*/ - unsigned long hulltime; /* ignore time to set up input and randomize */ - /* use unsigned to avoid wrap-around errors */ - boolT ALLOWrestart; /* true if qh_precision can use qh.restartexit */ - int build_cnt; /* number of calls to qh_initbuild */ - qh_CENTER CENTERtype; /* current type of facet->center, qh_CENTER */ - int furthest_id; /* pointid of furthest point, for tracing */ - facetT *GOODclosest; /* closest facet to GOODthreshold in qh_findgood */ - boolT hasAreaVolume; /* true if totarea, totvol was defined by qh_getarea */ - boolT hasTriangulation; /* true if triangulation created by qh_triangulate */ - realT JOGGLEmax; /* set 'QJn' if randomly joggle input */ - boolT maxoutdone; /* set qh_check_maxout(), cleared by qh_addpoint() */ - realT max_outside; /* maximum distance from a point to a facet, - before roundoff, not simplicial vertices - actual outer plane is +DISTround and - computed outer plane is +2*DISTround */ - realT max_vertex; /* maximum distance (>0) from vertex to a facet, - before roundoff, due to a merge */ - realT min_vertex; /* minimum distance (<0) from vertex to a facet, - before roundoff, due to a merge - if qh.JOGGLEmax, qh_makenewplanes sets it - recomputed if qh.DOcheckmax, default -qh.DISTround */ - boolT NEWfacets; /* true while visible facets invalid due to new or merge - from makecone/attachnewfacets to deletevisible */ - boolT findbestnew; /* true if partitioning calls qh_findbestnew */ - boolT findbest_notsharp; /* true if new facets are at least 90 degrees */ - boolT NOerrexit; /* true if qh.errexit is not available */ - realT PRINTcradius; /* radius for printing centrums */ - realT PRINTradius; /* radius for printing vertex spheres and points */ - boolT POSTmerging; /* true when post merging */ - int printoutvar; /* temporary variable for qh_printbegin, etc. */ - int printoutnum; /* number of facets printed */ - boolT QHULLfinished; /* True after qhull() is finished */ - realT totarea; /* 'FA': total facet area computed by qh_getarea, hasAreaVolume */ - realT totvol; /* 'FA': total volume computed by qh_getarea, hasAreaVolume */ - unsigned int visit_id; /* unique ID for searching neighborhoods, */ - unsigned int vertex_visit:31; /* unique ID for searching vertices, reset with qh_buildtracing */ - boolT ZEROall_ok; /* True if qh_checkzero always succeeds */ - boolT WAScoplanar; /* True if qh_partitioncoplanar (qh_check_maxout) */ - -/*-<a href="qh-globa.htm#TOC" - >--------------------------------</a><a name="qh-set">-</a> - - qh global sets - defines sets for merging, initial simplex, hashing, extra input points, - and deleted vertices -*/ - setT *facet_mergeset; /* temporary set of merges to be done */ - setT *degen_mergeset; /* temporary set of degenerate and redundant merges */ - setT *hash_table; /* hash table for matching ridges in qh_matchfacets - size is setsize() */ - setT *other_points; /* additional points */ - setT *del_vertices; /* vertices to partition and delete with visible - facets. Have deleted set for checkfacet */ - -/*-<a href="qh-globa.htm#TOC" - >--------------------------------</a><a name="qh-buf">-</a> - - qh global buffers - defines buffers for maxtrix operations, input, and error messages -*/ - coordT *gm_matrix; /* (dim+1)Xdim matrix for geom.c */ - coordT **gm_row; /* array of gm_matrix rows */ - char* line; /* malloc'd input line of maxline+1 chars */ - int maxline; - coordT *half_space; /* malloc'd input array for halfspace (qh normal_size+coordT) */ - coordT *temp_malloc; /* malloc'd input array for points */ - -/*-<a href="qh-globa.htm#TOC" - >--------------------------------</a><a name="qh-static">-</a> - - qh static variables - defines static variables for individual functions - - notes: - do not use 'static' within a function. Multiple instances of qhull - may exist. - - do not assume zero initialization, 'QPn' may cause a restart -*/ - boolT ERREXITcalled; /* true during qh_errexit (prevents duplicate calls */ - boolT firstcentrum; /* for qh_printcentrum */ - boolT old_randomdist; /* save RANDOMdist flag during io, tracing, or statistics */ - setT *coplanarfacetset; /* set of coplanar facets for searching qh_findbesthorizon() */ - realT last_low; /* qh_scalelast parameters for qh_setdelaunay */ - realT last_high; - realT last_newhigh; - unsigned lastreport; /* for qh_buildtracing */ - int mergereport; /* for qh_tracemerging */ - qhstatT *old_qhstat; /* for saving qh_qhstat in save_qhull() and UsingLibQhull. Free with qh_free() */ - setT *old_tempstack; /* for saving qhmem.tempstack in save_qhull */ - int ridgeoutnum; /* number of ridges for 4OFF output (qh_printbegin,etc) */ -}; - -/*=========== -macros- =========================*/ - -/*-<a href="qh-poly.htm#TOC" - >--------------------------------</a><a name="otherfacet_">-</a> - - otherfacet_(ridge, facet) - return neighboring facet for a ridge in facet -*/ -#define otherfacet_(ridge, facet) \ - (((ridge)->top == (facet)) ? (ridge)->bottom : (ridge)->top) - -/*-<a href="qh-poly.htm#TOC" - >--------------------------------</a><a name="getid_">-</a> - - getid_(p) - return int ID for facet, ridge, or vertex - return -1 if NULL -*/ -#define getid_(p) ((p) ? (int)((p)->id) : -1) - -/*============== FORALL macros ===================*/ - -/*-<a href="qh-poly.htm#TOC" - >--------------------------------</a><a name="FORALLfacets">-</a> - - FORALLfacets { ... } - assign 'facet' to each facet in qh.facet_list - - notes: - uses 'facetT *facet;' - assumes last facet is a sentinel - - see: - FORALLfacet_( facetlist ) -*/ -#define FORALLfacets for (facet=qh facet_list;facet && facet->next;facet=facet->next) - -/*-<a href="qh-poly.htm#TOC" - >--------------------------------</a><a name="FORALLpoints">-</a> - - FORALLpoints { ... } - assign 'point' to each point in qh.first_point, qh.num_points - - declare: - coordT *point, *pointtemp; -*/ -#define FORALLpoints FORALLpoint_(qh first_point, qh num_points) - -/*-<a href="qh-poly.htm#TOC" - >--------------------------------</a><a name="FORALLpoint_">-</a> - - FORALLpoint_( points, num) { ... } - assign 'point' to each point in points array of num points - - declare: - coordT *point, *pointtemp; -*/ -#define FORALLpoint_(points, num) for (point= (points), \ - pointtemp= (points)+qh hull_dim*(num); point < pointtemp; point += qh hull_dim) - -/*-<a href="qh-poly.htm#TOC" - >--------------------------------</a><a name="FORALLvertices">-</a> - - FORALLvertices { ... } - assign 'vertex' to each vertex in qh.vertex_list - - declare: - vertexT *vertex; - - notes: - assumes qh.vertex_list terminated with a sentinel -*/ -#define FORALLvertices for (vertex=qh vertex_list;vertex && vertex->next;vertex= vertex->next) - -/*-<a href="qh-poly.htm#TOC" - >--------------------------------</a><a name="FOREACHfacet_">-</a> - - FOREACHfacet_( facets ) { ... } - assign 'facet' to each facet in facets - - declare: - facetT *facet, **facetp; - - see: - <a href="qset.h#FOREACHsetelement_">FOREACHsetelement_</a> -*/ -#define FOREACHfacet_(facets) FOREACHsetelement_(facetT, facets, facet) - -/*-<a href="qh-poly.htm#TOC" - >--------------------------------</a><a name="FOREACHneighbor_">-</a> - - FOREACHneighbor_( facet ) { ... } - assign 'neighbor' to each neighbor in facet->neighbors - - FOREACHneighbor_( vertex ) { ... } - assign 'neighbor' to each neighbor in vertex->neighbors - - declare: - facetT *neighbor, **neighborp; - - see: - <a href="qset.h#FOREACHsetelement_">FOREACHsetelement_</a> -*/ -#define FOREACHneighbor_(facet) FOREACHsetelement_(facetT, facet->neighbors, neighbor) - -/*-<a href="qh-poly.htm#TOC" - >--------------------------------</a><a name="FOREACHpoint_">-</a> - - FOREACHpoint_( points ) { ... } - assign 'point' to each point in points set - - declare: - pointT *point, **pointp; - - see: - <a href="qset.h#FOREACHsetelement_">FOREACHsetelement_</a> -*/ -#define FOREACHpoint_(points) FOREACHsetelement_(pointT, points, point) - -/*-<a href="qh-poly.htm#TOC" - >--------------------------------</a><a name="FOREACHridge_">-</a> - - FOREACHridge_( ridges ) { ... } - assign 'ridge' to each ridge in ridges set - - declare: - ridgeT *ridge, **ridgep; - - see: - <a href="qset.h#FOREACHsetelement_">FOREACHsetelement_</a> -*/ -#define FOREACHridge_(ridges) FOREACHsetelement_(ridgeT, ridges, ridge) - -/*-<a href="qh-poly.htm#TOC" - >--------------------------------</a><a name="FOREACHvertex_">-</a> - - FOREACHvertex_( vertices ) { ... } - assign 'vertex' to each vertex in vertices set - - declare: - vertexT *vertex, **vertexp; - - see: - <a href="qset.h#FOREACHsetelement_">FOREACHsetelement_</a> -*/ -#define FOREACHvertex_(vertices) FOREACHsetelement_(vertexT, vertices,vertex) - -/*-<a href="qh-poly.htm#TOC" - >--------------------------------</a><a name="FOREACHfacet_i_">-</a> - - FOREACHfacet_i_( facets ) { ... } - assign 'facet' and 'facet_i' for each facet in facets set - - declare: - facetT *facet; - int facet_n, facet_i; - - see: - <a href="qset.h#FOREACHsetelement_i_">FOREACHsetelement_i_</a> -*/ -#define FOREACHfacet_i_(facets) FOREACHsetelement_i_(facetT, facets, facet) - -/*-<a href="qh-poly.htm#TOC" - >--------------------------------</a><a name="FOREACHneighbor_i_">-</a> - - FOREACHneighbor_i_( facet ) { ... } - assign 'neighbor' and 'neighbor_i' for each neighbor in facet->neighbors - - FOREACHneighbor_i_( vertex ) { ... } - assign 'neighbor' and 'neighbor_i' for each neighbor in vertex->neighbors - - declare: - facetT *neighbor; - int neighbor_n, neighbor_i; - - see: - <a href="qset.h#FOREACHsetelement_i_">FOREACHsetelement_i_</a> -*/ -#define FOREACHneighbor_i_(facet) FOREACHsetelement_i_(facetT, facet->neighbors, neighbor) - -/*-<a href="qh-poly.htm#TOC" - >--------------------------------</a><a name="FOREACHpoint_i_">-</a> - - FOREACHpoint_i_( points ) { ... } - assign 'point' and 'point_i' for each point in points set - - declare: - pointT *point; - int point_n, point_i; - - see: - <a href="qset.h#FOREACHsetelement_i_">FOREACHsetelement_i_</a> -*/ -#define FOREACHpoint_i_(points) FOREACHsetelement_i_(pointT, points, point) - -/*-<a href="qh-poly.htm#TOC" - >--------------------------------</a><a name="FOREACHridge_i_">-</a> - - FOREACHridge_i_( ridges ) { ... } - assign 'ridge' and 'ridge_i' for each ridge in ridges set - - declare: - ridgeT *ridge; - int ridge_n, ridge_i; - - see: - <a href="qset.h#FOREACHsetelement_i_">FOREACHsetelement_i_</a> -*/ -#define FOREACHridge_i_(ridges) FOREACHsetelement_i_(ridgeT, ridges, ridge) - -/*-<a href="qh-poly.htm#TOC" - >--------------------------------</a><a name="FOREACHvertex_i_">-</a> - - FOREACHvertex_i_( vertices ) { ... } - assign 'vertex' and 'vertex_i' for each vertex in vertices set - - declare: - vertexT *vertex; - int vertex_n, vertex_i; - - see: - <a href="qset.h#FOREACHsetelement_i_">FOREACHsetelement_i_</a> -*/ -#define FOREACHvertex_i_(vertices) FOREACHsetelement_i_(vertexT, vertices,vertex) - -/********* -libqhull.c prototypes (duplicated from qhull_a.h) **********************/ - -void qh_qhull(void); -boolT qh_addpoint(pointT *furthest, facetT *facet, boolT checkdist); -void qh_printsummary(FILE *fp); - -/********* -user.c prototypes (alphabetical) **********************/ - -void qh_errexit(int exitcode, facetT *facet, ridgeT *ridge); -void qh_errprint(const char* string, facetT *atfacet, facetT *otherfacet, ridgeT *atridge, vertexT *atvertex); -int qh_new_qhull(int dim, int numpoints, coordT *points, boolT ismalloc, - char *qhull_cmd, FILE *outfile, FILE *errfile); -void qh_printfacetlist(facetT *facetlist, setT *facets, boolT printall); -void qh_printhelp_degenerate(FILE *fp); -void qh_printhelp_narrowhull(FILE *fp, realT minangle); -void qh_printhelp_singular(FILE *fp); -void qh_user_memsizes(void); - -/********* -usermem.c prototypes (alphabetical) **********************/ -void qh_exit(int exitcode); -void qh_free(void *mem); -void *qh_malloc(size_t size); - -/********* -userprintf.c and userprintf_rbox.c prototypes **********************/ -void qh_fprintf(FILE *fp, int msgcode, const char *fmt, ... ); -void qh_fprintf_rbox(FILE *fp, int msgcode, const char *fmt, ... ); - -/***** -geom.c/geom2.c/random.c prototypes (duplicated from geom.h, random.h) ****************/ - -facetT *qh_findbest(pointT *point, facetT *startfacet, - boolT bestoutside, boolT newfacets, boolT noupper, - realT *dist, boolT *isoutside, int *numpart); -facetT *qh_findbestnew(pointT *point, facetT *startfacet, - realT *dist, boolT bestoutside, boolT *isoutside, int *numpart); -boolT qh_gram_schmidt(int dim, realT **rows); -void qh_outerinner(facetT *facet, realT *outerplane, realT *innerplane); -void qh_printsummary(FILE *fp); -void qh_projectinput(void); -void qh_randommatrix(realT *buffer, int dim, realT **row); -void qh_rotateinput(realT **rows); -void qh_scaleinput(void); -void qh_setdelaunay(int dim, int count, pointT *points); -coordT *qh_sethalfspace_all(int dim, int count, coordT *halfspaces, pointT *feasible); - -/***** -global.c prototypes (alphabetical) ***********************/ - -unsigned long qh_clock(void); -void qh_checkflags(char *command, char *hiddenflags); -void qh_clear_outputflags(void); -void qh_freebuffers(void); -void qh_freeqhull(boolT allmem); -void qh_freeqhull2(boolT allmem); -void qh_init_A(FILE *infile, FILE *outfile, FILE *errfile, int argc, char *argv[]); -void qh_init_B(coordT *points, int numpoints, int dim, boolT ismalloc); -void qh_init_qhull_command(int argc, char *argv[]); -void qh_initbuffers(coordT *points, int numpoints, int dim, boolT ismalloc); -void qh_initflags(char *command); -void qh_initqhull_buffers(void); -void qh_initqhull_globals(coordT *points, int numpoints, int dim, boolT ismalloc); -void qh_initqhull_mem(void); -void qh_initqhull_outputflags(void); -void qh_initqhull_start(FILE *infile, FILE *outfile, FILE *errfile); -void qh_initqhull_start2(FILE *infile, FILE *outfile, FILE *errfile); -void qh_initthresholds(char *command); -void qh_option(const char *option, int *i, realT *r); -#if qh_QHpointer -void qh_restore_qhull(qhT **oldqh); -qhT *qh_save_qhull(void); -#endif - -/***** -io.c prototypes (duplicated from io.h) ***********************/ - -void dfacet( unsigned id); -void dvertex( unsigned id); -void qh_printneighborhood(FILE *fp, qh_PRINT format, facetT *facetA, facetT *facetB, boolT printall); -void qh_produce_output(void); -coordT *qh_readpoints(int *numpoints, int *dimension, boolT *ismalloc); - - -/********* -mem.c prototypes (duplicated from mem.h) **********************/ - -void qh_meminit(FILE *ferr); -void qh_memfreeshort(int *curlong, int *totlong); - -/********* -poly.c/poly2.c prototypes (duplicated from poly.h) **********************/ - -void qh_check_output(void); -void qh_check_points(void); -setT *qh_facetvertices(facetT *facetlist, setT *facets, boolT allfacets); -facetT *qh_findbestfacet(pointT *point, boolT bestoutside, - realT *bestdist, boolT *isoutside); -vertexT *qh_nearvertex(facetT *facet, pointT *point, realT *bestdistp); -pointT *qh_point(int id); -setT *qh_pointfacet(void /*qh.facet_list*/); -int qh_pointid(pointT *point); -setT *qh_pointvertex(void /*qh.facet_list*/); -void qh_setvoronoi_all(void); -void qh_triangulate(void /*qh facet_list*/); - -/********* -rboxpoints.c prototypes **********************/ -int qh_rboxpoints(FILE* fout, FILE* ferr, char* rbox_command); -void qh_errexit_rbox(int exitcode); - -/********* -stat.c prototypes (duplicated from stat.h) **********************/ - -void qh_collectstatistics(void); -void qh_printallstatistics(FILE *fp, const char *string); - -#endif /* qhDEFlibqhull */ diff --git a/PyMca/Object3D/Object3DQhull/src/mem.c b/PyMca/Object3D/Object3DQhull/src/mem.c deleted file mode 100644 index 2b865ae..0000000 --- a/PyMca/Object3D/Object3DQhull/src/mem.c +++ /dev/null @@ -1,543 +0,0 @@ -/*<html><pre> -<a href="qh-mem.htm" - >-------------------------------</a><a name="TOP">-</a> - - mem.c - memory management routines for qhull - - This is a standalone program. - - To initialize memory: - - qh_meminit(stderr); - qh_meminitbuffers(qh IStracing, qh_MEMalign, 7, qh_MEMbufsize,qh_MEMinitbuf); - qh_memsize((int)sizeof(facetT)); - qh_memsize((int)sizeof(facetT)); - ... - qh_memsetup(); - - To free up all memory buffers: - qh_memfreeshort(&curlong, &totlong); - - if qh_NOmem, - malloc/free is used instead of mem.c - - notes: - uses Quickfit algorithm (freelists for commonly allocated sizes) - assumes small sizes for freelists (it discards the tail of memory buffers) - - see: - qh-mem.htm and mem.h - global.c (qh_initbuffers) for an example of using mem.c - - Copyright (c) 1993-2012 The Geometry Center. - $Id: //main/2011/qhull/src/libqhull/mem.c#4 $$Change: 1464 $ - $DateTime: 2012/01/25 22:58:41 $$Author: bbarber $ -*/ - -#include "mem.h" -#include <string.h> -#include <stdio.h> -#include <stdlib.h> - -#ifndef qhDEFlibqhull -typedef struct ridgeT ridgeT; -typedef struct facetT facetT; -#ifdef _MSC_VER /* Microsoft Visual C++ -- warning level 4 */ -#pragma warning( disable : 4127) /* conditional expression is constant */ -#pragma warning( disable : 4706) /* assignment within conditional function */ -#endif -void qh_errexit(int exitcode, facetT *, ridgeT *); -void qh_exit(int exitcode); -void qh_fprintf(FILE *fp, int msgcode, const char *fmt, ... ); -void qh_free(void *mem); -void *qh_malloc(size_t size); -#endif - -/*============ -global data structure ============== - see mem.h for definition -*/ - -qhmemT qhmem= {0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0}; /* remove "= {0}" if this causes a compiler error */ - -#ifndef qh_NOmem - -/*============= internal functions ==============*/ - -static int qh_intcompare(const void *i, const void *j); - -/*========== functions in alphabetical order ======== */ - -/*-<a href="qh-mem.htm#TOC" - >-------------------------------</a><a name="intcompare">-</a> - - qh_intcompare( i, j ) - used by qsort and bsearch to compare two integers -*/ -static int qh_intcompare(const void *i, const void *j) { - return(*((const int *)i) - *((const int *)j)); -} /* intcompare */ - - -/*-<a href="qh-mem.htm#TOC" - >--------------------------------</a><a name="memalloc">-</a> - - qh_memalloc( insize ) - returns object of insize bytes - qhmem is the global memory structure - - returns: - pointer to allocated memory - errors if insufficient memory - - notes: - use explicit type conversion to avoid type warnings on some compilers - actual object may be larger than insize - use qh_memalloc_() for inline code for quick allocations - logs allocations if 'T5' - - design: - if size < qhmem.LASTsize - if qhmem.freelists[size] non-empty - return first object on freelist - else - round up request to size of qhmem.freelists[size] - allocate new allocation buffer if necessary - allocate object from allocation buffer - else - allocate object with qh_malloc() in user.c -*/ -void *qh_memalloc(int insize) { - void **freelistp, *newbuffer; - int idx, size, n; - int outsize, bufsize; - void *object; - - if (insize<0) { - qh_fprintf(qhmem.ferr, 6235, "qhull error (qh_memalloc): negative request size (%d). Did int overflow due to high-D?\n", insize); /* WARN64 */ - qh_errexit(qhmem_ERRmem, NULL, NULL); - } - if (insize>=0 && insize <= qhmem.LASTsize) { - idx= qhmem.indextable[insize]; - outsize= qhmem.sizetable[idx]; - qhmem.totshort += outsize; - freelistp= qhmem.freelists+idx; - if ((object= *freelistp)) { - qhmem.cntquick++; - qhmem.totfree -= outsize; - *freelistp= *((void **)*freelistp); /* replace freelist with next object */ -#ifdef qh_TRACEshort - n= qhmem.cntshort+qhmem.cntquick+qhmem.freeshort; - if (qhmem.IStracing >= 5) - qh_fprintf(qhmem.ferr, 8141, "qh_mem %p n %8d alloc quick: %d bytes (tot %d cnt %d)\n", object, n, outsize, qhmem.totshort, qhmem.cntshort+qhmem.cntquick-qhmem.freeshort); -#endif - return(object); - }else { - qhmem.cntshort++; - if (outsize > qhmem .freesize) { - qhmem .totdropped += qhmem .freesize; - if (!qhmem.curbuffer) - bufsize= qhmem.BUFinit; - else - bufsize= qhmem.BUFsize; - if (!(newbuffer= qh_malloc((size_t)bufsize))) { - qh_fprintf(qhmem.ferr, 6080, "qhull error (qh_memalloc): insufficient memory to allocate short memory buffer (%d bytes)\n", bufsize); - qh_errexit(qhmem_ERRmem, NULL, NULL); - } - *((void **)newbuffer)= qhmem.curbuffer; /* prepend newbuffer to curbuffer - list */ - qhmem.curbuffer= newbuffer; - size= (sizeof(void **) + qhmem.ALIGNmask) & ~qhmem.ALIGNmask; - qhmem.freemem= (void *)((char *)newbuffer+size); - qhmem.freesize= bufsize - size; - qhmem.totbuffer += bufsize - size; /* easier to check */ - /* Periodically test totbuffer. It matches at beginning and exit of every call */ - n = qhmem.totshort + qhmem.totfree + qhmem.totdropped + qhmem.freesize - outsize; - if (qhmem.totbuffer != n) { - qh_fprintf(qhmem.ferr, 6212, "qh_memalloc internal error: short totbuffer %d != totshort+totfree... %d\n", qhmem.totbuffer, n); - qh_errexit(qhmem_ERRmem, NULL, NULL); - } - } - object= qhmem.freemem; - qhmem.freemem= (void *)((char *)qhmem.freemem + outsize); - qhmem.freesize -= outsize; - qhmem.totunused += outsize - insize; -#ifdef qh_TRACEshort - n= qhmem.cntshort+qhmem.cntquick+qhmem.freeshort; - if (qhmem.IStracing >= 5) - qh_fprintf(qhmem.ferr, 8140, "qh_mem %p n %8d alloc short: %d bytes (tot %d cnt %d)\n", object, n, outsize, qhmem.totshort, qhmem.cntshort+qhmem.cntquick-qhmem.freeshort); -#endif - return object; - } - }else { /* long allocation */ - if (!qhmem.indextable) { - qh_fprintf(qhmem.ferr, 6081, "qhull internal error (qh_memalloc): qhmem has not been initialized.\n"); - qh_errexit(qhmem_ERRqhull, NULL, NULL); - } - outsize= insize; - qhmem .cntlong++; - qhmem .totlong += outsize; - if (qhmem.maxlong < qhmem.totlong) - qhmem.maxlong= qhmem.totlong; - if (!(object= qh_malloc((size_t)outsize))) { - qh_fprintf(qhmem.ferr, 6082, "qhull error (qh_memalloc): insufficient memory to allocate %d bytes\n", outsize); - qh_errexit(qhmem_ERRmem, NULL, NULL); - } - if (qhmem.IStracing >= 5) - qh_fprintf(qhmem.ferr, 8057, "qh_mem %p n %8d alloc long: %d bytes (tot %d cnt %d)\n", object, qhmem.cntlong+qhmem.freelong, outsize, qhmem.totlong, qhmem.cntlong-qhmem.freelong); - } - return(object); -} /* memalloc */ - - -/*-<a href="qh-mem.htm#TOC" - >--------------------------------</a><a name="memfree">-</a> - - qh_memfree( object, insize ) - free up an object of size bytes - size is insize from qh_memalloc - - notes: - object may be NULL - type checking warns if using (void **)object - use qh_memfree_() for quick free's of small objects - - design: - if size <= qhmem.LASTsize - append object to corresponding freelist - else - call qh_free(object) -*/ -void qh_memfree(void *object, int insize) { - void **freelistp; - int idx, outsize; - - if (!object) - return; - if (insize <= qhmem.LASTsize) { - qhmem .freeshort++; - idx= qhmem.indextable[insize]; - outsize= qhmem.sizetable[idx]; - qhmem .totfree += outsize; - qhmem .totshort -= outsize; - freelistp= qhmem.freelists + idx; - *((void **)object)= *freelistp; - *freelistp= object; -#ifdef qh_TRACEshort - idx= qhmem.cntshort+qhmem.cntquick+qhmem.freeshort; - if (qhmem.IStracing >= 5) - qh_fprintf(qhmem.ferr, 8142, "qh_mem %p n %8d free short: %d bytes (tot %d cnt %d)\n", object, idx, outsize, qhmem.totshort, qhmem.cntshort+qhmem.cntquick-qhmem.freeshort); -#endif - }else { - qhmem .freelong++; - qhmem .totlong -= insize; - qh_free(object); - if (qhmem.IStracing >= 5) - qh_fprintf(qhmem.ferr, 8058, "qh_mem %p n %8d free long: %d bytes (tot %d cnt %d)\n", object, qhmem.cntlong+qhmem.freelong, insize, qhmem.totlong, qhmem.cntlong-qhmem.freelong); - } -} /* memfree */ - - -/*-<a href="qh-mem.htm#TOC" - >-------------------------------</a><a name="memfreeshort">-</a> - - qh_memfreeshort( curlong, totlong ) - frees up all short and qhmem memory allocations - - returns: - number and size of current long allocations - - see: - qh_freeqhull(allMem) - qh_memtotal(curlong, totlong, curshort, totshort, maxlong, totbuffer); -*/ -void qh_memfreeshort(int *curlong, int *totlong) { - void *buffer, *nextbuffer; - FILE *ferr; - - *curlong= qhmem .cntlong - qhmem .freelong; - *totlong= qhmem .totlong; - for (buffer= qhmem.curbuffer; buffer; buffer= nextbuffer) { - nextbuffer= *((void **) buffer); - qh_free(buffer); - } - qhmem.curbuffer= NULL; - if (qhmem .LASTsize) { - qh_free(qhmem .indextable); - qh_free(qhmem .freelists); - qh_free(qhmem .sizetable); - } - ferr= qhmem.ferr; - memset((char *)&qhmem, 0, sizeof(qhmem)); /* every field is 0, FALSE, NULL */ - qhmem.ferr= ferr; -} /* memfreeshort */ - - -/*-<a href="qh-mem.htm#TOC" - >--------------------------------</a><a name="meminit">-</a> - - qh_meminit( ferr ) - initialize qhmem and test sizeof( void*) -*/ -void qh_meminit(FILE *ferr) { - - memset((char *)&qhmem, 0, sizeof(qhmem)); /* every field is 0, FALSE, NULL */ - qhmem.ferr= ferr; - if (sizeof(void*) < sizeof(int)) { - qh_fprintf(ferr, 6083, "qhull internal error (qh_meminit): sizeof(void*) %d < sizeof(int) %d. qset.c will not work\n", (int)sizeof(void*), (int)sizeof(int)); - qh_exit(qhmem_ERRqhull); /* can not use qh_errexit() */ - } - if (sizeof(void*) > sizeof(ptr_intT)) { - qh_fprintf(ferr, 6084, "qhull internal error (qh_meminit): sizeof(void*) %d > sizeof(ptr_intT) %d. Change ptr_intT in mem.h to 'long long'\n", (int)sizeof(void*), (int)sizeof(ptr_intT)); - qh_exit(qhmem_ERRqhull); /* can not use qh_errexit() */ - } -} /* meminit */ - -/*-<a href="qh-mem.htm#TOC" - >-------------------------------</a><a name="meminitbuffers">-</a> - - qh_meminitbuffers( tracelevel, alignment, numsizes, bufsize, bufinit ) - initialize qhmem - if tracelevel >= 5, trace memory allocations - alignment= desired address alignment for memory allocations - numsizes= number of freelists - bufsize= size of additional memory buffers for short allocations - bufinit= size of initial memory buffer for short allocations -*/ -void qh_meminitbuffers(int tracelevel, int alignment, int numsizes, int bufsize, int bufinit) { - - qhmem.IStracing= tracelevel; - qhmem.NUMsizes= numsizes; - qhmem.BUFsize= bufsize; - qhmem.BUFinit= bufinit; - qhmem.ALIGNmask= alignment-1; - if (qhmem.ALIGNmask & ~qhmem.ALIGNmask) { - qh_fprintf(qhmem.ferr, 6085, "qhull internal error (qh_meminit): memory alignment %d is not a power of 2\n", alignment); - qh_errexit(qhmem_ERRqhull, NULL, NULL); - } - qhmem.sizetable= (int *) calloc((size_t)numsizes, sizeof(int)); - qhmem.freelists= (void **) calloc((size_t)numsizes, sizeof(void *)); - if (!qhmem.sizetable || !qhmem.freelists) { - qh_fprintf(qhmem.ferr, 6086, "qhull error (qh_meminit): insufficient memory\n"); - qh_errexit(qhmem_ERRmem, NULL, NULL); - } - if (qhmem.IStracing >= 1) - qh_fprintf(qhmem.ferr, 8059, "qh_meminitbuffers: memory initialized with alignment %d\n", alignment); -} /* meminitbuffers */ - -/*-<a href="qh-mem.htm#TOC" - >-------------------------------</a><a name="memsetup">-</a> - - qh_memsetup() - set up memory after running memsize() -*/ -void qh_memsetup(void) { - int k,i; - - qsort(qhmem.sizetable, (size_t)qhmem.TABLEsize, sizeof(int), qh_intcompare); - qhmem.LASTsize= qhmem.sizetable[qhmem.TABLEsize-1]; - if (qhmem .LASTsize >= qhmem .BUFsize || qhmem.LASTsize >= qhmem .BUFinit) { - qh_fprintf(qhmem.ferr, 6087, "qhull error (qh_memsetup): largest mem size %d is >= buffer size %d or initial buffer size %d\n", - qhmem .LASTsize, qhmem .BUFsize, qhmem .BUFinit); - qh_errexit(qhmem_ERRmem, NULL, NULL); - } - if (!(qhmem.indextable= (int *)qh_malloc((qhmem.LASTsize+1) * sizeof(int)))) { - qh_fprintf(qhmem.ferr, 6088, "qhull error (qh_memsetup): insufficient memory\n"); - qh_errexit(qhmem_ERRmem, NULL, NULL); - } - for (k=qhmem.LASTsize+1; k--; ) - qhmem.indextable[k]= k; - i= 0; - for (k=0; k <= qhmem.LASTsize; k++) { - if (qhmem.indextable[k] <= qhmem.sizetable[i]) - qhmem.indextable[k]= i; - else - qhmem.indextable[k]= ++i; - } -} /* memsetup */ - -/*-<a href="qh-mem.htm#TOC" - >-------------------------------</a><a name="memsize">-</a> - - qh_memsize( size ) - define a free list for this size -*/ -void qh_memsize(int size) { - int k; - - if (qhmem .LASTsize) { - qh_fprintf(qhmem.ferr, 6089, "qhull error (qh_memsize): called after qhmem_setup\n"); - qh_errexit(qhmem_ERRqhull, NULL, NULL); - } - size= (size + qhmem.ALIGNmask) & ~qhmem.ALIGNmask; - for (k=qhmem.TABLEsize; k--; ) { - if (qhmem.sizetable[k] == size) - return; - } - if (qhmem.TABLEsize < qhmem.NUMsizes) - qhmem.sizetable[qhmem.TABLEsize++]= size; - else - qh_fprintf(qhmem.ferr, 7060, "qhull warning (memsize): free list table has room for only %d sizes\n", qhmem.NUMsizes); -} /* memsize */ - - -/*-<a href="qh-mem.htm#TOC" - >-------------------------------</a><a name="memstatistics">-</a> - - qh_memstatistics( fp ) - print out memory statistics - - Verifies that qhmem.totfree == sum of freelists -*/ -void qh_memstatistics(FILE *fp) { - int i, count, totfree= 0; - void *object; - - for (i=0; i < qhmem.TABLEsize; i++) { - count=0; - for (object= qhmem .freelists[i]; object; object= *((void **)object)) - count++; - totfree += qhmem.sizetable[i] * count; - } - if (totfree != qhmem .totfree) { - qh_fprintf(qhmem.ferr, 6211, "qh_memstatistics internal error: totfree %d not equal to freelist total %d\n", qhmem.totfree, totfree); - qh_errexit(qhmem_ERRqhull, NULL, NULL); - } - qh_fprintf(fp, 9278, "\nmemory statistics:\n\ -%7d quick allocations\n\ -%7d short allocations\n\ -%7d long allocations\n\ -%7d short frees\n\ -%7d long frees\n\ -%7d bytes of short memory in use\n\ -%7d bytes of short memory in freelists\n\ -%7d bytes of dropped short memory\n\ -%7d bytes of unused short memory (estimated)\n\ -%7d bytes of long memory allocated (max, except for input)\n\ -%7d bytes of long memory in use (in %d pieces)\n\ -%7d bytes of short memory buffers (minus links)\n\ -%7d bytes per short memory buffer (initially %d bytes)\n", - qhmem .cntquick, qhmem .cntshort, qhmem .cntlong, - qhmem .freeshort, qhmem .freelong, - qhmem .totshort, qhmem .totfree, - qhmem .totdropped + qhmem .freesize, qhmem .totunused, - qhmem .maxlong, qhmem .totlong, qhmem .cntlong - qhmem .freelong, - qhmem .totbuffer, qhmem .BUFsize, qhmem .BUFinit); - if (qhmem.cntlarger) { - qh_fprintf(fp, 9279, "%7d calls to qh_setlarger\n%7.2g average copy size\n", - qhmem.cntlarger, ((float)qhmem.totlarger)/(float)qhmem.cntlarger); - qh_fprintf(fp, 9280, " freelists(bytes->count):"); - } - for (i=0; i < qhmem.TABLEsize; i++) { - count=0; - for (object= qhmem .freelists[i]; object; object= *((void **)object)) - count++; - qh_fprintf(fp, 9281, " %d->%d", qhmem.sizetable[i], count); - } - qh_fprintf(fp, 9282, "\n\n"); -} /* memstatistics */ - - -/*-<a href="qh-mem.htm#TOC" - >-------------------------------</a><a name="NOmem">-</a> - - qh_NOmem - turn off quick-fit memory allocation - - notes: - uses qh_malloc() and qh_free() instead -*/ -#else /* qh_NOmem */ - -void *qh_memalloc(int insize) { - void *object; - - if (!(object= qh_malloc((size_t)insize))) { - qh_fprintf(qhmem.ferr, 6090, "qhull error (qh_memalloc): insufficient memory\n"); - qh_errexit(qhmem_ERRmem, NULL, NULL); - } - qhmem .cntlong++; - qhmem .totlong += insize; - if (qhmem.maxlong < qhmem.totlong) - qhmem.maxlong= qhmem.totlong; - if (qhmem.IStracing >= 5) - qh_fprintf(qhmem.ferr, 8060, "qh_mem %p n %8d alloc long: %d bytes (tot %d cnt %d)\n", object, qhmem.cntlong+qhmem.freelong, insize, qhmem.totlong, qhmem.cntlong-qhmem.freelong); - return object; -} - -void qh_memfree(void *object, int insize) { - - if (!object) - return; - qh_free(object); - qhmem .freelong++; - qhmem .totlong -= insize; - if (qhmem.IStracing >= 5) - qh_fprintf(qhmem.ferr, 8061, "qh_mem %p n %8d free long: %d bytes (tot %d cnt %d)\n", object, qhmem.cntlong+qhmem.freelong, insize, qhmem.totlong, qhmem.cntlong-qhmem.freelong); -} - -void qh_memfreeshort(int *curlong, int *totlong) { - *totlong= qhmem .totlong; - *curlong= qhmem .cntlong - qhmem .freelong; - memset((char *)&qhmem, 0, sizeof(qhmem)); /* every field is 0, FALSE, NULL */ -} - -void qh_meminit(FILE *ferr) { - - memset((char *)&qhmem, 0, sizeof(qhmem)); /* every field is 0, FALSE, NULL */ - qhmem.ferr= ferr; - if (sizeof(void*) < sizeof(int)) { - qh_fprintf(ferr, 6091, "qhull internal error (qh_meminit): sizeof(void*) %d < sizeof(int) %d. qset.c will not work\n", (int)sizeof(void*), (int)sizeof(int)); - qh_errexit(qhmem_ERRqhull, NULL, NULL); - } -} - -void qh_meminitbuffers(int tracelevel, int alignment, int numsizes, int bufsize, int bufinit) { - - qhmem.IStracing= tracelevel; -} - -void qh_memsetup(void) { - -} - -void qh_memsize(int size) { - -} - -void qh_memstatistics(FILE *fp) { - - qh_fprintf(fp, 9409, "\nmemory statistics:\n\ -%7d long allocations\n\ -%7d long frees\n\ -%7d bytes of long memory allocated (max, except for input)\n\ -%7d bytes of long memory in use (in %d pieces)\n", - qhmem .cntlong, - qhmem .freelong, - qhmem .maxlong, qhmem .totlong, qhmem .cntlong - qhmem .freelong); -} - -#endif /* qh_NOmem */ - -/*-<a href="qh-mem.htm#TOC" ->-------------------------------</a><a name="memtotlong">-</a> - - qh_memtotal( totlong, curlong, totshort, curshort, maxlong, totbuffer ) - Return the total, allocated long and short memory - - returns: - Returns the total current bytes of long and short allocations - Returns the current count of long and short allocations - Returns the maximum long memory and total short buffer (minus one link per buffer) - Does not error (UsingLibQhull.cpp) -*/ -void qh_memtotal(int *totlong, int *curlong, int *totshort, int *curshort, int *maxlong, int *totbuffer) { - *totlong= qhmem .totlong; - *curlong= qhmem .cntlong - qhmem .freelong; - *totshort= qhmem .totshort; - *curshort= qhmem .cntshort + qhmem .cntquick - qhmem .freeshort; - *maxlong= qhmem .maxlong; - *totbuffer= qhmem .totbuffer; -} /* memtotlong */ - diff --git a/PyMca/Object3D/Object3DQhull/src/mem.h b/PyMca/Object3D/Object3DQhull/src/mem.h deleted file mode 100644 index ad89de8..0000000 --- a/PyMca/Object3D/Object3DQhull/src/mem.h +++ /dev/null @@ -1,219 +0,0 @@ -/*<html><pre> -<a href="qh-mem.htm" - >-------------------------------</a><a name="TOP">-</a> - - mem.h - prototypes for memory management functions - - see qh-mem.htm, mem.c and qset.h - - for error handling, writes message and calls - qh_errexit(qhmem_ERRmem, NULL, NULL) if insufficient memory - and - qh_errexit(qhmem_ERRqhull, NULL, NULL) otherwise - - Copyright (c) 1993-2012 The Geometry Center. - $Id: //main/2011/qhull/src/libqhull/mem.h#4 $$Change: 1464 $ - $DateTime: 2012/01/25 22:58:41 $$Author: bbarber $ -*/ - -#ifndef qhDEFmem -#define qhDEFmem 1 - -#include <stdio.h> - -/*-<a href="qh-mem.htm#TOC" - >-------------------------------</a><a name="NOmem">-</a> - - qh_NOmem - turn off quick-fit memory allocation - - notes: - mem.c implements Quickfit memory allocation for about 20% time - savings. If it fails on your machine, try to locate the - problem, and send the answer to qhull@qhull.org. If this can - not be done, define qh_NOmem to use malloc/free instead. - - #define qh_NOmem -*/ - -/*-<a href="qh-mem.htm#TOC" ->-------------------------------</a><a name="TRACEshort">-</a> - -qh_TRACEshort -Trace short and quick memory allocations at T5 - -*/ -#define qh_TRACEshort - -/*------------------------------------------- - to avoid bus errors, memory allocation must consider alignment requirements. - malloc() automatically takes care of alignment. Since mem.c manages - its own memory, we need to explicitly specify alignment in - qh_meminitbuffers(). - - A safe choice is sizeof(double). sizeof(float) may be used if doubles - do not occur in data structures and pointers are the same size. Be careful - of machines (e.g., DEC Alpha) with large pointers. If gcc is available, - use __alignof__(double) or fmax_(__alignof__(float), __alignof__(void *)). - - see <a href="user.h#MEMalign">qh_MEMalign</a> in user.h for qhull's alignment -*/ - -#define qhmem_ERRmem 4 /* matches qh_ERRmem in libqhull.h */ -#define qhmem_ERRqhull 5 /* matches qh_ERRqhull in libqhull.h */ - -/*-<a href="qh-mem.htm#TOC" - >--------------------------------</a><a name="ptr_intT">-</a> - - ptr_intT - for casting a void * to an integer-type that holds a pointer - Used for integer expressions (e.g., computing qh_gethash() in poly.c) - - notes: - WARN64 -- these notes indicate 64-bit issues - On 64-bit machines, a pointer may be larger than an 'int'. - qh_meminit()/mem.c checks that 'ptr_intT' holds a 'void*' - ptr_intT is typically a signed value, but not necessarily so - size_t is typically unsigned, but should match the parameter type - Qhull uses int instead of size_t except for system calls such as malloc, qsort, qh_malloc, etc. - This matches Qt convention and is easier to work with. -*/ -#if _MSC_VER && defined(_WIN64) -typedef long long ptr_intT; -#else -typedef long ptr_intT; -#endif - -/*-<a href="qh-mem.htm#TOC" - >--------------------------------</a><a name="qhmemT">-</a> - - qhmemT - global memory structure for mem.c - - notes: - users should ignore qhmem except for writing extensions - qhmem is allocated in mem.c - - qhmem could be swapable like qh and qhstat, but then - multiple qh's and qhmem's would need to keep in synch. - A swapable qhmem would also waste memory buffers. As long - as memory operations are atomic, there is no problem with - multiple qh structures being active at the same time. - If you need separate address spaces, you can swap the - contents of qhmem. -*/ -typedef struct qhmemT qhmemT; -extern qhmemT qhmem; - -#ifndef DEFsetT -#define DEFsetT 1 -typedef struct setT setT; /* defined in qset.h */ -#endif - -/* Update qhmem in mem.c if add or remove fields */ -struct qhmemT { /* global memory management variables */ - int BUFsize; /* size of memory allocation buffer */ - int BUFinit; /* initial size of memory allocation buffer */ - int TABLEsize; /* actual number of sizes in free list table */ - int NUMsizes; /* maximum number of sizes in free list table */ - int LASTsize; /* last size in free list table */ - int ALIGNmask; /* worst-case alignment, must be 2^n-1 */ - void **freelists; /* free list table, linked by offset 0 */ - int *sizetable; /* size of each freelist */ - int *indextable; /* size->index table */ - void *curbuffer; /* current buffer, linked by offset 0 */ - void *freemem; /* free memory in curbuffer */ - int freesize; /* size of freemem in bytes */ - setT *tempstack; /* stack of temporary memory, managed by users */ - FILE *ferr; /* file for reporting errors, only user is qh_fprintf() */ - int IStracing; /* =5 if tracing memory allocations */ - int cntquick; /* count of quick allocations */ - /* Note: removing statistics doesn't effect speed */ - int cntshort; /* count of short allocations */ - int cntlong; /* count of long allocations */ - int freeshort; /* count of short memfrees */ - int freelong; /* count of long memfrees */ - int totbuffer; /* total short memory buffers minus buffer links */ - int totdropped; /* total dropped memory at end of short memory buffers (e.g., freesize) */ - int totfree; /* total size of free, short memory on freelists */ - int totlong; /* total size of long memory in use */ - int maxlong; /* maximum totlong */ - int totshort; /* total size of short memory in use */ - int totunused; /* total unused short memory (estimated, short size - request size of first allocations) */ - int cntlarger; /* count of setlarger's */ - int totlarger; /* total copied by setlarger */ -}; - - -/*==================== -macros ====================*/ - -/*-<a href="qh-mem.htm#TOC" - >--------------------------------</a><a name="memalloc_">-</a> - - qh_memalloc_(insize, object, type) - returns object of size bytes - assumes size<=qhmem.LASTsize and void **freelistp is a temp -*/ - -#if defined qh_NOmem -#define qh_memalloc_(insize, freelistp, object, type) {\ - object= (type*)qh_memalloc(insize); } -#elif defined qh_TRACEshort -#define qh_memalloc_(insize, freelistp, object, type) {\ - freelistp= NULL; /* Avoid warnings */ \ - object= (type*)qh_memalloc(insize); } -#else /* !qh_NOmem */ - -#define qh_memalloc_(insize, freelistp, object, type) {\ - freelistp= qhmem.freelists + qhmem.indextable[insize];\ - if ((object= (type*)*freelistp)) {\ - qhmem.totshort += qhmem.sizetable[qhmem.indextable[insize]]; \ - qhmem.totfree -= qhmem.sizetable[qhmem.indextable[insize]]; \ - qhmem.cntquick++; \ - *freelistp= *((void **)*freelistp);\ - }else object= (type*)qh_memalloc(insize);} -#endif - -/*-<a href="qh-mem.htm#TOC" - >--------------------------------</a><a name="memfree_">-</a> - - qh_memfree_(object, insize) - free up an object - - notes: - object may be NULL - assumes size<=qhmem.LASTsize and void **freelistp is a temp -*/ -#if defined qh_NOmem -#define qh_memfree_(object, insize, freelistp) {\ - qh_memfree(object, insize); } -#elif defined qh_TRACEshort -#define qh_memfree_(object, insize, freelistp) {\ - freelistp= NULL; /* Avoid warnings */ \ - qh_memfree(object, insize); } -#else /* !qh_NOmem */ - -#define qh_memfree_(object, insize, freelistp) {\ - if (object) { \ - qhmem .freeshort++;\ - freelistp= qhmem.freelists + qhmem.indextable[insize];\ - qhmem.totshort -= qhmem.sizetable[qhmem.indextable[insize]]; \ - qhmem.totfree += qhmem.sizetable[qhmem.indextable[insize]]; \ - *((void **)object)= *freelistp;\ - *freelistp= object;}} -#endif - -/*=============== prototypes in alphabetical order ============*/ - -void *qh_memalloc(int insize); -void qh_memfree(void *object, int insize); -void qh_memfreeshort(int *curlong, int *totlong); -void qh_meminit(FILE *ferr); -void qh_meminitbuffers(int tracelevel, int alignment, int numsizes, - int bufsize, int bufinit); -void qh_memsetup(void); -void qh_memsize(int size); -void qh_memstatistics(FILE *fp); -void qh_memtotal(int *totlong, int *curlong, int *totshort, int *curshort, int *maxlong, int *totbuffer); - -#endif /* qhDEFmem */ diff --git a/PyMca/Object3D/Object3DQhull/src/merge.c b/PyMca/Object3D/Object3DQhull/src/merge.c deleted file mode 100644 index 70c7f57..0000000 --- a/PyMca/Object3D/Object3DQhull/src/merge.c +++ /dev/null @@ -1,3623 +0,0 @@ -/*<html><pre> -<a href="qh-merge.htm#TOC" - >-------------------------------</a><a name="TOP">-</a> - - merge.c - merges non-convex facets - - see qh-merge.htm and merge.h - - other modules call qh_premerge() and qh_postmerge() - - the user may call qh_postmerge() to perform additional merges. - - To remove deleted facets and vertices (qhull() in libqhull.c): - qh_partitionvisible(!qh_ALL, &numoutside); // visible_list, newfacet_list - qh_deletevisible(); // qh.visible_list - qh_resetlists(False, qh_RESETvisible); // qh.visible_list newvertex_list newfacet_list - - assumes qh.CENTERtype= centrum - - merges occur in qh_mergefacet and in qh_mergecycle - vertex->neighbors not set until the first merge occurs - - Copyright (c) 1993-2012 C.B. Barber. - $Id: //main/2011/qhull/src/libqhull/merge.c#4 $$Change: 1490 $ - $DateTime: 2012/02/19 20:27:01 $$Author: bbarber $ -*/ - -#include "qhull_a.h" - -#ifndef qh_NOmerge - -/*===== functions(alphabetical after premerge and postmerge) ======*/ - -/*-<a href="qh-merge.htm#TOC" - >-------------------------------</a><a name="premerge">-</a> - - qh_premerge( apex, maxcentrum ) - pre-merge nonconvex facets in qh.newfacet_list for apex - maxcentrum defines coplanar and concave (qh_test_appendmerge) - - returns: - deleted facets added to qh.visible_list with facet->visible set - - notes: - uses globals, qh.MERGEexact, qh.PREmerge - - design: - mark duplicate ridges in qh.newfacet_list - merge facet cycles in qh.newfacet_list - merge duplicate ridges and concave facets in qh.newfacet_list - check merged facet cycles for degenerate and redundant facets - merge degenerate and redundant facets - collect coplanar and concave facets - merge concave, coplanar, degenerate, and redundant facets -*/ -void qh_premerge(vertexT *apex, realT maxcentrum, realT maxangle) { - boolT othermerge= False; - facetT *newfacet; - - if (qh ZEROcentrum && qh_checkzero(!qh_ALL)) - return; - trace2((qh ferr, 2008, "qh_premerge: premerge centrum %2.2g angle %2.2g for apex v%d facetlist f%d\n", - maxcentrum, maxangle, apex->id, getid_(qh newfacet_list))); - if (qh IStracing >= 4 && qh num_facets < 50) - qh_printlists(); - qh centrum_radius= maxcentrum; - qh cos_max= maxangle; - qh degen_mergeset= qh_settemp(qh TEMPsize); - qh facet_mergeset= qh_settemp(qh TEMPsize); - if (qh hull_dim >=3) { - qh_mark_dupridges(qh newfacet_list); /* facet_mergeset */ - qh_mergecycle_all(qh newfacet_list, &othermerge); - qh_forcedmerges(&othermerge /* qh facet_mergeset */); - FORALLnew_facets { /* test samecycle merges */ - if (!newfacet->simplicial && !newfacet->mergeridge) - qh_degen_redundant_neighbors(newfacet, NULL); - } - if (qh_merge_degenredundant()) - othermerge= True; - }else /* qh hull_dim == 2 */ - qh_mergecycle_all(qh newfacet_list, &othermerge); - qh_flippedmerges(qh newfacet_list, &othermerge); - if (!qh MERGEexact || zzval_(Ztotmerge)) { - zinc_(Zpremergetot); - qh POSTmerging= False; - qh_getmergeset_initial(qh newfacet_list); - qh_all_merges(othermerge, False); - } - qh_settempfree(&qh facet_mergeset); - qh_settempfree(&qh degen_mergeset); -} /* premerge */ - -/*-<a href="qh-merge.htm#TOC" - >-------------------------------</a><a name="postmerge">-</a> - - qh_postmerge( reason, maxcentrum, maxangle, vneighbors ) - post-merge nonconvex facets as defined by maxcentrum and maxangle - 'reason' is for reporting progress - if vneighbors, - calls qh_test_vneighbors at end of qh_all_merge - if firstmerge, - calls qh_reducevertices before qh_getmergeset - - returns: - if first call (qh.visible_list != qh.facet_list), - builds qh.facet_newlist, qh.newvertex_list - deleted facets added to qh.visible_list with facet->visible - qh.visible_list == qh.facet_list - - notes: - - - design: - if first call - set qh.visible_list and qh.newfacet_list to qh.facet_list - add all facets to qh.newfacet_list - mark non-simplicial facets, facet->newmerge - set qh.newvertext_list to qh.vertex_list - add all vertices to qh.newvertex_list - if a pre-merge occured - set vertex->delridge {will retest the ridge} - if qh.MERGEexact - call qh_reducevertices() - if no pre-merging - merge flipped facets - determine non-convex facets - merge all non-convex facets -*/ -void qh_postmerge(const char *reason, realT maxcentrum, realT maxangle, - boolT vneighbors) { - facetT *newfacet; - boolT othermerges= False; - vertexT *vertex; - - if (qh REPORTfreq || qh IStracing) { - qh_buildtracing(NULL, NULL); - qh_printsummary(qh ferr); - if (qh PRINTstatistics) - qh_printallstatistics(qh ferr, "reason"); - qh_fprintf(qh ferr, 8062, "\n%s with 'C%.2g' and 'A%.2g'\n", - reason, maxcentrum, maxangle); - } - trace2((qh ferr, 2009, "qh_postmerge: postmerge. test vneighbors? %d\n", - vneighbors)); - qh centrum_radius= maxcentrum; - qh cos_max= maxangle; - qh POSTmerging= True; - qh degen_mergeset= qh_settemp(qh TEMPsize); - qh facet_mergeset= qh_settemp(qh TEMPsize); - if (qh visible_list != qh facet_list) { /* first call */ - qh NEWfacets= True; - qh visible_list= qh newfacet_list= qh facet_list; - FORALLnew_facets { - newfacet->newfacet= True; - if (!newfacet->simplicial) - newfacet->newmerge= True; - zinc_(Zpostfacets); - } - qh newvertex_list= qh vertex_list; - FORALLvertices - vertex->newlist= True; - if (qh VERTEXneighbors) { /* a merge has occurred */ - FORALLvertices - vertex->delridge= True; /* test for redundant, needed? */ - if (qh MERGEexact) { - if (qh hull_dim <= qh_DIMreduceBuild) - qh_reducevertices(); /* was skipped during pre-merging */ - } - } - if (!qh PREmerge && !qh MERGEexact) - qh_flippedmerges(qh newfacet_list, &othermerges); - } - qh_getmergeset_initial(qh newfacet_list); - qh_all_merges(False, vneighbors); - qh_settempfree(&qh facet_mergeset); - qh_settempfree(&qh degen_mergeset); -} /* post_merge */ - -/*-<a href="qh-merge.htm#TOC" - >-------------------------------</a><a name="all_merges">-</a> - - qh_all_merges( othermerge, vneighbors ) - merge all non-convex facets - - set othermerge if already merged facets (for qh_reducevertices) - if vneighbors - tests vertex neighbors for convexity at end - qh.facet_mergeset lists the non-convex ridges in qh_newfacet_list - qh.degen_mergeset is defined - if qh.MERGEexact && !qh.POSTmerging, - does not merge coplanar facets - - returns: - deleted facets added to qh.visible_list with facet->visible - deleted vertices added qh.delvertex_list with vertex->delvertex - - notes: - unless !qh.MERGEindependent, - merges facets in independent sets - uses qh.newfacet_list as argument since merges call qh_removefacet() - - design: - while merges occur - for each merge in qh.facet_mergeset - unless one of the facets was already merged in this pass - merge the facets - test merged facets for additional merges - add merges to qh.facet_mergeset - if vertices record neighboring facets - rename redundant vertices - update qh.facet_mergeset - if vneighbors ?? - tests vertex neighbors for convexity at end -*/ -void qh_all_merges(boolT othermerge, boolT vneighbors) { - facetT *facet1, *facet2; - mergeT *merge; - boolT wasmerge= True, isreduce; - void **freelistp; /* used !qh_NOmem */ - vertexT *vertex; - mergeType mergetype; - int numcoplanar=0, numconcave=0, numdegenredun= 0, numnewmerges= 0; - - trace2((qh ferr, 2010, "qh_all_merges: starting to merge facets beginning from f%d\n", - getid_(qh newfacet_list))); - while (True) { - wasmerge= False; - while (qh_setsize(qh facet_mergeset)) { - while ((merge= (mergeT*)qh_setdellast(qh facet_mergeset))) { - facet1= merge->facet1; - facet2= merge->facet2; - mergetype= merge->type; - qh_memfree_(merge, (int)sizeof(mergeT), freelistp); - if (facet1->visible || facet2->visible) /*deleted facet*/ - continue; - if ((facet1->newfacet && !facet1->tested) - || (facet2->newfacet && !facet2->tested)) { - if (qh MERGEindependent && mergetype <= MRGanglecoplanar) - continue; /* perform independent sets of merges */ - } - qh_merge_nonconvex(facet1, facet2, mergetype); - numdegenredun += qh_merge_degenredundant(); - numnewmerges++; - wasmerge= True; - if (mergetype == MRGconcave) - numconcave++; - else /* MRGcoplanar or MRGanglecoplanar */ - numcoplanar++; - } /* while setdellast */ - if (qh POSTmerging && qh hull_dim <= qh_DIMreduceBuild - && numnewmerges > qh_MAXnewmerges) { - numnewmerges= 0; - qh_reducevertices(); /* otherwise large post merges too slow */ - } - qh_getmergeset(qh newfacet_list); /* facet_mergeset */ - } /* while mergeset */ - if (qh VERTEXneighbors) { - isreduce= False; - if (qh hull_dim >=4 && qh POSTmerging) { - FORALLvertices - vertex->delridge= True; - isreduce= True; - } - if ((wasmerge || othermerge) && (!qh MERGEexact || qh POSTmerging) - && qh hull_dim <= qh_DIMreduceBuild) { - othermerge= False; - isreduce= True; - } - if (isreduce) { - if (qh_reducevertices()) { - qh_getmergeset(qh newfacet_list); /* facet_mergeset */ - continue; - } - } - } - if (vneighbors && qh_test_vneighbors(/* qh newfacet_list */)) - continue; - break; - } /* while (True) */ - if (qh CHECKfrequently && !qh MERGEexact) { - qh old_randomdist= qh RANDOMdist; - qh RANDOMdist= False; - qh_checkconvex(qh newfacet_list, qh_ALGORITHMfault); - /* qh_checkconnect(); [this is slow and it changes the facet order] */ - qh RANDOMdist= qh old_randomdist; - } - trace1((qh ferr, 1009, "qh_all_merges: merged %d coplanar facets %d concave facets and %d degen or redundant facets.\n", - numcoplanar, numconcave, numdegenredun)); - if (qh IStracing >= 4 && qh num_facets < 50) - qh_printlists(); -} /* all_merges */ - - -/*-<a href="qh-merge.htm#TOC" - >-------------------------------</a><a name="appendmergeset">-</a> - - qh_appendmergeset( facet, neighbor, mergetype, angle ) - appends an entry to qh.facet_mergeset or qh.degen_mergeset - - angle ignored if NULL or !qh.ANGLEmerge - - returns: - merge appended to facet_mergeset or degen_mergeset - sets ->degenerate or ->redundant if degen_mergeset - - see: - qh_test_appendmerge() - - design: - allocate merge entry - if regular merge - append to qh.facet_mergeset - else if degenerate merge and qh.facet_mergeset is all degenerate - append to qh.degen_mergeset - else if degenerate merge - prepend to qh.degen_mergeset - else if redundant merge - append to qh.degen_mergeset -*/ -void qh_appendmergeset(facetT *facet, facetT *neighbor, mergeType mergetype, realT *angle) { - mergeT *merge, *lastmerge; - void **freelistp; /* used !qh_NOmem */ - - if (facet->redundant) - return; - if (facet->degenerate && mergetype == MRGdegen) - return; - qh_memalloc_((int)sizeof(mergeT), freelistp, merge, mergeT); - merge->facet1= facet; - merge->facet2= neighbor; - merge->type= mergetype; - if (angle && qh ANGLEmerge) - merge->angle= *angle; - if (mergetype < MRGdegen) - qh_setappend(&(qh facet_mergeset), merge); - else if (mergetype == MRGdegen) { - facet->degenerate= True; - if (!(lastmerge= (mergeT*)qh_setlast(qh degen_mergeset)) - || lastmerge->type == MRGdegen) - qh_setappend(&(qh degen_mergeset), merge); - else - qh_setaddnth(&(qh degen_mergeset), 0, merge); - }else if (mergetype == MRGredundant) { - facet->redundant= True; - qh_setappend(&(qh degen_mergeset), merge); - }else /* mergetype == MRGmirror */ { - if (facet->redundant || neighbor->redundant) { - qh_fprintf(qh ferr, 6092, "qhull error (qh_appendmergeset): facet f%d or f%d is already a mirrored facet\n", - facet->id, neighbor->id); - qh_errexit2 (qh_ERRqhull, facet, neighbor); - } - if (!qh_setequal(facet->vertices, neighbor->vertices)) { - qh_fprintf(qh ferr, 6093, "qhull error (qh_appendmergeset): mirrored facets f%d and f%d do not have the same vertices\n", - facet->id, neighbor->id); - qh_errexit2 (qh_ERRqhull, facet, neighbor); - } - facet->redundant= True; - neighbor->redundant= True; - qh_setappend(&(qh degen_mergeset), merge); - } -} /* appendmergeset */ - - -/*-<a href="qh-merge.htm#TOC" - >-------------------------------</a><a name="basevertices">-</a> - - qh_basevertices( samecycle ) - return temporary set of base vertices for samecycle - samecycle is first facet in the cycle - assumes apex is SETfirst_( samecycle->vertices ) - - returns: - vertices(settemp) - all ->seen are cleared - - notes: - uses qh_vertex_visit; - - design: - for each facet in samecycle - for each unseen vertex in facet->vertices - append to result -*/ -setT *qh_basevertices(facetT *samecycle) { - facetT *same; - vertexT *apex, *vertex, **vertexp; - setT *vertices= qh_settemp(qh TEMPsize); - - apex= SETfirstt_(samecycle->vertices, vertexT); - apex->visitid= ++qh vertex_visit; - FORALLsame_cycle_(samecycle) { - if (same->mergeridge) - continue; - FOREACHvertex_(same->vertices) { - if (vertex->visitid != qh vertex_visit) { - qh_setappend(&vertices, vertex); - vertex->visitid= qh vertex_visit; - vertex->seen= False; - } - } - } - trace4((qh ferr, 4019, "qh_basevertices: found %d vertices\n", - qh_setsize(vertices))); - return vertices; -} /* basevertices */ - -/*-<a href="qh-merge.htm#TOC" - >-------------------------------</a><a name="checkconnect">-</a> - - qh_checkconnect() - check that new facets are connected - new facets are on qh.newfacet_list - - notes: - this is slow and it changes the order of the facets - uses qh.visit_id - - design: - move first new facet to end of qh.facet_list - for all newly appended facets - append unvisited neighbors to end of qh.facet_list - for all new facets - report error if unvisited -*/ -void qh_checkconnect(void /* qh newfacet_list */) { - facetT *facet, *newfacet, *errfacet= NULL, *neighbor, **neighborp; - - facet= qh newfacet_list; - qh_removefacet(facet); - qh_appendfacet(facet); - facet->visitid= ++qh visit_id; - FORALLfacet_(facet) { - FOREACHneighbor_(facet) { - if (neighbor->visitid != qh visit_id) { - qh_removefacet(neighbor); - qh_appendfacet(neighbor); - neighbor->visitid= qh visit_id; - } - } - } - FORALLnew_facets { - if (newfacet->visitid == qh visit_id) - break; - qh_fprintf(qh ferr, 6094, "qhull error: f%d is not attached to the new facets\n", - newfacet->id); - errfacet= newfacet; - } - if (errfacet) - qh_errexit(qh_ERRqhull, errfacet, NULL); -} /* checkconnect */ - -/*-<a href="qh-merge.htm#TOC" - >-------------------------------</a><a name="checkzero">-</a> - - qh_checkzero( testall ) - check that facets are clearly convex for qh.DISTround with qh.MERGEexact - - if testall, - test all facets for qh.MERGEexact post-merging - else - test qh.newfacet_list - - if qh.MERGEexact, - allows coplanar ridges - skips convexity test while qh.ZEROall_ok - - returns: - True if all facets !flipped, !dupridge, normal - if all horizon facets are simplicial - if all vertices are clearly below neighbor - if all opposite vertices of horizon are below - clears qh.ZEROall_ok if any problems or coplanar facets - - notes: - uses qh.vertex_visit - horizon facets may define multiple new facets - - design: - for all facets in qh.newfacet_list or qh.facet_list - check for flagged faults (flipped, etc.) - for all facets in qh.newfacet_list or qh.facet_list - for each neighbor of facet - skip horizon facets for qh.newfacet_list - test the opposite vertex - if qh.newfacet_list - test the other vertices in the facet's horizon facet -*/ -boolT qh_checkzero(boolT testall) { - facetT *facet, *neighbor, **neighborp; - facetT *horizon, *facetlist; - int neighbor_i; - vertexT *vertex, **vertexp; - realT dist; - - if (testall) - facetlist= qh facet_list; - else { - facetlist= qh newfacet_list; - FORALLfacet_(facetlist) { - horizon= SETfirstt_(facet->neighbors, facetT); - if (!horizon->simplicial) - goto LABELproblem; - if (facet->flipped || facet->dupridge || !facet->normal) - goto LABELproblem; - } - if (qh MERGEexact && qh ZEROall_ok) { - trace2((qh ferr, 2011, "qh_checkzero: skip convexity check until first pre-merge\n")); - return True; - } - } - FORALLfacet_(facetlist) { - qh vertex_visit++; - neighbor_i= 0; - horizon= NULL; - FOREACHneighbor_(facet) { - if (!neighbor_i && !testall) { - horizon= neighbor; - neighbor_i++; - continue; /* horizon facet tested in qh_findhorizon */ - } - vertex= SETelemt_(facet->vertices, neighbor_i++, vertexT); - vertex->visitid= qh vertex_visit; - zzinc_(Zdistzero); - qh_distplane(vertex->point, neighbor, &dist); - if (dist >= -qh DISTround) { - qh ZEROall_ok= False; - if (!qh MERGEexact || testall || dist > qh DISTround) - goto LABELnonconvex; - } - } - if (!testall) { - FOREACHvertex_(horizon->vertices) { - if (vertex->visitid != qh vertex_visit) { - zzinc_(Zdistzero); - qh_distplane(vertex->point, facet, &dist); - if (dist >= -qh DISTround) { - qh ZEROall_ok= False; - if (!qh MERGEexact || dist > qh DISTround) - goto LABELnonconvex; - } - break; - } - } - } - } - trace2((qh ferr, 2012, "qh_checkzero: testall %d, facets are %s\n", testall, - (qh MERGEexact && !testall) ? - "not concave, flipped, or duplicate ridged" : "clearly convex")); - return True; - - LABELproblem: - qh ZEROall_ok= False; - trace2((qh ferr, 2013, "qh_checkzero: facet f%d needs pre-merging\n", - facet->id)); - return False; - - LABELnonconvex: - trace2((qh ferr, 2014, "qh_checkzero: facet f%d and f%d are not clearly convex. v%d dist %.2g\n", - facet->id, neighbor->id, vertex->id, dist)); - return False; -} /* checkzero */ - -/*-<a href="qh-merge.htm#TOC" - >-------------------------------</a><a name="compareangle">-</a> - - qh_compareangle( angle1, angle2 ) - used by qsort() to order merges by angle -*/ -int qh_compareangle(const void *p1, const void *p2) { - const mergeT *a= *((mergeT *const*)p1), *b= *((mergeT *const*)p2); - - return((a->angle > b->angle) ? 1 : -1); -} /* compareangle */ - -/*-<a href="qh-merge.htm#TOC" - >-------------------------------</a><a name="comparemerge">-</a> - - qh_comparemerge( merge1, merge2 ) - used by qsort() to order merges -*/ -int qh_comparemerge(const void *p1, const void *p2) { - const mergeT *a= *((mergeT *const*)p1), *b= *((mergeT *const*)p2); - - return(a->type - b->type); -} /* comparemerge */ - -/*-<a href="qh-merge.htm#TOC" - >-------------------------------</a><a name="comparevisit">-</a> - - qh_comparevisit( vertex1, vertex2 ) - used by qsort() to order vertices by their visitid -*/ -int qh_comparevisit(const void *p1, const void *p2) { - const vertexT *a= *((vertexT *const*)p1), *b= *((vertexT *const*)p2); - - return(a->visitid - b->visitid); -} /* comparevisit */ - -/*-<a href="qh-merge.htm#TOC" - >-------------------------------</a><a name="copynonconvex">-</a> - - qh_copynonconvex( atridge ) - set non-convex flag on other ridges (if any) between same neighbors - - notes: - may be faster if use smaller ridge set - - design: - for each ridge of atridge's top facet - if ridge shares the same neighbor - set nonconvex flag -*/ -void qh_copynonconvex(ridgeT *atridge) { - facetT *facet, *otherfacet; - ridgeT *ridge, **ridgep; - - facet= atridge->top; - otherfacet= atridge->bottom; - FOREACHridge_(facet->ridges) { - if (otherfacet == otherfacet_(ridge, facet) && ridge != atridge) { - ridge->nonconvex= True; - trace4((qh ferr, 4020, "qh_copynonconvex: moved nonconvex flag from r%d to r%d\n", - atridge->id, ridge->id)); - break; - } - } -} /* copynonconvex */ - -/*-<a href="qh-merge.htm#TOC" - >-------------------------------</a><a name="degen_redundant_facet">-</a> - - qh_degen_redundant_facet( facet ) - check facet for degen. or redundancy - - notes: - bumps vertex_visit - called if a facet was redundant but no longer is (qh_merge_degenredundant) - qh_appendmergeset() only appends first reference to facet (i.e., redundant) - - see: - qh_degen_redundant_neighbors() - - design: - test for redundant neighbor - test for degenerate facet -*/ -void qh_degen_redundant_facet(facetT *facet) { - vertexT *vertex, **vertexp; - facetT *neighbor, **neighborp; - - trace4((qh ferr, 4021, "qh_degen_redundant_facet: test facet f%d for degen/redundant\n", - facet->id)); - FOREACHneighbor_(facet) { - qh vertex_visit++; - FOREACHvertex_(neighbor->vertices) - vertex->visitid= qh vertex_visit; - FOREACHvertex_(facet->vertices) { - if (vertex->visitid != qh vertex_visit) - break; - } - if (!vertex) { - qh_appendmergeset(facet, neighbor, MRGredundant, NULL); - trace2((qh ferr, 2015, "qh_degen_redundant_facet: f%d is contained in f%d. merge\n", facet->id, neighbor->id)); - return; - } - } - if (qh_setsize(facet->neighbors) < qh hull_dim) { - qh_appendmergeset(facet, facet, MRGdegen, NULL); - trace2((qh ferr, 2016, "qh_degen_redundant_neighbors: f%d is degenerate.\n", facet->id)); - } -} /* degen_redundant_facet */ - - -/*-<a href="qh-merge.htm#TOC" - >-------------------------------</a><a name="degen_redundant_neighbors">-</a> - - qh_degen_redundant_neighbors( facet, delfacet, ) - append degenerate and redundant neighbors to facet_mergeset - if delfacet, - only checks neighbors of both delfacet and facet - also checks current facet for degeneracy - - notes: - bumps vertex_visit - called for each qh_mergefacet() and qh_mergecycle() - merge and statistics occur in merge_nonconvex - qh_appendmergeset() only appends first reference to facet (i.e., redundant) - it appends redundant facets after degenerate ones - - a degenerate facet has fewer than hull_dim neighbors - a redundant facet's vertices is a subset of its neighbor's vertices - tests for redundant merges first (appendmergeset is nop for others) - in a merge, only needs to test neighbors of merged facet - - see: - qh_merge_degenredundant() and qh_degen_redundant_facet() - - design: - test for degenerate facet - test for redundant neighbor - test for degenerate neighbor -*/ -void qh_degen_redundant_neighbors(facetT *facet, facetT *delfacet) { - vertexT *vertex, **vertexp; - facetT *neighbor, **neighborp; - int size; - - trace4((qh ferr, 4022, "qh_degen_redundant_neighbors: test neighbors of f%d with delfacet f%d\n", - facet->id, getid_(delfacet))); - if ((size= qh_setsize(facet->neighbors)) < qh hull_dim) { - qh_appendmergeset(facet, facet, MRGdegen, NULL); - trace2((qh ferr, 2017, "qh_degen_redundant_neighbors: f%d is degenerate with %d neighbors.\n", facet->id, size)); - } - if (!delfacet) - delfacet= facet; - qh vertex_visit++; - FOREACHvertex_(facet->vertices) - vertex->visitid= qh vertex_visit; - FOREACHneighbor_(delfacet) { - /* uses early out instead of checking vertex count */ - if (neighbor == facet) - continue; - FOREACHvertex_(neighbor->vertices) { - if (vertex->visitid != qh vertex_visit) - break; - } - if (!vertex) { - qh_appendmergeset(neighbor, facet, MRGredundant, NULL); - trace2((qh ferr, 2018, "qh_degen_redundant_neighbors: f%d is contained in f%d. merge\n", neighbor->id, facet->id)); - } - } - FOREACHneighbor_(delfacet) { /* redundant merges occur first */ - if (neighbor == facet) - continue; - if ((size= qh_setsize(neighbor->neighbors)) < qh hull_dim) { - qh_appendmergeset(neighbor, neighbor, MRGdegen, NULL); - trace2((qh ferr, 2019, "qh_degen_redundant_neighbors: f%d is degenerate with %d neighbors. Neighbor of f%d.\n", neighbor->id, size, facet->id)); - } - } -} /* degen_redundant_neighbors */ - - -/*-<a href="qh-merge.htm#TOC" - >-------------------------------</a><a name="find_newvertex">-</a> - - qh_find_newvertex( oldvertex, vertices, ridges ) - locate new vertex for renaming old vertex - vertices is a set of possible new vertices - vertices sorted by number of deleted ridges - - returns: - newvertex or NULL - each ridge includes both vertex and oldvertex - vertices sorted by number of deleted ridges - - notes: - modifies vertex->visitid - new vertex is in one of the ridges - renaming will not cause a duplicate ridge - renaming will minimize the number of deleted ridges - newvertex may not be adjacent in the dual (though unlikely) - - design: - for each vertex in vertices - set vertex->visitid to number of references in ridges - remove unvisited vertices - set qh.vertex_visit above all possible values - sort vertices by number of references in ridges - add each ridge to qh.hash_table - for each vertex in vertices - look for a vertex that would not cause a duplicate ridge after a rename -*/ -vertexT *qh_find_newvertex(vertexT *oldvertex, setT *vertices, setT *ridges) { - vertexT *vertex, **vertexp; - setT *newridges; - ridgeT *ridge, **ridgep; - int size, hashsize; - int hash; - -#ifndef qh_NOtrace - if (qh IStracing >= 4) { - qh_fprintf(qh ferr, 8063, "qh_find_newvertex: find new vertex for v%d from ", - oldvertex->id); - FOREACHvertex_(vertices) - qh_fprintf(qh ferr, 8064, "v%d ", vertex->id); - FOREACHridge_(ridges) - qh_fprintf(qh ferr, 8065, "r%d ", ridge->id); - qh_fprintf(qh ferr, 8066, "\n"); - } -#endif - FOREACHvertex_(vertices) - vertex->visitid= 0; - FOREACHridge_(ridges) { - FOREACHvertex_(ridge->vertices) - vertex->visitid++; - } - FOREACHvertex_(vertices) { - if (!vertex->visitid) { - qh_setdelnth(vertices, SETindex_(vertices,vertex)); - vertexp--; /* repeat since deleted this vertex */ - } - } - qh vertex_visit += (unsigned int)qh_setsize(ridges); - if (!qh_setsize(vertices)) { - trace4((qh ferr, 4023, "qh_find_newvertex: vertices not in ridges for v%d\n", - oldvertex->id)); - return NULL; - } - qsort(SETaddr_(vertices, vertexT), (size_t)qh_setsize(vertices), - sizeof(vertexT *), qh_comparevisit); - /* can now use qh vertex_visit */ - if (qh PRINTstatistics) { - size= qh_setsize(vertices); - zinc_(Zintersect); - zadd_(Zintersecttot, size); - zmax_(Zintersectmax, size); - } - hashsize= qh_newhashtable(qh_setsize(ridges)); - FOREACHridge_(ridges) - qh_hashridge(qh hash_table, hashsize, ridge, oldvertex); - FOREACHvertex_(vertices) { - newridges= qh_vertexridges(vertex); - FOREACHridge_(newridges) { - if (qh_hashridge_find(qh hash_table, hashsize, ridge, vertex, oldvertex, &hash)) { - zinc_(Zdupridge); - break; - } - } - qh_settempfree(&newridges); - if (!ridge) - break; /* found a rename */ - } - if (vertex) { - /* counted in qh_renamevertex */ - trace2((qh ferr, 2020, "qh_find_newvertex: found v%d for old v%d from %d vertices and %d ridges.\n", - vertex->id, oldvertex->id, qh_setsize(vertices), qh_setsize(ridges))); - }else { - zinc_(Zfindfail); - trace0((qh ferr, 14, "qh_find_newvertex: no vertex for renaming v%d(all duplicated ridges) during p%d\n", - oldvertex->id, qh furthest_id)); - } - qh_setfree(&qh hash_table); - return vertex; -} /* find_newvertex */ - -/*-<a href="qh-merge.htm#TOC" - >-------------------------------</a><a name="findbest_test">-</a> - - qh_findbest_test( testcentrum, facet, neighbor, bestfacet, dist, mindist, maxdist ) - test neighbor of facet for qh_findbestneighbor() - if testcentrum, - tests centrum (assumes it is defined) - else - tests vertices - - returns: - if a better facet (i.e., vertices/centrum of facet closer to neighbor) - updates bestfacet, dist, mindist, and maxdist -*/ -void qh_findbest_test(boolT testcentrum, facetT *facet, facetT *neighbor, - facetT **bestfacet, realT *distp, realT *mindistp, realT *maxdistp) { - realT dist, mindist, maxdist; - - if (testcentrum) { - zzinc_(Zbestdist); - qh_distplane(facet->center, neighbor, &dist); - dist *= qh hull_dim; /* estimate furthest vertex */ - if (dist < 0) { - maxdist= 0; - mindist= dist; - dist= -dist; - }else { - mindist= 0; - maxdist= dist; - } - }else - dist= qh_getdistance(facet, neighbor, &mindist, &maxdist); - if (dist < *distp) { - *bestfacet= neighbor; - *mindistp= mindist; - *maxdistp= maxdist; - *distp= dist; - } -} /* findbest_test */ - -/*-<a href="qh-merge.htm#TOC" - >-------------------------------</a><a name="findbestneighbor">-</a> - - qh_findbestneighbor( facet, dist, mindist, maxdist ) - finds best neighbor (least dist) of a facet for merging - - returns: - returns min and max distances and their max absolute value - - notes: - avoids merging old into new - assumes ridge->nonconvex only set on one ridge between a pair of facets - could use an early out predicate but not worth it - - design: - if a large facet - will test centrum - else - will test vertices - if a large facet - test nonconvex neighbors for best merge - else - test all neighbors for the best merge - if testing centrum - get distance information -*/ -facetT *qh_findbestneighbor(facetT *facet, realT *distp, realT *mindistp, realT *maxdistp) { - facetT *neighbor, **neighborp, *bestfacet= NULL; - ridgeT *ridge, **ridgep; - boolT nonconvex= True, testcentrum= False; - int size= qh_setsize(facet->vertices); - - *distp= REALmax; - if (size > qh_BESTcentrum2 * qh hull_dim + qh_BESTcentrum) { - testcentrum= True; - zinc_(Zbestcentrum); - if (!facet->center) - facet->center= qh_getcentrum(facet); - } - if (size > qh hull_dim + qh_BESTnonconvex) { - FOREACHridge_(facet->ridges) { - if (ridge->nonconvex) { - neighbor= otherfacet_(ridge, facet); - qh_findbest_test(testcentrum, facet, neighbor, - &bestfacet, distp, mindistp, maxdistp); - } - } - } - if (!bestfacet) { - nonconvex= False; - FOREACHneighbor_(facet) - qh_findbest_test(testcentrum, facet, neighbor, - &bestfacet, distp, mindistp, maxdistp); - } - if (!bestfacet) { - qh_fprintf(qh ferr, 6095, "qhull internal error (qh_findbestneighbor): no neighbors for f%d\n", facet->id); - - qh_errexit(qh_ERRqhull, facet, NULL); - } - if (testcentrum) - qh_getdistance(facet, bestfacet, mindistp, maxdistp); - trace3((qh ferr, 3002, "qh_findbestneighbor: f%d is best neighbor for f%d testcentrum? %d nonconvex? %d dist %2.2g min %2.2g max %2.2g\n", - bestfacet->id, facet->id, testcentrum, nonconvex, *distp, *mindistp, *maxdistp)); - return(bestfacet); -} /* findbestneighbor */ - - -/*-<a href="qh-merge.htm#TOC" - >-------------------------------</a><a name="flippedmerges">-</a> - - qh_flippedmerges( facetlist, wasmerge ) - merge flipped facets into best neighbor - assumes qh.facet_mergeset at top of temporary stack - - returns: - no flipped facets on facetlist - sets wasmerge if merge occurred - degen/redundant merges passed through - - notes: - othermerges not needed since qh.facet_mergeset is empty before & after - keep it in case of change - - design: - append flipped facets to qh.facetmergeset - for each flipped merge - find best neighbor - merge facet into neighbor - merge degenerate and redundant facets - remove flipped merges from qh.facet_mergeset -*/ -void qh_flippedmerges(facetT *facetlist, boolT *wasmerge) { - facetT *facet, *neighbor, *facet1; - realT dist, mindist, maxdist; - mergeT *merge, **mergep; - setT *othermerges; - int nummerge=0; - - trace4((qh ferr, 4024, "qh_flippedmerges: begin\n")); - FORALLfacet_(facetlist) { - if (facet->flipped && !facet->visible) - qh_appendmergeset(facet, facet, MRGflip, NULL); - } - othermerges= qh_settemppop(); /* was facet_mergeset */ - qh facet_mergeset= qh_settemp(qh TEMPsize); - qh_settemppush(othermerges); - FOREACHmerge_(othermerges) { - facet1= merge->facet1; - if (merge->type != MRGflip || facet1->visible) - continue; - if (qh TRACEmerge-1 == zzval_(Ztotmerge)) - qhmem.IStracing= qh IStracing= qh TRACElevel; - neighbor= qh_findbestneighbor(facet1, &dist, &mindist, &maxdist); - trace0((qh ferr, 15, "qh_flippedmerges: merge flipped f%d into f%d dist %2.2g during p%d\n", - facet1->id, neighbor->id, dist, qh furthest_id)); - qh_mergefacet(facet1, neighbor, &mindist, &maxdist, !qh_MERGEapex); - nummerge++; - if (qh PRINTstatistics) { - zinc_(Zflipped); - wadd_(Wflippedtot, dist); - wmax_(Wflippedmax, dist); - } - qh_merge_degenredundant(); - } - FOREACHmerge_(othermerges) { - if (merge->facet1->visible || merge->facet2->visible) - qh_memfree(merge, (int)sizeof(mergeT)); - else - qh_setappend(&qh facet_mergeset, merge); - } - qh_settempfree(&othermerges); - if (nummerge) - *wasmerge= True; - trace1((qh ferr, 1010, "qh_flippedmerges: merged %d flipped facets into a good neighbor\n", nummerge)); -} /* flippedmerges */ - - -/*-<a href="qh-merge.htm#TOC" - >-------------------------------</a><a name="forcedmerges">-</a> - - qh_forcedmerges( wasmerge ) - merge duplicated ridges - - returns: - removes all duplicate ridges on facet_mergeset - wasmerge set if merge - qh.facet_mergeset may include non-forced merges(none for now) - qh.degen_mergeset includes degen/redun merges - - notes: - duplicate ridges occur when the horizon is pinched, - i.e. a subridge occurs in more than two horizon ridges. - could rename vertices that pinch the horizon - assumes qh_merge_degenredundant() has not be called - othermerges isn't needed since facet_mergeset is empty afterwards - keep it in case of change - - design: - for each duplicate ridge - find current facets by chasing f.replace links - determine best direction for facet - merge one facet into the other - remove duplicate ridges from qh.facet_mergeset -*/ -void qh_forcedmerges(boolT *wasmerge) { - facetT *facet1, *facet2; - mergeT *merge, **mergep; - realT dist1, dist2, mindist1, mindist2, maxdist1, maxdist2; - setT *othermerges; - int nummerge=0, numflip=0; - - if (qh TRACEmerge-1 == zzval_(Ztotmerge)) - qhmem.IStracing= qh IStracing= qh TRACElevel; - trace4((qh ferr, 4025, "qh_forcedmerges: begin\n")); - othermerges= qh_settemppop(); /* was facet_mergeset */ - qh facet_mergeset= qh_settemp(qh TEMPsize); - qh_settemppush(othermerges); - FOREACHmerge_(othermerges) { - if (merge->type != MRGridge) - continue; - facet1= merge->facet1; - facet2= merge->facet2; - while (facet1->visible) /* must exist, no qh_merge_degenredunant */ - facet1= facet1->f.replace; /* previously merged facet */ - while (facet2->visible) - facet2= facet2->f.replace; /* previously merged facet */ - if (facet1 == facet2) - continue; - if (!qh_setin(facet2->neighbors, facet1)) { - qh_fprintf(qh ferr, 6096, "qhull internal error (qh_forcedmerges): f%d and f%d had a duplicate ridge but as f%d and f%d they are no longer neighbors\n", - merge->facet1->id, merge->facet2->id, facet1->id, facet2->id); - qh_errexit2 (qh_ERRqhull, facet1, facet2); - } - if (qh TRACEmerge-1 == zzval_(Ztotmerge)) - qhmem.IStracing= qh IStracing= qh TRACElevel; - dist1= qh_getdistance(facet1, facet2, &mindist1, &maxdist1); - dist2= qh_getdistance(facet2, facet1, &mindist2, &maxdist2); - trace0((qh ferr, 16, "qh_forcedmerges: duplicate ridge between f%d and f%d, dist %2.2g and reverse dist %2.2g during p%d\n", - facet1->id, facet2->id, dist1, dist2, qh furthest_id)); - if (dist1 < dist2) - qh_mergefacet(facet1, facet2, &mindist1, &maxdist1, !qh_MERGEapex); - else { - qh_mergefacet(facet2, facet1, &mindist2, &maxdist2, !qh_MERGEapex); - dist1= dist2; - facet1= facet2; - } - if (facet1->flipped) { - zinc_(Zmergeflipdup); - numflip++; - }else - nummerge++; - if (qh PRINTstatistics) { - zinc_(Zduplicate); - wadd_(Wduplicatetot, dist1); - wmax_(Wduplicatemax, dist1); - } - } - FOREACHmerge_(othermerges) { - if (merge->type == MRGridge) - qh_memfree(merge, (int)sizeof(mergeT)); - else - qh_setappend(&qh facet_mergeset, merge); - } - qh_settempfree(&othermerges); - if (nummerge) - *wasmerge= True; - trace1((qh ferr, 1011, "qh_forcedmerges: merged %d facets and %d flipped facets across duplicated ridges\n", - nummerge, numflip)); -} /* forcedmerges */ - - -/*-<a href="qh-merge.htm#TOC" - >-------------------------------</a><a name="getmergeset">-</a> - - qh_getmergeset( facetlist ) - determines nonconvex facets on facetlist - tests !tested ridges and nonconvex ridges of !tested facets - - returns: - returns sorted qh.facet_mergeset of facet-neighbor pairs to be merged - all ridges tested - - notes: - assumes no nonconvex ridges with both facets tested - uses facet->tested/ridge->tested to prevent duplicate tests - can not limit tests to modified ridges since the centrum changed - uses qh.visit_id - - see: - qh_getmergeset_initial() - - design: - for each facet on facetlist - for each ridge of facet - if untested ridge - test ridge for convexity - if non-convex - append ridge to qh.facet_mergeset - sort qh.facet_mergeset by angle -*/ -void qh_getmergeset(facetT *facetlist) { - facetT *facet, *neighbor, **neighborp; - ridgeT *ridge, **ridgep; - int nummerges; - - nummerges= qh_setsize(qh facet_mergeset); - trace4((qh ferr, 4026, "qh_getmergeset: started.\n")); - qh visit_id++; - FORALLfacet_(facetlist) { - if (facet->tested) - continue; - facet->visitid= qh visit_id; - facet->tested= True; /* must be non-simplicial due to merge */ - FOREACHneighbor_(facet) - neighbor->seen= False; - FOREACHridge_(facet->ridges) { - if (ridge->tested && !ridge->nonconvex) - continue; - /* if tested & nonconvex, need to append merge */ - neighbor= otherfacet_(ridge, facet); - if (neighbor->seen) { - ridge->tested= True; - ridge->nonconvex= False; - }else if (neighbor->visitid != qh visit_id) { - ridge->tested= True; - ridge->nonconvex= False; - neighbor->seen= True; /* only one ridge is marked nonconvex */ - if (qh_test_appendmerge(facet, neighbor)) - ridge->nonconvex= True; - } - } - } - nummerges= qh_setsize(qh facet_mergeset); - if (qh ANGLEmerge) - qsort(SETaddr_(qh facet_mergeset, mergeT), (size_t)nummerges, sizeof(mergeT *), qh_compareangle); - else - qsort(SETaddr_(qh facet_mergeset, mergeT), (size_t)nummerges, sizeof(mergeT *), qh_comparemerge); - if (qh POSTmerging) { - zadd_(Zmergesettot2, nummerges); - }else { - zadd_(Zmergesettot, nummerges); - zmax_(Zmergesetmax, nummerges); - } - trace2((qh ferr, 2021, "qh_getmergeset: %d merges found\n", nummerges)); -} /* getmergeset */ - - -/*-<a href="qh-merge.htm#TOC" - >-------------------------------</a><a name="getmergeset_initial">-</a> - - qh_getmergeset_initial( facetlist ) - determine initial qh.facet_mergeset for facets - tests all facet/neighbor pairs on facetlist - - returns: - sorted qh.facet_mergeset with nonconvex ridges - sets facet->tested, ridge->tested, and ridge->nonconvex - - notes: - uses visit_id, assumes ridge->nonconvex is False - - see: - qh_getmergeset() - - design: - for each facet on facetlist - for each untested neighbor of facet - test facet and neighbor for convexity - if non-convex - append merge to qh.facet_mergeset - mark one of the ridges as nonconvex - sort qh.facet_mergeset by angle -*/ -void qh_getmergeset_initial(facetT *facetlist) { - facetT *facet, *neighbor, **neighborp; - ridgeT *ridge, **ridgep; - int nummerges; - - qh visit_id++; - FORALLfacet_(facetlist) { - facet->visitid= qh visit_id; - facet->tested= True; - FOREACHneighbor_(facet) { - if (neighbor->visitid != qh visit_id) { - if (qh_test_appendmerge(facet, neighbor)) { - FOREACHridge_(neighbor->ridges) { - if (facet == otherfacet_(ridge, neighbor)) { - ridge->nonconvex= True; - break; /* only one ridge is marked nonconvex */ - } - } - } - } - } - FOREACHridge_(facet->ridges) - ridge->tested= True; - } - nummerges= qh_setsize(qh facet_mergeset); - if (qh ANGLEmerge) - qsort(SETaddr_(qh facet_mergeset, mergeT), (size_t)nummerges, sizeof(mergeT *), qh_compareangle); - else - qsort(SETaddr_(qh facet_mergeset, mergeT), (size_t)nummerges, sizeof(mergeT *), qh_comparemerge); - if (qh POSTmerging) { - zadd_(Zmergeinittot2, nummerges); - }else { - zadd_(Zmergeinittot, nummerges); - zmax_(Zmergeinitmax, nummerges); - } - trace2((qh ferr, 2022, "qh_getmergeset_initial: %d merges found\n", nummerges)); -} /* getmergeset_initial */ - - -/*-<a href="qh-merge.htm#TOC" - >-------------------------------</a><a name="hashridge">-</a> - - qh_hashridge( hashtable, hashsize, ridge, oldvertex ) - add ridge to hashtable without oldvertex - - notes: - assumes hashtable is large enough - - design: - determine hash value for ridge without oldvertex - find next empty slot for ridge -*/ -void qh_hashridge(setT *hashtable, int hashsize, ridgeT *ridge, vertexT *oldvertex) { - int hash; - ridgeT *ridgeA; - - hash= qh_gethash(hashsize, ridge->vertices, qh hull_dim-1, 0, oldvertex); - while (True) { - if (!(ridgeA= SETelemt_(hashtable, hash, ridgeT))) { - SETelem_(hashtable, hash)= ridge; - break; - }else if (ridgeA == ridge) - break; - if (++hash == hashsize) - hash= 0; - } -} /* hashridge */ - - -/*-<a href="qh-merge.htm#TOC" - >-------------------------------</a><a name="hashridge_find">-</a> - - qh_hashridge_find( hashtable, hashsize, ridge, vertex, oldvertex, hashslot ) - returns matching ridge without oldvertex in hashtable - for ridge without vertex - if oldvertex is NULL - matches with any one skip - - returns: - matching ridge or NULL - if no match, - if ridge already in table - hashslot= -1 - else - hashslot= next NULL index - - notes: - assumes hashtable is large enough - can't match ridge to itself - - design: - get hash value for ridge without vertex - for each hashslot - return match if ridge matches ridgeA without oldvertex -*/ -ridgeT *qh_hashridge_find(setT *hashtable, int hashsize, ridgeT *ridge, - vertexT *vertex, vertexT *oldvertex, int *hashslot) { - int hash; - ridgeT *ridgeA; - - *hashslot= 0; - zinc_(Zhashridge); - hash= qh_gethash(hashsize, ridge->vertices, qh hull_dim-1, 0, vertex); - while ((ridgeA= SETelemt_(hashtable, hash, ridgeT))) { - if (ridgeA == ridge) - *hashslot= -1; - else { - zinc_(Zhashridgetest); - if (qh_setequal_except(ridge->vertices, vertex, ridgeA->vertices, oldvertex)) - return ridgeA; - } - if (++hash == hashsize) - hash= 0; - } - if (!*hashslot) - *hashslot= hash; - return NULL; -} /* hashridge_find */ - - -/*-<a href="qh-merge.htm#TOC" - >-------------------------------</a><a name="makeridges">-</a> - - qh_makeridges( facet ) - creates explicit ridges between simplicial facets - - returns: - facet with ridges and without qh_MERGEridge - ->simplicial is False - - notes: - allows qh_MERGEridge flag - uses existing ridges - duplicate neighbors ok if ridges already exist (qh_mergecycle_ridges) - - see: - qh_mergecycle_ridges() - - design: - look for qh_MERGEridge neighbors - mark neighbors that already have ridges - for each unprocessed neighbor of facet - create a ridge for neighbor and facet - if any qh_MERGEridge neighbors - delete qh_MERGEridge flags (already handled by qh_mark_dupridges) -*/ -void qh_makeridges(facetT *facet) { - facetT *neighbor, **neighborp; - ridgeT *ridge, **ridgep; - int neighbor_i, neighbor_n; - boolT toporient, mergeridge= False; - - if (!facet->simplicial) - return; - trace4((qh ferr, 4027, "qh_makeridges: make ridges for f%d\n", facet->id)); - facet->simplicial= False; - FOREACHneighbor_(facet) { - if (neighbor == qh_MERGEridge) - mergeridge= True; - else - neighbor->seen= False; - } - FOREACHridge_(facet->ridges) - otherfacet_(ridge, facet)->seen= True; - FOREACHneighbor_i_(facet) { - if (neighbor == qh_MERGEridge) - continue; /* fixed by qh_mark_dupridges */ - else if (!neighbor->seen) { /* no current ridges */ - ridge= qh_newridge(); - ridge->vertices= qh_setnew_delnthsorted(facet->vertices, qh hull_dim, - neighbor_i, 0); - toporient= facet->toporient ^ (neighbor_i & 0x1); - if (toporient) { - ridge->top= facet; - ridge->bottom= neighbor; - }else { - ridge->top= neighbor; - ridge->bottom= facet; - } -#if 0 /* this also works */ - flip= (facet->toporient ^ neighbor->toporient)^(skip1 & 0x1) ^ (skip2 & 0x1); - if (facet->toporient ^ (skip1 & 0x1) ^ flip) { - ridge->top= neighbor; - ridge->bottom= facet; - }else { - ridge->top= facet; - ridge->bottom= neighbor; - } -#endif - qh_setappend(&(facet->ridges), ridge); - qh_setappend(&(neighbor->ridges), ridge); - } - } - if (mergeridge) { - while (qh_setdel(facet->neighbors, qh_MERGEridge)) - ; /* delete each one */ - } -} /* makeridges */ - - -/*-<a href="qh-merge.htm#TOC" - >-------------------------------</a><a name="mark_dupridges">-</a> - - qh_mark_dupridges( facetlist ) - add duplicated ridges to qh.facet_mergeset - facet->dupridge is true - - returns: - duplicate ridges on qh.facet_mergeset - ->mergeridge/->mergeridge2 set - duplicate ridges marked by qh_MERGEridge and both sides facet->dupridge - no MERGEridges in neighbor sets - - notes: - duplicate ridges occur when the horizon is pinched, - i.e. a subridge occurs in more than two horizon ridges. - could rename vertices that pinch the horizon - uses qh.visit_id - - design: - for all facets on facetlist - if facet contains a duplicate ridge - for each neighbor of facet - if neighbor marked qh_MERGEridge (one side of the merge) - set facet->mergeridge - else - if neighbor contains a duplicate ridge - and the back link is qh_MERGEridge - append duplicate ridge to qh.facet_mergeset - for each duplicate ridge - make ridge sets in preparation for merging - remove qh_MERGEridge from neighbor set - for each duplicate ridge - restore the missing neighbor from the neighbor set that was qh_MERGEridge - add the missing ridge for this neighbor -*/ -void qh_mark_dupridges(facetT *facetlist) { - facetT *facet, *neighbor, **neighborp; - int nummerge=0; - mergeT *merge, **mergep; - - - trace4((qh ferr, 4028, "qh_mark_dupridges: identify duplicate ridges\n")); - FORALLfacet_(facetlist) { - if (facet->dupridge) { - FOREACHneighbor_(facet) { - if (neighbor == qh_MERGEridge) { - facet->mergeridge= True; - continue; - } - if (neighbor->dupridge - && !qh_setin(neighbor->neighbors, facet)) { /* qh_MERGEridge */ - qh_appendmergeset(facet, neighbor, MRGridge, NULL); - facet->mergeridge2= True; - facet->mergeridge= True; - nummerge++; - } - } - } - } - if (!nummerge) - return; - FORALLfacet_(facetlist) { /* gets rid of qh_MERGEridge */ - if (facet->mergeridge && !facet->mergeridge2) - qh_makeridges(facet); - } - FOREACHmerge_(qh facet_mergeset) { /* restore the missing neighbors */ - if (merge->type == MRGridge) { - qh_setappend(&merge->facet2->neighbors, merge->facet1); - qh_makeridges(merge->facet1); /* and the missing ridges */ - } - } - trace1((qh ferr, 1012, "qh_mark_dupridges: found %d duplicated ridges\n", - nummerge)); -} /* mark_dupridges */ - -/*-<a href="qh-merge.htm#TOC" - >-------------------------------</a><a name="maydropneighbor">-</a> - - qh_maydropneighbor( facet ) - drop neighbor relationship if no ridge between facet and neighbor - - returns: - neighbor sets updated - appends degenerate facets to qh.facet_mergeset - - notes: - won't cause redundant facets since vertex inclusion is the same - may drop vertex and neighbor if no ridge - uses qh.visit_id - - design: - visit all neighbors with ridges - for each unvisited neighbor of facet - delete neighbor and facet from the neighbor sets - if neighbor becomes degenerate - append neighbor to qh.degen_mergeset - if facet is degenerate - append facet to qh.degen_mergeset -*/ -void qh_maydropneighbor(facetT *facet) { - ridgeT *ridge, **ridgep; - realT angledegen= qh_ANGLEdegen; - facetT *neighbor, **neighborp; - - qh visit_id++; - trace4((qh ferr, 4029, "qh_maydropneighbor: test f%d for no ridges to a neighbor\n", - facet->id)); - FOREACHridge_(facet->ridges) { - ridge->top->visitid= qh visit_id; - ridge->bottom->visitid= qh visit_id; - } - FOREACHneighbor_(facet) { - if (neighbor->visitid != qh visit_id) { - trace0((qh ferr, 17, "qh_maydropneighbor: facets f%d and f%d are no longer neighbors during p%d\n", - facet->id, neighbor->id, qh furthest_id)); - zinc_(Zdropneighbor); - qh_setdel(facet->neighbors, neighbor); - neighborp--; /* repeat, deleted a neighbor */ - qh_setdel(neighbor->neighbors, facet); - if (qh_setsize(neighbor->neighbors) < qh hull_dim) { - zinc_(Zdropdegen); - qh_appendmergeset(neighbor, neighbor, MRGdegen, &angledegen); - trace2((qh ferr, 2023, "qh_maydropneighbors: f%d is degenerate.\n", neighbor->id)); - } - } - } - if (qh_setsize(facet->neighbors) < qh hull_dim) { - zinc_(Zdropdegen); - qh_appendmergeset(facet, facet, MRGdegen, &angledegen); - trace2((qh ferr, 2024, "qh_maydropneighbors: f%d is degenerate.\n", facet->id)); - } -} /* maydropneighbor */ - - -/*-<a href="qh-merge.htm#TOC" - >-------------------------------</a><a name="merge_degenredundant">-</a> - - qh_merge_degenredundant() - merge all degenerate and redundant facets - qh.degen_mergeset contains merges from qh_degen_redundant_neighbors() - - returns: - number of merges performed - resets facet->degenerate/redundant - if deleted (visible) facet has no neighbors - sets ->f.replace to NULL - - notes: - redundant merges happen before degenerate ones - merging and renaming vertices can result in degen/redundant facets - - design: - for each merge on qh.degen_mergeset - if redundant merge - if non-redundant facet merged into redundant facet - recheck facet for redundancy - else - merge redundant facet into other facet -*/ -int qh_merge_degenredundant(void) { - int size; - mergeT *merge; - facetT *bestneighbor, *facet1, *facet2; - realT dist, mindist, maxdist; - vertexT *vertex, **vertexp; - int nummerges= 0; - mergeType mergetype; - - while ((merge= (mergeT*)qh_setdellast(qh degen_mergeset))) { - facet1= merge->facet1; - facet2= merge->facet2; - mergetype= merge->type; - qh_memfree(merge, (int)sizeof(mergeT)); - if (facet1->visible) - continue; - facet1->degenerate= False; - facet1->redundant= False; - if (qh TRACEmerge-1 == zzval_(Ztotmerge)) - qhmem.IStracing= qh IStracing= qh TRACElevel; - if (mergetype == MRGredundant) { - zinc_(Zneighbor); - while (facet2->visible) { - if (!facet2->f.replace) { - qh_fprintf(qh ferr, 6097, "qhull internal error (qh_merge_degenredunant): f%d redundant but f%d has no replacement\n", - facet1->id, facet2->id); - qh_errexit2 (qh_ERRqhull, facet1, facet2); - } - facet2= facet2->f.replace; - } - if (facet1 == facet2) { - qh_degen_redundant_facet(facet1); /* in case of others */ - continue; - } - trace2((qh ferr, 2025, "qh_merge_degenredundant: facet f%d is contained in f%d, will merge\n", - facet1->id, facet2->id)); - qh_mergefacet(facet1, facet2, NULL, NULL, !qh_MERGEapex); - /* merge distance is already accounted for */ - nummerges++; - }else { /* mergetype == MRGdegen, other merges may have fixed */ - if (!(size= qh_setsize(facet1->neighbors))) { - zinc_(Zdelfacetdup); - trace2((qh ferr, 2026, "qh_merge_degenredundant: facet f%d has no neighbors. Deleted\n", facet1->id)); - qh_willdelete(facet1, NULL); - FOREACHvertex_(facet1->vertices) { - qh_setdel(vertex->neighbors, facet1); - if (!SETfirst_(vertex->neighbors)) { - zinc_(Zdegenvertex); - trace2((qh ferr, 2027, "qh_merge_degenredundant: deleted v%d because f%d has no neighbors\n", - vertex->id, facet1->id)); - vertex->deleted= True; - qh_setappend(&qh del_vertices, vertex); - } - } - nummerges++; - }else if (size < qh hull_dim) { - bestneighbor= qh_findbestneighbor(facet1, &dist, &mindist, &maxdist); - trace2((qh ferr, 2028, "qh_merge_degenredundant: facet f%d has %d neighbors, merge into f%d dist %2.2g\n", - facet1->id, size, bestneighbor->id, dist)); - qh_mergefacet(facet1, bestneighbor, &mindist, &maxdist, !qh_MERGEapex); - nummerges++; - if (qh PRINTstatistics) { - zinc_(Zdegen); - wadd_(Wdegentot, dist); - wmax_(Wdegenmax, dist); - } - } /* else, another merge fixed the degeneracy and redundancy tested */ - } - } - return nummerges; -} /* merge_degenredundant */ - -/*-<a href="qh-merge.htm#TOC" - >-------------------------------</a><a name="merge_nonconvex">-</a> - - qh_merge_nonconvex( facet1, facet2, mergetype ) - remove non-convex ridge between facet1 into facet2 - mergetype gives why the facet's are non-convex - - returns: - merges one of the facets into the best neighbor - - design: - if one of the facets is a new facet - prefer merging new facet into old facet - find best neighbors for both facets - merge the nearest facet into its best neighbor - update the statistics -*/ -void qh_merge_nonconvex(facetT *facet1, facetT *facet2, mergeType mergetype) { - facetT *bestfacet, *bestneighbor, *neighbor; - realT dist, dist2, mindist, mindist2, maxdist, maxdist2; - - if (qh TRACEmerge-1 == zzval_(Ztotmerge)) - qhmem.IStracing= qh IStracing= qh TRACElevel; - trace3((qh ferr, 3003, "qh_merge_nonconvex: merge #%d for f%d and f%d type %d\n", - zzval_(Ztotmerge) + 1, facet1->id, facet2->id, mergetype)); - /* concave or coplanar */ - if (!facet1->newfacet) { - bestfacet= facet2; /* avoid merging old facet if new is ok */ - facet2= facet1; - facet1= bestfacet; - }else - bestfacet= facet1; - bestneighbor= qh_findbestneighbor(bestfacet, &dist, &mindist, &maxdist); - neighbor= qh_findbestneighbor(facet2, &dist2, &mindist2, &maxdist2); - if (dist < dist2) { - qh_mergefacet(bestfacet, bestneighbor, &mindist, &maxdist, !qh_MERGEapex); - }else if (qh AVOIDold && !facet2->newfacet - && ((mindist >= -qh MAXcoplanar && maxdist <= qh max_outside) - || dist * 1.5 < dist2)) { - zinc_(Zavoidold); - wadd_(Wavoidoldtot, dist); - wmax_(Wavoidoldmax, dist); - trace2((qh ferr, 2029, "qh_merge_nonconvex: avoid merging old facet f%d dist %2.2g. Use f%d dist %2.2g instead\n", - facet2->id, dist2, facet1->id, dist2)); - qh_mergefacet(bestfacet, bestneighbor, &mindist, &maxdist, !qh_MERGEapex); - }else { - qh_mergefacet(facet2, neighbor, &mindist2, &maxdist2, !qh_MERGEapex); - dist= dist2; - } - if (qh PRINTstatistics) { - if (mergetype == MRGanglecoplanar) { - zinc_(Zacoplanar); - wadd_(Wacoplanartot, dist); - wmax_(Wacoplanarmax, dist); - }else if (mergetype == MRGconcave) { - zinc_(Zconcave); - wadd_(Wconcavetot, dist); - wmax_(Wconcavemax, dist); - }else { /* MRGcoplanar */ - zinc_(Zcoplanar); - wadd_(Wcoplanartot, dist); - wmax_(Wcoplanarmax, dist); - } - } -} /* merge_nonconvex */ - -/*-<a href="qh-merge.htm#TOC" - >-------------------------------</a><a name="mergecycle">-</a> - - qh_mergecycle( samecycle, newfacet ) - merge a cycle of facets starting at samecycle into a newfacet - newfacet is a horizon facet with ->normal - samecycle facets are simplicial from an apex - - returns: - initializes vertex neighbors on first merge - samecycle deleted (placed on qh.visible_list) - newfacet at end of qh.facet_list - deleted vertices on qh.del_vertices - - see: - qh_mergefacet() - called by qh_mergecycle_all() for multiple, same cycle facets - - design: - make vertex neighbors if necessary - make ridges for newfacet - merge neighbor sets of samecycle into newfacet - merge ridges of samecycle into newfacet - merge vertex neighbors of samecycle into newfacet - make apex of samecycle the apex of newfacet - if newfacet wasn't a new facet - add its vertices to qh.newvertex_list - delete samecycle facets a make newfacet a newfacet -*/ -void qh_mergecycle(facetT *samecycle, facetT *newfacet) { - int traceonce= False, tracerestore= 0; - vertexT *apex; -#ifndef qh_NOtrace - facetT *same; -#endif - - if (newfacet->tricoplanar) { - if (!qh TRInormals) { - qh_fprintf(qh ferr, 6224, "Qhull internal error (qh_mergecycle): does not work for tricoplanar facets. Use option 'Q11'\n"); - qh_errexit(qh_ERRqhull, newfacet, NULL); - } - newfacet->tricoplanar= False; - newfacet->keepcentrum= False; - } - if (!qh VERTEXneighbors) - qh_vertexneighbors(); - zzinc_(Ztotmerge); - if (qh REPORTfreq2 && qh POSTmerging) { - if (zzval_(Ztotmerge) > qh mergereport + qh REPORTfreq2) - qh_tracemerging(); - } -#ifndef qh_NOtrace - if (qh TRACEmerge == zzval_(Ztotmerge)) - qhmem.IStracing= qh IStracing= qh TRACElevel; - trace2((qh ferr, 2030, "qh_mergecycle: merge #%d for facets from cycle f%d into coplanar horizon f%d\n", - zzval_(Ztotmerge), samecycle->id, newfacet->id)); - if (newfacet == qh tracefacet) { - tracerestore= qh IStracing; - qh IStracing= 4; - qh_fprintf(qh ferr, 8068, "qh_mergecycle: ========= trace merge %d of samecycle %d into trace f%d, furthest is p%d\n", - zzval_(Ztotmerge), samecycle->id, newfacet->id, qh furthest_id); - traceonce= True; - } - if (qh IStracing >=4) { - qh_fprintf(qh ferr, 8069, " same cycle:"); - FORALLsame_cycle_(samecycle) - qh_fprintf(qh ferr, 8070, " f%d", same->id); - qh_fprintf(qh ferr, 8071, "\n"); - } - if (qh IStracing >=4) - qh_errprint("MERGING CYCLE", samecycle, newfacet, NULL, NULL); -#endif /* !qh_NOtrace */ - apex= SETfirstt_(samecycle->vertices, vertexT); - qh_makeridges(newfacet); - qh_mergecycle_neighbors(samecycle, newfacet); - qh_mergecycle_ridges(samecycle, newfacet); - qh_mergecycle_vneighbors(samecycle, newfacet); - if (SETfirstt_(newfacet->vertices, vertexT) != apex) - qh_setaddnth(&newfacet->vertices, 0, apex); /* apex has last id */ - if (!newfacet->newfacet) - qh_newvertices(newfacet->vertices); - qh_mergecycle_facets(samecycle, newfacet); - qh_tracemerge(samecycle, newfacet); - /* check for degen_redundant_neighbors after qh_forcedmerges() */ - if (traceonce) { - qh_fprintf(qh ferr, 8072, "qh_mergecycle: end of trace facet\n"); - qh IStracing= tracerestore; - } -} /* mergecycle */ - -/*-<a href="qh-merge.htm#TOC" - >-------------------------------</a><a name="mergecycle_all">-</a> - - qh_mergecycle_all( facetlist, wasmerge ) - merge all samecycles of coplanar facets into horizon - don't merge facets with ->mergeridge (these already have ->normal) - all facets are simplicial from apex - all facet->cycledone == False - - returns: - all newfacets merged into coplanar horizon facets - deleted vertices on qh.del_vertices - sets wasmerge if any merge - - see: - calls qh_mergecycle for multiple, same cycle facets - - design: - for each facet on facetlist - skip facets with duplicate ridges and normals - check that facet is in a samecycle (->mergehorizon) - if facet only member of samecycle - sets vertex->delridge for all vertices except apex - merge facet into horizon - else - mark all facets in samecycle - remove facets with duplicate ridges from samecycle - merge samecycle into horizon (deletes facets from facetlist) -*/ -void qh_mergecycle_all(facetT *facetlist, boolT *wasmerge) { - facetT *facet, *same, *prev, *horizon; - facetT *samecycle= NULL, *nextfacet, *nextsame; - vertexT *apex, *vertex, **vertexp; - int cycles=0, total=0, facets, nummerge; - - trace2((qh ferr, 2031, "qh_mergecycle_all: begin\n")); - for (facet= facetlist; facet && (nextfacet= facet->next); facet= nextfacet) { - if (facet->normal) - continue; - if (!facet->mergehorizon) { - qh_fprintf(qh ferr, 6225, "Qhull internal error (qh_mergecycle_all): f%d without normal\n", facet->id); - qh_errexit(qh_ERRqhull, facet, NULL); - } - horizon= SETfirstt_(facet->neighbors, facetT); - if (facet->f.samecycle == facet) { - zinc_(Zonehorizon); - /* merge distance done in qh_findhorizon */ - apex= SETfirstt_(facet->vertices, vertexT); - FOREACHvertex_(facet->vertices) { - if (vertex != apex) - vertex->delridge= True; - } - horizon->f.newcycle= NULL; - qh_mergefacet(facet, horizon, NULL, NULL, qh_MERGEapex); - }else { - samecycle= facet; - facets= 0; - prev= facet; - for (same= facet->f.samecycle; same; /* FORALLsame_cycle_(facet) */ - same= (same == facet ? NULL :nextsame)) { /* ends at facet */ - nextsame= same->f.samecycle; - if (same->cycledone || same->visible) - qh_infiniteloop(same); - same->cycledone= True; - if (same->normal) { - prev->f.samecycle= same->f.samecycle; /* unlink ->mergeridge */ - same->f.samecycle= NULL; - }else { - prev= same; - facets++; - } - } - while (nextfacet && nextfacet->cycledone) /* will delete samecycle */ - nextfacet= nextfacet->next; - horizon->f.newcycle= NULL; - qh_mergecycle(samecycle, horizon); - nummerge= horizon->nummerge + facets; - if (nummerge > qh_MAXnummerge) - horizon->nummerge= qh_MAXnummerge; - else - horizon->nummerge= (short unsigned int)nummerge; - zzinc_(Zcyclehorizon); - total += facets; - zzadd_(Zcyclefacettot, facets); - zmax_(Zcyclefacetmax, facets); - } - cycles++; - } - if (cycles) - *wasmerge= True; - trace1((qh ferr, 1013, "qh_mergecycle_all: merged %d same cycles or facets into coplanar horizons\n", cycles)); -} /* mergecycle_all */ - -/*-<a href="qh-merge.htm#TOC" - >-------------------------------</a><a name="mergecycle_facets">-</a> - - qh_mergecycle_facets( samecycle, newfacet ) - finish merge of samecycle into newfacet - - returns: - samecycle prepended to visible_list for later deletion and partitioning - each facet->f.replace == newfacet - - newfacet moved to end of qh.facet_list - makes newfacet a newfacet (get's facet1->id if it was old) - sets newfacet->newmerge - clears newfacet->center (unless merging into a large facet) - clears newfacet->tested and ridge->tested for facet1 - - adds neighboring facets to facet_mergeset if redundant or degenerate - - design: - make newfacet a new facet and set its flags - move samecycle facets to qh.visible_list for later deletion - unless newfacet is large - remove its centrum -*/ -void qh_mergecycle_facets(facetT *samecycle, facetT *newfacet) { - facetT *same, *next; - - trace4((qh ferr, 4030, "qh_mergecycle_facets: make newfacet new and samecycle deleted\n")); - qh_removefacet(newfacet); /* append as a newfacet to end of qh facet_list */ - qh_appendfacet(newfacet); - newfacet->newfacet= True; - newfacet->simplicial= False; - newfacet->newmerge= True; - - for (same= samecycle->f.samecycle; same; same= (same == samecycle ? NULL : next)) { - next= same->f.samecycle; /* reused by willdelete */ - qh_willdelete(same, newfacet); - } - if (newfacet->center - && qh_setsize(newfacet->vertices) <= qh hull_dim + qh_MAXnewcentrum) { - qh_memfree(newfacet->center, qh normal_size); - newfacet->center= NULL; - } - trace3((qh ferr, 3004, "qh_mergecycle_facets: merged facets from cycle f%d into f%d\n", - samecycle->id, newfacet->id)); -} /* mergecycle_facets */ - -/*-<a href="qh-merge.htm#TOC" - >-------------------------------</a><a name="mergecycle_neighbors">-</a> - - qh_mergecycle_neighbors( samecycle, newfacet ) - add neighbors for samecycle facets to newfacet - - returns: - newfacet with updated neighbors and vice-versa - newfacet has ridges - all neighbors of newfacet marked with qh.visit_id - samecycle facets marked with qh.visit_id-1 - ridges updated for simplicial neighbors of samecycle with a ridge - - notes: - assumes newfacet not in samecycle - usually, samecycle facets are new, simplicial facets without internal ridges - not so if horizon facet is coplanar to two different samecycles - - see: - qh_mergeneighbors() - - design: - check samecycle - delete neighbors from newfacet that are also in samecycle - for each neighbor of a facet in samecycle - if neighbor is simplicial - if first visit - move the neighbor relation to newfacet - update facet links for its ridges - else - make ridges for neighbor - remove samecycle reference - else - update neighbor sets -*/ -void qh_mergecycle_neighbors(facetT *samecycle, facetT *newfacet) { - facetT *same, *neighbor, **neighborp; - int delneighbors= 0, newneighbors= 0; - unsigned int samevisitid; - ridgeT *ridge, **ridgep; - - samevisitid= ++qh visit_id; - FORALLsame_cycle_(samecycle) { - if (same->visitid == samevisitid || same->visible) - qh_infiniteloop(samecycle); - same->visitid= samevisitid; - } - newfacet->visitid= ++qh visit_id; - trace4((qh ferr, 4031, "qh_mergecycle_neighbors: delete shared neighbors from newfacet\n")); - FOREACHneighbor_(newfacet) { - if (neighbor->visitid == samevisitid) { - SETref_(neighbor)= NULL; /* samecycle neighbors deleted */ - delneighbors++; - }else - neighbor->visitid= qh visit_id; - } - qh_setcompact(newfacet->neighbors); - - trace4((qh ferr, 4032, "qh_mergecycle_neighbors: update neighbors\n")); - FORALLsame_cycle_(samecycle) { - FOREACHneighbor_(same) { - if (neighbor->visitid == samevisitid) - continue; - if (neighbor->simplicial) { - if (neighbor->visitid != qh visit_id) { - qh_setappend(&newfacet->neighbors, neighbor); - qh_setreplace(neighbor->neighbors, same, newfacet); - newneighbors++; - neighbor->visitid= qh visit_id; - FOREACHridge_(neighbor->ridges) { /* update ridge in case of qh_makeridges */ - if (ridge->top == same) { - ridge->top= newfacet; - break; - }else if (ridge->bottom == same) { - ridge->bottom= newfacet; - break; - } - } - }else { - qh_makeridges(neighbor); - qh_setdel(neighbor->neighbors, same); - /* same can't be horizon facet for neighbor */ - } - }else { /* non-simplicial neighbor */ - qh_setdel(neighbor->neighbors, same); - if (neighbor->visitid != qh visit_id) { - qh_setappend(&neighbor->neighbors, newfacet); - qh_setappend(&newfacet->neighbors, neighbor); - neighbor->visitid= qh visit_id; - newneighbors++; - } - } - } - } - trace2((qh ferr, 2032, "qh_mergecycle_neighbors: deleted %d neighbors and added %d\n", - delneighbors, newneighbors)); -} /* mergecycle_neighbors */ - -/*-<a href="qh-merge.htm#TOC" - >-------------------------------</a><a name="mergecycle_ridges">-</a> - - qh_mergecycle_ridges( samecycle, newfacet ) - add ridges/neighbors for facets in samecycle to newfacet - all new/old neighbors of newfacet marked with qh.visit_id - facets in samecycle marked with qh.visit_id-1 - newfacet marked with qh.visit_id - - returns: - newfacet has merged ridges - - notes: - ridge already updated for simplicial neighbors of samecycle with a ridge - - see: - qh_mergeridges() - qh_makeridges() - - design: - remove ridges between newfacet and samecycle - for each facet in samecycle - for each ridge in facet - update facet pointers in ridge - skip ridges processed in qh_mergecycle_neighors - free ridges between newfacet and samecycle - free ridges between facets of samecycle (on 2nd visit) - append remaining ridges to newfacet - if simpilicial facet - for each neighbor of facet - if simplicial facet - and not samecycle facet or newfacet - make ridge between neighbor and newfacet -*/ -void qh_mergecycle_ridges(facetT *samecycle, facetT *newfacet) { - facetT *same, *neighbor= NULL; - int numold=0, numnew=0; - int neighbor_i, neighbor_n; - unsigned int samevisitid; - ridgeT *ridge, **ridgep; - boolT toporient; - void **freelistp; /* used !qh_NOmem */ - - trace4((qh ferr, 4033, "qh_mergecycle_ridges: delete shared ridges from newfacet\n")); - samevisitid= qh visit_id -1; - FOREACHridge_(newfacet->ridges) { - neighbor= otherfacet_(ridge, newfacet); - if (neighbor->visitid == samevisitid) - SETref_(ridge)= NULL; /* ridge free'd below */ - } - qh_setcompact(newfacet->ridges); - - trace4((qh ferr, 4034, "qh_mergecycle_ridges: add ridges to newfacet\n")); - FORALLsame_cycle_(samecycle) { - FOREACHridge_(same->ridges) { - if (ridge->top == same) { - ridge->top= newfacet; - neighbor= ridge->bottom; - }else if (ridge->bottom == same) { - ridge->bottom= newfacet; - neighbor= ridge->top; - }else if (ridge->top == newfacet || ridge->bottom == newfacet) { - qh_setappend(&newfacet->ridges, ridge); - numold++; /* already set by qh_mergecycle_neighbors */ - continue; - }else { - qh_fprintf(qh ferr, 6098, "qhull internal error (qh_mergecycle_ridges): bad ridge r%d\n", ridge->id); - qh_errexit(qh_ERRqhull, NULL, ridge); - } - if (neighbor == newfacet) { - qh_setfree(&(ridge->vertices)); - qh_memfree_(ridge, (int)sizeof(ridgeT), freelistp); - numold++; - }else if (neighbor->visitid == samevisitid) { - qh_setdel(neighbor->ridges, ridge); - qh_setfree(&(ridge->vertices)); - qh_memfree_(ridge, (int)sizeof(ridgeT), freelistp); - numold++; - }else { - qh_setappend(&newfacet->ridges, ridge); - numold++; - } - } - if (same->ridges) - qh_settruncate(same->ridges, 0); - if (!same->simplicial) - continue; - FOREACHneighbor_i_(same) { /* note: !newfact->simplicial */ - if (neighbor->visitid != samevisitid && neighbor->simplicial) { - ridge= qh_newridge(); - ridge->vertices= qh_setnew_delnthsorted(same->vertices, qh hull_dim, - neighbor_i, 0); - toporient= same->toporient ^ (neighbor_i & 0x1); - if (toporient) { - ridge->top= newfacet; - ridge->bottom= neighbor; - }else { - ridge->top= neighbor; - ridge->bottom= newfacet; - } - qh_setappend(&(newfacet->ridges), ridge); - qh_setappend(&(neighbor->ridges), ridge); - numnew++; - } - } - } - - trace2((qh ferr, 2033, "qh_mergecycle_ridges: found %d old ridges and %d new ones\n", - numold, numnew)); -} /* mergecycle_ridges */ - -/*-<a href="qh-merge.htm#TOC" - >-------------------------------</a><a name="mergecycle_vneighbors">-</a> - - qh_mergecycle_vneighbors( samecycle, newfacet ) - create vertex neighbors for newfacet from vertices of facets in samecycle - samecycle marked with visitid == qh.visit_id - 1 - - returns: - newfacet vertices with updated neighbors - marks newfacet with qh.visit_id-1 - deletes vertices that are merged away - sets delridge on all vertices (faster here than in mergecycle_ridges) - - see: - qh_mergevertex_neighbors() - - design: - for each vertex of samecycle facet - set vertex->delridge - delete samecycle facets from vertex neighbors - append newfacet to vertex neighbors - if vertex only in newfacet - delete it from newfacet - add it to qh.del_vertices for later deletion -*/ -void qh_mergecycle_vneighbors(facetT *samecycle, facetT *newfacet) { - facetT *neighbor, **neighborp; - unsigned int mergeid; - vertexT *vertex, **vertexp, *apex; - setT *vertices; - - trace4((qh ferr, 4035, "qh_mergecycle_vneighbors: update vertex neighbors for newfacet\n")); - mergeid= qh visit_id - 1; - newfacet->visitid= mergeid; - vertices= qh_basevertices(samecycle); /* temp */ - apex= SETfirstt_(samecycle->vertices, vertexT); - qh_setappend(&vertices, apex); - FOREACHvertex_(vertices) { - vertex->delridge= True; - FOREACHneighbor_(vertex) { - if (neighbor->visitid == mergeid) - SETref_(neighbor)= NULL; - } - qh_setcompact(vertex->neighbors); - qh_setappend(&vertex->neighbors, newfacet); - if (!SETsecond_(vertex->neighbors)) { - zinc_(Zcyclevertex); - trace2((qh ferr, 2034, "qh_mergecycle_vneighbors: deleted v%d when merging cycle f%d into f%d\n", - vertex->id, samecycle->id, newfacet->id)); - qh_setdelsorted(newfacet->vertices, vertex); - vertex->deleted= True; - qh_setappend(&qh del_vertices, vertex); - } - } - qh_settempfree(&vertices); - trace3((qh ferr, 3005, "qh_mergecycle_vneighbors: merged vertices from cycle f%d into f%d\n", - samecycle->id, newfacet->id)); -} /* mergecycle_vneighbors */ - -/*-<a href="qh-merge.htm#TOC" - >-------------------------------</a><a name="mergefacet">-</a> - - qh_mergefacet( facet1, facet2, mindist, maxdist, mergeapex ) - merges facet1 into facet2 - mergeapex==qh_MERGEapex if merging new facet into coplanar horizon - - returns: - qh.max_outside and qh.min_vertex updated - initializes vertex neighbors on first merge - - returns: - facet2 contains facet1's vertices, neighbors, and ridges - facet2 moved to end of qh.facet_list - makes facet2 a newfacet - sets facet2->newmerge set - clears facet2->center (unless merging into a large facet) - clears facet2->tested and ridge->tested for facet1 - - facet1 prepended to visible_list for later deletion and partitioning - facet1->f.replace == facet2 - - adds neighboring facets to facet_mergeset if redundant or degenerate - - notes: - mindist/maxdist may be NULL (only if both NULL) - traces merge if fmax_(maxdist,-mindist) > TRACEdist - - see: - qh_mergecycle() - - design: - trace merge and check for degenerate simplex - make ridges for both facets - update qh.max_outside, qh.max_vertex, qh.min_vertex - update facet2->maxoutside and keepcentrum - update facet2->nummerge - update tested flags for facet2 - if facet1 is simplicial - merge facet1 into facet2 - else - merge facet1's neighbors into facet2 - merge facet1's ridges into facet2 - merge facet1's vertices into facet2 - merge facet1's vertex neighbors into facet2 - add facet2's vertices to qh.new_vertexlist - unless qh_MERGEapex - test facet2 for degenerate or redundant neighbors - move facet1 to qh.visible_list for later deletion - move facet2 to end of qh.newfacet_list -*/ -void qh_mergefacet(facetT *facet1, facetT *facet2, realT *mindist, realT *maxdist, boolT mergeapex) { - boolT traceonce= False; - vertexT *vertex, **vertexp; - int tracerestore=0, nummerge; - - if (facet1->tricoplanar || facet2->tricoplanar) { - if (!qh TRInormals) { - qh_fprintf(qh ferr, 6226, "Qhull internal error (qh_mergefacet): does not work for tricoplanar facets. Use option 'Q11'\n"); - qh_errexit2 (qh_ERRqhull, facet1, facet2); - } - if (facet2->tricoplanar) { - facet2->tricoplanar= False; - facet2->keepcentrum= False; - } - } - zzinc_(Ztotmerge); - if (qh REPORTfreq2 && qh POSTmerging) { - if (zzval_(Ztotmerge) > qh mergereport + qh REPORTfreq2) - qh_tracemerging(); - } -#ifndef qh_NOtrace - if (qh build_cnt >= qh RERUN) { - if (mindist && (-*mindist > qh TRACEdist || *maxdist > qh TRACEdist)) { - tracerestore= 0; - qh IStracing= qh TRACElevel; - traceonce= True; - qh_fprintf(qh ferr, 8075, "qh_mergefacet: ========= trace wide merge #%d(%2.2g) for f%d into f%d, last point was p%d\n", zzval_(Ztotmerge), - fmax_(-*mindist, *maxdist), facet1->id, facet2->id, qh furthest_id); - }else if (facet1 == qh tracefacet || facet2 == qh tracefacet) { - tracerestore= qh IStracing; - qh IStracing= 4; - traceonce= True; - qh_fprintf(qh ferr, 8076, "qh_mergefacet: ========= trace merge #%d involving f%d, furthest is p%d\n", - zzval_(Ztotmerge), qh tracefacet_id, qh furthest_id); - } - } - if (qh IStracing >= 2) { - realT mergemin= -2; - realT mergemax= -2; - - if (mindist) { - mergemin= *mindist; - mergemax= *maxdist; - } - qh_fprintf(qh ferr, 8077, "qh_mergefacet: #%d merge f%d into f%d, mindist= %2.2g, maxdist= %2.2g\n", - zzval_(Ztotmerge), facet1->id, facet2->id, mergemin, mergemax); - } -#endif /* !qh_NOtrace */ - if (facet1 == facet2 || facet1->visible || facet2->visible) { - qh_fprintf(qh ferr, 6099, "qhull internal error (qh_mergefacet): either f%d and f%d are the same or one is a visible facet\n", - facet1->id, facet2->id); - qh_errexit2 (qh_ERRqhull, facet1, facet2); - } - if (qh num_facets - qh num_visible <= qh hull_dim + 1) { - qh_fprintf(qh ferr, 6227, "\n\ -qhull precision error: Only %d facets remain. Can not merge another\n\ -pair. The input is too degenerate or the convexity constraints are\n\ -too strong.\n", qh hull_dim+1); - if (qh hull_dim >= 5 && !qh MERGEexact) - qh_fprintf(qh ferr, 8079, "Option 'Qx' may avoid this problem.\n"); - qh_errexit(qh_ERRprec, NULL, NULL); - } - if (!qh VERTEXneighbors) - qh_vertexneighbors(); - qh_makeridges(facet1); - qh_makeridges(facet2); - if (qh IStracing >=4) - qh_errprint("MERGING", facet1, facet2, NULL, NULL); - if (mindist) { - maximize_(qh max_outside, *maxdist); - maximize_(qh max_vertex, *maxdist); -#if qh_MAXoutside - maximize_(facet2->maxoutside, *maxdist); -#endif - minimize_(qh min_vertex, *mindist); - if (!facet2->keepcentrum - && (*maxdist > qh WIDEfacet || *mindist < -qh WIDEfacet)) { - facet2->keepcentrum= True; - zinc_(Zwidefacet); - } - } - nummerge= facet1->nummerge + facet2->nummerge + 1; - if (nummerge >= qh_MAXnummerge) - facet2->nummerge= qh_MAXnummerge; - else - facet2->nummerge= (short unsigned int)nummerge; - facet2->newmerge= True; - facet2->dupridge= False; - qh_updatetested (facet1, facet2); - if (qh hull_dim > 2 && qh_setsize(facet1->vertices) == qh hull_dim) - qh_mergesimplex(facet1, facet2, mergeapex); - else { - qh vertex_visit++; - FOREACHvertex_(facet2->vertices) - vertex->visitid= qh vertex_visit; - if (qh hull_dim == 2) - qh_mergefacet2d(facet1, facet2); - else { - qh_mergeneighbors(facet1, facet2); - qh_mergevertices(facet1->vertices, &facet2->vertices); - } - qh_mergeridges(facet1, facet2); - qh_mergevertex_neighbors(facet1, facet2); - if (!facet2->newfacet) - qh_newvertices(facet2->vertices); - } - if (!mergeapex) - qh_degen_redundant_neighbors(facet2, facet1); - if (facet2->coplanar || !facet2->newfacet) { - zinc_(Zmergeintohorizon); - }else if (!facet1->newfacet && facet2->newfacet) { - zinc_(Zmergehorizon); - }else { - zinc_(Zmergenew); - } - qh_willdelete(facet1, facet2); - qh_removefacet(facet2); /* append as a newfacet to end of qh facet_list */ - qh_appendfacet(facet2); - facet2->newfacet= True; - facet2->tested= False; - qh_tracemerge(facet1, facet2); - if (traceonce) { - qh_fprintf(qh ferr, 8080, "qh_mergefacet: end of wide tracing\n"); - qh IStracing= tracerestore; - } -} /* mergefacet */ - - -/*-<a href="qh-merge.htm#TOC" - >-------------------------------</a><a name="mergefacet2d">-</a> - - qh_mergefacet2d( facet1, facet2 ) - in 2d, merges neighbors and vertices of facet1 into facet2 - - returns: - build ridges for neighbors if necessary - facet2 looks like a simplicial facet except for centrum, ridges - neighbors are opposite the corresponding vertex - maintains orientation of facet2 - - notes: - qh_mergefacet() retains non-simplicial structures - they are not needed in 2d, but later routines may use them - preserves qh.vertex_visit for qh_mergevertex_neighbors() - - design: - get vertices and neighbors - determine new vertices and neighbors - set new vertices and neighbors and adjust orientation - make ridges for new neighbor if needed -*/ -void qh_mergefacet2d(facetT *facet1, facetT *facet2) { - vertexT *vertex1A, *vertex1B, *vertex2A, *vertex2B, *vertexA, *vertexB; - facetT *neighbor1A, *neighbor1B, *neighbor2A, *neighbor2B, *neighborA, *neighborB; - - vertex1A= SETfirstt_(facet1->vertices, vertexT); - vertex1B= SETsecondt_(facet1->vertices, vertexT); - vertex2A= SETfirstt_(facet2->vertices, vertexT); - vertex2B= SETsecondt_(facet2->vertices, vertexT); - neighbor1A= SETfirstt_(facet1->neighbors, facetT); - neighbor1B= SETsecondt_(facet1->neighbors, facetT); - neighbor2A= SETfirstt_(facet2->neighbors, facetT); - neighbor2B= SETsecondt_(facet2->neighbors, facetT); - if (vertex1A == vertex2A) { - vertexA= vertex1B; - vertexB= vertex2B; - neighborA= neighbor2A; - neighborB= neighbor1A; - }else if (vertex1A == vertex2B) { - vertexA= vertex1B; - vertexB= vertex2A; - neighborA= neighbor2B; - neighborB= neighbor1A; - }else if (vertex1B == vertex2A) { - vertexA= vertex1A; - vertexB= vertex2B; - neighborA= neighbor2A; - neighborB= neighbor1B; - }else { /* 1B == 2B */ - vertexA= vertex1A; - vertexB= vertex2A; - neighborA= neighbor2B; - neighborB= neighbor1B; - } - /* vertexB always from facet2, neighborB always from facet1 */ - if (vertexA->id > vertexB->id) { - SETfirst_(facet2->vertices)= vertexA; - SETsecond_(facet2->vertices)= vertexB; - if (vertexB == vertex2A) - facet2->toporient= !facet2->toporient; - SETfirst_(facet2->neighbors)= neighborA; - SETsecond_(facet2->neighbors)= neighborB; - }else { - SETfirst_(facet2->vertices)= vertexB; - SETsecond_(facet2->vertices)= vertexA; - if (vertexB == vertex2B) - facet2->toporient= !facet2->toporient; - SETfirst_(facet2->neighbors)= neighborB; - SETsecond_(facet2->neighbors)= neighborA; - } - qh_makeridges(neighborB); - qh_setreplace(neighborB->neighbors, facet1, facet2); - trace4((qh ferr, 4036, "qh_mergefacet2d: merged v%d and neighbor f%d of f%d into f%d\n", - vertexA->id, neighborB->id, facet1->id, facet2->id)); -} /* mergefacet2d */ - - -/*-<a href="qh-merge.htm#TOC" - >-------------------------------</a><a name="mergeneighbors">-</a> - - qh_mergeneighbors( facet1, facet2 ) - merges the neighbors of facet1 into facet2 - - see: - qh_mergecycle_neighbors() - - design: - for each neighbor of facet1 - if neighbor is also a neighbor of facet2 - if neighbor is simpilicial - make ridges for later deletion as a degenerate facet - update its neighbor set - else - move the neighbor relation to facet2 - remove the neighbor relation for facet1 and facet2 -*/ -void qh_mergeneighbors(facetT *facet1, facetT *facet2) { - facetT *neighbor, **neighborp; - - trace4((qh ferr, 4037, "qh_mergeneighbors: merge neighbors of f%d and f%d\n", - facet1->id, facet2->id)); - qh visit_id++; - FOREACHneighbor_(facet2) { - neighbor->visitid= qh visit_id; - } - FOREACHneighbor_(facet1) { - if (neighbor->visitid == qh visit_id) { - if (neighbor->simplicial) /* is degen, needs ridges */ - qh_makeridges(neighbor); - if (SETfirstt_(neighbor->neighbors, facetT) != facet1) /*keep newfacet->horizon*/ - qh_setdel(neighbor->neighbors, facet1); - else { - qh_setdel(neighbor->neighbors, facet2); - qh_setreplace(neighbor->neighbors, facet1, facet2); - } - }else if (neighbor != facet2) { - qh_setappend(&(facet2->neighbors), neighbor); - qh_setreplace(neighbor->neighbors, facet1, facet2); - } - } - qh_setdel(facet1->neighbors, facet2); /* here for makeridges */ - qh_setdel(facet2->neighbors, facet1); -} /* mergeneighbors */ - - -/*-<a href="qh-merge.htm#TOC" - >-------------------------------</a><a name="mergeridges">-</a> - - qh_mergeridges( facet1, facet2 ) - merges the ridge set of facet1 into facet2 - - returns: - may delete all ridges for a vertex - sets vertex->delridge on deleted ridges - - see: - qh_mergecycle_ridges() - - design: - delete ridges between facet1 and facet2 - mark (delridge) vertices on these ridges for later testing - for each remaining ridge - rename facet1 to facet2 -*/ -void qh_mergeridges(facetT *facet1, facetT *facet2) { - ridgeT *ridge, **ridgep; - vertexT *vertex, **vertexp; - - trace4((qh ferr, 4038, "qh_mergeridges: merge ridges of f%d and f%d\n", - facet1->id, facet2->id)); - FOREACHridge_(facet2->ridges) { - if ((ridge->top == facet1) || (ridge->bottom == facet1)) { - FOREACHvertex_(ridge->vertices) - vertex->delridge= True; - qh_delridge(ridge); /* expensive in high-d, could rebuild */ - ridgep--; /*repeat*/ - } - } - FOREACHridge_(facet1->ridges) { - if (ridge->top == facet1) - ridge->top= facet2; - else - ridge->bottom= facet2; - qh_setappend(&(facet2->ridges), ridge); - } -} /* mergeridges */ - - -/*-<a href="qh-merge.htm#TOC" - >-------------------------------</a><a name="mergesimplex">-</a> - - qh_mergesimplex( facet1, facet2, mergeapex ) - merge simplicial facet1 into facet2 - mergeapex==qh_MERGEapex if merging samecycle into horizon facet - vertex id is latest (most recently created) - facet1 may be contained in facet2 - ridges exist for both facets - - returns: - facet2 with updated vertices, ridges, neighbors - updated neighbors for facet1's vertices - facet1 not deleted - sets vertex->delridge on deleted ridges - - notes: - special case code since this is the most common merge - called from qh_mergefacet() - - design: - if qh_MERGEapex - add vertices of facet2 to qh.new_vertexlist if necessary - add apex to facet2 - else - for each ridge between facet1 and facet2 - set vertex->delridge - determine the apex for facet1 (i.e., vertex to be merged) - unless apex already in facet2 - insert apex into vertices for facet2 - add vertices of facet2 to qh.new_vertexlist if necessary - add apex to qh.new_vertexlist if necessary - for each vertex of facet1 - if apex - rename facet1 to facet2 in its vertex neighbors - else - delete facet1 from vertex neighors - if only in facet2 - add vertex to qh.del_vertices for later deletion - for each ridge of facet1 - delete ridges between facet1 and facet2 - append other ridges to facet2 after renaming facet to facet2 -*/ -void qh_mergesimplex(facetT *facet1, facetT *facet2, boolT mergeapex) { - vertexT *vertex, **vertexp, *apex; - ridgeT *ridge, **ridgep; - boolT issubset= False; - int vertex_i= -1, vertex_n; - facetT *neighbor, **neighborp, *otherfacet; - - if (mergeapex) { - if (!facet2->newfacet) - qh_newvertices(facet2->vertices); /* apex is new */ - apex= SETfirstt_(facet1->vertices, vertexT); - if (SETfirstt_(facet2->vertices, vertexT) != apex) - qh_setaddnth(&facet2->vertices, 0, apex); /* apex has last id */ - else - issubset= True; - }else { - zinc_(Zmergesimplex); - FOREACHvertex_(facet1->vertices) - vertex->seen= False; - FOREACHridge_(facet1->ridges) { - if (otherfacet_(ridge, facet1) == facet2) { - FOREACHvertex_(ridge->vertices) { - vertex->seen= True; - vertex->delridge= True; - } - break; - } - } - FOREACHvertex_(facet1->vertices) { - if (!vertex->seen) - break; /* must occur */ - } - apex= vertex; - trace4((qh ferr, 4039, "qh_mergesimplex: merge apex v%d of f%d into facet f%d\n", - apex->id, facet1->id, facet2->id)); - FOREACHvertex_i_(facet2->vertices) { - if (vertex->id < apex->id) { - break; - }else if (vertex->id == apex->id) { - issubset= True; - break; - } - } - if (!issubset) - qh_setaddnth(&facet2->vertices, vertex_i, apex); - if (!facet2->newfacet) - qh_newvertices(facet2->vertices); - else if (!apex->newlist) { - qh_removevertex(apex); - qh_appendvertex(apex); - } - } - trace4((qh ferr, 4040, "qh_mergesimplex: update vertex neighbors of f%d\n", - facet1->id)); - FOREACHvertex_(facet1->vertices) { - if (vertex == apex && !issubset) - qh_setreplace(vertex->neighbors, facet1, facet2); - else { - qh_setdel(vertex->neighbors, facet1); - if (!SETsecond_(vertex->neighbors)) - qh_mergevertex_del(vertex, facet1, facet2); - } - } - trace4((qh ferr, 4041, "qh_mergesimplex: merge ridges and neighbors of f%d into f%d\n", - facet1->id, facet2->id)); - qh visit_id++; - FOREACHneighbor_(facet2) - neighbor->visitid= qh visit_id; - FOREACHridge_(facet1->ridges) { - otherfacet= otherfacet_(ridge, facet1); - if (otherfacet == facet2) { - qh_setdel(facet2->ridges, ridge); - qh_setfree(&(ridge->vertices)); - qh_memfree(ridge, (int)sizeof(ridgeT)); - qh_setdel(facet2->neighbors, facet1); - }else { - qh_setappend(&facet2->ridges, ridge); - if (otherfacet->visitid != qh visit_id) { - qh_setappend(&facet2->neighbors, otherfacet); - qh_setreplace(otherfacet->neighbors, facet1, facet2); - otherfacet->visitid= qh visit_id; - }else { - if (otherfacet->simplicial) /* is degen, needs ridges */ - qh_makeridges(otherfacet); - if (SETfirstt_(otherfacet->neighbors, facetT) != facet1) - qh_setdel(otherfacet->neighbors, facet1); - else { /*keep newfacet->neighbors->horizon*/ - qh_setdel(otherfacet->neighbors, facet2); - qh_setreplace(otherfacet->neighbors, facet1, facet2); - } - } - if (ridge->top == facet1) /* wait until after qh_makeridges */ - ridge->top= facet2; - else - ridge->bottom= facet2; - } - } - SETfirst_(facet1->ridges)= NULL; /* it will be deleted */ - trace3((qh ferr, 3006, "qh_mergesimplex: merged simplex f%d apex v%d into facet f%d\n", - facet1->id, getid_(apex), facet2->id)); -} /* mergesimplex */ - -/*-<a href="qh-merge.htm#TOC" - >-------------------------------</a><a name="mergevertex_del">-</a> - - qh_mergevertex_del( vertex, facet1, facet2 ) - delete a vertex because of merging facet1 into facet2 - - returns: - deletes vertex from facet2 - adds vertex to qh.del_vertices for later deletion -*/ -void qh_mergevertex_del(vertexT *vertex, facetT *facet1, facetT *facet2) { - - zinc_(Zmergevertex); - trace2((qh ferr, 2035, "qh_mergevertex_del: deleted v%d when merging f%d into f%d\n", - vertex->id, facet1->id, facet2->id)); - qh_setdelsorted(facet2->vertices, vertex); - vertex->deleted= True; - qh_setappend(&qh del_vertices, vertex); -} /* mergevertex_del */ - -/*-<a href="qh-merge.htm#TOC" - >-------------------------------</a><a name="mergevertex_neighbors">-</a> - - qh_mergevertex_neighbors( facet1, facet2 ) - merge the vertex neighbors of facet1 to facet2 - - returns: - if vertex is current qh.vertex_visit - deletes facet1 from vertex->neighbors - else - renames facet1 to facet2 in vertex->neighbors - deletes vertices if only one neighbor - - notes: - assumes vertex neighbor sets are good -*/ -void qh_mergevertex_neighbors(facetT *facet1, facetT *facet2) { - vertexT *vertex, **vertexp; - - trace4((qh ferr, 4042, "qh_mergevertex_neighbors: merge vertex neighbors of f%d and f%d\n", - facet1->id, facet2->id)); - if (qh tracevertex) { - qh_fprintf(qh ferr, 8081, "qh_mergevertex_neighbors: of f%d and f%d at furthest p%d f0= %p\n", - facet1->id, facet2->id, qh furthest_id, qh tracevertex->neighbors->e[0].p); - qh_errprint("TRACE", NULL, NULL, NULL, qh tracevertex); - } - FOREACHvertex_(facet1->vertices) { - if (vertex->visitid != qh vertex_visit) - qh_setreplace(vertex->neighbors, facet1, facet2); - else { - qh_setdel(vertex->neighbors, facet1); - if (!SETsecond_(vertex->neighbors)) - qh_mergevertex_del(vertex, facet1, facet2); - } - } - if (qh tracevertex) - qh_errprint("TRACE", NULL, NULL, NULL, qh tracevertex); -} /* mergevertex_neighbors */ - - -/*-<a href="qh-merge.htm#TOC" - >-------------------------------</a><a name="mergevertices">-</a> - - qh_mergevertices( vertices1, vertices2 ) - merges the vertex set of facet1 into facet2 - - returns: - replaces vertices2 with merged set - preserves vertex_visit for qh_mergevertex_neighbors - updates qh.newvertex_list - - design: - create a merged set of both vertices (in inverse id order) -*/ -void qh_mergevertices(setT *vertices1, setT **vertices2) { - int newsize= qh_setsize(vertices1)+qh_setsize(*vertices2) - qh hull_dim + 1; - setT *mergedvertices; - vertexT *vertex, **vertexp, **vertex2= SETaddr_(*vertices2, vertexT); - - mergedvertices= qh_settemp(newsize); - FOREACHvertex_(vertices1) { - if (!*vertex2 || vertex->id > (*vertex2)->id) - qh_setappend(&mergedvertices, vertex); - else { - while (*vertex2 && (*vertex2)->id > vertex->id) - qh_setappend(&mergedvertices, *vertex2++); - if (!*vertex2 || (*vertex2)->id < vertex->id) - qh_setappend(&mergedvertices, vertex); - else - qh_setappend(&mergedvertices, *vertex2++); - } - } - while (*vertex2) - qh_setappend(&mergedvertices, *vertex2++); - if (newsize < qh_setsize(mergedvertices)) { - qh_fprintf(qh ferr, 6100, "qhull internal error (qh_mergevertices): facets did not share a ridge\n"); - qh_errexit(qh_ERRqhull, NULL, NULL); - } - qh_setfree(vertices2); - *vertices2= mergedvertices; - qh_settemppop(); -} /* mergevertices */ - - -/*-<a href="qh-merge.htm#TOC" - >-------------------------------</a><a name="neighbor_intersections">-</a> - - qh_neighbor_intersections( vertex ) - return intersection of all vertices in vertex->neighbors except for vertex - - returns: - returns temporary set of vertices - does not include vertex - NULL if a neighbor is simplicial - NULL if empty set - - notes: - used for renaming vertices - - design: - initialize the intersection set with vertices of the first two neighbors - delete vertex from the intersection - for each remaining neighbor - intersect its vertex set with the intersection set - return NULL if empty - return the intersection set -*/ -setT *qh_neighbor_intersections(vertexT *vertex) { - facetT *neighbor, **neighborp, *neighborA, *neighborB; - setT *intersect; - int neighbor_i, neighbor_n; - - FOREACHneighbor_(vertex) { - if (neighbor->simplicial) - return NULL; - } - neighborA= SETfirstt_(vertex->neighbors, facetT); - neighborB= SETsecondt_(vertex->neighbors, facetT); - zinc_(Zintersectnum); - if (!neighborA) - return NULL; - if (!neighborB) - intersect= qh_setcopy(neighborA->vertices, 0); - else - intersect= qh_vertexintersect_new(neighborA->vertices, neighborB->vertices); - qh_settemppush(intersect); - qh_setdelsorted(intersect, vertex); - FOREACHneighbor_i_(vertex) { - if (neighbor_i >= 2) { - zinc_(Zintersectnum); - qh_vertexintersect(&intersect, neighbor->vertices); - if (!SETfirst_(intersect)) { - zinc_(Zintersectfail); - qh_settempfree(&intersect); - return NULL; - } - } - } - trace3((qh ferr, 3007, "qh_neighbor_intersections: %d vertices in neighbor intersection of v%d\n", - qh_setsize(intersect), vertex->id)); - return intersect; -} /* neighbor_intersections */ - -/*-<a href="qh-merge.htm#TOC" - >-------------------------------</a><a name="newvertices">-</a> - - qh_newvertices( vertices ) - add vertices to end of qh.vertex_list (marks as new vertices) - - returns: - vertices on qh.newvertex_list - vertex->newlist set -*/ -void qh_newvertices(setT *vertices) { - vertexT *vertex, **vertexp; - - FOREACHvertex_(vertices) { - if (!vertex->newlist) { - qh_removevertex(vertex); - qh_appendvertex(vertex); - } - } -} /* newvertices */ - -/*-<a href="qh-merge.htm#TOC" - >-------------------------------</a><a name="reducevertices">-</a> - - qh_reducevertices() - reduce extra vertices, shared vertices, and redundant vertices - facet->newmerge is set if merged since last call - if !qh.MERGEvertices, only removes extra vertices - - returns: - True if also merged degen_redundant facets - vertices are renamed if possible - clears facet->newmerge and vertex->delridge - - notes: - ignored if 2-d - - design: - merge any degenerate or redundant facets - for each newly merged facet - remove extra vertices - if qh.MERGEvertices - for each newly merged facet - for each vertex - if vertex was on a deleted ridge - rename vertex if it is shared - remove delridge flag from new vertices -*/ -boolT qh_reducevertices(void) { - int numshare=0, numrename= 0; - boolT degenredun= False; - facetT *newfacet; - vertexT *vertex, **vertexp; - - if (qh hull_dim == 2) - return False; - if (qh_merge_degenredundant()) - degenredun= True; - LABELrestart: - FORALLnew_facets { - if (newfacet->newmerge) { - if (!qh MERGEvertices) - newfacet->newmerge= False; - qh_remove_extravertices(newfacet); - } - } - if (!qh MERGEvertices) - return False; - FORALLnew_facets { - if (newfacet->newmerge) { - newfacet->newmerge= False; - FOREACHvertex_(newfacet->vertices) { - if (vertex->delridge) { - if (qh_rename_sharedvertex(vertex, newfacet)) { - numshare++; - vertexp--; /* repeat since deleted vertex */ - } - } - } - } - } - FORALLvertex_(qh newvertex_list) { - if (vertex->delridge && !vertex->deleted) { - vertex->delridge= False; - if (qh hull_dim >= 4 && qh_redundant_vertex(vertex)) { - numrename++; - if (qh_merge_degenredundant()) { - degenredun= True; - goto LABELrestart; - } - } - } - } - trace1((qh ferr, 1014, "qh_reducevertices: renamed %d shared vertices and %d redundant vertices. Degen? %d\n", - numshare, numrename, degenredun)); - return degenredun; -} /* reducevertices */ - -/*-<a href="qh-merge.htm#TOC" - >-------------------------------</a><a name="redundant_vertex">-</a> - - qh_redundant_vertex( vertex ) - detect and rename a redundant vertex - vertices have full vertex->neighbors - - returns: - returns true if find a redundant vertex - deletes vertex(vertex->deleted) - - notes: - only needed if vertex->delridge and hull_dim >= 4 - may add degenerate facets to qh.facet_mergeset - doesn't change vertex->neighbors or create redundant facets - - design: - intersect vertices of all facet neighbors of vertex - determine ridges for these vertices - if find a new vertex for vertex amoung these ridges and vertices - rename vertex to the new vertex -*/ -vertexT *qh_redundant_vertex(vertexT *vertex) { - vertexT *newvertex= NULL; - setT *vertices, *ridges; - - trace3((qh ferr, 3008, "qh_redundant_vertex: check if v%d can be renamed\n", vertex->id)); - if ((vertices= qh_neighbor_intersections(vertex))) { - ridges= qh_vertexridges(vertex); - if ((newvertex= qh_find_newvertex(vertex, vertices, ridges))) - qh_renamevertex(vertex, newvertex, ridges, NULL, NULL); - qh_settempfree(&ridges); - qh_settempfree(&vertices); - } - return newvertex; -} /* redundant_vertex */ - -/*-<a href="qh-merge.htm#TOC" - >-------------------------------</a><a name="remove_extravertices">-</a> - - qh_remove_extravertices( facet ) - remove extra vertices from non-simplicial facets - - returns: - returns True if it finds them - - design: - for each vertex in facet - if vertex not in a ridge (i.e., no longer used) - delete vertex from facet - delete facet from vertice's neighbors - unless vertex in another facet - add vertex to qh.del_vertices for later deletion -*/ -boolT qh_remove_extravertices(facetT *facet) { - ridgeT *ridge, **ridgep; - vertexT *vertex, **vertexp; - boolT foundrem= False; - - trace4((qh ferr, 4043, "qh_remove_extravertices: test f%d for extra vertices\n", - facet->id)); - FOREACHvertex_(facet->vertices) - vertex->seen= False; - FOREACHridge_(facet->ridges) { - FOREACHvertex_(ridge->vertices) - vertex->seen= True; - } - FOREACHvertex_(facet->vertices) { - if (!vertex->seen) { - foundrem= True; - zinc_(Zremvertex); - qh_setdelsorted(facet->vertices, vertex); - qh_setdel(vertex->neighbors, facet); - if (!qh_setsize(vertex->neighbors)) { - vertex->deleted= True; - qh_setappend(&qh del_vertices, vertex); - zinc_(Zremvertexdel); - trace2((qh ferr, 2036, "qh_remove_extravertices: v%d deleted because it's lost all ridges\n", vertex->id)); - }else - trace3((qh ferr, 3009, "qh_remove_extravertices: v%d removed from f%d because it's lost all ridges\n", vertex->id, facet->id)); - vertexp--; /*repeat*/ - } - } - return foundrem; -} /* remove_extravertices */ - -/*-<a href="qh-merge.htm#TOC" - >-------------------------------</a><a name="rename_sharedvertex">-</a> - - qh_rename_sharedvertex( vertex, facet ) - detect and rename if shared vertex in facet - vertices have full ->neighbors - - returns: - newvertex or NULL - the vertex may still exist in other facets (i.e., a neighbor was pinched) - does not change facet->neighbors - updates vertex->neighbors - - notes: - a shared vertex for a facet is only in ridges to one neighbor - this may undo a pinched facet - - it does not catch pinches involving multiple facets. These appear - to be difficult to detect, since an exhaustive search is too expensive. - - design: - if vertex only has two neighbors - determine the ridges that contain the vertex - determine the vertices shared by both neighbors - if can find a new vertex in this set - rename the vertex to the new vertex -*/ -vertexT *qh_rename_sharedvertex(vertexT *vertex, facetT *facet) { - facetT *neighbor, **neighborp, *neighborA= NULL; - setT *vertices, *ridges; - vertexT *newvertex; - - if (qh_setsize(vertex->neighbors) == 2) { - neighborA= SETfirstt_(vertex->neighbors, facetT); - if (neighborA == facet) - neighborA= SETsecondt_(vertex->neighbors, facetT); - }else if (qh hull_dim == 3) - return NULL; - else { - qh visit_id++; - FOREACHneighbor_(facet) - neighbor->visitid= qh visit_id; - FOREACHneighbor_(vertex) { - if (neighbor->visitid == qh visit_id) { - if (neighborA) - return NULL; - neighborA= neighbor; - } - } - if (!neighborA) { - qh_fprintf(qh ferr, 6101, "qhull internal error (qh_rename_sharedvertex): v%d's neighbors not in f%d\n", - vertex->id, facet->id); - qh_errprint("ERRONEOUS", facet, NULL, NULL, vertex); - qh_errexit(qh_ERRqhull, NULL, NULL); - } - } - /* the vertex is shared by facet and neighborA */ - ridges= qh_settemp(qh TEMPsize); - neighborA->visitid= ++qh visit_id; - qh_vertexridges_facet(vertex, facet, &ridges); - trace2((qh ferr, 2037, "qh_rename_sharedvertex: p%d(v%d) is shared by f%d(%d ridges) and f%d\n", - qh_pointid(vertex->point), vertex->id, facet->id, qh_setsize(ridges), neighborA->id)); - zinc_(Zintersectnum); - vertices= qh_vertexintersect_new(facet->vertices, neighborA->vertices); - qh_setdel(vertices, vertex); - qh_settemppush(vertices); - if ((newvertex= qh_find_newvertex(vertex, vertices, ridges))) - qh_renamevertex(vertex, newvertex, ridges, facet, neighborA); - qh_settempfree(&vertices); - qh_settempfree(&ridges); - return newvertex; -} /* rename_sharedvertex */ - -/*-<a href="qh-merge.htm#TOC" - >-------------------------------</a><a name="renameridgevertex">-</a> - - qh_renameridgevertex( ridge, oldvertex, newvertex ) - renames oldvertex as newvertex in ridge - - returns: - - design: - delete oldvertex from ridge - if newvertex already in ridge - copy ridge->noconvex to another ridge if possible - delete the ridge - else - insert newvertex into the ridge - adjust the ridge's orientation -*/ -void qh_renameridgevertex(ridgeT *ridge, vertexT *oldvertex, vertexT *newvertex) { - int nth= 0, oldnth; - facetT *temp; - vertexT *vertex, **vertexp; - - oldnth= qh_setindex(ridge->vertices, oldvertex); - qh_setdelnthsorted(ridge->vertices, oldnth); - FOREACHvertex_(ridge->vertices) { - if (vertex == newvertex) { - zinc_(Zdelridge); - if (ridge->nonconvex) /* only one ridge has nonconvex set */ - qh_copynonconvex(ridge); - qh_delridge(ridge); - trace2((qh ferr, 2038, "qh_renameridgevertex: ridge r%d deleted. It contained both v%d and v%d\n", - ridge->id, oldvertex->id, newvertex->id)); - return; - } - if (vertex->id < newvertex->id) - break; - nth++; - } - qh_setaddnth(&ridge->vertices, nth, newvertex); - if (abs(oldnth - nth)%2) { - trace3((qh ferr, 3010, "qh_renameridgevertex: swapped the top and bottom of ridge r%d\n", - ridge->id)); - temp= ridge->top; - ridge->top= ridge->bottom; - ridge->bottom= temp; - } -} /* renameridgevertex */ - - -/*-<a href="qh-merge.htm#TOC" - >-------------------------------</a><a name="renamevertex">-</a> - - qh_renamevertex( oldvertex, newvertex, ridges, oldfacet, neighborA ) - renames oldvertex as newvertex in ridges - gives oldfacet/neighborA if oldvertex is shared between two facets - - returns: - oldvertex may still exist afterwards - - - notes: - can not change neighbors of newvertex (since it's a subset) - - design: - for each ridge in ridges - rename oldvertex to newvertex and delete degenerate ridges - if oldfacet not defined - for each neighbor of oldvertex - delete oldvertex from neighbor's vertices - remove extra vertices from neighbor - add oldvertex to qh.del_vertices - else if oldvertex only between oldfacet and neighborA - delete oldvertex from oldfacet and neighborA - add oldvertex to qh.del_vertices - else oldvertex is in oldfacet and neighborA and other facets (i.e., pinched) - delete oldvertex from oldfacet - delete oldfacet from oldvertice's neighbors - remove extra vertices (e.g., oldvertex) from neighborA -*/ -void qh_renamevertex(vertexT *oldvertex, vertexT *newvertex, setT *ridges, facetT *oldfacet, facetT *neighborA) { - facetT *neighbor, **neighborp; - ridgeT *ridge, **ridgep; - boolT istrace= False; - - if (qh IStracing >= 2 || oldvertex->id == qh tracevertex_id || - newvertex->id == qh tracevertex_id) - istrace= True; - FOREACHridge_(ridges) - qh_renameridgevertex(ridge, oldvertex, newvertex); - if (!oldfacet) { - zinc_(Zrenameall); - if (istrace) - qh_fprintf(qh ferr, 8082, "qh_renamevertex: renamed v%d to v%d in several facets\n", - oldvertex->id, newvertex->id); - FOREACHneighbor_(oldvertex) { - qh_maydropneighbor(neighbor); - qh_setdelsorted(neighbor->vertices, oldvertex); - if (qh_remove_extravertices(neighbor)) - neighborp--; /* neighbor may be deleted */ - } - if (!oldvertex->deleted) { - oldvertex->deleted= True; - qh_setappend(&qh del_vertices, oldvertex); - } - }else if (qh_setsize(oldvertex->neighbors) == 2) { - zinc_(Zrenameshare); - if (istrace) - qh_fprintf(qh ferr, 8083, "qh_renamevertex: renamed v%d to v%d in oldfacet f%d\n", - oldvertex->id, newvertex->id, oldfacet->id); - FOREACHneighbor_(oldvertex) - qh_setdelsorted(neighbor->vertices, oldvertex); - oldvertex->deleted= True; - qh_setappend(&qh del_vertices, oldvertex); - }else { - zinc_(Zrenamepinch); - if (istrace || qh IStracing) - qh_fprintf(qh ferr, 8084, "qh_renamevertex: renamed pinched v%d to v%d between f%d and f%d\n", - oldvertex->id, newvertex->id, oldfacet->id, neighborA->id); - qh_setdelsorted(oldfacet->vertices, oldvertex); - qh_setdel(oldvertex->neighbors, oldfacet); - qh_remove_extravertices(neighborA); - } -} /* renamevertex */ - - -/*-<a href="qh-merge.htm#TOC" - >-------------------------------</a><a name="test_appendmerge">-</a> - - qh_test_appendmerge( facet, neighbor ) - tests facet/neighbor for convexity - appends to mergeset if non-convex - if pre-merging, - nop if qh.SKIPconvex, or qh.MERGEexact and coplanar - - returns: - true if appends facet/neighbor to mergeset - sets facet->center as needed - does not change facet->seen - - design: - if qh.cos_max is defined - if the angle between facet normals is too shallow - append an angle-coplanar merge to qh.mergeset - return True - make facet's centrum if needed - if facet's centrum is above the neighbor - set isconcave - else - if facet's centrum is not below the neighbor - set iscoplanar - make neighbor's centrum if needed - if neighbor's centrum is above the facet - set isconcave - else if neighbor's centrum is not below the facet - set iscoplanar - if isconcave or iscoplanar - get angle if needed - append concave or coplanar merge to qh.mergeset -*/ -boolT qh_test_appendmerge(facetT *facet, facetT *neighbor) { - realT dist, dist2= -REALmax, angle= -REALmax; - boolT isconcave= False, iscoplanar= False, okangle= False; - - if (qh SKIPconvex && !qh POSTmerging) - return False; - if ((!qh MERGEexact || qh POSTmerging) && qh cos_max < REALmax/2) { - angle= qh_getangle(facet->normal, neighbor->normal); - zinc_(Zangletests); - if (angle > qh cos_max) { - zinc_(Zcoplanarangle); - qh_appendmergeset(facet, neighbor, MRGanglecoplanar, &angle); - trace2((qh ferr, 2039, "qh_test_appendmerge: coplanar angle %4.4g between f%d and f%d\n", - angle, facet->id, neighbor->id)); - return True; - }else - okangle= True; - } - if (!facet->center) - facet->center= qh_getcentrum(facet); - zzinc_(Zcentrumtests); - qh_distplane(facet->center, neighbor, &dist); - if (dist > qh centrum_radius) - isconcave= True; - else { - if (dist > -qh centrum_radius) - iscoplanar= True; - if (!neighbor->center) - neighbor->center= qh_getcentrum(neighbor); - zzinc_(Zcentrumtests); - qh_distplane(neighbor->center, facet, &dist2); - if (dist2 > qh centrum_radius) - isconcave= True; - else if (!iscoplanar && dist2 > -qh centrum_radius) - iscoplanar= True; - } - if (!isconcave && (!iscoplanar || (qh MERGEexact && !qh POSTmerging))) - return False; - if (!okangle && qh ANGLEmerge) { - angle= qh_getangle(facet->normal, neighbor->normal); - zinc_(Zangletests); - } - if (isconcave) { - zinc_(Zconcaveridge); - if (qh ANGLEmerge) - angle += qh_ANGLEconcave + 0.5; - qh_appendmergeset(facet, neighbor, MRGconcave, &angle); - trace0((qh ferr, 18, "qh_test_appendmerge: concave f%d to f%d dist %4.4g and reverse dist %4.4g angle %4.4g during p%d\n", - facet->id, neighbor->id, dist, dist2, angle, qh furthest_id)); - }else /* iscoplanar */ { - zinc_(Zcoplanarcentrum); - qh_appendmergeset(facet, neighbor, MRGcoplanar, &angle); - trace2((qh ferr, 2040, "qh_test_appendmerge: coplanar f%d to f%d dist %4.4g, reverse dist %4.4g angle %4.4g\n", - facet->id, neighbor->id, dist, dist2, angle)); - } - return True; -} /* test_appendmerge */ - -/*-<a href="qh-merge.htm#TOC" - >-------------------------------</a><a name="test_vneighbors">-</a> - - qh_test_vneighbors() - test vertex neighbors for convexity - tests all facets on qh.newfacet_list - - returns: - true if non-convex vneighbors appended to qh.facet_mergeset - initializes vertex neighbors if needed - - notes: - assumes all facet neighbors have been tested - this can be expensive - this does not guarantee that a centrum is below all facets - but it is unlikely - uses qh.visit_id - - design: - build vertex neighbors if necessary - for all new facets - for all vertices - for each unvisited facet neighbor of the vertex - test new facet and neighbor for convexity -*/ -boolT qh_test_vneighbors(void /* qh newfacet_list */) { - facetT *newfacet, *neighbor, **neighborp; - vertexT *vertex, **vertexp; - int nummerges= 0; - - trace1((qh ferr, 1015, "qh_test_vneighbors: testing vertex neighbors for convexity\n")); - if (!qh VERTEXneighbors) - qh_vertexneighbors(); - FORALLnew_facets - newfacet->seen= False; - FORALLnew_facets { - newfacet->seen= True; - newfacet->visitid= qh visit_id++; - FOREACHneighbor_(newfacet) - newfacet->visitid= qh visit_id; - FOREACHvertex_(newfacet->vertices) { - FOREACHneighbor_(vertex) { - if (neighbor->seen || neighbor->visitid == qh visit_id) - continue; - if (qh_test_appendmerge(newfacet, neighbor)) - nummerges++; - } - } - } - zadd_(Ztestvneighbor, nummerges); - trace1((qh ferr, 1016, "qh_test_vneighbors: found %d non-convex, vertex neighbors\n", - nummerges)); - return (nummerges > 0); -} /* test_vneighbors */ - -/*-<a href="qh-merge.htm#TOC" - >-------------------------------</a><a name="tracemerge">-</a> - - qh_tracemerge( facet1, facet2 ) - print trace message after merge -*/ -void qh_tracemerge(facetT *facet1, facetT *facet2) { - boolT waserror= False; - -#ifndef qh_NOtrace - if (qh IStracing >= 4) - qh_errprint("MERGED", facet2, NULL, NULL, NULL); - if (facet2 == qh tracefacet || (qh tracevertex && qh tracevertex->newlist)) { - qh_fprintf(qh ferr, 8085, "qh_tracemerge: trace facet and vertex after merge of f%d and f%d, furthest p%d\n", facet1->id, facet2->id, qh furthest_id); - if (facet2 != qh tracefacet) - qh_errprint("TRACE", qh tracefacet, - (qh tracevertex && qh tracevertex->neighbors) ? - SETfirstt_(qh tracevertex->neighbors, facetT) : NULL, - NULL, qh tracevertex); - } - if (qh tracevertex) { - if (qh tracevertex->deleted) - qh_fprintf(qh ferr, 8086, "qh_tracemerge: trace vertex deleted at furthest p%d\n", - qh furthest_id); - else - qh_checkvertex(qh tracevertex); - } - if (qh tracefacet) { - qh_checkfacet(qh tracefacet, True, &waserror); - if (waserror) - qh_errexit(qh_ERRqhull, qh tracefacet, NULL); - } -#endif /* !qh_NOtrace */ - if (qh CHECKfrequently || qh IStracing >= 4) { /* can't check polygon here */ - qh_checkfacet(facet2, True, &waserror); - if (waserror) - qh_errexit(qh_ERRqhull, NULL, NULL); - } -} /* tracemerge */ - -/*-<a href="qh-merge.htm#TOC" - >-------------------------------</a><a name="tracemerging">-</a> - - qh_tracemerging() - print trace message during POSTmerging - - returns: - updates qh.mergereport - - notes: - called from qh_mergecycle() and qh_mergefacet() - - see: - qh_buildtracing() -*/ -void qh_tracemerging(void) { - realT cpu; - int total; - time_t timedata; - struct tm *tp; - - qh mergereport= zzval_(Ztotmerge); - time(&timedata); - tp= localtime(&timedata); - cpu= qh_CPUclock; - cpu /= qh_SECticks; - total= zzval_(Ztotmerge) - zzval_(Zcyclehorizon) + zzval_(Zcyclefacettot); - qh_fprintf(qh ferr, 8087, "\n\ -At %d:%d:%d & %2.5g CPU secs, qhull has merged %d facets. The hull\n\ - contains %d facets and %d vertices.\n", - tp->tm_hour, tp->tm_min, tp->tm_sec, cpu, - total, qh num_facets - qh num_visible, - qh num_vertices-qh_setsize(qh del_vertices)); -} /* tracemerging */ - -/*-<a href="qh-merge.htm#TOC" - >-------------------------------</a><a name="updatetested">-</a> - - qh_updatetested( facet1, facet2 ) - clear facet2->tested and facet1->ridge->tested for merge - - returns: - deletes facet2->center unless it's already large - if so, clears facet2->ridge->tested - - design: - clear facet2->tested - clear ridge->tested for facet1's ridges - if facet2 has a centrum - if facet2 is large - set facet2->keepcentrum - else if facet2 has 3 vertices due to many merges, or not large and post merging - clear facet2->keepcentrum - unless facet2->keepcentrum - clear facet2->center to recompute centrum later - clear ridge->tested for facet2's ridges -*/ -void qh_updatetested(facetT *facet1, facetT *facet2) { - ridgeT *ridge, **ridgep; - int size; - - facet2->tested= False; - FOREACHridge_(facet1->ridges) - ridge->tested= False; - if (!facet2->center) - return; - size= qh_setsize(facet2->vertices); - if (!facet2->keepcentrum) { - if (size > qh hull_dim + qh_MAXnewcentrum) { - facet2->keepcentrum= True; - zinc_(Zwidevertices); - } - }else if (size <= qh hull_dim + qh_MAXnewcentrum) { - /* center and keepcentrum was set */ - if (size == qh hull_dim || qh POSTmerging) - facet2->keepcentrum= False; /* if many merges need to recompute centrum */ - } - if (!facet2->keepcentrum) { - qh_memfree(facet2->center, qh normal_size); - facet2->center= NULL; - FOREACHridge_(facet2->ridges) - ridge->tested= False; - } -} /* updatetested */ - -/*-<a href="qh-merge.htm#TOC" - >-------------------------------</a><a name="vertexridges">-</a> - - qh_vertexridges( vertex ) - return temporary set of ridges adjacent to a vertex - vertex->neighbors defined - - ntoes: - uses qh.visit_id - does not include implicit ridges for simplicial facets - - design: - for each neighbor of vertex - add ridges that include the vertex to ridges -*/ -setT *qh_vertexridges(vertexT *vertex) { - facetT *neighbor, **neighborp; - setT *ridges= qh_settemp(qh TEMPsize); - int size; - - qh visit_id++; - FOREACHneighbor_(vertex) - neighbor->visitid= qh visit_id; - FOREACHneighbor_(vertex) { - if (*neighborp) /* no new ridges in last neighbor */ - qh_vertexridges_facet(vertex, neighbor, &ridges); - } - if (qh PRINTstatistics || qh IStracing) { - size= qh_setsize(ridges); - zinc_(Zvertexridge); - zadd_(Zvertexridgetot, size); - zmax_(Zvertexridgemax, size); - trace3((qh ferr, 3011, "qh_vertexridges: found %d ridges for v%d\n", - size, vertex->id)); - } - return ridges; -} /* vertexridges */ - -/*-<a href="qh-merge.htm#TOC" - >-------------------------------</a><a name="vertexridges_facet">-</a> - - qh_vertexridges_facet( vertex, facet, ridges ) - add adjacent ridges for vertex in facet - neighbor->visitid==qh.visit_id if it hasn't been visited - - returns: - ridges updated - sets facet->visitid to qh.visit_id-1 - - design: - for each ridge of facet - if ridge of visited neighbor (i.e., unprocessed) - if vertex in ridge - append ridge to vertex - mark facet processed -*/ -void qh_vertexridges_facet(vertexT *vertex, facetT *facet, setT **ridges) { - ridgeT *ridge, **ridgep; - facetT *neighbor; - - FOREACHridge_(facet->ridges) { - neighbor= otherfacet_(ridge, facet); - if (neighbor->visitid == qh visit_id - && qh_setin(ridge->vertices, vertex)) - qh_setappend(ridges, ridge); - } - facet->visitid= qh visit_id-1; -} /* vertexridges_facet */ - -/*-<a href="qh-merge.htm#TOC" - >-------------------------------</a><a name="willdelete">-</a> - - qh_willdelete( facet, replace ) - moves facet to visible list - sets facet->f.replace to replace (may be NULL) - - returns: - bumps qh.num_visible -*/ -void qh_willdelete(facetT *facet, facetT *replace) { - - qh_removefacet(facet); - qh_prependfacet(facet, &qh visible_list); - qh num_visible++; - facet->visible= True; - facet->f.replace= replace; -} /* willdelete */ - -#else /* qh_NOmerge */ -void qh_premerge(vertexT *apex, realT maxcentrum, realT maxangle) { -} -void qh_postmerge(const char *reason, realT maxcentrum, realT maxangle, - boolT vneighbors) { -} -boolT qh_checkzero(boolT testall) { - } -#endif /* qh_NOmerge */ - diff --git a/PyMca/Object3D/Object3DQhull/src/merge.h b/PyMca/Object3D/Object3DQhull/src/merge.h deleted file mode 100644 index da0fb53..0000000 --- a/PyMca/Object3D/Object3DQhull/src/merge.h +++ /dev/null @@ -1,178 +0,0 @@ -/*<html><pre> -<a href="qh-merge.htm" - >-------------------------------</a><a name="TOP">-</a> - - merge.h - header file for merge.c - - see qh-merge.htm and merge.c - - Copyright (c) 1993-2012 C.B. Barber. - $Id: //main/2011/qhull/src/libqhull/merge.h#3 $$Change: 1464 $ - $DateTime: 2012/01/25 22:58:41 $$Author: bbarber $ -*/ - -#ifndef qhDEFmerge -#define qhDEFmerge 1 - -#include "libqhull.h" - - -/*============ -constants- ==============*/ - -/*-<a href="qh-merge.htm#TOC" - >--------------------------------</a><a name="qh_ANGLEredundant">-</a> - - qh_ANGLEredundant - indicates redundant merge in mergeT->angle -*/ -#define qh_ANGLEredundant 6.0 - -/*-<a href="qh-merge.htm#TOC" - >--------------------------------</a><a name="qh_ANGLEdegen">-</a> - - qh_ANGLEdegen - indicates degenerate facet in mergeT->angle -*/ -#define qh_ANGLEdegen 5.0 - -/*-<a href="qh-merge.htm#TOC" - >--------------------------------</a><a name="qh_ANGLEconcave">-</a> - - qh_ANGLEconcave - offset to indicate concave facets in mergeT->angle - - notes: - concave facets are assigned the range of [2,4] in mergeT->angle - roundoff error may make the angle less than 2 -*/ -#define qh_ANGLEconcave 1.5 - -/*-<a href="qh-merge.htm#TOC" - >--------------------------------</a><a name="MRG">-</a> - - MRG... (mergeType) - indicates the type of a merge (mergeT->type) -*/ -typedef enum { /* in sort order for facet_mergeset */ - MRGnone= 0, - MRGcoplanar, /* centrum coplanar */ - MRGanglecoplanar, /* angle coplanar */ - /* could detect half concave ridges */ - MRGconcave, /* concave ridge */ - MRGflip, /* flipped facet. facet1 == facet2 */ - MRGridge, /* duplicate ridge (qh_MERGEridge) */ - /* degen and redundant go onto degen_mergeset */ - MRGdegen, /* degenerate facet (!enough neighbors) facet1 == facet2 */ - MRGredundant, /* redundant facet (vertex subset) */ - /* merge_degenredundant assumes degen < redundant */ - MRGmirror, /* mirror facet from qh_triangulate */ - ENDmrg -} mergeType; - -/*-<a href="qh-merge.htm#TOC" - >--------------------------------</a><a name="qh_MERGEapex">-</a> - - qh_MERGEapex - flag for qh_mergefacet() to indicate an apex merge -*/ -#define qh_MERGEapex True - -/*============ -structures- ====================*/ - -/*-<a href="qh-merge.htm#TOC" - >--------------------------------</a><a name="mergeT">-</a> - - mergeT - structure used to merge facets -*/ - -typedef struct mergeT mergeT; -struct mergeT { /* initialize in qh_appendmergeset */ - realT angle; /* angle between normals of facet1 and facet2 */ - facetT *facet1; /* will merge facet1 into facet2 */ - facetT *facet2; - mergeType type; -}; - - -/*=========== -macros- =========================*/ - -/*-<a href="qh-merge.htm#TOC" - >--------------------------------</a><a name="FOREACHmerge_">-</a> - - FOREACHmerge_( merges ) {...} - assign 'merge' to each merge in merges - - notes: - uses 'mergeT *merge, **mergep;' - if qh_mergefacet(), - restart since qh.facet_mergeset may change - see <a href="qset.h#FOREACHsetelement_">FOREACHsetelement_</a> -*/ -#define FOREACHmerge_( merges ) FOREACHsetelement_(mergeT, merges, merge) - -/*============ prototypes in alphabetical order after pre/postmerge =======*/ - -void qh_premerge(vertexT *apex, realT maxcentrum, realT maxangle); -void qh_postmerge(const char *reason, realT maxcentrum, realT maxangle, - boolT vneighbors); -void qh_all_merges(boolT othermerge, boolT vneighbors); -void qh_appendmergeset(facetT *facet, facetT *neighbor, mergeType mergetype, realT *angle); -setT *qh_basevertices( facetT *samecycle); -void qh_checkconnect(void /* qh new_facets */); -boolT qh_checkzero(boolT testall); -int qh_compareangle(const void *p1, const void *p2); -int qh_comparemerge(const void *p1, const void *p2); -int qh_comparevisit(const void *p1, const void *p2); -void qh_copynonconvex(ridgeT *atridge); -void qh_degen_redundant_facet(facetT *facet); -void qh_degen_redundant_neighbors(facetT *facet, facetT *delfacet); -vertexT *qh_find_newvertex(vertexT *oldvertex, setT *vertices, setT *ridges); -void qh_findbest_test(boolT testcentrum, facetT *facet, facetT *neighbor, - facetT **bestfacet, realT *distp, realT *mindistp, realT *maxdistp); -facetT *qh_findbestneighbor(facetT *facet, realT *distp, realT *mindistp, realT *maxdistp); -void qh_flippedmerges(facetT *facetlist, boolT *wasmerge); -void qh_forcedmerges( boolT *wasmerge); -void qh_getmergeset(facetT *facetlist); -void qh_getmergeset_initial(facetT *facetlist); -void qh_hashridge(setT *hashtable, int hashsize, ridgeT *ridge, vertexT *oldvertex); -ridgeT *qh_hashridge_find(setT *hashtable, int hashsize, ridgeT *ridge, - vertexT *vertex, vertexT *oldvertex, int *hashslot); -void qh_makeridges(facetT *facet); -void qh_mark_dupridges(facetT *facetlist); -void qh_maydropneighbor(facetT *facet); -int qh_merge_degenredundant(void); -void qh_merge_nonconvex( facetT *facet1, facetT *facet2, mergeType mergetype); -void qh_mergecycle(facetT *samecycle, facetT *newfacet); -void qh_mergecycle_all(facetT *facetlist, boolT *wasmerge); -void qh_mergecycle_facets( facetT *samecycle, facetT *newfacet); -void qh_mergecycle_neighbors(facetT *samecycle, facetT *newfacet); -void qh_mergecycle_ridges(facetT *samecycle, facetT *newfacet); -void qh_mergecycle_vneighbors( facetT *samecycle, facetT *newfacet); -void qh_mergefacet(facetT *facet1, facetT *facet2, realT *mindist, realT *maxdist, boolT mergeapex); -void qh_mergefacet2d(facetT *facet1, facetT *facet2); -void qh_mergeneighbors(facetT *facet1, facetT *facet2); -void qh_mergeridges(facetT *facet1, facetT *facet2); -void qh_mergesimplex(facetT *facet1, facetT *facet2, boolT mergeapex); -void qh_mergevertex_del(vertexT *vertex, facetT *facet1, facetT *facet2); -void qh_mergevertex_neighbors(facetT *facet1, facetT *facet2); -void qh_mergevertices(setT *vertices1, setT **vertices); -setT *qh_neighbor_intersections(vertexT *vertex); -void qh_newvertices(setT *vertices); -boolT qh_reducevertices(void); -vertexT *qh_redundant_vertex(vertexT *vertex); -boolT qh_remove_extravertices(facetT *facet); -vertexT *qh_rename_sharedvertex(vertexT *vertex, facetT *facet); -void qh_renameridgevertex(ridgeT *ridge, vertexT *oldvertex, vertexT *newvertex); -void qh_renamevertex(vertexT *oldvertex, vertexT *newvertex, setT *ridges, - facetT *oldfacet, facetT *neighborA); -boolT qh_test_appendmerge(facetT *facet, facetT *neighbor); -boolT qh_test_vneighbors(void /* qh newfacet_list */); -void qh_tracemerge(facetT *facet1, facetT *facet2); -void qh_tracemerging(void); -void qh_updatetested( facetT *facet1, facetT *facet2); -setT *qh_vertexridges(vertexT *vertex); -void qh_vertexridges_facet(vertexT *vertex, facetT *facet, setT **ridges); -void qh_willdelete(facetT *facet, facetT *replace); - -#endif /* qhDEFmerge */ diff --git a/PyMca/Object3D/Object3DQhull/src/poly.c b/PyMca/Object3D/Object3DQhull/src/poly.c deleted file mode 100644 index a3a0a48..0000000 --- a/PyMca/Object3D/Object3DQhull/src/poly.c +++ /dev/null @@ -1,1199 +0,0 @@ -/*<html><pre> -<a href="qh-poly.htm" - >-------------------------------</a><a name="TOP">-</a> - - poly.c - implements polygons and simplices - - see qh-poly.htm, poly.h and libqhull.h - - infrequent code is in poly2.c - (all but top 50 and their callers 12/3/95) - - Copyright (c) 1993-2012 The Geometry Center. - $Id: //main/2011/qhull/src/libqhull/poly.c#5 $$Change: 1464 $ - $DateTime: 2012/01/25 22:58:41 $$Author: bbarber $ -*/ - -#include "qhull_a.h" - -/*======== functions in alphabetical order ==========*/ - -/*-<a href="qh-poly.htm#TOC" - >-------------------------------</a><a name="appendfacet">-</a> - - qh_appendfacet( facet ) - appends facet to end of qh.facet_list, - - returns: - updates qh.newfacet_list, facet_next, facet_list - increments qh.numfacets - - notes: - assumes qh.facet_list/facet_tail is defined (createsimplex) - - see: - qh_removefacet() - -*/ -void qh_appendfacet(facetT *facet) { - facetT *tail= qh facet_tail; - - if (tail == qh newfacet_list) - qh newfacet_list= facet; - if (tail == qh facet_next) - qh facet_next= facet; - facet->previous= tail->previous; - facet->next= tail; - if (tail->previous) - tail->previous->next= facet; - else - qh facet_list= facet; - tail->previous= facet; - qh num_facets++; - trace4((qh ferr, 4044, "qh_appendfacet: append f%d to facet_list\n", facet->id)); -} /* appendfacet */ - - -/*-<a href="qh-poly.htm#TOC" - >-------------------------------</a><a name="appendvertex">-</a> - - qh_appendvertex( vertex ) - appends vertex to end of qh.vertex_list, - - returns: - sets vertex->newlist - updates qh.vertex_list, newvertex_list - increments qh.num_vertices - - notes: - assumes qh.vertex_list/vertex_tail is defined (createsimplex) - -*/ -void qh_appendvertex(vertexT *vertex) { - vertexT *tail= qh vertex_tail; - - if (tail == qh newvertex_list) - qh newvertex_list= vertex; - vertex->newlist= True; - vertex->previous= tail->previous; - vertex->next= tail; - if (tail->previous) - tail->previous->next= vertex; - else - qh vertex_list= vertex; - tail->previous= vertex; - qh num_vertices++; - trace4((qh ferr, 4045, "qh_appendvertex: append v%d to vertex_list\n", vertex->id)); -} /* appendvertex */ - - -/*-<a href="qh-poly.htm#TOC" - >-------------------------------</a><a name="attachnewfacets">-</a> - - qh_attachnewfacets( ) - attach horizon facets to new facets in qh.newfacet_list - newfacets have neighbor and ridge links to horizon but not vice versa - only needed for qh.ONLYgood - - returns: - set qh.NEWfacets - horizon facets linked to new facets - ridges changed from visible facets to new facets - simplicial ridges deleted - qh.visible_list, no ridges valid - facet->f.replace is a newfacet (if any) - - design: - delete interior ridges and neighbor sets by - for each visible, non-simplicial facet - for each ridge - if last visit or if neighbor is simplicial - if horizon neighbor - delete ridge for horizon's ridge set - delete ridge - erase neighbor set - attach horizon facets and new facets by - for all new facets - if corresponding horizon facet is simplicial - locate corresponding visible facet {may be more than one} - link visible facet to new facet - replace visible facet with new facet in horizon - else it's non-simplicial - for all visible neighbors of the horizon facet - link visible neighbor to new facet - delete visible neighbor from horizon facet - append new facet to horizon's neighbors - the first ridge of the new facet is the horizon ridge - link the new facet into the horizon ridge -*/ -void qh_attachnewfacets(void ) { - facetT *newfacet= NULL, *neighbor, **neighborp, *horizon, *visible; - ridgeT *ridge, **ridgep; - - qh NEWfacets= True; - trace3((qh ferr, 3012, "qh_attachnewfacets: delete interior ridges\n")); - qh visit_id++; - FORALLvisible_facets { - visible->visitid= qh visit_id; - if (visible->ridges) { - FOREACHridge_(visible->ridges) { - neighbor= otherfacet_(ridge, visible); - if (neighbor->visitid == qh visit_id - || (!neighbor->visible && neighbor->simplicial)) { - if (!neighbor->visible) /* delete ridge for simplicial horizon */ - qh_setdel(neighbor->ridges, ridge); - qh_setfree(&(ridge->vertices)); /* delete on 2nd visit */ - qh_memfree(ridge, (int)sizeof(ridgeT)); - } - } - SETfirst_(visible->ridges)= NULL; - } - SETfirst_(visible->neighbors)= NULL; - } - trace1((qh ferr, 1017, "qh_attachnewfacets: attach horizon facets to new facets\n")); - FORALLnew_facets { - horizon= SETfirstt_(newfacet->neighbors, facetT); - if (horizon->simplicial) { - visible= NULL; - FOREACHneighbor_(horizon) { /* may have more than one horizon ridge */ - if (neighbor->visible) { - if (visible) { - if (qh_setequal_skip(newfacet->vertices, 0, horizon->vertices, - SETindex_(horizon->neighbors, neighbor))) { - visible= neighbor; - break; - } - }else - visible= neighbor; - } - } - if (visible) { - visible->f.replace= newfacet; - qh_setreplace(horizon->neighbors, visible, newfacet); - }else { - qh_fprintf(qh ferr, 6102, "qhull internal error (qh_attachnewfacets): couldn't find visible facet for horizon f%d of newfacet f%d\n", - horizon->id, newfacet->id); - qh_errexit2 (qh_ERRqhull, horizon, newfacet); - } - }else { /* non-simplicial, with a ridge for newfacet */ - FOREACHneighbor_(horizon) { /* may hold for many new facets */ - if (neighbor->visible) { - neighbor->f.replace= newfacet; - qh_setdelnth(horizon->neighbors, - SETindex_(horizon->neighbors, neighbor)); - neighborp--; /* repeat */ - } - } - qh_setappend(&horizon->neighbors, newfacet); - ridge= SETfirstt_(newfacet->ridges, ridgeT); - if (ridge->top == horizon) - ridge->bottom= newfacet; - else - ridge->top= newfacet; - } - } /* newfacets */ - if (qh PRINTstatistics) { - FORALLvisible_facets { - if (!visible->f.replace) - zinc_(Zinsidevisible); - } - } -} /* attachnewfacets */ - -/*-<a href="qh-poly.htm#TOC" - >-------------------------------</a><a name="checkflipped">-</a> - - qh_checkflipped( facet, dist, allerror ) - checks facet orientation to interior point - - if allerror set, - tests against qh.DISTround - else - tests against 0 since tested against DISTround before - - returns: - False if it flipped orientation (sets facet->flipped) - distance if non-NULL -*/ -boolT qh_checkflipped(facetT *facet, realT *distp, boolT allerror) { - realT dist; - - if (facet->flipped && !distp) - return False; - zzinc_(Zdistcheck); - qh_distplane(qh interior_point, facet, &dist); - if (distp) - *distp= dist; - if ((allerror && dist > -qh DISTround)|| (!allerror && dist >= 0.0)) { - facet->flipped= True; - zzinc_(Zflippedfacets); - trace0((qh ferr, 19, "qh_checkflipped: facet f%d is flipped, distance= %6.12g during p%d\n", - facet->id, dist, qh furthest_id)); - qh_precision("flipped facet"); - return False; - } - return True; -} /* checkflipped */ - -/*-<a href="qh-poly.htm#TOC" - >-------------------------------</a><a name="delfacet">-</a> - - qh_delfacet( facet ) - removes facet from facet_list and frees up its memory - - notes: - assumes vertices and ridges already freed -*/ -void qh_delfacet(facetT *facet) { - void **freelistp; /* used !qh_NOmem */ - - trace4((qh ferr, 4046, "qh_delfacet: delete f%d\n", facet->id)); - if (facet == qh tracefacet) - qh tracefacet= NULL; - if (facet == qh GOODclosest) - qh GOODclosest= NULL; - qh_removefacet(facet); - if (!facet->tricoplanar || facet->keepcentrum) { - qh_memfree_(facet->normal, qh normal_size, freelistp); - if (qh CENTERtype == qh_ASvoronoi) { /* uses macro calls */ - qh_memfree_(facet->center, qh center_size, freelistp); - }else /* AScentrum */ { - qh_memfree_(facet->center, qh normal_size, freelistp); - } - } - qh_setfree(&(facet->neighbors)); - if (facet->ridges) - qh_setfree(&(facet->ridges)); - qh_setfree(&(facet->vertices)); - if (facet->outsideset) - qh_setfree(&(facet->outsideset)); - if (facet->coplanarset) - qh_setfree(&(facet->coplanarset)); - qh_memfree_(facet, (int)sizeof(facetT), freelistp); -} /* delfacet */ - - -/*-<a href="qh-poly.htm#TOC" - >-------------------------------</a><a name="deletevisible">-</a> - - qh_deletevisible() - delete visible facets and vertices - - returns: - deletes each facet and removes from facetlist - at exit, qh.visible_list empty (== qh.newfacet_list) - - notes: - ridges already deleted - horizon facets do not reference facets on qh.visible_list - new facets in qh.newfacet_list - uses qh.visit_id; -*/ -void qh_deletevisible(void /*qh visible_list*/) { - facetT *visible, *nextfacet; - vertexT *vertex, **vertexp; - int numvisible= 0, numdel= qh_setsize(qh del_vertices); - - trace1((qh ferr, 1018, "qh_deletevisible: delete %d visible facets and %d vertices\n", - qh num_visible, numdel)); - for (visible= qh visible_list; visible && visible->visible; - visible= nextfacet) { /* deleting current */ - nextfacet= visible->next; - numvisible++; - qh_delfacet(visible); - } - if (numvisible != qh num_visible) { - qh_fprintf(qh ferr, 6103, "qhull internal error (qh_deletevisible): qh num_visible %d is not number of visible facets %d\n", - qh num_visible, numvisible); - qh_errexit(qh_ERRqhull, NULL, NULL); - } - qh num_visible= 0; - zadd_(Zvisfacettot, numvisible); - zmax_(Zvisfacetmax, numvisible); - zzadd_(Zdelvertextot, numdel); - zmax_(Zdelvertexmax, numdel); - FOREACHvertex_(qh del_vertices) - qh_delvertex(vertex); - qh_settruncate(qh del_vertices, 0); -} /* deletevisible */ - -/*-<a href="qh-poly.htm#TOC" - >-------------------------------</a><a name="facetintersect">-</a> - - qh_facetintersect( facetA, facetB, skipa, skipB, prepend ) - return vertices for intersection of two simplicial facets - may include 1 prepended entry (if more, need to settemppush) - - returns: - returns set of qh.hull_dim-1 + prepend vertices - returns skipped index for each test and checks for exactly one - - notes: - does not need settemp since set in quick memory - - see also: - qh_vertexintersect and qh_vertexintersect_new - use qh_setnew_delnthsorted to get nth ridge (no skip information) - - design: - locate skipped vertex by scanning facet A's neighbors - locate skipped vertex by scanning facet B's neighbors - intersect the vertex sets -*/ -setT *qh_facetintersect(facetT *facetA, facetT *facetB, - int *skipA,int *skipB, int prepend) { - setT *intersect; - int dim= qh hull_dim, i, j; - facetT **neighborsA, **neighborsB; - - neighborsA= SETaddr_(facetA->neighbors, facetT); - neighborsB= SETaddr_(facetB->neighbors, facetT); - i= j= 0; - if (facetB == *neighborsA++) - *skipA= 0; - else if (facetB == *neighborsA++) - *skipA= 1; - else if (facetB == *neighborsA++) - *skipA= 2; - else { - for (i=3; i < dim; i++) { - if (facetB == *neighborsA++) { - *skipA= i; - break; - } - } - } - if (facetA == *neighborsB++) - *skipB= 0; - else if (facetA == *neighborsB++) - *skipB= 1; - else if (facetA == *neighborsB++) - *skipB= 2; - else { - for (j=3; j < dim; j++) { - if (facetA == *neighborsB++) { - *skipB= j; - break; - } - } - } - if (i >= dim || j >= dim) { - qh_fprintf(qh ferr, 6104, "qhull internal error (qh_facetintersect): f%d or f%d not in others neighbors\n", - facetA->id, facetB->id); - qh_errexit2 (qh_ERRqhull, facetA, facetB); - } - intersect= qh_setnew_delnthsorted(facetA->vertices, qh hull_dim, *skipA, prepend); - trace4((qh ferr, 4047, "qh_facetintersect: f%d skip %d matches f%d skip %d\n", - facetA->id, *skipA, facetB->id, *skipB)); - return(intersect); -} /* facetintersect */ - -/*-<a href="qh-poly.htm#TOC" - >-------------------------------</a><a name="gethash">-</a> - - qh_gethash( hashsize, set, size, firstindex, skipelem ) - return hashvalue for a set with firstindex and skipelem - - notes: - returned hash is in [0,hashsize) - assumes at least firstindex+1 elements - assumes skipelem is NULL, in set, or part of hash - - hashes memory addresses which may change over different runs of the same data - using sum for hash does badly in high d -*/ -int qh_gethash(int hashsize, setT *set, int size, int firstindex, void *skipelem) { - void **elemp= SETelemaddr_(set, firstindex, void); - ptr_intT hash = 0, elem; - unsigned result; - int i; -#ifdef _MSC_VER /* Microsoft Visual C++ -- warn about 64-bit issues */ -#pragma warning( push) /* WARN64 -- ptr_intT holds a 64-bit pointer */ -#pragma warning( disable : 4311) /* 'type cast': pointer truncation from 'void*' to 'ptr_intT' */ -#endif - - switch (size-firstindex) { - case 1: - hash= (ptr_intT)(*elemp) - (ptr_intT) skipelem; - break; - case 2: - hash= (ptr_intT)(*elemp) + (ptr_intT)elemp[1] - (ptr_intT) skipelem; - break; - case 3: - hash= (ptr_intT)(*elemp) + (ptr_intT)elemp[1] + (ptr_intT)elemp[2] - - (ptr_intT) skipelem; - break; - case 4: - hash= (ptr_intT)(*elemp) + (ptr_intT)elemp[1] + (ptr_intT)elemp[2] - + (ptr_intT)elemp[3] - (ptr_intT) skipelem; - break; - case 5: - hash= (ptr_intT)(*elemp) + (ptr_intT)elemp[1] + (ptr_intT)elemp[2] - + (ptr_intT)elemp[3] + (ptr_intT)elemp[4] - (ptr_intT) skipelem; - break; - case 6: - hash= (ptr_intT)(*elemp) + (ptr_intT)elemp[1] + (ptr_intT)elemp[2] - + (ptr_intT)elemp[3] + (ptr_intT)elemp[4]+ (ptr_intT)elemp[5] - - (ptr_intT) skipelem; - break; - default: - hash= 0; - i= 3; - do { /* this is about 10% in 10-d */ - if ((elem= (ptr_intT)*elemp++) != (ptr_intT)skipelem) { - hash ^= (elem << i) + (elem >> (32-i)); - i += 3; - if (i >= 32) - i -= 32; - } - }while (*elemp); - break; - } - if (hashsize<0) { - qh_fprintf(qh ferr, 6202, "qhull internal error: negative hashsize %d passed to qh_gethash [poly.c]\n", hashsize); - qh_errexit2 (qh_ERRqhull, NULL, NULL); - } - result= (unsigned)hash; - result %= (unsigned)hashsize; - /* result= 0; for debugging */ - return result; -#ifdef _MSC_VER -#pragma warning( pop) -#endif -} /* gethash */ - -/*-<a href="qh-poly.htm#TOC" - >-------------------------------</a><a name="makenewfacet">-</a> - - qh_makenewfacet( vertices, toporient, horizon ) - creates a toporient? facet from vertices - - returns: - returns newfacet - adds newfacet to qh.facet_list - newfacet->vertices= vertices - if horizon - newfacet->neighbor= horizon, but not vice versa - newvertex_list updated with vertices -*/ -facetT *qh_makenewfacet(setT *vertices, boolT toporient,facetT *horizon) { - facetT *newfacet; - vertexT *vertex, **vertexp; - - FOREACHvertex_(vertices) { - if (!vertex->newlist) { - qh_removevertex(vertex); - qh_appendvertex(vertex); - } - } - newfacet= qh_newfacet(); - newfacet->vertices= vertices; - newfacet->toporient= (unsigned char)toporient; - if (horizon) - qh_setappend(&(newfacet->neighbors), horizon); - qh_appendfacet(newfacet); - return(newfacet); -} /* makenewfacet */ - - -/*-<a href="qh-poly.htm#TOC" - >-------------------------------</a><a name="makenewplanes">-</a> - - qh_makenewplanes() - make new hyperplanes for facets on qh.newfacet_list - - returns: - all facets have hyperplanes or are marked for merging - doesn't create hyperplane if horizon is coplanar (will merge) - updates qh.min_vertex if qh.JOGGLEmax - - notes: - facet->f.samecycle is defined for facet->mergehorizon facets -*/ -void qh_makenewplanes(void /* newfacet_list */) { - facetT *newfacet; - - FORALLnew_facets { - if (!newfacet->mergehorizon) - qh_setfacetplane(newfacet); - } - if (qh JOGGLEmax < REALmax/2) - minimize_(qh min_vertex, -wwval_(Wnewvertexmax)); -} /* makenewplanes */ - -/*-<a href="qh-poly.htm#TOC" - >-------------------------------</a><a name="makenew_nonsimplicial">-</a> - - qh_makenew_nonsimplicial( visible, apex, numnew ) - make new facets for ridges of a visible facet - - returns: - first newfacet, bumps numnew as needed - attaches new facets if !qh.ONLYgood - marks ridge neighbors for simplicial visible - if (qh.ONLYgood) - ridges on newfacet, horizon, and visible - else - ridge and neighbors between newfacet and horizon - visible facet's ridges are deleted - - notes: - qh.visit_id if visible has already been processed - sets neighbor->seen for building f.samecycle - assumes all 'seen' flags initially false - - design: - for each ridge of visible facet - get neighbor of visible facet - if neighbor was already processed - delete the ridge (will delete all visible facets later) - if neighbor is a horizon facet - create a new facet - if neighbor coplanar - adds newfacet to f.samecycle for later merging - else - updates neighbor's neighbor set - (checks for non-simplicial facet with multiple ridges to visible facet) - updates neighbor's ridge set - (checks for simplicial neighbor to non-simplicial visible facet) - (deletes ridge if neighbor is simplicial) - -*/ -#ifndef qh_NOmerge -facetT *qh_makenew_nonsimplicial(facetT *visible, vertexT *apex, int *numnew) { - void **freelistp; /* used !qh_NOmem */ - ridgeT *ridge, **ridgep; - facetT *neighbor, *newfacet= NULL, *samecycle; - setT *vertices; - boolT toporient; - int ridgeid; - - FOREACHridge_(visible->ridges) { - ridgeid= ridge->id; - neighbor= otherfacet_(ridge, visible); - if (neighbor->visible) { - if (!qh ONLYgood) { - if (neighbor->visitid == qh visit_id) { - qh_setfree(&(ridge->vertices)); /* delete on 2nd visit */ - qh_memfree_(ridge, (int)sizeof(ridgeT), freelistp); - } - } - }else { /* neighbor is an horizon facet */ - toporient= (ridge->top == visible); - vertices= qh_setnew(qh hull_dim); /* makes sure this is quick */ - qh_setappend(&vertices, apex); - qh_setappend_set(&vertices, ridge->vertices); - newfacet= qh_makenewfacet(vertices, toporient, neighbor); - (*numnew)++; - if (neighbor->coplanar) { - newfacet->mergehorizon= True; - if (!neighbor->seen) { - newfacet->f.samecycle= newfacet; - neighbor->f.newcycle= newfacet; - }else { - samecycle= neighbor->f.newcycle; - newfacet->f.samecycle= samecycle->f.samecycle; - samecycle->f.samecycle= newfacet; - } - } - if (qh ONLYgood) { - if (!neighbor->simplicial) - qh_setappend(&(newfacet->ridges), ridge); - }else { /* qh_attachnewfacets */ - if (neighbor->seen) { - if (neighbor->simplicial) { - qh_fprintf(qh ferr, 6105, "qhull internal error (qh_makenew_nonsimplicial): simplicial f%d sharing two ridges with f%d\n", - neighbor->id, visible->id); - qh_errexit2 (qh_ERRqhull, neighbor, visible); - } - qh_setappend(&(neighbor->neighbors), newfacet); - }else - qh_setreplace(neighbor->neighbors, visible, newfacet); - if (neighbor->simplicial) { - qh_setdel(neighbor->ridges, ridge); - qh_setfree(&(ridge->vertices)); - qh_memfree(ridge, (int)sizeof(ridgeT)); - }else { - qh_setappend(&(newfacet->ridges), ridge); - if (toporient) - ridge->top= newfacet; - else - ridge->bottom= newfacet; - } - trace4((qh ferr, 4048, "qh_makenew_nonsimplicial: created facet f%d from v%d and r%d of horizon f%d\n", - newfacet->id, apex->id, ridgeid, neighbor->id)); - } - } - neighbor->seen= True; - } /* for each ridge */ - if (!qh ONLYgood) - SETfirst_(visible->ridges)= NULL; - return newfacet; -} /* makenew_nonsimplicial */ -#else /* qh_NOmerge */ -facetT *qh_makenew_nonsimplicial(facetT *visible, vertexT *apex, int *numnew) { - return NULL; -} -#endif /* qh_NOmerge */ - -/*-<a href="qh-poly.htm#TOC" - >-------------------------------</a><a name="makenew_simplicial">-</a> - - qh_makenew_simplicial( visible, apex, numnew ) - make new facets for simplicial visible facet and apex - - returns: - attaches new facets if (!qh.ONLYgood) - neighbors between newfacet and horizon - - notes: - nop if neighbor->seen or neighbor->visible(see qh_makenew_nonsimplicial) - - design: - locate neighboring horizon facet for visible facet - determine vertices and orientation - create new facet - if coplanar, - add new facet to f.samecycle - update horizon facet's neighbor list -*/ -facetT *qh_makenew_simplicial(facetT *visible, vertexT *apex, int *numnew) { - facetT *neighbor, **neighborp, *newfacet= NULL; - setT *vertices; - boolT flip, toporient; - int horizonskip, visibleskip; - - FOREACHneighbor_(visible) { - if (!neighbor->seen && !neighbor->visible) { - vertices= qh_facetintersect(neighbor,visible, &horizonskip, &visibleskip, 1); - SETfirst_(vertices)= apex; - flip= ((horizonskip & 0x1) ^ (visibleskip & 0x1)); - if (neighbor->toporient) - toporient= horizonskip & 0x1; - else - toporient= (horizonskip & 0x1) ^ 0x1; - newfacet= qh_makenewfacet(vertices, toporient, neighbor); - (*numnew)++; - if (neighbor->coplanar && (qh PREmerge || qh MERGEexact)) { -#ifndef qh_NOmerge - newfacet->f.samecycle= newfacet; - newfacet->mergehorizon= True; -#endif - } - if (!qh ONLYgood) - SETelem_(neighbor->neighbors, horizonskip)= newfacet; - trace4((qh ferr, 4049, "qh_makenew_simplicial: create facet f%d top %d from v%d and horizon f%d skip %d top %d and visible f%d skip %d, flip? %d\n", - newfacet->id, toporient, apex->id, neighbor->id, horizonskip, - neighbor->toporient, visible->id, visibleskip, flip)); - } - } - return newfacet; -} /* makenew_simplicial */ - -/*-<a href="qh-poly.htm#TOC" - >-------------------------------</a><a name="matchneighbor">-</a> - - qh_matchneighbor( newfacet, newskip, hashsize, hashcount ) - either match subridge of newfacet with neighbor or add to hash_table - - returns: - duplicate ridges are unmatched and marked by qh_DUPLICATEridge - - notes: - ridge is newfacet->vertices w/o newskip vertex - do not allocate memory (need to free hash_table cleanly) - uses linear hash chains - - see also: - qh_matchduplicates - - design: - for each possible matching facet in qh.hash_table - if vertices match - set ismatch, if facets have opposite orientation - if ismatch and matching facet doesn't have a match - match the facets by updating their neighbor sets - else - indicate a duplicate ridge - set facet hyperplane for later testing - add facet to hashtable - unless the other facet was already a duplicate ridge - mark both facets with a duplicate ridge - add other facet (if defined) to hash table -*/ -void qh_matchneighbor(facetT *newfacet, int newskip, int hashsize, int *hashcount) { - boolT newfound= False; /* True, if new facet is already in hash chain */ - boolT same, ismatch; - int hash, scan; - facetT *facet, *matchfacet; - int skip, matchskip; - - hash= qh_gethash(hashsize, newfacet->vertices, qh hull_dim, 1, - SETelem_(newfacet->vertices, newskip)); - trace4((qh ferr, 4050, "qh_matchneighbor: newfacet f%d skip %d hash %d hashcount %d\n", - newfacet->id, newskip, hash, *hashcount)); - zinc_(Zhashlookup); - for (scan= hash; (facet= SETelemt_(qh hash_table, scan, facetT)); - scan= (++scan >= hashsize ? 0 : scan)) { - if (facet == newfacet) { - newfound= True; - continue; - } - zinc_(Zhashtests); - if (qh_matchvertices(1, newfacet->vertices, newskip, facet->vertices, &skip, &same)) { - if (SETelem_(newfacet->vertices, newskip) == - SETelem_(facet->vertices, skip)) { - qh_precision("two facets with the same vertices"); - qh_fprintf(qh ferr, 6106, "qhull precision error: Vertex sets are the same for f%d and f%d. Can not force output.\n", - facet->id, newfacet->id); - qh_errexit2 (qh_ERRprec, facet, newfacet); - } - ismatch= (same == (boolT)((newfacet->toporient ^ facet->toporient))); - matchfacet= SETelemt_(facet->neighbors, skip, facetT); - if (ismatch && !matchfacet) { - SETelem_(facet->neighbors, skip)= newfacet; - SETelem_(newfacet->neighbors, newskip)= facet; - (*hashcount)--; - trace4((qh ferr, 4051, "qh_matchneighbor: f%d skip %d matched with new f%d skip %d\n", - facet->id, skip, newfacet->id, newskip)); - return; - } - if (!qh PREmerge && !qh MERGEexact) { - qh_precision("a ridge with more than two neighbors"); - qh_fprintf(qh ferr, 6107, "qhull precision error: facets f%d, f%d and f%d meet at a ridge with more than 2 neighbors. Can not continue.\n", - facet->id, newfacet->id, getid_(matchfacet)); - qh_errexit2 (qh_ERRprec, facet, newfacet); - } - SETelem_(newfacet->neighbors, newskip)= qh_DUPLICATEridge; - newfacet->dupridge= True; - if (!newfacet->normal) - qh_setfacetplane(newfacet); - qh_addhash(newfacet, qh hash_table, hashsize, hash); - (*hashcount)++; - if (!facet->normal) - qh_setfacetplane(facet); - if (matchfacet != qh_DUPLICATEridge) { - SETelem_(facet->neighbors, skip)= qh_DUPLICATEridge; - facet->dupridge= True; - if (!facet->normal) - qh_setfacetplane(facet); - if (matchfacet) { - matchskip= qh_setindex(matchfacet->neighbors, facet); - SETelem_(matchfacet->neighbors, matchskip)= qh_DUPLICATEridge; - matchfacet->dupridge= True; - if (!matchfacet->normal) - qh_setfacetplane(matchfacet); - qh_addhash(matchfacet, qh hash_table, hashsize, hash); - *hashcount += 2; - } - } - trace4((qh ferr, 4052, "qh_matchneighbor: new f%d skip %d duplicates ridge for f%d skip %d matching f%d ismatch %d at hash %d\n", - newfacet->id, newskip, facet->id, skip, - (matchfacet == qh_DUPLICATEridge ? -2 : getid_(matchfacet)), - ismatch, hash)); - return; /* end of duplicate ridge */ - } - } - if (!newfound) - SETelem_(qh hash_table, scan)= newfacet; /* same as qh_addhash */ - (*hashcount)++; - trace4((qh ferr, 4053, "qh_matchneighbor: no match for f%d skip %d at hash %d\n", - newfacet->id, newskip, hash)); -} /* matchneighbor */ - - -/*-<a href="qh-poly.htm#TOC" - >-------------------------------</a><a name="matchnewfacets">-</a> - - qh_matchnewfacets() - match newfacets in qh.newfacet_list to their newfacet neighbors - - returns: - qh.newfacet_list with full neighbor sets - get vertices with nth neighbor by deleting nth vertex - if qh.PREmerge/MERGEexact or qh.FORCEoutput - sets facet->flippped if flipped normal (also prevents point partitioning) - if duplicate ridges and qh.PREmerge/MERGEexact - sets facet->dupridge - missing neighbor links identifies extra ridges to be merging (qh_MERGEridge) - - notes: - newfacets already have neighbor[0] (horizon facet) - assumes qh.hash_table is NULL - vertex->neighbors has not been updated yet - do not allocate memory after qh.hash_table (need to free it cleanly) - - design: - delete neighbor sets for all new facets - initialize a hash table - for all new facets - match facet with neighbors - if unmatched facets (due to duplicate ridges) - for each new facet with a duplicate ridge - match it with a facet - check for flipped facets -*/ -void qh_matchnewfacets(void /* qh newfacet_list */) { - int numnew=0, hashcount=0, newskip; - facetT *newfacet, *neighbor; - int dim= qh hull_dim, hashsize, neighbor_i, neighbor_n; - setT *neighbors; -#ifndef qh_NOtrace - int facet_i, facet_n, numfree= 0; - facetT *facet; -#endif - - trace1((qh ferr, 1019, "qh_matchnewfacets: match neighbors for new facets.\n")); - FORALLnew_facets { - numnew++; - { /* inline qh_setzero(newfacet->neighbors, 1, qh hull_dim); */ - neighbors= newfacet->neighbors; - neighbors->e[neighbors->maxsize].i= dim+1; /*may be overwritten*/ - memset((char *)SETelemaddr_(neighbors, 1, void), 0, dim * SETelemsize); - } - } - - qh_newhashtable(numnew*(qh hull_dim-1)); /* twice what is normally needed, - but every ridge could be DUPLICATEridge */ - hashsize= qh_setsize(qh hash_table); - FORALLnew_facets { - for (newskip=1; newskip<qh hull_dim; newskip++) /* furthest/horizon already matched */ - qh_matchneighbor(newfacet, newskip, hashsize, &hashcount); -#if 0 /* use the following to trap hashcount errors */ - { - int count= 0, k; - facetT *facet, *neighbor; - - count= 0; - FORALLfacet_(qh newfacet_list) { /* newfacet already in use */ - for (k=1; k < qh hull_dim; k++) { - neighbor= SETelemt_(facet->neighbors, k, facetT); - if (!neighbor || neighbor == qh_DUPLICATEridge) - count++; - } - if (facet == newfacet) - break; - } - if (count != hashcount) { - qh_fprintf(qh ferr, 8088, "qh_matchnewfacets: after adding facet %d, hashcount %d != count %d\n", - newfacet->id, hashcount, count); - qh_errexit(qh_ERRqhull, newfacet, NULL); - } - } -#endif /* end of trap code */ - } - if (hashcount) { - FORALLnew_facets { - if (newfacet->dupridge) { - FOREACHneighbor_i_(newfacet) { - if (neighbor == qh_DUPLICATEridge) { - qh_matchduplicates(newfacet, neighbor_i, hashsize, &hashcount); - /* this may report MERGEfacet */ - } - } - } - } - } - if (hashcount) { - qh_fprintf(qh ferr, 6108, "qhull internal error (qh_matchnewfacets): %d neighbors did not match up\n", - hashcount); - qh_printhashtable(qh ferr); - qh_errexit(qh_ERRqhull, NULL, NULL); - } -#ifndef qh_NOtrace - if (qh IStracing >= 2) { - FOREACHfacet_i_(qh hash_table) { - if (!facet) - numfree++; - } - qh_fprintf(qh ferr, 8089, "qh_matchnewfacets: %d new facets, %d unused hash entries . hashsize %d\n", - numnew, numfree, qh_setsize(qh hash_table)); - } -#endif /* !qh_NOtrace */ - qh_setfree(&qh hash_table); - if (qh PREmerge || qh MERGEexact) { - if (qh IStracing >= 4) - qh_printfacetlist(qh newfacet_list, NULL, qh_ALL); - FORALLnew_facets { - if (newfacet->normal) - qh_checkflipped(newfacet, NULL, qh_ALL); - } - }else if (qh FORCEoutput) - qh_checkflipped_all(qh newfacet_list); /* prints warnings for flipped */ -} /* matchnewfacets */ - - -/*-<a href="qh-poly.htm#TOC" - >-------------------------------</a><a name="matchvertices">-</a> - - qh_matchvertices( firstindex, verticesA, skipA, verticesB, skipB, same ) - tests whether vertices match with a single skip - starts match at firstindex since all new facets have a common vertex - - returns: - true if matched vertices - skip index for each set - sets same iff vertices have the same orientation - - notes: - assumes skipA is in A and both sets are the same size - - design: - set up pointers - scan both sets checking for a match - test orientation -*/ -boolT qh_matchvertices(int firstindex, setT *verticesA, int skipA, - setT *verticesB, int *skipB, boolT *same) { - vertexT **elemAp, **elemBp, **skipBp=NULL, **skipAp; - - elemAp= SETelemaddr_(verticesA, firstindex, vertexT); - elemBp= SETelemaddr_(verticesB, firstindex, vertexT); - skipAp= SETelemaddr_(verticesA, skipA, vertexT); - do if (elemAp != skipAp) { - while (*elemAp != *elemBp++) { - if (skipBp) - return False; - skipBp= elemBp; /* one extra like FOREACH */ - } - }while (*(++elemAp)); - if (!skipBp) - skipBp= ++elemBp; - *skipB= SETindex_(verticesB, skipB); /* i.e., skipBp - verticesB */ - *same= !((skipA & 0x1) ^ (*skipB & 0x1)); /* result is 0 or 1 */ - trace4((qh ferr, 4054, "qh_matchvertices: matched by skip %d(v%d) and skip %d(v%d) same? %d\n", - skipA, (*skipAp)->id, *skipB, (*(skipBp-1))->id, *same)); - return(True); -} /* matchvertices */ - -/*-<a href="qh-poly.htm#TOC" - >-------------------------------</a><a name="newfacet">-</a> - - qh_newfacet() - return a new facet - - returns: - all fields initialized or cleared (NULL) - preallocates neighbors set -*/ -facetT *qh_newfacet(void) { - facetT *facet; - void **freelistp; /* used !qh_NOmem */ - - qh_memalloc_((int)sizeof(facetT), freelistp, facet, facetT); - memset((char *)facet, (size_t)0, sizeof(facetT)); - if (qh facet_id == qh tracefacet_id) - qh tracefacet= facet; - facet->id= qh facet_id++; - facet->neighbors= qh_setnew(qh hull_dim); -#if !qh_COMPUTEfurthest - facet->furthestdist= 0.0; -#endif -#if qh_MAXoutside - if (qh FORCEoutput && qh APPROXhull) - facet->maxoutside= qh MINoutside; - else - facet->maxoutside= qh DISTround; -#endif - facet->simplicial= True; - facet->good= True; - facet->newfacet= True; - trace4((qh ferr, 4055, "qh_newfacet: created facet f%d\n", facet->id)); - return(facet); -} /* newfacet */ - - -/*-<a href="qh-poly.htm#TOC" - >-------------------------------</a><a name="newridge">-</a> - - qh_newridge() - return a new ridge -*/ -ridgeT *qh_newridge(void) { - ridgeT *ridge; - void **freelistp; /* used !qh_NOmem */ - - qh_memalloc_((int)sizeof(ridgeT), freelistp, ridge, ridgeT); - memset((char *)ridge, (size_t)0, sizeof(ridgeT)); - zinc_(Ztotridges); - if (qh ridge_id == 0xFFFFFF) { - qh_fprintf(qh ferr, 7074, "\ -qhull warning: more than %d ridges. ID field overflows and two ridges\n\ -may have the same identifier. Otherwise output ok.\n", 0xFFFFFF); - } - ridge->id= qh ridge_id++; - trace4((qh ferr, 4056, "qh_newridge: created ridge r%d\n", ridge->id)); - return(ridge); -} /* newridge */ - - -/*-<a href="qh-poly.htm#TOC" - >-------------------------------</a><a name="pointid">-</a> - - qh_pointid( ) - return id for a point, - returns -3 if null, -2 if interior, or -1 if not known - - alternative code: - unsigned long id; - id= ((unsigned long)point - (unsigned long)qh.first_point)/qh.normal_size; - - notes: - WARN64 -- id truncated to 32-bits, at most 2G points - NOerrors returned (QhullPoint::id) - if point not in point array - the code does a comparison of unrelated pointers. -*/ -int qh_pointid(pointT *point) { - ptr_intT offset, id; - - if (!point) - return -3; - else if (point == qh interior_point) - return -2; - else if (point >= qh first_point - && point < qh first_point + qh num_points * qh hull_dim) { - offset= (ptr_intT)(point - qh first_point); - id= offset / qh hull_dim; - }else if ((id= qh_setindex(qh other_points, point)) != -1) - id += qh num_points; - else - return -1; - return (int)id; -} /* pointid */ - -/*-<a href="qh-poly.htm#TOC" - >-------------------------------</a><a name="removefacet">-</a> - - qh_removefacet( facet ) - unlinks facet from qh.facet_list, - - returns: - updates qh.facet_list .newfacet_list .facet_next visible_list - decrements qh.num_facets - - see: - qh_appendfacet -*/ -void qh_removefacet(facetT *facet) { - facetT *next= facet->next, *previous= facet->previous; - - if (facet == qh newfacet_list) - qh newfacet_list= next; - if (facet == qh facet_next) - qh facet_next= next; - if (facet == qh visible_list) - qh visible_list= next; - if (previous) { - previous->next= next; - next->previous= previous; - }else { /* 1st facet in qh facet_list */ - qh facet_list= next; - qh facet_list->previous= NULL; - } - qh num_facets--; - trace4((qh ferr, 4057, "qh_removefacet: remove f%d from facet_list\n", facet->id)); -} /* removefacet */ - - -/*-<a href="qh-poly.htm#TOC" - >-------------------------------</a><a name="removevertex">-</a> - - qh_removevertex( vertex ) - unlinks vertex from qh.vertex_list, - - returns: - updates qh.vertex_list .newvertex_list - decrements qh.num_vertices -*/ -void qh_removevertex(vertexT *vertex) { - vertexT *next= vertex->next, *previous= vertex->previous; - - if (vertex == qh newvertex_list) - qh newvertex_list= next; - if (previous) { - previous->next= next; - next->previous= previous; - }else { /* 1st vertex in qh vertex_list */ - qh vertex_list= vertex->next; - qh vertex_list->previous= NULL; - } - qh num_vertices--; - trace4((qh ferr, 4058, "qh_removevertex: remove v%d from vertex_list\n", vertex->id)); -} /* removevertex */ - - -/*-<a href="qh-poly.htm#TOC" - >-------------------------------</a><a name="updatevertices">-</a> - - qh_updatevertices() - update vertex neighbors and delete interior vertices - - returns: - if qh.VERTEXneighbors, updates neighbors for each vertex - if qh.newvertex_list, - removes visible neighbors from vertex neighbors - if qh.newfacet_list - adds new facets to vertex neighbors - if qh.visible_list - interior vertices added to qh.del_vertices for later partitioning - - design: - if qh.VERTEXneighbors - deletes references to visible facets from vertex neighbors - appends new facets to the neighbor list for each vertex - checks all vertices of visible facets - removes visible facets from neighbor lists - marks unused vertices for deletion -*/ -void qh_updatevertices(void /*qh newvertex_list, newfacet_list, visible_list*/) { - facetT *newfacet= NULL, *neighbor, **neighborp, *visible; - vertexT *vertex, **vertexp; - - trace3((qh ferr, 3013, "qh_updatevertices: delete interior vertices and update vertex->neighbors\n")); - if (qh VERTEXneighbors) { - FORALLvertex_(qh newvertex_list) { - FOREACHneighbor_(vertex) { - if (neighbor->visible) - SETref_(neighbor)= NULL; - } - qh_setcompact(vertex->neighbors); - } - FORALLnew_facets { - FOREACHvertex_(newfacet->vertices) - qh_setappend(&vertex->neighbors, newfacet); - } - FORALLvisible_facets { - FOREACHvertex_(visible->vertices) { - if (!vertex->newlist && !vertex->deleted) { - FOREACHneighbor_(vertex) { /* this can happen under merging */ - if (!neighbor->visible) - break; - } - if (neighbor) - qh_setdel(vertex->neighbors, visible); - else { - vertex->deleted= True; - qh_setappend(&qh del_vertices, vertex); - trace2((qh ferr, 2041, "qh_updatevertices: delete vertex p%d(v%d) in f%d\n", - qh_pointid(vertex->point), vertex->id, visible->id)); - } - } - } - } - }else { /* !VERTEXneighbors */ - FORALLvisible_facets { - FOREACHvertex_(visible->vertices) { - if (!vertex->newlist && !vertex->deleted) { - vertex->deleted= True; - qh_setappend(&qh del_vertices, vertex); - trace2((qh ferr, 2042, "qh_updatevertices: delete vertex p%d(v%d) in f%d\n", - qh_pointid(vertex->point), vertex->id, visible->id)); - } - } - } - } -} /* updatevertices */ - - - diff --git a/PyMca/Object3D/Object3DQhull/src/poly.h b/PyMca/Object3D/Object3DQhull/src/poly.h deleted file mode 100644 index 9cf04cf..0000000 --- a/PyMca/Object3D/Object3DQhull/src/poly.h +++ /dev/null @@ -1,295 +0,0 @@ -/*<html><pre> -<a href="qh-poly.htm" - >-------------------------------</a><a name="TOP">-</a> - - poly.h - header file for poly.c and poly2.c - - see qh-poly.htm, libqhull.h and poly.c - - Copyright (c) 1993-2012 The Geometry Center. - $Id: //main/2011/qhull/src/libqhull/poly.h#3 $$Change: 1464 $ - $DateTime: 2012/01/25 22:58:41 $$Author: bbarber $ -*/ - -#ifndef qhDEFpoly -#define qhDEFpoly 1 - -#include "libqhull.h" - -/*=============== constants ========================== */ - -/*-<a href="qh-geom.htm#TOC" - >--------------------------------</a><a name="ALGORITHMfault">-</a> - - ALGORITHMfault - use as argument to checkconvex() to report errors during buildhull -*/ -#define qh_ALGORITHMfault 0 - -/*-<a href="qh-poly.htm#TOC" - >--------------------------------</a><a name="DATAfault">-</a> - - DATAfault - use as argument to checkconvex() to report errors during initialhull -*/ -#define qh_DATAfault 1 - -/*-<a href="qh-poly.htm#TOC" - >--------------------------------</a><a name="DUPLICATEridge">-</a> - - DUPLICATEridge - special value for facet->neighbor to indicate a duplicate ridge - - notes: - set by matchneighbor, used by matchmatch and mark_dupridge -*/ -#define qh_DUPLICATEridge (facetT *)1L - -/*-<a href="qh-poly.htm#TOC" - >--------------------------------</a><a name="MERGEridge">-</a> - - MERGEridge flag in facet - special value for facet->neighbor to indicate a merged ridge - - notes: - set by matchneighbor, used by matchmatch and mark_dupridge -*/ -#define qh_MERGEridge (facetT *)2L - - -/*============ -structures- ====================*/ - -/*=========== -macros- =========================*/ - -/*-<a href="qh-poly.htm#TOC" - >--------------------------------</a><a name="FORALLfacet_">-</a> - - FORALLfacet_( facetlist ) { ... } - assign 'facet' to each facet in facetlist - - notes: - uses 'facetT *facet;' - assumes last facet is a sentinel - - see: - FORALLfacets -*/ -#define FORALLfacet_( facetlist ) if (facetlist ) for ( facet=( facetlist ); facet && facet->next; facet= facet->next ) - -/*-<a href="qh-poly.htm#TOC" - >--------------------------------</a><a name="FORALLnew_facets">-</a> - - FORALLnew_facets { ... } - assign 'newfacet' to each facet in qh.newfacet_list - - notes: - uses 'facetT *newfacet;' - at exit, newfacet==NULL -*/ -#define FORALLnew_facets for ( newfacet=qh newfacet_list;newfacet && newfacet->next;newfacet=newfacet->next ) - -/*-<a href="qh-poly.htm#TOC" - >--------------------------------</a><a name="FORALLvertex_">-</a> - - FORALLvertex_( vertexlist ) { ... } - assign 'vertex' to each vertex in vertexlist - - notes: - uses 'vertexT *vertex;' - at exit, vertex==NULL -*/ -#define FORALLvertex_( vertexlist ) for (vertex=( vertexlist );vertex && vertex->next;vertex= vertex->next ) - -/*-<a href="qh-poly.htm#TOC" - >--------------------------------</a><a name="FORALLvisible_facets">-</a> - - FORALLvisible_facets { ... } - assign 'visible' to each visible facet in qh.visible_list - - notes: - uses 'vacetT *visible;' - at exit, visible==NULL -*/ -#define FORALLvisible_facets for (visible=qh visible_list; visible && visible->visible; visible= visible->next) - -/*-<a href="qh-poly.htm#TOC" - >--------------------------------</a><a name="FORALLsame_">-</a> - - FORALLsame_( newfacet ) { ... } - assign 'same' to each facet in newfacet->f.samecycle - - notes: - uses 'facetT *same;' - stops when it returns to newfacet -*/ -#define FORALLsame_(newfacet) for (same= newfacet->f.samecycle; same != newfacet; same= same->f.samecycle) - -/*-<a href="qh-poly.htm#TOC" - >--------------------------------</a><a name="FORALLsame_cycle_">-</a> - - FORALLsame_cycle_( newfacet ) { ... } - assign 'same' to each facet in newfacet->f.samecycle - - notes: - uses 'facetT *same;' - at exit, same == NULL -*/ -#define FORALLsame_cycle_(newfacet) \ - for (same= newfacet->f.samecycle; \ - same; same= (same == newfacet ? NULL : same->f.samecycle)) - -/*-<a href="qh-poly.htm#TOC" - >--------------------------------</a><a name="FOREACHneighborA_">-</a> - - FOREACHneighborA_( facet ) { ... } - assign 'neighborA' to each neighbor in facet->neighbors - - FOREACHneighborA_( vertex ) { ... } - assign 'neighborA' to each neighbor in vertex->neighbors - - declare: - facetT *neighborA, **neighborAp; - - see: - <a href="qset.h#FOREACHsetelement_">FOREACHsetelement_</a> -*/ -#define FOREACHneighborA_(facet) FOREACHsetelement_(facetT, facet->neighbors, neighborA) - -/*-<a href="qh-poly.htm#TOC" - >--------------------------------</a><a name="FOREACHvisible_">-</a> - - FOREACHvisible_( facets ) { ... } - assign 'visible' to each facet in facets - - notes: - uses 'facetT *facet, *facetp;' - see <a href="qset.h#FOREACHsetelement_">FOREACHsetelement_</a> -*/ -#define FOREACHvisible_(facets) FOREACHsetelement_(facetT, facets, visible) - -/*-<a href="qh-poly.htm#TOC" - >--------------------------------</a><a name="FOREACHnewfacet_">-</a> - - FOREACHnewfacet_( facets ) { ... } - assign 'newfacet' to each facet in facets - - notes: - uses 'facetT *newfacet, *newfacetp;' - see <a href="qset.h#FOREACHsetelement_">FOREACHsetelement_</a> -*/ -#define FOREACHnewfacet_(facets) FOREACHsetelement_(facetT, facets, newfacet) - -/*-<a href="qh-poly.htm#TOC" - >--------------------------------</a><a name="FOREACHvertexA_">-</a> - - FOREACHvertexA_( vertices ) { ... } - assign 'vertexA' to each vertex in vertices - - notes: - uses 'vertexT *vertexA, *vertexAp;' - see <a href="qset.h#FOREACHsetelement_">FOREACHsetelement_</a> -*/ -#define FOREACHvertexA_(vertices) FOREACHsetelement_(vertexT, vertices, vertexA) - -/*-<a href="qh-poly.htm#TOC" - >--------------------------------</a><a name="FOREACHvertexreverse12_">-</a> - - FOREACHvertexreverse12_( vertices ) { ... } - assign 'vertex' to each vertex in vertices - reverse order of first two vertices - - notes: - uses 'vertexT *vertex, *vertexp;' - see <a href="qset.h#FOREACHsetelement_">FOREACHsetelement_</a> -*/ -#define FOREACHvertexreverse12_(vertices) FOREACHsetelementreverse12_(vertexT, vertices, vertex) - - -/*=============== prototypes poly.c in alphabetical order ================*/ - -void qh_appendfacet(facetT *facet); -void qh_appendvertex(vertexT *vertex); -void qh_attachnewfacets(void); -boolT qh_checkflipped(facetT *facet, realT *dist, boolT allerror); -void qh_delfacet(facetT *facet); -void qh_deletevisible(void /*qh visible_list, qh horizon_list*/); -setT *qh_facetintersect(facetT *facetA, facetT *facetB, int *skipAp,int *skipBp, int extra); -int qh_gethash(int hashsize, setT *set, int size, int firstindex, void *skipelem); -facetT *qh_makenewfacet(setT *vertices, boolT toporient, facetT *facet); -void qh_makenewplanes(void /* newfacet_list */); -facetT *qh_makenew_nonsimplicial(facetT *visible, vertexT *apex, int *numnew); -facetT *qh_makenew_simplicial(facetT *visible, vertexT *apex, int *numnew); -void qh_matchneighbor(facetT *newfacet, int newskip, int hashsize, - int *hashcount); -void qh_matchnewfacets(void); -boolT qh_matchvertices(int firstindex, setT *verticesA, int skipA, - setT *verticesB, int *skipB, boolT *same); -facetT *qh_newfacet(void); -ridgeT *qh_newridge(void); -int qh_pointid(pointT *point); -void qh_removefacet(facetT *facet); -void qh_removevertex(vertexT *vertex); -void qh_updatevertices(void); - - -/*========== -prototypes poly2.c in alphabetical order ===========*/ - -void qh_addhash(void* newelem, setT *hashtable, int hashsize, int hash); -void qh_check_bestdist(void); -void qh_check_maxout(void); -void qh_check_output(void); -void qh_check_point(pointT *point, facetT *facet, realT *maxoutside, realT *maxdist, facetT **errfacet1, facetT **errfacet2); -void qh_check_points(void); -void qh_checkconvex(facetT *facetlist, int fault); -void qh_checkfacet(facetT *facet, boolT newmerge, boolT *waserrorp); -void qh_checkflipped_all(facetT *facetlist); -void qh_checkpolygon(facetT *facetlist); -void qh_checkvertex(vertexT *vertex); -void qh_clearcenters(qh_CENTER type); -void qh_createsimplex(setT *vertices); -void qh_delridge(ridgeT *ridge); -void qh_delvertex(vertexT *vertex); -setT *qh_facet3vertex(facetT *facet); -facetT *qh_findbestfacet(pointT *point, boolT bestoutside, - realT *bestdist, boolT *isoutside); -facetT *qh_findbestlower(facetT *upperfacet, pointT *point, realT *bestdistp, int *numpart); -facetT *qh_findfacet_all(pointT *point, realT *bestdist, boolT *isoutside, - int *numpart); -int qh_findgood(facetT *facetlist, int goodhorizon); -void qh_findgood_all(facetT *facetlist); -void qh_furthestnext(void /* qh facet_list */); -void qh_furthestout(facetT *facet); -void qh_infiniteloop(facetT *facet); -void qh_initbuild(void); -void qh_initialhull(setT *vertices); -setT *qh_initialvertices(int dim, setT *maxpoints, pointT *points, int numpoints); -vertexT *qh_isvertex(pointT *point, setT *vertices); -vertexT *qh_makenewfacets(pointT *point /*horizon_list, visible_list*/); -void qh_matchduplicates(facetT *atfacet, int atskip, int hashsize, int *hashcount); -void qh_nearcoplanar(void /* qh.facet_list */); -vertexT *qh_nearvertex(facetT *facet, pointT *point, realT *bestdistp); -int qh_newhashtable(int newsize); -vertexT *qh_newvertex(pointT *point); -ridgeT *qh_nextridge3d(ridgeT *atridge, facetT *facet, vertexT **vertexp); -void qh_outcoplanar(void /* facet_list */); -pointT *qh_point(int id); -void qh_point_add(setT *set, pointT *point, void *elem); -setT *qh_pointfacet(void /*qh facet_list*/); -setT *qh_pointvertex(void /*qh facet_list*/); -void qh_prependfacet(facetT *facet, facetT **facetlist); -void qh_printhashtable(FILE *fp); -void qh_printlists(void); -void qh_resetlists(boolT stats, boolT resetVisible /*qh newvertex_list newfacet_list visible_list*/); -void qh_setvoronoi_all(void); -void qh_triangulate(void /*qh facet_list*/); -void qh_triangulate_facet(facetT *facetA, vertexT **first_vertex); -void qh_triangulate_link(facetT *oldfacetA, facetT *facetA, facetT *oldfacetB, facetT *facetB); -void qh_triangulate_mirror(facetT *facetA, facetT *facetB); -void qh_triangulate_null(facetT *facetA); -void qh_vertexintersect(setT **vertexsetA,setT *vertexsetB); -setT *qh_vertexintersect_new(setT *vertexsetA,setT *vertexsetB); -void qh_vertexneighbors(void /*qh facet_list*/); -boolT qh_vertexsubset(setT *vertexsetA, setT *vertexsetB); - - -#endif /* qhDEFpoly */ diff --git a/PyMca/Object3D/Object3DQhull/src/poly2.c b/PyMca/Object3D/Object3DQhull/src/poly2.c deleted file mode 100644 index 317461f..0000000 --- a/PyMca/Object3D/Object3DQhull/src/poly2.c +++ /dev/null @@ -1,3154 +0,0 @@ -/*<html><pre> -<a href="qh-poly.htm" - >-------------------------------</a><a name="TOP">-</a> - - poly2.c - implements polygons and simplices - - see qh-poly.htm, poly.h and libqhull.h - - frequently used code is in poly.c - - Copyright (c) 1993-2012 The Geometry Center. - $Id: //main/2011/qhull/src/libqhull/poly2.c#5 $$Change: 1490 $ - $DateTime: 2012/02/19 20:27:01 $$Author: bbarber $ -*/ - -#include "qhull_a.h" - -/*======== functions in alphabetical order ==========*/ - -/*-<a href="qh-poly.htm#TOC" - >-------------------------------</a><a name="addhash">-</a> - - qh_addhash( newelem, hashtable, hashsize, hash ) - add newelem to linear hash table at hash if not already there -*/ -void qh_addhash(void* newelem, setT *hashtable, int hashsize, int hash) { - int scan; - void *elem; - - for (scan= (int)hash; (elem= SETelem_(hashtable, scan)); - scan= (++scan >= hashsize ? 0 : scan)) { - if (elem == newelem) - break; - } - /* loop terminates because qh_HASHfactor >= 1.1 by qh_initbuffers */ - if (!elem) - SETelem_(hashtable, scan)= newelem; -} /* addhash */ - -/*-<a href="qh-poly.htm#TOC" - >-------------------------------</a><a name="check_bestdist">-</a> - - qh_check_bestdist() - check that all points are within max_outside of the nearest facet - if qh.ONLYgood, - ignores !good facets - - see: - qh_check_maxout(), qh_outerinner() - - notes: - only called from qh_check_points() - seldom used since qh.MERGING is almost always set - if notverified>0 at end of routine - some points were well inside the hull. If the hull contains - a lens-shaped component, these points were not verified. Use - options 'Qi Tv' to verify all points. (Exhaustive check also verifies) - - design: - determine facet for each point (if any) - for each point - start with the assigned facet or with the first facet - find the best facet for the point and check all coplanar facets - error if point is outside of facet -*/ -void qh_check_bestdist(void) { - boolT waserror= False, unassigned; - facetT *facet, *bestfacet, *errfacet1= NULL, *errfacet2= NULL; - facetT *facetlist; - realT dist, maxoutside, maxdist= -REALmax; - pointT *point; - int numpart= 0, facet_i, facet_n, notgood= 0, notverified= 0; - setT *facets; - - trace1((qh ferr, 1020, "qh_check_bestdist: check points below nearest facet. Facet_list f%d\n", - qh facet_list->id)); - maxoutside= qh_maxouter(); - maxoutside += qh DISTround; - /* one more qh.DISTround for check computation */ - trace1((qh ferr, 1021, "qh_check_bestdist: check that all points are within %2.2g of best facet\n", maxoutside)); - facets= qh_pointfacet(/*qh facet_list*/); - if (!qh_QUICKhelp && qh PRINTprecision) - qh_fprintf(qh ferr, 8091, "\n\ -qhull output completed. Verifying that %d points are\n\ -below %2.2g of the nearest %sfacet.\n", - qh_setsize(facets), maxoutside, (qh ONLYgood ? "good " : "")); - FOREACHfacet_i_(facets) { /* for each point with facet assignment */ - if (facet) - unassigned= False; - else { - unassigned= True; - facet= qh facet_list; - } - point= qh_point(facet_i); - if (point == qh GOODpointp) - continue; - qh_distplane(point, facet, &dist); - numpart++; - bestfacet= qh_findbesthorizon(!qh_IScheckmax, point, facet, qh_NOupper, &dist, &numpart); - /* occurs after statistics reported */ - maximize_(maxdist, dist); - if (dist > maxoutside) { - if (qh ONLYgood && !bestfacet->good - && !((bestfacet= qh_findgooddist(point, bestfacet, &dist, &facetlist)) - && dist > maxoutside)) - notgood++; - else { - waserror= True; - qh_fprintf(qh ferr, 6109, "qhull precision error: point p%d is outside facet f%d, distance= %6.8g maxoutside= %6.8g\n", - facet_i, bestfacet->id, dist, maxoutside); - if (errfacet1 != bestfacet) { - errfacet2= errfacet1; - errfacet1= bestfacet; - } - } - }else if (unassigned && dist < -qh MAXcoplanar) - notverified++; - } - qh_settempfree(&facets); - if (notverified && !qh DELAUNAY && !qh_QUICKhelp && qh PRINTprecision) - qh_fprintf(qh ferr, 8092, "\n%d points were well inside the hull. If the hull contains\n\ -a lens-shaped component, these points were not verified. Use\n\ -options 'Qci Tv' to verify all points.\n", notverified); - if (maxdist > qh outside_err) { - qh_fprintf(qh ferr, 6110, "qhull precision error (qh_check_bestdist): a coplanar point is %6.2g from convex hull. The maximum value(qh.outside_err) is %6.2g\n", - maxdist, qh outside_err); - qh_errexit2 (qh_ERRprec, errfacet1, errfacet2); - }else if (waserror && qh outside_err > REALmax/2) - qh_errexit2 (qh_ERRprec, errfacet1, errfacet2); - /* else if waserror, the error was logged to qh.ferr but does not effect the output */ - trace0((qh ferr, 20, "qh_check_bestdist: max distance outside %2.2g\n", maxdist)); -} /* check_bestdist */ - -/*-<a href="qh-poly.htm#TOC" - >-------------------------------</a><a name="check_maxout">-</a> - - qh_check_maxout() - updates qh.max_outside by checking all points against bestfacet - if qh.ONLYgood, ignores !good facets - - returns: - updates facet->maxoutside via qh_findbesthorizon() - sets qh.maxoutdone - if printing qh.min_vertex (qh_outerinner), - it is updated to the current vertices - removes inside/coplanar points from coplanarset as needed - - notes: - defines coplanar as min_vertex instead of MAXcoplanar - may not need to check near-inside points because of qh.MAXcoplanar - and qh.KEEPnearinside (before it was -DISTround) - - see also: - qh_check_bestdist() - - design: - if qh.min_vertex is needed - for all neighbors of all vertices - test distance from vertex to neighbor - determine facet for each point (if any) - for each point with an assigned facet - find the best facet for the point and check all coplanar facets - (updates outer planes) - remove near-inside points from coplanar sets -*/ -#ifndef qh_NOmerge -void qh_check_maxout(void) { - facetT *facet, *bestfacet, *neighbor, **neighborp, *facetlist; - realT dist, maxoutside, minvertex, old_maxoutside; - pointT *point; - int numpart= 0, facet_i, facet_n, notgood= 0; - setT *facets, *vertices; - vertexT *vertex; - - trace1((qh ferr, 1022, "qh_check_maxout: check and update maxoutside for each facet.\n")); - maxoutside= minvertex= 0; - if (qh VERTEXneighbors - && (qh PRINTsummary || qh KEEPinside || qh KEEPcoplanar - || qh TRACElevel || qh PRINTstatistics - || qh PRINTout[0] == qh_PRINTsummary || qh PRINTout[0] == qh_PRINTnone)) { - trace1((qh ferr, 1023, "qh_check_maxout: determine actual maxoutside and minvertex\n")); - vertices= qh_pointvertex(/*qh facet_list*/); - FORALLvertices { - FOREACHneighbor_(vertex) { - zinc_(Zdistvertex); /* distance also computed by main loop below */ - qh_distplane(vertex->point, neighbor, &dist); - minimize_(minvertex, dist); - if (-dist > qh TRACEdist || dist > qh TRACEdist - || neighbor == qh tracefacet || vertex == qh tracevertex) - qh_fprintf(qh ferr, 8093, "qh_check_maxout: p%d(v%d) is %.2g from f%d\n", - qh_pointid(vertex->point), vertex->id, dist, neighbor->id); - } - } - if (qh MERGING) { - wmin_(Wminvertex, qh min_vertex); - } - qh min_vertex= minvertex; - qh_settempfree(&vertices); - } - facets= qh_pointfacet(/*qh facet_list*/); - do { - old_maxoutside= fmax_(qh max_outside, maxoutside); - FOREACHfacet_i_(facets) { /* for each point with facet assignment */ - if (facet) { - point= qh_point(facet_i); - if (point == qh GOODpointp) - continue; - zzinc_(Ztotcheck); - qh_distplane(point, facet, &dist); - numpart++; - bestfacet= qh_findbesthorizon(qh_IScheckmax, point, facet, !qh_NOupper, &dist, &numpart); - if (bestfacet && dist > maxoutside) { - if (qh ONLYgood && !bestfacet->good - && !((bestfacet= qh_findgooddist(point, bestfacet, &dist, &facetlist)) - && dist > maxoutside)) - notgood++; - else - maxoutside= dist; - } - if (dist > qh TRACEdist || (bestfacet && bestfacet == qh tracefacet)) - qh_fprintf(qh ferr, 8094, "qh_check_maxout: p%d is %.2g above f%d\n", - qh_pointid(point), dist, bestfacet->id); - } - } - }while - (maxoutside > 2*old_maxoutside); - /* if qh.maxoutside increases substantially, qh_SEARCHdist is not valid - e.g., RBOX 5000 s Z1 G1e-13 t1001200614 | qhull */ - zzadd_(Zcheckpart, numpart); - qh_settempfree(&facets); - wval_(Wmaxout)= maxoutside - qh max_outside; - wmax_(Wmaxoutside, qh max_outside); - qh max_outside= maxoutside; - qh_nearcoplanar(/*qh.facet_list*/); - qh maxoutdone= True; - trace1((qh ferr, 1024, "qh_check_maxout: maxoutside %2.2g, min_vertex %2.2g, outside of not good %d\n", - maxoutside, qh min_vertex, notgood)); -} /* check_maxout */ -#else /* qh_NOmerge */ -void qh_check_maxout(void) { -} -#endif - -/*-<a href="qh-poly.htm#TOC" - >-------------------------------</a><a name="check_output">-</a> - - qh_check_output() - performs the checks at the end of qhull algorithm - Maybe called after voronoi output. Will recompute otherwise centrums are Voronoi centers instead -*/ -void qh_check_output(void) { - int i; - - if (qh STOPcone) - return; - if (qh VERIFYoutput | qh IStracing | qh CHECKfrequently) { - qh_checkpolygon(qh facet_list); - qh_checkflipped_all(qh facet_list); - qh_checkconvex(qh facet_list, qh_ALGORITHMfault); - }else if (!qh MERGING && qh_newstats(qhstat precision, &i)) { - qh_checkflipped_all(qh facet_list); - qh_checkconvex(qh facet_list, qh_ALGORITHMfault); - } -} /* check_output */ - - - -/*-<a href="qh-poly.htm#TOC" - >-------------------------------</a><a name="check_point">-</a> - - qh_check_point( point, facet, maxoutside, maxdist, errfacet1, errfacet2 ) - check that point is less than maxoutside from facet -*/ -void qh_check_point(pointT *point, facetT *facet, realT *maxoutside, realT *maxdist, facetT **errfacet1, facetT **errfacet2) { - realT dist; - - /* occurs after statistics reported */ - qh_distplane(point, facet, &dist); - if (dist > *maxoutside) { - if (*errfacet1 != facet) { - *errfacet2= *errfacet1; - *errfacet1= facet; - } - qh_fprintf(qh ferr, 6111, "qhull precision error: point p%d is outside facet f%d, distance= %6.8g maxoutside= %6.8g\n", - qh_pointid(point), facet->id, dist, *maxoutside); - } - maximize_(*maxdist, dist); -} /* qh_check_point */ - - -/*-<a href="qh-poly.htm#TOC" - >-------------------------------</a><a name="check_points">-</a> - - qh_check_points() - checks that all points are inside all facets - - notes: - if many points and qh_check_maxout not called (i.e., !qh.MERGING), - calls qh_findbesthorizon (seldom done). - ignores flipped facets - maxoutside includes 2 qh.DISTrounds - one qh.DISTround for the computed distances in qh_check_points - qh_printafacet and qh_printsummary needs only one qh.DISTround - the computation for qh.VERIFYdirect does not account for qh.other_points - - design: - if many points - use qh_check_bestdist() - else - for all facets - for all points - check that point is inside facet -*/ -void qh_check_points(void) { - facetT *facet, *errfacet1= NULL, *errfacet2= NULL; - realT total, maxoutside, maxdist= -REALmax; - pointT *point, **pointp, *pointtemp; - boolT testouter; - - maxoutside= qh_maxouter(); - maxoutside += qh DISTround; - /* one more qh.DISTround for check computation */ - trace1((qh ferr, 1025, "qh_check_points: check all points below %2.2g of all facet planes\n", - maxoutside)); - if (qh num_good) /* miss counts other_points and !good facets */ - total= (float)qh num_good * (float)qh num_points; - else - total= (float)qh num_facets * (float)qh num_points; - if (total >= qh_VERIFYdirect && !qh maxoutdone) { - if (!qh_QUICKhelp && qh SKIPcheckmax && qh MERGING) - qh_fprintf(qh ferr, 7075, "qhull input warning: merging without checking outer planes('Q5' or 'Po').\n\ -Verify may report that a point is outside of a facet.\n"); - qh_check_bestdist(); - }else { - if (qh_MAXoutside && qh maxoutdone) - testouter= True; - else - testouter= False; - if (!qh_QUICKhelp) { - if (qh MERGEexact) - qh_fprintf(qh ferr, 7076, "qhull input warning: exact merge ('Qx'). Verify may report that a point\n\ -is outside of a facet. See qh-optq.htm#Qx\n"); - else if (qh SKIPcheckmax || qh NOnearinside) - qh_fprintf(qh ferr, 7077, "qhull input warning: no outer plane check ('Q5') or no processing of\n\ -near-inside points ('Q8'). Verify may report that a point is outside\n\ -of a facet.\n"); - } - if (qh PRINTprecision) { - if (testouter) - qh_fprintf(qh ferr, 8098, "\n\ -Output completed. Verifying that all points are below outer planes of\n\ -all %sfacets. Will make %2.0f distance computations.\n", - (qh ONLYgood ? "good " : ""), total); - else - qh_fprintf(qh ferr, 8099, "\n\ -Output completed. Verifying that all points are below %2.2g of\n\ -all %sfacets. Will make %2.0f distance computations.\n", - maxoutside, (qh ONLYgood ? "good " : ""), total); - } - FORALLfacets { - if (!facet->good && qh ONLYgood) - continue; - if (facet->flipped) - continue; - if (!facet->normal) { - qh_fprintf(qh ferr, 7061, "qhull warning (qh_check_points): missing normal for facet f%d\n", facet->id); - continue; - } - if (testouter) { -#if qh_MAXoutside - maxoutside= facet->maxoutside + 2* qh DISTround; - /* one DISTround to actual point and another to computed point */ -#endif - } - FORALLpoints { - if (point != qh GOODpointp) - qh_check_point(point, facet, &maxoutside, &maxdist, &errfacet1, &errfacet2); - } - FOREACHpoint_(qh other_points) { - if (point != qh GOODpointp) - qh_check_point(point, facet, &maxoutside, &maxdist, &errfacet1, &errfacet2); - } - } - if (maxdist > qh outside_err) { - qh_fprintf(qh ferr, 6112, "qhull precision error (qh_check_points): a coplanar point is %6.2g from convex hull. The maximum value(qh.outside_err) is %6.2g\n", - maxdist, qh outside_err ); - qh_errexit2( qh_ERRprec, errfacet1, errfacet2 ); - }else if (errfacet1 && qh outside_err > REALmax/2) - qh_errexit2( qh_ERRprec, errfacet1, errfacet2 ); - /* else if errfacet1, the error was logged to qh.ferr but does not effect the output */ - trace0((qh ferr, 21, "qh_check_points: max distance outside %2.2g\n", maxdist)); - } -} /* check_points */ - - -/*-<a href="qh-poly.htm#TOC" - >-------------------------------</a><a name="checkconvex">-</a> - - qh_checkconvex( facetlist, fault ) - check that each ridge in facetlist is convex - fault = qh_DATAfault if reporting errors - = qh_ALGORITHMfault otherwise - - returns: - counts Zconcaveridges and Zcoplanarridges - errors if concaveridge or if merging an coplanar ridge - - note: - if not merging, - tests vertices for neighboring simplicial facets - else if ZEROcentrum, - tests vertices for neighboring simplicial facets - else - tests centrums of neighboring facets - - design: - for all facets - report flipped facets - if ZEROcentrum and simplicial neighbors - test vertices for neighboring simplicial facets - else - test centrum against all neighbors -*/ -void qh_checkconvex(facetT *facetlist, int fault) { - facetT *facet, *neighbor, **neighborp, *errfacet1=NULL, *errfacet2=NULL; - vertexT *vertex; - realT dist; - pointT *centrum; - boolT waserror= False, centrum_warning= False, tempcentrum= False, allsimplicial; - int neighbor_i; - - trace1((qh ferr, 1026, "qh_checkconvex: check all ridges are convex\n")); - if (!qh RERUN) { - zzval_(Zconcaveridges)= 0; - zzval_(Zcoplanarridges)= 0; - } - FORALLfacet_(facetlist) { - if (facet->flipped) { - qh_precision("flipped facet"); - qh_fprintf(qh ferr, 6113, "qhull precision error: f%d is flipped(interior point is outside)\n", - facet->id); - errfacet1= facet; - waserror= True; - continue; - } - if (qh MERGING && (!qh ZEROcentrum || !facet->simplicial || facet->tricoplanar)) - allsimplicial= False; - else { - allsimplicial= True; - neighbor_i= 0; - FOREACHneighbor_(facet) { - vertex= SETelemt_(facet->vertices, neighbor_i++, vertexT); - if (!neighbor->simplicial || neighbor->tricoplanar) { - allsimplicial= False; - continue; - } - qh_distplane(vertex->point, neighbor, &dist); - if (dist > -qh DISTround) { - if (fault == qh_DATAfault) { - qh_precision("coplanar or concave ridge"); - qh_fprintf(qh ferr, 6114, "qhull precision error: initial simplex is not convex. Distance=%.2g\n", dist); - qh_errexit(qh_ERRsingular, NULL, NULL); - } - if (dist > qh DISTround) { - zzinc_(Zconcaveridges); - qh_precision("concave ridge"); - qh_fprintf(qh ferr, 6115, "qhull precision error: f%d is concave to f%d, since p%d(v%d) is %6.4g above\n", - facet->id, neighbor->id, qh_pointid(vertex->point), vertex->id, dist); - errfacet1= facet; - errfacet2= neighbor; - waserror= True; - }else if (qh ZEROcentrum) { - if (dist > 0) { /* qh_checkzero checks that dist < - qh DISTround */ - zzinc_(Zcoplanarridges); - qh_precision("coplanar ridge"); - qh_fprintf(qh ferr, 6116, "qhull precision error: f%d is clearly not convex to f%d, since p%d(v%d) is %6.4g above\n", - facet->id, neighbor->id, qh_pointid(vertex->point), vertex->id, dist); - errfacet1= facet; - errfacet2= neighbor; - waserror= True; - } - }else { - zzinc_(Zcoplanarridges); - qh_precision("coplanar ridge"); - trace0((qh ferr, 22, "qhull precision error: f%d may be coplanar to f%d, since p%d(v%d) is within %6.4g during p%d\n", - facet->id, neighbor->id, qh_pointid(vertex->point), vertex->id, dist, qh furthest_id)); - } - } - } - } - if (!allsimplicial) { - if (qh CENTERtype == qh_AScentrum) { - if (!facet->center) - facet->center= qh_getcentrum(facet); - centrum= facet->center; - }else { - if (!centrum_warning && (!facet->simplicial || facet->tricoplanar)) { - centrum_warning= True; - qh_fprintf(qh ferr, 7062, "qhull warning: recomputing centrums for convexity test. This may lead to false, precision errors.\n"); - } - centrum= qh_getcentrum(facet); - tempcentrum= True; - } - FOREACHneighbor_(facet) { - if (qh ZEROcentrum && facet->simplicial && neighbor->simplicial) - continue; - if (facet->tricoplanar || neighbor->tricoplanar) - continue; - zzinc_(Zdistconvex); - qh_distplane(centrum, neighbor, &dist); - if (dist > qh DISTround) { - zzinc_(Zconcaveridges); - qh_precision("concave ridge"); - qh_fprintf(qh ferr, 6117, "qhull precision error: f%d is concave to f%d. Centrum of f%d is %6.4g above f%d\n", - facet->id, neighbor->id, facet->id, dist, neighbor->id); - errfacet1= facet; - errfacet2= neighbor; - waserror= True; - }else if (dist >= 0.0) { /* if arithmetic always rounds the same, - can test against centrum radius instead */ - zzinc_(Zcoplanarridges); - qh_precision("coplanar ridge"); - qh_fprintf(qh ferr, 6118, "qhull precision error: f%d is coplanar or concave to f%d. Centrum of f%d is %6.4g above f%d\n", - facet->id, neighbor->id, facet->id, dist, neighbor->id); - errfacet1= facet; - errfacet2= neighbor; - waserror= True; - } - } - if (tempcentrum) - qh_memfree(centrum, qh normal_size); - } - } - if (waserror && !qh FORCEoutput) - qh_errexit2 (qh_ERRprec, errfacet1, errfacet2); -} /* checkconvex */ - - -/*-<a href="qh-poly.htm#TOC" - >-------------------------------</a><a name="checkfacet">-</a> - - qh_checkfacet( facet, newmerge, waserror ) - checks for consistency errors in facet - newmerge set if from merge.c - - returns: - sets waserror if any error occurs - - checks: - vertex ids are inverse sorted - unless newmerge, at least hull_dim neighbors and vertices (exactly if simplicial) - if non-simplicial, at least as many ridges as neighbors - neighbors are not duplicated - ridges are not duplicated - in 3-d, ridges=verticies - (qh.hull_dim-1) ridge vertices - neighbors are reciprocated - ridge neighbors are facet neighbors and a ridge for every neighbor - simplicial neighbors match facetintersect - vertex intersection matches vertices of common ridges - vertex neighbors and facet vertices agree - all ridges have distinct vertex sets - - notes: - uses neighbor->seen - - design: - check sets - check vertices - check sizes of neighbors and vertices - check for qh_MERGEridge and qh_DUPLICATEridge flags - check neighbor set - check ridge set - check ridges, neighbors, and vertices -*/ -void qh_checkfacet(facetT *facet, boolT newmerge, boolT *waserrorp) { - facetT *neighbor, **neighborp, *errother=NULL; - ridgeT *ridge, **ridgep, *errridge= NULL, *ridge2; - vertexT *vertex, **vertexp; - unsigned previousid= INT_MAX; - int numneighbors, numvertices, numridges=0, numRvertices=0; - boolT waserror= False; - int skipA, skipB, ridge_i, ridge_n, i; - setT *intersection; - - if (facet->visible) { - qh_fprintf(qh ferr, 6119, "qhull internal error (qh_checkfacet): facet f%d is on the visible_list\n", - facet->id); - qh_errexit(qh_ERRqhull, facet, NULL); - } - if (!facet->normal) { - qh_fprintf(qh ferr, 6120, "qhull internal error (qh_checkfacet): facet f%d does not have a normal\n", - facet->id); - waserror= True; - } - qh_setcheck(facet->vertices, "vertices for f", facet->id); - qh_setcheck(facet->ridges, "ridges for f", facet->id); - qh_setcheck(facet->outsideset, "outsideset for f", facet->id); - qh_setcheck(facet->coplanarset, "coplanarset for f", facet->id); - qh_setcheck(facet->neighbors, "neighbors for f", facet->id); - FOREACHvertex_(facet->vertices) { - if (vertex->deleted) { - qh_fprintf(qh ferr, 6121, "qhull internal error (qh_checkfacet): deleted vertex v%d in f%d\n", vertex->id, facet->id); - qh_errprint("ERRONEOUS", NULL, NULL, NULL, vertex); - waserror= True; - } - if (vertex->id >= previousid) { - qh_fprintf(qh ferr, 6122, "qhull internal error (qh_checkfacet): vertices of f%d are not in descending id order at v%d\n", facet->id, vertex->id); - waserror= True; - break; - } - previousid= vertex->id; - } - numneighbors= qh_setsize(facet->neighbors); - numvertices= qh_setsize(facet->vertices); - numridges= qh_setsize(facet->ridges); - if (facet->simplicial) { - if (numvertices+numneighbors != 2*qh hull_dim - && !facet->degenerate && !facet->redundant) { - qh_fprintf(qh ferr, 6123, "qhull internal error (qh_checkfacet): for simplicial facet f%d, #vertices %d + #neighbors %d != 2*qh hull_dim\n", - facet->id, numvertices, numneighbors); - qh_setprint(qh ferr, "", facet->neighbors); - waserror= True; - } - }else { /* non-simplicial */ - if (!newmerge - &&(numvertices < qh hull_dim || numneighbors < qh hull_dim) - && !facet->degenerate && !facet->redundant) { - qh_fprintf(qh ferr, 6124, "qhull internal error (qh_checkfacet): for facet f%d, #vertices %d or #neighbors %d < qh hull_dim\n", - facet->id, numvertices, numneighbors); - waserror= True; - } - /* in 3-d, can get a vertex twice in an edge list, e.g., RBOX 1000 s W1e-13 t995849315 D2 | QHULL d Tc Tv TP624 TW1e-13 T4 */ - if (numridges < numneighbors - ||(qh hull_dim == 3 && numvertices > numridges && !qh NEWfacets) - ||(qh hull_dim == 2 && numridges + numvertices + numneighbors != 6)) { - if (!facet->degenerate && !facet->redundant) { - qh_fprintf(qh ferr, 6125, "qhull internal error (qh_checkfacet): for facet f%d, #ridges %d < #neighbors %d or(3-d) > #vertices %d or(2-d) not all 2\n", - facet->id, numridges, numneighbors, numvertices); - waserror= True; - } - } - } - FOREACHneighbor_(facet) { - if (neighbor == qh_MERGEridge || neighbor == qh_DUPLICATEridge) { - qh_fprintf(qh ferr, 6126, "qhull internal error (qh_checkfacet): facet f%d still has a MERGE or DUP neighbor\n", facet->id); - qh_errexit(qh_ERRqhull, facet, NULL); - } - neighbor->seen= True; - } - FOREACHneighbor_(facet) { - if (!qh_setin(neighbor->neighbors, facet)) { - qh_fprintf(qh ferr, 6127, "qhull internal error (qh_checkfacet): facet f%d has neighbor f%d, but f%d does not have neighbor f%d\n", - facet->id, neighbor->id, neighbor->id, facet->id); - errother= neighbor; - waserror= True; - } - if (!neighbor->seen) { - qh_fprintf(qh ferr, 6128, "qhull internal error (qh_checkfacet): facet f%d has a duplicate neighbor f%d\n", - facet->id, neighbor->id); - errother= neighbor; - waserror= True; - } - neighbor->seen= False; - } - FOREACHridge_(facet->ridges) { - qh_setcheck(ridge->vertices, "vertices for r", ridge->id); - ridge->seen= False; - } - FOREACHridge_(facet->ridges) { - if (ridge->seen) { - qh_fprintf(qh ferr, 6129, "qhull internal error (qh_checkfacet): facet f%d has a duplicate ridge r%d\n", - facet->id, ridge->id); - errridge= ridge; - waserror= True; - } - ridge->seen= True; - numRvertices= qh_setsize(ridge->vertices); - if (numRvertices != qh hull_dim - 1) { - qh_fprintf(qh ferr, 6130, "qhull internal error (qh_checkfacet): ridge between f%d and f%d has %d vertices\n", - ridge->top->id, ridge->bottom->id, numRvertices); - errridge= ridge; - waserror= True; - } - neighbor= otherfacet_(ridge, facet); - neighbor->seen= True; - if (!qh_setin(facet->neighbors, neighbor)) { - qh_fprintf(qh ferr, 6131, "qhull internal error (qh_checkfacet): for facet f%d, neighbor f%d of ridge r%d not in facet\n", - facet->id, neighbor->id, ridge->id); - errridge= ridge; - waserror= True; - } - } - if (!facet->simplicial) { - FOREACHneighbor_(facet) { - if (!neighbor->seen) { - qh_fprintf(qh ferr, 6132, "qhull internal error (qh_checkfacet): facet f%d does not have a ridge for neighbor f%d\n", - facet->id, neighbor->id); - errother= neighbor; - waserror= True; - } - intersection= qh_vertexintersect_new(facet->vertices, neighbor->vertices); - qh_settemppush(intersection); - FOREACHvertex_(facet->vertices) { - vertex->seen= False; - vertex->seen2= False; - } - FOREACHvertex_(intersection) - vertex->seen= True; - FOREACHridge_(facet->ridges) { - if (neighbor != otherfacet_(ridge, facet)) - continue; - FOREACHvertex_(ridge->vertices) { - if (!vertex->seen) { - qh_fprintf(qh ferr, 6133, "qhull internal error (qh_checkfacet): vertex v%d in r%d not in f%d intersect f%d\n", - vertex->id, ridge->id, facet->id, neighbor->id); - qh_errexit(qh_ERRqhull, facet, ridge); - } - vertex->seen2= True; - } - } - if (!newmerge) { - FOREACHvertex_(intersection) { - if (!vertex->seen2) { - if (qh IStracing >=3 || !qh MERGING) { - qh_fprintf(qh ferr, 6134, "qhull precision error (qh_checkfacet): vertex v%d in f%d intersect f%d but\n\ - not in a ridge. This is ok under merging. Last point was p%d\n", - vertex->id, facet->id, neighbor->id, qh furthest_id); - if (!qh FORCEoutput && !qh MERGING) { - qh_errprint("ERRONEOUS", facet, neighbor, NULL, vertex); - if (!qh MERGING) - qh_errexit(qh_ERRqhull, NULL, NULL); - } - } - } - } - } - qh_settempfree(&intersection); - } - }else { /* simplicial */ - FOREACHneighbor_(facet) { - if (neighbor->simplicial) { - skipA= SETindex_(facet->neighbors, neighbor); - skipB= qh_setindex(neighbor->neighbors, facet); - if (!qh_setequal_skip(facet->vertices, skipA, neighbor->vertices, skipB)) { - qh_fprintf(qh ferr, 6135, "qhull internal error (qh_checkfacet): facet f%d skip %d and neighbor f%d skip %d do not match \n", - facet->id, skipA, neighbor->id, skipB); - errother= neighbor; - waserror= True; - } - } - } - } - if (qh hull_dim < 5 && (qh IStracing > 2 || qh CHECKfrequently)) { - FOREACHridge_i_(facet->ridges) { /* expensive */ - for (i=ridge_i+1; i < ridge_n; i++) { - ridge2= SETelemt_(facet->ridges, i, ridgeT); - if (qh_setequal(ridge->vertices, ridge2->vertices)) { - qh_fprintf(qh ferr, 6227, "Qhull internal error (qh_checkfacet): ridges r%d and r%d have the same vertices\n", - ridge->id, ridge2->id); - errridge= ridge; - waserror= True; - } - } - } - } - if (waserror) { - qh_errprint("ERRONEOUS", facet, errother, errridge, NULL); - *waserrorp= True; - } -} /* checkfacet */ - - -/*-<a href="qh-poly.htm#TOC" - >-------------------------------</a><a name="checkflipped_all">-</a> - - qh_checkflipped_all( facetlist ) - checks orientation of facets in list against interior point -*/ -void qh_checkflipped_all(facetT *facetlist) { - facetT *facet; - boolT waserror= False; - realT dist; - - if (facetlist == qh facet_list) - zzval_(Zflippedfacets)= 0; - FORALLfacet_(facetlist) { - if (facet->normal && !qh_checkflipped(facet, &dist, !qh_ALL)) { - qh_fprintf(qh ferr, 6136, "qhull precision error: facet f%d is flipped, distance= %6.12g\n", - facet->id, dist); - if (!qh FORCEoutput) { - qh_errprint("ERRONEOUS", facet, NULL, NULL, NULL); - waserror= True; - } - } - } - if (waserror) { - qh_fprintf(qh ferr, 8101, "\n\ -A flipped facet occurs when its distance to the interior point is\n\ -greater than %2.2g, the maximum roundoff error.\n", -qh DISTround); - qh_errexit(qh_ERRprec, NULL, NULL); - } -} /* checkflipped_all */ - -/*-<a href="qh-poly.htm#TOC" - >-------------------------------</a><a name="checkpolygon">-</a> - - qh_checkpolygon( facetlist ) - checks the correctness of the structure - - notes: - call with either qh.facet_list or qh.newfacet_list - checks num_facets and num_vertices if qh.facet_list - - design: - for each facet - checks facet and outside set - initializes vertexlist - for each facet - checks vertex set - if checking all facets(qh.facetlist) - check facet count - if qh.VERTEXneighbors - check vertex neighbors and count - check vertex count -*/ -void qh_checkpolygon(facetT *facetlist) { - facetT *facet; - vertexT *vertex, **vertexp, *vertexlist; - int numfacets= 0, numvertices= 0, numridges= 0; - int totvneighbors= 0, totvertices= 0; - boolT waserror= False, nextseen= False, visibleseen= False; - - trace1((qh ferr, 1027, "qh_checkpolygon: check all facets from f%d\n", facetlist->id)); - if (facetlist != qh facet_list || qh ONLYgood) - nextseen= True; - FORALLfacet_(facetlist) { - if (facet == qh visible_list) - visibleseen= True; - if (!facet->visible) { - if (!nextseen) { - if (facet == qh facet_next) - nextseen= True; - else if (qh_setsize(facet->outsideset)) { - if (!qh NARROWhull -#if !qh_COMPUTEfurthest - || facet->furthestdist >= qh MINoutside -#endif - ) { - qh_fprintf(qh ferr, 6137, "qhull internal error (qh_checkpolygon): f%d has outside points before qh facet_next\n", - facet->id); - qh_errexit(qh_ERRqhull, facet, NULL); - } - } - } - numfacets++; - qh_checkfacet(facet, False, &waserror); - } - } - if (qh visible_list && !visibleseen && facetlist == qh facet_list) { - qh_fprintf(qh ferr, 6138, "qhull internal error (qh_checkpolygon): visible list f%d no longer on facet list\n", qh visible_list->id); - qh_printlists(); - qh_errexit(qh_ERRqhull, qh visible_list, NULL); - } - if (facetlist == qh facet_list) - vertexlist= qh vertex_list; - else if (facetlist == qh newfacet_list) - vertexlist= qh newvertex_list; - else - vertexlist= NULL; - FORALLvertex_(vertexlist) { - vertex->seen= False; - vertex->visitid= 0; - } - FORALLfacet_(facetlist) { - if (facet->visible) - continue; - if (facet->simplicial) - numridges += qh hull_dim; - else - numridges += qh_setsize(facet->ridges); - FOREACHvertex_(facet->vertices) { - vertex->visitid++; - if (!vertex->seen) { - vertex->seen= True; - numvertices++; - if (qh_pointid(vertex->point) == -1) { - qh_fprintf(qh ferr, 6139, "qhull internal error (qh_checkpolygon): unknown point %p for vertex v%d first_point %p\n", - vertex->point, vertex->id, qh first_point); - waserror= True; - } - } - } - } - qh vertex_visit += (unsigned int)numfacets; - if (facetlist == qh facet_list) { - if (numfacets != qh num_facets - qh num_visible) { - qh_fprintf(qh ferr, 6140, "qhull internal error (qh_checkpolygon): actual number of facets is %d, cumulative facet count is %d - %d visible facets\n", - numfacets, qh num_facets, qh num_visible); - waserror= True; - } - qh vertex_visit++; - if (qh VERTEXneighbors) { - FORALLvertices { - qh_setcheck(vertex->neighbors, "neighbors for v", vertex->id); - if (vertex->deleted) - continue; - totvneighbors += qh_setsize(vertex->neighbors); - } - FORALLfacet_(facetlist) - totvertices += qh_setsize(facet->vertices); - if (totvneighbors != totvertices) { - qh_fprintf(qh ferr, 6141, "qhull internal error (qh_checkpolygon): vertex neighbors inconsistent. Totvneighbors %d, totvertices %d\n", - totvneighbors, totvertices); - waserror= True; - } - } - if (numvertices != qh num_vertices - qh_setsize(qh del_vertices)) { - qh_fprintf(qh ferr, 6142, "qhull internal error (qh_checkpolygon): actual number of vertices is %d, cumulative vertex count is %d\n", - numvertices, qh num_vertices - qh_setsize(qh del_vertices)); - waserror= True; - } - if (qh hull_dim == 2 && numvertices != numfacets) { - qh_fprintf(qh ferr, 6143, "qhull internal error (qh_checkpolygon): #vertices %d != #facets %d\n", - numvertices, numfacets); - waserror= True; - } - if (qh hull_dim == 3 && numvertices + numfacets - numridges/2 != 2) { - qh_fprintf(qh ferr, 7063, "qhull warning: #vertices %d + #facets %d - #edges %d != 2\n\ - A vertex appears twice in a edge list. May occur during merging.", - numvertices, numfacets, numridges/2); - /* occurs if lots of merging and a vertex ends up twice in an edge list. e.g., RBOX 1000 s W1e-13 t995849315 D2 | QHULL d Tc Tv */ - } - } - if (waserror) - qh_errexit(qh_ERRqhull, NULL, NULL); -} /* checkpolygon */ - - -/*-<a href="qh-poly.htm#TOC" - >-------------------------------</a><a name="checkvertex">-</a> - - qh_checkvertex( vertex ) - check vertex for consistency - checks vertex->neighbors - - notes: - neighbors checked efficiently in checkpolygon -*/ -void qh_checkvertex(vertexT *vertex) { - boolT waserror= False; - facetT *neighbor, **neighborp, *errfacet=NULL; - - if (qh_pointid(vertex->point) == -1) { - qh_fprintf(qh ferr, 6144, "qhull internal error (qh_checkvertex): unknown point id %p\n", vertex->point); - waserror= True; - } - if (vertex->id >= qh vertex_id) { - qh_fprintf(qh ferr, 6145, "qhull internal error (qh_checkvertex): unknown vertex id %d\n", vertex->id); - waserror= True; - } - if (!waserror && !vertex->deleted) { - if (qh_setsize(vertex->neighbors)) { - FOREACHneighbor_(vertex) { - if (!qh_setin(neighbor->vertices, vertex)) { - qh_fprintf(qh ferr, 6146, "qhull internal error (qh_checkvertex): neighbor f%d does not contain v%d\n", neighbor->id, vertex->id); - errfacet= neighbor; - waserror= True; - } - } - } - } - if (waserror) { - qh_errprint("ERRONEOUS", NULL, NULL, NULL, vertex); - qh_errexit(qh_ERRqhull, errfacet, NULL); - } -} /* checkvertex */ - -/*-<a href="qh-poly.htm#TOC" - >-------------------------------</a><a name="clearcenters">-</a> - - qh_clearcenters( type ) - clear old data from facet->center - - notes: - sets new centertype - nop if CENTERtype is the same -*/ -void qh_clearcenters(qh_CENTER type) { - facetT *facet; - - if (qh CENTERtype != type) { - FORALLfacets { - if (facet->tricoplanar && !facet->keepcentrum) - facet->center= NULL; - else if (qh CENTERtype == qh_ASvoronoi){ - if (facet->center) { - qh_memfree(facet->center, qh center_size); - facet->center= NULL; - } - }else /* qh CENTERtype == qh_AScentrum */ { - if (facet->center) { - qh_memfree(facet->center, qh normal_size); - facet->center= NULL; - } - } - } - qh CENTERtype= type; - } - trace2((qh ferr, 2043, "qh_clearcenters: switched to center type %d\n", type)); -} /* clearcenters */ - -/*-<a href="qh-poly.htm#TOC" - >-------------------------------</a><a name="createsimplex">-</a> - - qh_createsimplex( vertices ) - creates a simplex from a set of vertices - - returns: - initializes qh.facet_list to the simplex - initializes qh.newfacet_list, .facet_tail - initializes qh.vertex_list, .newvertex_list, .vertex_tail - - design: - initializes lists - for each vertex - create a new facet - for each new facet - create its neighbor set -*/ -void qh_createsimplex(setT *vertices) { - facetT *facet= NULL, *newfacet; - boolT toporient= True; - int vertex_i, vertex_n, nth; - setT *newfacets= qh_settemp(qh hull_dim+1); - vertexT *vertex; - - qh facet_list= qh newfacet_list= qh facet_tail= qh_newfacet(); - qh num_facets= qh num_vertices= qh num_visible= 0; - qh vertex_list= qh newvertex_list= qh vertex_tail= qh_newvertex(NULL); - FOREACHvertex_i_(vertices) { - newfacet= qh_newfacet(); - newfacet->vertices= qh_setnew_delnthsorted(vertices, vertex_n, - vertex_i, 0); - newfacet->toporient= (unsigned char)toporient; - qh_appendfacet(newfacet); - newfacet->newfacet= True; - qh_appendvertex(vertex); - qh_setappend(&newfacets, newfacet); - toporient ^= True; - } - FORALLnew_facets { - nth= 0; - FORALLfacet_(qh newfacet_list) { - if (facet != newfacet) - SETelem_(newfacet->neighbors, nth++)= facet; - } - qh_settruncate(newfacet->neighbors, qh hull_dim); - } - qh_settempfree(&newfacets); - trace1((qh ferr, 1028, "qh_createsimplex: created simplex\n")); -} /* createsimplex */ - -/*-<a href="qh-poly.htm#TOC" - >-------------------------------</a><a name="delridge">-</a> - - qh_delridge( ridge ) - deletes ridge from data structures it belongs to - frees up its memory - - notes: - in merge.c, caller sets vertex->delridge for each vertex - ridges also freed in qh_freeqhull -*/ -void qh_delridge(ridgeT *ridge) { - void **freelistp; /* used !qh_NOmem */ - - qh_setdel(ridge->top->ridges, ridge); - qh_setdel(ridge->bottom->ridges, ridge); - qh_setfree(&(ridge->vertices)); - qh_memfree_(ridge, (int)sizeof(ridgeT), freelistp); -} /* delridge */ - - -/*-<a href="qh-poly.htm#TOC" - >-------------------------------</a><a name="delvertex">-</a> - - qh_delvertex( vertex ) - deletes a vertex and frees its memory - - notes: - assumes vertex->adjacencies have been updated if needed - unlinks from vertex_list -*/ -void qh_delvertex(vertexT *vertex) { - - if (vertex == qh tracevertex) - qh tracevertex= NULL; - qh_removevertex(vertex); - qh_setfree(&vertex->neighbors); - qh_memfree(vertex, (int)sizeof(vertexT)); -} /* delvertex */ - - -/*-<a href="qh-poly.htm#TOC" - >-------------------------------</a><a name="facet3vertex">-</a> - - qh_facet3vertex( ) - return temporary set of 3-d vertices in qh_ORIENTclock order - - design: - if simplicial facet - build set from facet->vertices with facet->toporient - else - for each ridge in order - build set from ridge's vertices -*/ -setT *qh_facet3vertex(facetT *facet) { - ridgeT *ridge, *firstridge; - vertexT *vertex; - int cntvertices, cntprojected=0; - setT *vertices; - - cntvertices= qh_setsize(facet->vertices); - vertices= qh_settemp(cntvertices); - if (facet->simplicial) { - if (cntvertices != 3) { - qh_fprintf(qh ferr, 6147, "qhull internal error (qh_facet3vertex): only %d vertices for simplicial facet f%d\n", - cntvertices, facet->id); - qh_errexit(qh_ERRqhull, facet, NULL); - } - qh_setappend(&vertices, SETfirst_(facet->vertices)); - if (facet->toporient ^ qh_ORIENTclock) - qh_setappend(&vertices, SETsecond_(facet->vertices)); - else - qh_setaddnth(&vertices, 0, SETsecond_(facet->vertices)); - qh_setappend(&vertices, SETelem_(facet->vertices, 2)); - }else { - ridge= firstridge= SETfirstt_(facet->ridges, ridgeT); /* no infinite */ - while ((ridge= qh_nextridge3d(ridge, facet, &vertex))) { - qh_setappend(&vertices, vertex); - if (++cntprojected > cntvertices || ridge == firstridge) - break; - } - if (!ridge || cntprojected != cntvertices) { - qh_fprintf(qh ferr, 6148, "qhull internal error (qh_facet3vertex): ridges for facet %d don't match up. got at least %d\n", - facet->id, cntprojected); - qh_errexit(qh_ERRqhull, facet, ridge); - } - } - return vertices; -} /* facet3vertex */ - -/*-<a href="qh-poly.htm#TOC" - >-------------------------------</a><a name="findbestfacet">-</a> - - qh_findbestfacet( point, bestoutside, bestdist, isoutside ) - find facet that is furthest below a point - - for Delaunay triangulations, - Use qh_setdelaunay() to lift point to paraboloid and scale by 'Qbb' if needed - Do not use options 'Qbk', 'QBk', or 'QbB' since they scale the coordinates. - - returns: - if bestoutside is set (e.g., qh_ALL) - returns best facet that is not upperdelaunay - if Delaunay and inside, point is outside circumsphere of bestfacet - else - returns first facet below point - if point is inside, returns nearest, !upperdelaunay facet - distance to facet - isoutside set if outside of facet - - notes: - For tricoplanar facets, this finds one of the tricoplanar facets closest - to the point. For Delaunay triangulations, the point may be inside a - different tricoplanar facet. See <a href="../html/qh-code.htm#findfacet">locate a facet with qh_findbestfacet()</a> - - If inside, qh_findbestfacet performs an exhaustive search - this may be too conservative. Sometimes it is clearly required. - - qh_findbestfacet is not used by qhull. - uses qh.visit_id and qh.coplanarset - - see: - <a href="geom.c#findbest">qh_findbest</a> -*/ -facetT *qh_findbestfacet(pointT *point, boolT bestoutside, - realT *bestdist, boolT *isoutside) { - facetT *bestfacet= NULL; - int numpart, totpart= 0; - - bestfacet= qh_findbest(point, qh facet_list, - bestoutside, !qh_ISnewfacets, bestoutside /* qh_NOupper */, - bestdist, isoutside, &totpart); - if (*bestdist < -qh DISTround) { - bestfacet= qh_findfacet_all(point, bestdist, isoutside, &numpart); - totpart += numpart; - if ((isoutside && bestoutside) - || (!isoutside && bestfacet->upperdelaunay)) { - bestfacet= qh_findbest(point, bestfacet, - bestoutside, False, bestoutside, - bestdist, isoutside, &totpart); - totpart += numpart; - } - } - trace3((qh ferr, 3014, "qh_findbestfacet: f%d dist %2.2g isoutside %d totpart %d\n", - bestfacet->id, *bestdist, *isoutside, totpart)); - return bestfacet; -} /* findbestfacet */ - -/*-<a href="qh-poly.htm#TOC" - >-------------------------------</a><a name="findbestlower">-</a> - - qh_findbestlower( facet, point, bestdist, numpart ) - returns best non-upper, non-flipped neighbor of facet for point - if needed, searches vertex neighbors - - returns: - returns bestdist and updates numpart - - notes: - if Delaunay and inside, point is outside of circumsphere of bestfacet - called by qh_findbest() for points above an upperdelaunay facet - -*/ -facetT *qh_findbestlower(facetT *upperfacet, pointT *point, realT *bestdistp, int *numpart) { - facetT *neighbor, **neighborp, *bestfacet= NULL; - realT bestdist= -REALmax/2 /* avoid underflow */; - realT dist; - vertexT *vertex; - - zinc_(Zbestlower); - FOREACHneighbor_(upperfacet) { - if (neighbor->upperdelaunay || neighbor->flipped) - continue; - (*numpart)++; - qh_distplane(point, neighbor, &dist); - if (dist > bestdist) { - bestfacet= neighbor; - bestdist= dist; - } - } - if (!bestfacet) { - zinc_(Zbestlowerv); - /* rarely called, numpart does not count nearvertex computations */ - vertex= qh_nearvertex(upperfacet, point, &dist); - qh_vertexneighbors(); - FOREACHneighbor_(vertex) { - if (neighbor->upperdelaunay || neighbor->flipped) - continue; - (*numpart)++; - qh_distplane(point, neighbor, &dist); - if (dist > bestdist) { - bestfacet= neighbor; - bestdist= dist; - } - } - } - if (!bestfacet) { - qh_fprintf(qh ferr, 6228, "\n\ -Qhull internal error (qh_findbestlower): all neighbors of facet %d are flipped or upper Delaunay.\n\ -Please report this error to qhull_bug@qhull.org with the input and all of the output.\n", - upperfacet->id); - qh_errexit(qh_ERRqhull, upperfacet, NULL); - } - *bestdistp= bestdist; - trace3((qh ferr, 3015, "qh_findbestlower: f%d dist %2.2g for f%d p%d\n", - bestfacet->id, bestdist, upperfacet->id, qh_pointid(point))); - return bestfacet; -} /* findbestlower */ - -/*-<a href="qh-poly.htm#TOC" - >-------------------------------</a><a name="findfacet_all">-</a> - - qh_findfacet_all( point, bestdist, isoutside, numpart ) - exhaustive search for facet below a point - - for Delaunay triangulations, - Use qh_setdelaunay() to lift point to paraboloid and scale by 'Qbb' if needed - Do not use options 'Qbk', 'QBk', or 'QbB' since they scale the coordinates. - - returns: - returns first facet below point - if point is inside, - returns nearest facet - distance to facet - isoutside if point is outside of the hull - number of distance tests - - notes: - for library users, not used by Qhull -*/ -facetT *qh_findfacet_all(pointT *point, realT *bestdist, boolT *isoutside, - int *numpart) { - facetT *bestfacet= NULL, *facet; - realT dist; - int totpart= 0; - - *bestdist= -REALmax; - *isoutside= False; - FORALLfacets { - if (facet->flipped || !facet->normal) - continue; - totpart++; - qh_distplane(point, facet, &dist); - if (dist > *bestdist) { - *bestdist= dist; - bestfacet= facet; - if (dist > qh MINoutside) { - *isoutside= True; - break; - } - } - } - *numpart= totpart; - trace3((qh ferr, 3016, "qh_findfacet_all: f%d dist %2.2g isoutside %d totpart %d\n", - getid_(bestfacet), *bestdist, *isoutside, totpart)); - return bestfacet; -} /* findfacet_all */ - -/*-<a href="qh-poly.htm#TOC" - >-------------------------------</a><a name="findgood">-</a> - - qh_findgood( facetlist, goodhorizon ) - identify good facets for qh.PRINTgood - if qh.GOODvertex>0 - facet includes point as vertex - if !match, returns goodhorizon - inactive if qh.MERGING - if qh.GOODpoint - facet is visible or coplanar (>0) or not visible (<0) - if qh.GOODthreshold - facet->normal matches threshold - if !goodhorizon and !match, - selects facet with closest angle - sets GOODclosest - - returns: - number of new, good facets found - determines facet->good - may update qh.GOODclosest - - notes: - qh_findgood_all further reduces the good region - - design: - count good facets - mark good facets for qh.GOODpoint - mark good facets for qh.GOODthreshold - if necessary - update qh.GOODclosest -*/ -int qh_findgood(facetT *facetlist, int goodhorizon) { - facetT *facet, *bestfacet= NULL; - realT angle, bestangle= REALmax, dist; - int numgood=0; - - FORALLfacet_(facetlist) { - if (facet->good) - numgood++; - } - if (qh GOODvertex>0 && !qh MERGING) { - FORALLfacet_(facetlist) { - if (!qh_isvertex(qh GOODvertexp, facet->vertices)) { - facet->good= False; - numgood--; - } - } - } - if (qh GOODpoint && numgood) { - FORALLfacet_(facetlist) { - if (facet->good && facet->normal) { - zinc_(Zdistgood); - qh_distplane(qh GOODpointp, facet, &dist); - if ((qh GOODpoint > 0) ^ (dist > 0.0)) { - facet->good= False; - numgood--; - } - } - } - } - if (qh GOODthreshold && (numgood || goodhorizon || qh GOODclosest)) { - FORALLfacet_(facetlist) { - if (facet->good && facet->normal) { - if (!qh_inthresholds(facet->normal, &angle)) { - facet->good= False; - numgood--; - if (angle < bestangle) { - bestangle= angle; - bestfacet= facet; - } - } - } - } - if (!numgood && (!goodhorizon || qh GOODclosest)) { - if (qh GOODclosest) { - if (qh GOODclosest->visible) - qh GOODclosest= NULL; - else { - qh_inthresholds(qh GOODclosest->normal, &angle); - if (angle < bestangle) - bestfacet= qh GOODclosest; - } - } - if (bestfacet && bestfacet != qh GOODclosest) { - if (qh GOODclosest) - qh GOODclosest->good= False; - qh GOODclosest= bestfacet; - bestfacet->good= True; - numgood++; - trace2((qh ferr, 2044, "qh_findgood: f%d is closest(%2.2g) to thresholds\n", - bestfacet->id, bestangle)); - return numgood; - } - }else if (qh GOODclosest) { /* numgood > 0 */ - qh GOODclosest->good= False; - qh GOODclosest= NULL; - } - } - zadd_(Zgoodfacet, numgood); - trace2((qh ferr, 2045, "qh_findgood: found %d good facets with %d good horizon\n", - numgood, goodhorizon)); - if (!numgood && qh GOODvertex>0 && !qh MERGING) - return goodhorizon; - return numgood; -} /* findgood */ - -/*-<a href="qh-poly.htm#TOC" - >-------------------------------</a><a name="findgood_all">-</a> - - qh_findgood_all( facetlist ) - apply other constraints for good facets (used by qh.PRINTgood) - if qh.GOODvertex - facet includes (>0) or doesn't include (<0) point as vertex - if last good facet and ONLYgood, prints warning and continues - if qh.SPLITthresholds - facet->normal matches threshold, or if none, the closest one - calls qh_findgood - nop if good not used - - returns: - clears facet->good if not good - sets qh.num_good - - notes: - this is like qh_findgood but more restrictive - - design: - uses qh_findgood to mark good facets - marks facets for qh.GOODvertex - marks facets for qh.SPLITthreholds -*/ -void qh_findgood_all(facetT *facetlist) { - facetT *facet, *bestfacet=NULL; - realT angle, bestangle= REALmax; - int numgood=0, startgood; - - if (!qh GOODvertex && !qh GOODthreshold && !qh GOODpoint - && !qh SPLITthresholds) - return; - if (!qh ONLYgood) - qh_findgood(qh facet_list, 0); - FORALLfacet_(facetlist) { - if (facet->good) - numgood++; - } - if (qh GOODvertex <0 || (qh GOODvertex > 0 && qh MERGING)) { - FORALLfacet_(facetlist) { - if (facet->good && ((qh GOODvertex > 0) ^ !!qh_isvertex(qh GOODvertexp, facet->vertices))) { - if (!--numgood) { - if (qh ONLYgood) { - qh_fprintf(qh ferr, 7064, "qhull warning: good vertex p%d does not match last good facet f%d. Ignored.\n", - qh_pointid(qh GOODvertexp), facet->id); - return; - }else if (qh GOODvertex > 0) - qh_fprintf(qh ferr, 7065, "qhull warning: point p%d is not a vertex('QV%d').\n", - qh GOODvertex-1, qh GOODvertex-1); - else - qh_fprintf(qh ferr, 7066, "qhull warning: point p%d is a vertex for every facet('QV-%d').\n", - -qh GOODvertex - 1, -qh GOODvertex - 1); - } - facet->good= False; - } - } - } - startgood= numgood; - if (qh SPLITthresholds) { - FORALLfacet_(facetlist) { - if (facet->good) { - if (!qh_inthresholds(facet->normal, &angle)) { - facet->good= False; - numgood--; - if (angle < bestangle) { - bestangle= angle; - bestfacet= facet; - } - } - } - } - if (!numgood && bestfacet) { - bestfacet->good= True; - numgood++; - trace0((qh ferr, 23, "qh_findgood_all: f%d is closest(%2.2g) to thresholds\n", - bestfacet->id, bestangle)); - return; - } - } - qh num_good= numgood; - trace0((qh ferr, 24, "qh_findgood_all: %d good facets remain out of %d facets\n", - numgood, startgood)); -} /* findgood_all */ - -/*-<a href="qh-poly.htm#TOC" - >-------------------------------</a><a name="furthestnext">-</a> - - qh_furthestnext() - set qh.facet_next to facet with furthest of all furthest points - searches all facets on qh.facet_list - - notes: - this may help avoid precision problems -*/ -void qh_furthestnext(void /* qh facet_list */) { - facetT *facet, *bestfacet= NULL; - realT dist, bestdist= -REALmax; - - FORALLfacets { - if (facet->outsideset) { -#if qh_COMPUTEfurthest - pointT *furthest; - furthest= (pointT*)qh_setlast(facet->outsideset); - zinc_(Zcomputefurthest); - qh_distplane(furthest, facet, &dist); -#else - dist= facet->furthestdist; -#endif - if (dist > bestdist) { - bestfacet= facet; - bestdist= dist; - } - } - } - if (bestfacet) { - qh_removefacet(bestfacet); - qh_prependfacet(bestfacet, &qh facet_next); - trace1((qh ferr, 1029, "qh_furthestnext: made f%d next facet(dist %.2g)\n", - bestfacet->id, bestdist)); - } -} /* furthestnext */ - -/*-<a href="qh-poly.htm#TOC" - >-------------------------------</a><a name="furthestout">-</a> - - qh_furthestout( facet ) - make furthest outside point the last point of outsideset - - returns: - updates facet->outsideset - clears facet->notfurthest - sets facet->furthestdist - - design: - determine best point of outsideset - make it the last point of outsideset -*/ -void qh_furthestout(facetT *facet) { - pointT *point, **pointp, *bestpoint= NULL; - realT dist, bestdist= -REALmax; - - FOREACHpoint_(facet->outsideset) { - qh_distplane(point, facet, &dist); - zinc_(Zcomputefurthest); - if (dist > bestdist) { - bestpoint= point; - bestdist= dist; - } - } - if (bestpoint) { - qh_setdel(facet->outsideset, point); - qh_setappend(&facet->outsideset, point); -#if !qh_COMPUTEfurthest - facet->furthestdist= bestdist; -#endif - } - facet->notfurthest= False; - trace3((qh ferr, 3017, "qh_furthestout: p%d is furthest outside point of f%d\n", - qh_pointid(point), facet->id)); -} /* furthestout */ - - -/*-<a href="qh-qhull.htm#TOC" - >-------------------------------</a><a name="infiniteloop">-</a> - - qh_infiniteloop( facet ) - report infinite loop error due to facet -*/ -void qh_infiniteloop(facetT *facet) { - - qh_fprintf(qh ferr, 6149, "qhull internal error (qh_infiniteloop): potential infinite loop detected\n"); - qh_errexit(qh_ERRqhull, facet, NULL); -} /* qh_infiniteloop */ - -/*-<a href="qh-poly.htm#TOC" - >-------------------------------</a><a name="initbuild">-</a> - - qh_initbuild() - initialize hull and outside sets with point array - qh.FIRSTpoint/qh.NUMpoints is point array - if qh.GOODpoint - adds qh.GOODpoint to initial hull - - returns: - qh_facetlist with initial hull - points partioned into outside sets, coplanar sets, or inside - initializes qh.GOODpointp, qh.GOODvertexp, - - design: - initialize global variables used during qh_buildhull - determine precision constants and points with max/min coordinate values - if qh.SCALElast, scale last coordinate(for 'd') - build initial simplex - partition input points into facets of initial simplex - set up lists - if qh.ONLYgood - check consistency - add qh.GOODvertex if defined -*/ -void qh_initbuild( void) { - setT *maxpoints, *vertices; - facetT *facet; - int i, numpart; - realT dist; - boolT isoutside; - - qh furthest_id= -1; - qh lastreport= 0; - qh facet_id= qh vertex_id= qh ridge_id= 0; - qh visit_id= qh vertex_visit= 0; - qh maxoutdone= False; - - if (qh GOODpoint > 0) - qh GOODpointp= qh_point(qh GOODpoint-1); - else if (qh GOODpoint < 0) - qh GOODpointp= qh_point(-qh GOODpoint-1); - if (qh GOODvertex > 0) - qh GOODvertexp= qh_point(qh GOODvertex-1); - else if (qh GOODvertex < 0) - qh GOODvertexp= qh_point(-qh GOODvertex-1); - if ((qh GOODpoint - && (qh GOODpointp < qh first_point /* also catches !GOODpointp */ - || qh GOODpointp > qh_point(qh num_points-1))) - || (qh GOODvertex - && (qh GOODvertexp < qh first_point /* also catches !GOODvertexp */ - || qh GOODvertexp > qh_point(qh num_points-1)))) { - qh_fprintf(qh ferr, 6150, "qhull input error: either QGn or QVn point is > p%d\n", - qh num_points-1); - qh_errexit(qh_ERRinput, NULL, NULL); - } - maxpoints= qh_maxmin(qh first_point, qh num_points, qh hull_dim); - if (qh SCALElast) - qh_scalelast(qh first_point, qh num_points, qh hull_dim, - qh MINlastcoord, qh MAXlastcoord, qh MAXwidth); - qh_detroundoff(); - if (qh DELAUNAY && qh upper_threshold[qh hull_dim-1] > REALmax/2 - && qh lower_threshold[qh hull_dim-1] < -REALmax/2) { - for (i=qh_PRINTEND; i--; ) { - if (qh PRINTout[i] == qh_PRINTgeom && qh DROPdim < 0 - && !qh GOODthreshold && !qh SPLITthresholds) - break; /* in this case, don't set upper_threshold */ - } - if (i < 0) { - if (qh UPPERdelaunay) { /* matches qh.upperdelaunay in qh_setfacetplane */ - qh lower_threshold[qh hull_dim-1]= qh ANGLEround * qh_ZEROdelaunay; - qh GOODthreshold= True; - }else { - qh upper_threshold[qh hull_dim-1]= -qh ANGLEround * qh_ZEROdelaunay; - if (!qh GOODthreshold) - qh SPLITthresholds= True; /* build upper-convex hull even if Qg */ - /* qh_initqhull_globals errors if Qg without Pdk/etc. */ - } - } - } - vertices= qh_initialvertices(qh hull_dim, maxpoints, qh first_point, qh num_points); - qh_initialhull(vertices); /* initial qh facet_list */ - qh_partitionall(vertices, qh first_point, qh num_points); - if (qh PRINToptions1st || qh TRACElevel || qh IStracing) { - if (qh TRACElevel || qh IStracing) - qh_fprintf(qh ferr, 8103, "\nTrace level %d for %s | %s\n", - qh IStracing ? qh IStracing : qh TRACElevel, qh rbox_command, qh qhull_command); - qh_fprintf(qh ferr, 8104, "Options selected for Qhull %s:\n%s\n", qh_version, qh qhull_options); - } - qh_resetlists(False, qh_RESETvisible /*qh visible_list newvertex_list newfacet_list */); - qh facet_next= qh facet_list; - qh_furthestnext(/* qh facet_list */); - if (qh PREmerge) { - qh cos_max= qh premerge_cos; - qh centrum_radius= qh premerge_centrum; - } - if (qh ONLYgood) { - if (qh GOODvertex > 0 && qh MERGING) { - qh_fprintf(qh ferr, 6151, "qhull input error: 'Qg QVn' (only good vertex) does not work with merging.\nUse 'QJ' to joggle the input or 'Q0' to turn off merging.\n"); - qh_errexit(qh_ERRinput, NULL, NULL); - } - if (!(qh GOODthreshold || qh GOODpoint - || (!qh MERGEexact && !qh PREmerge && qh GOODvertexp))) { - qh_fprintf(qh ferr, 6152, "qhull input error: 'Qg' (ONLYgood) needs a good threshold('Pd0D0'), a\n\ -good point(QGn or QG-n), or a good vertex with 'QJ' or 'Q0' (QVn).\n"); - qh_errexit(qh_ERRinput, NULL, NULL); - } - if (qh GOODvertex > 0 && !qh MERGING /* matches qh_partitionall */ - && !qh_isvertex(qh GOODvertexp, vertices)) { - facet= qh_findbestnew(qh GOODvertexp, qh facet_list, - &dist, !qh_ALL, &isoutside, &numpart); - zadd_(Zdistgood, numpart); - if (!isoutside) { - qh_fprintf(qh ferr, 6153, "qhull input error: point for QV%d is inside initial simplex. It can not be made a vertex.\n", - qh_pointid(qh GOODvertexp)); - qh_errexit(qh_ERRinput, NULL, NULL); - } - if (!qh_addpoint(qh GOODvertexp, facet, False)) { - qh_settempfree(&vertices); - qh_settempfree(&maxpoints); - return; - } - } - qh_findgood(qh facet_list, 0); - } - qh_settempfree(&vertices); - qh_settempfree(&maxpoints); - trace1((qh ferr, 1030, "qh_initbuild: initial hull created and points partitioned\n")); -} /* initbuild */ - -/*-<a href="qh-poly.htm#TOC" - >-------------------------------</a><a name="initialhull">-</a> - - qh_initialhull( vertices ) - constructs the initial hull as a DIM3 simplex of vertices - - design: - creates a simplex (initializes lists) - determines orientation of simplex - sets hyperplanes for facets - doubles checks orientation (in case of axis-parallel facets with Gaussian elimination) - checks for flipped facets and qh.NARROWhull - checks the result -*/ -void qh_initialhull(setT *vertices) { - facetT *facet, *firstfacet, *neighbor, **neighborp; - realT dist, angle, minangle= REALmax; -#ifndef qh_NOtrace - int k; -#endif - - qh_createsimplex(vertices); /* qh facet_list */ - qh_resetlists(False, qh_RESETvisible); - qh facet_next= qh facet_list; /* advance facet when processed */ - qh interior_point= qh_getcenter(vertices); - firstfacet= qh facet_list; - qh_setfacetplane(firstfacet); - zinc_(Znumvisibility); /* needs to be in printsummary */ - qh_distplane(qh interior_point, firstfacet, &dist); - if (dist > 0) { - FORALLfacets - facet->toporient ^= (unsigned char)True; - } - FORALLfacets - qh_setfacetplane(facet); - FORALLfacets { - if (!qh_checkflipped(facet, NULL, qh_ALL)) {/* due to axis-parallel facet */ - trace1((qh ferr, 1031, "qh_initialhull: initial orientation incorrect. Correct all facets\n")); - facet->flipped= False; - FORALLfacets { - facet->toporient ^= (unsigned char)True; - qh_orientoutside(facet); - } - break; - } - } - FORALLfacets { - if (!qh_checkflipped(facet, NULL, !qh_ALL)) { /* can happen with 'R0.1' */ - if (qh DELAUNAY && ! qh ATinfinity) { - if (qh UPPERdelaunay) - qh_fprintf(qh ferr, 6240, "Qhull input error: Can not compute the upper Delaunay triangulation or upper Voronoi diagram of cocircular/cospherical points.\n"); - else - qh_fprintf(qh ferr, 6239, "Qhull input error: Use option 'Qz' for the Delaunay triangulation or Voronoi diagram of cocircular/cospherical points. Option 'Qz' adds a point \"at infinity\" (above the corresponding paraboloid).\n"); - qh_errexit(qh_ERRinput, NULL, NULL); - } - qh_precision("initial facet is coplanar with interior point"); - qh_fprintf(qh ferr, 6154, "qhull precision error: initial facet %d is coplanar with the interior point\n", - facet->id); - qh_errexit(qh_ERRsingular, facet, NULL); - } - FOREACHneighbor_(facet) { - angle= qh_getangle(facet->normal, neighbor->normal); - minimize_( minangle, angle); - } - } - if (minangle < qh_MAXnarrow && !qh NOnarrow) { - realT diff= 1.0 + minangle; - - qh NARROWhull= True; - qh_option("_narrow-hull", NULL, &diff); - if (minangle < qh_WARNnarrow && !qh RERUN && qh PRINTprecision) - qh_printhelp_narrowhull(qh ferr, minangle); - } - zzval_(Zprocessed)= qh hull_dim+1; - qh_checkpolygon(qh facet_list); - qh_checkconvex(qh facet_list, qh_DATAfault); -#ifndef qh_NOtrace - if (qh IStracing >= 1) { - qh_fprintf(qh ferr, 8105, "qh_initialhull: simplex constructed, interior point:"); - for (k=0; k < qh hull_dim; k++) - qh_fprintf(qh ferr, 8106, " %6.4g", qh interior_point[k]); - qh_fprintf(qh ferr, 8107, "\n"); - } -#endif -} /* initialhull */ - -/*-<a href="qh-poly.htm#TOC" - >-------------------------------</a><a name="initialvertices">-</a> - - qh_initialvertices( dim, maxpoints, points, numpoints ) - determines a non-singular set of initial vertices - maxpoints may include duplicate points - - returns: - temporary set of dim+1 vertices in descending order by vertex id - if qh.RANDOMoutside && !qh.ALLpoints - picks random points - if dim >= qh_INITIALmax, - uses min/max x and max points with non-zero determinants - - notes: - unless qh.ALLpoints, - uses maxpoints as long as determinate is non-zero -*/ -setT *qh_initialvertices(int dim, setT *maxpoints, pointT *points, int numpoints) { - pointT *point, **pointp; - setT *vertices, *simplex, *tested; - realT randr; - int idx, point_i, point_n, k; - boolT nearzero= False; - - vertices= qh_settemp(dim + 1); - simplex= qh_settemp(dim+1); - if (qh ALLpoints) - qh_maxsimplex(dim, NULL, points, numpoints, &simplex); - else if (qh RANDOMoutside) { - while (qh_setsize(simplex) != dim+1) { - randr= qh_RANDOMint; - randr= randr/(qh_RANDOMmax+1); - idx= (int)floor(qh num_points * randr); - while (qh_setin(simplex, qh_point(idx))) { - idx++; /* in case qh_RANDOMint always returns the same value */ - idx= idx < qh num_points ? idx : 0; - } - qh_setappend(&simplex, qh_point(idx)); - } - }else if (qh hull_dim >= qh_INITIALmax) { - tested= qh_settemp(dim+1); - qh_setappend(&simplex, SETfirst_(maxpoints)); /* max and min X coord */ - qh_setappend(&simplex, SETsecond_(maxpoints)); - qh_maxsimplex(fmin_(qh_INITIALsearch, dim), maxpoints, points, numpoints, &simplex); - k= qh_setsize(simplex); - FOREACHpoint_i_(maxpoints) { - if (point_i & 0x1) { /* first pick up max. coord. points */ - if (!qh_setin(simplex, point) && !qh_setin(tested, point)){ - qh_detsimplex(point, simplex, k, &nearzero); - if (nearzero) - qh_setappend(&tested, point); - else { - qh_setappend(&simplex, point); - if (++k == dim) /* use search for last point */ - break; - } - } - } - } - while (k != dim && (point= (pointT*)qh_setdellast(maxpoints))) { - if (!qh_setin(simplex, point) && !qh_setin(tested, point)){ - qh_detsimplex(point, simplex, k, &nearzero); - if (nearzero) - qh_setappend(&tested, point); - else { - qh_setappend(&simplex, point); - k++; - } - } - } - idx= 0; - while (k != dim && (point= qh_point(idx++))) { - if (!qh_setin(simplex, point) && !qh_setin(tested, point)){ - qh_detsimplex(point, simplex, k, &nearzero); - if (!nearzero){ - qh_setappend(&simplex, point); - k++; - } - } - } - qh_settempfree(&tested); - qh_maxsimplex(dim, maxpoints, points, numpoints, &simplex); - }else - qh_maxsimplex(dim, maxpoints, points, numpoints, &simplex); - FOREACHpoint_(simplex) - qh_setaddnth(&vertices, 0, qh_newvertex(point)); /* descending order */ - qh_settempfree(&simplex); - return vertices; -} /* initialvertices */ - - -/*-<a href="qh-poly.htm#TOC" - >-------------------------------</a><a name="isvertex">-</a> - - qh_isvertex( ) - returns vertex if point is in vertex set, else returns NULL - - notes: - for qh.GOODvertex -*/ -vertexT *qh_isvertex(pointT *point, setT *vertices) { - vertexT *vertex, **vertexp; - - FOREACHvertex_(vertices) { - if (vertex->point == point) - return vertex; - } - return NULL; -} /* isvertex */ - -/*-<a href="qh-poly.htm#TOC" - >-------------------------------</a><a name="makenewfacets">-</a> - - qh_makenewfacets( point ) - make new facets from point and qh.visible_list - - returns: - qh.newfacet_list= list of new facets with hyperplanes and ->newfacet - qh.newvertex_list= list of vertices in new facets with ->newlist set - - if (qh.ONLYgood) - newfacets reference horizon facets, but not vice versa - ridges reference non-simplicial horizon ridges, but not vice versa - does not change existing facets - else - sets qh.NEWfacets - new facets attached to horizon facets and ridges - for visible facets, - visible->r.replace is corresponding new facet - - see also: - qh_makenewplanes() -- make hyperplanes for facets - qh_attachnewfacets() -- attachnewfacets if not done here(qh ONLYgood) - qh_matchnewfacets() -- match up neighbors - qh_updatevertices() -- update vertex neighbors and delvertices - qh_deletevisible() -- delete visible facets - qh_checkpolygon() --check the result - qh_triangulate() -- triangulate a non-simplicial facet - - design: - for each visible facet - make new facets to its horizon facets - update its f.replace - clear its neighbor set -*/ -vertexT *qh_makenewfacets(pointT *point /*visible_list*/) { - facetT *visible, *newfacet= NULL, *newfacet2= NULL, *neighbor, **neighborp; - vertexT *apex; - int numnew=0; - - qh newfacet_list= qh facet_tail; - qh newvertex_list= qh vertex_tail; - apex= qh_newvertex(point); - qh_appendvertex(apex); - qh visit_id++; - if (!qh ONLYgood) - qh NEWfacets= True; - FORALLvisible_facets { - FOREACHneighbor_(visible) - neighbor->seen= False; - if (visible->ridges) { - visible->visitid= qh visit_id; - newfacet2= qh_makenew_nonsimplicial(visible, apex, &numnew); - } - if (visible->simplicial) - newfacet= qh_makenew_simplicial(visible, apex, &numnew); - if (!qh ONLYgood) { - if (newfacet2) /* newfacet is null if all ridges defined */ - newfacet= newfacet2; - if (newfacet) - visible->f.replace= newfacet; - else - zinc_(Zinsidevisible); - SETfirst_(visible->neighbors)= NULL; - } - } - trace1((qh ferr, 1032, "qh_makenewfacets: created %d new facets from point p%d to horizon\n", - numnew, qh_pointid(point))); - if (qh IStracing >= 4) - qh_printfacetlist(qh newfacet_list, NULL, qh_ALL); - return apex; -} /* makenewfacets */ - -/*-<a href="qh-poly.htm#TOC" - >-------------------------------</a><a name="matchduplicates">-</a> - - qh_matchduplicates( atfacet, atskip, hashsize, hashcount ) - match duplicate ridges in qh.hash_table for atfacet/atskip - duplicates marked with ->dupridge and qh_DUPLICATEridge - - returns: - picks match with worst merge (min distance apart) - updates hashcount - - see also: - qh_matchneighbor - - notes: - - design: - compute hash value for atfacet and atskip - repeat twice -- once to make best matches, once to match the rest - for each possible facet in qh.hash_table - if it is a matching facet and pass 2 - make match - unless tricoplanar, mark match for merging (qh_MERGEridge) - [e.g., tricoplanar RBOX s 1000 t993602376 | QHULL C-1e-3 d Qbb FA Qt] - if it is a matching facet and pass 1 - test if this is a better match - if pass 1, - make best match (it will not be merged) -*/ -#ifndef qh_NOmerge -void qh_matchduplicates(facetT *atfacet, int atskip, int hashsize, int *hashcount) { - boolT same, ismatch; - int hash, scan; - facetT *facet, *newfacet, *maxmatch= NULL, *maxmatch2= NULL, *nextfacet; - int skip, newskip, nextskip= 0, maxskip= 0, maxskip2= 0, makematch; - realT maxdist= -REALmax, mindist, dist2, low, high; - - hash= qh_gethash(hashsize, atfacet->vertices, qh hull_dim, 1, - SETelem_(atfacet->vertices, atskip)); - trace2((qh ferr, 2046, "qh_matchduplicates: find duplicate matches for f%d skip %d hash %d hashcount %d\n", - atfacet->id, atskip, hash, *hashcount)); - for (makematch= 0; makematch < 2; makematch++) { - qh visit_id++; - for (newfacet= atfacet, newskip= atskip; newfacet; newfacet= nextfacet, newskip= nextskip) { - zinc_(Zhashlookup); - nextfacet= NULL; - newfacet->visitid= qh visit_id; - for (scan= hash; (facet= SETelemt_(qh hash_table, scan, facetT)); - scan= (++scan >= hashsize ? 0 : scan)) { - if (!facet->dupridge || facet->visitid == qh visit_id) - continue; - zinc_(Zhashtests); - if (qh_matchvertices(1, newfacet->vertices, newskip, facet->vertices, &skip, &same)) { - ismatch= (same == (boolT)(newfacet->toporient ^ facet->toporient)); - if (SETelemt_(facet->neighbors, skip, facetT) != qh_DUPLICATEridge) { - if (!makematch) { - qh_fprintf(qh ferr, 6155, "qhull internal error (qh_matchduplicates): missing dupridge at f%d skip %d for new f%d skip %d hash %d\n", - facet->id, skip, newfacet->id, newskip, hash); - qh_errexit2 (qh_ERRqhull, facet, newfacet); - } - }else if (ismatch && makematch) { - if (SETelemt_(newfacet->neighbors, newskip, facetT) == qh_DUPLICATEridge) { - SETelem_(facet->neighbors, skip)= newfacet; - if (newfacet->tricoplanar) - SETelem_(newfacet->neighbors, newskip)= facet; - else - SETelem_(newfacet->neighbors, newskip)= qh_MERGEridge; - *hashcount -= 2; /* removed two unmatched facets */ - trace4((qh ferr, 4059, "qh_matchduplicates: duplicate f%d skip %d matched with new f%d skip %d merge\n", - facet->id, skip, newfacet->id, newskip)); - } - }else if (ismatch) { - mindist= qh_getdistance(facet, newfacet, &low, &high); - dist2= qh_getdistance(newfacet, facet, &low, &high); - minimize_(mindist, dist2); - if (mindist > maxdist) { - maxdist= mindist; - maxmatch= facet; - maxskip= skip; - maxmatch2= newfacet; - maxskip2= newskip; - } - trace3((qh ferr, 3018, "qh_matchduplicates: duplicate f%d skip %d new f%d skip %d at dist %2.2g, max is now f%d f%d\n", - facet->id, skip, newfacet->id, newskip, mindist, - maxmatch->id, maxmatch2->id)); - }else { /* !ismatch */ - nextfacet= facet; - nextskip= skip; - } - } - if (makematch && !facet - && SETelemt_(facet->neighbors, skip, facetT) == qh_DUPLICATEridge) { - qh_fprintf(qh ferr, 6156, "qhull internal error (qh_matchduplicates): no MERGEridge match for duplicate f%d skip %d at hash %d\n", - newfacet->id, newskip, hash); - qh_errexit(qh_ERRqhull, newfacet, NULL); - } - } - } /* end of for each new facet at hash */ - if (!makematch) { - if (!maxmatch) { - qh_fprintf(qh ferr, 6157, "qhull internal error (qh_matchduplicates): no maximum match at duplicate f%d skip %d at hash %d\n", - atfacet->id, atskip, hash); - qh_errexit(qh_ERRqhull, atfacet, NULL); - } - SETelem_(maxmatch->neighbors, maxskip)= maxmatch2; - SETelem_(maxmatch2->neighbors, maxskip2)= maxmatch; - *hashcount -= 2; /* removed two unmatched facets */ - zzinc_(Zmultiridge); - trace0((qh ferr, 25, "qh_matchduplicates: duplicate f%d skip %d matched with new f%d skip %d keep\n", - maxmatch->id, maxskip, maxmatch2->id, maxskip2)); - qh_precision("ridge with multiple neighbors"); - if (qh IStracing >= 4) - qh_errprint("DUPLICATED/MATCH", maxmatch, maxmatch2, NULL, NULL); - } - } -} /* matchduplicates */ - -/*-<a href="qh-poly.htm#TOC" - >-------------------------------</a><a name="nearcoplanar">-</a> - - qh_nearcoplanar() - for all facets, remove near-inside points from facet->coplanarset</li> - coplanar points defined by innerplane from qh_outerinner() - - returns: - if qh KEEPcoplanar && !qh KEEPinside - facet->coplanarset only contains coplanar points - if qh.JOGGLEmax - drops inner plane by another qh.JOGGLEmax diagonal since a - vertex could shift out while a coplanar point shifts in - - notes: - used for qh.PREmerge and qh.JOGGLEmax - must agree with computation of qh.NEARcoplanar in qh_detroundoff() - design: - if not keeping coplanar or inside points - free all coplanar sets - else if not keeping both coplanar and inside points - remove !coplanar or !inside points from coplanar sets -*/ -void qh_nearcoplanar(void /* qh.facet_list */) { - facetT *facet; - pointT *point, **pointp; - int numpart; - realT dist, innerplane; - - if (!qh KEEPcoplanar && !qh KEEPinside) { - FORALLfacets { - if (facet->coplanarset) - qh_setfree( &facet->coplanarset); - } - }else if (!qh KEEPcoplanar || !qh KEEPinside) { - qh_outerinner(NULL, NULL, &innerplane); - if (qh JOGGLEmax < REALmax/2) - innerplane -= qh JOGGLEmax * sqrt((realT)qh hull_dim); - numpart= 0; - FORALLfacets { - if (facet->coplanarset) { - FOREACHpoint_(facet->coplanarset) { - numpart++; - qh_distplane(point, facet, &dist); - if (dist < innerplane) { - if (!qh KEEPinside) - SETref_(point)= NULL; - }else if (!qh KEEPcoplanar) - SETref_(point)= NULL; - } - qh_setcompact(facet->coplanarset); - } - } - zzadd_(Zcheckpart, numpart); - } -} /* nearcoplanar */ - -/*-<a href="qh-poly.htm#TOC" - >-------------------------------</a><a name="nearvertex">-</a> - - qh_nearvertex( facet, point, bestdist ) - return nearest vertex in facet to point - - returns: - vertex and its distance - - notes: - if qh.DELAUNAY - distance is measured in the input set - searches neighboring tricoplanar facets (requires vertexneighbors) - Slow implementation. Recomputes vertex set for each point. - The vertex set could be stored in the qh.keepcentrum facet. -*/ -vertexT *qh_nearvertex(facetT *facet, pointT *point, realT *bestdistp) { - realT bestdist= REALmax, dist; - vertexT *bestvertex= NULL, *vertex, **vertexp, *apex; - coordT *center; - facetT *neighbor, **neighborp; - setT *vertices; - int dim= qh hull_dim; - - if (qh DELAUNAY) - dim--; - if (facet->tricoplanar) { - if (!qh VERTEXneighbors || !facet->center) { - qh_fprintf(qh ferr, 6158, "qhull internal error (qh_nearvertex): qh.VERTEXneighbors and facet->center required for tricoplanar facets\n"); - qh_errexit(qh_ERRqhull, facet, NULL); - } - vertices= qh_settemp(qh TEMPsize); - apex= SETfirstt_(facet->vertices, vertexT); - center= facet->center; - FOREACHneighbor_(apex) { - if (neighbor->center == center) { - FOREACHvertex_(neighbor->vertices) - qh_setappend(&vertices, vertex); - } - } - }else - vertices= facet->vertices; - FOREACHvertex_(vertices) { - dist= qh_pointdist(vertex->point, point, -dim); - if (dist < bestdist) { - bestdist= dist; - bestvertex= vertex; - } - } - if (facet->tricoplanar) - qh_settempfree(&vertices); - *bestdistp= sqrt(bestdist); - trace3((qh ferr, 3019, "qh_nearvertex: v%d dist %2.2g for f%d p%d\n", - bestvertex->id, *bestdistp, facet->id, qh_pointid(point))); - return bestvertex; -} /* nearvertex */ - -/*-<a href="qh-poly.htm#TOC" - >-------------------------------</a><a name="newhashtable">-</a> - - qh_newhashtable( newsize ) - returns size of qh.hash_table of at least newsize slots - - notes: - assumes qh.hash_table is NULL - qh_HASHfactor determines the number of extra slots - size is not divisible by 2, 3, or 5 -*/ -int qh_newhashtable(int newsize) { - int size; - - size= ((newsize+1)*qh_HASHfactor) | 0x1; /* odd number */ - while (True) { - if (newsize<0 || size<0) { - qh_fprintf(qhmem.ferr, 6236, "qhull error (qh_newhashtable): negative request (%d) or size (%d). Did int overflow due to high-D?\n", newsize, size); /* WARN64 */ - qh_errexit(qhmem_ERRmem, NULL, NULL); - } - if ((size%3) && (size%5)) - break; - size += 2; - /* loop terminates because there is an infinite number of primes */ - } - qh hash_table= qh_setnew(size); - qh_setzero(qh hash_table, 0, size); - return size; -} /* newhashtable */ - -/*-<a href="qh-poly.htm#TOC" - >-------------------------------</a><a name="newvertex">-</a> - - qh_newvertex( point ) - returns a new vertex for point -*/ -vertexT *qh_newvertex(pointT *point) { - vertexT *vertex; - - zinc_(Ztotvertices); - vertex= (vertexT *)qh_memalloc((int)sizeof(vertexT)); - memset((char *) vertex, (size_t)0, sizeof(vertexT)); - if (qh vertex_id == 0xFFFFFF) { - qh_fprintf(qh ferr, 6159, "qhull error: more than %d vertices. ID field overflows and two vertices\n\ -may have the same identifier. Vertices will not be sorted correctly.\n", 0xFFFFFF); - qh_errexit(qh_ERRqhull, NULL, NULL); - } - if (qh vertex_id == qh tracevertex_id) - qh tracevertex= vertex; - vertex->id= qh vertex_id++; - vertex->point= point; - vertex->dim= (unsigned char)(qh hull_dim <= MAX_vdim ? qh hull_dim : 0); - trace4((qh ferr, 4060, "qh_newvertex: vertex p%d(v%d) created\n", qh_pointid(vertex->point), - vertex->id)); - return(vertex); -} /* newvertex */ - -/*-<a href="qh-poly.htm#TOC" - >-------------------------------</a><a name="nextridge3d">-</a> - - qh_nextridge3d( atridge, facet, vertex ) - return next ridge and vertex for a 3d facet - returns NULL on error - [for QhullFacet::nextRidge3d] Does not call qh_errexit nor access qh_qh. - - notes: - in qh_ORIENTclock order - this is a O(n^2) implementation to trace all ridges - be sure to stop on any 2nd visit - same as QhullRidge::nextRidge3d - does not use qh_qh or qh_errexit [QhullFacet.cpp] - - design: - for each ridge - exit if it is the ridge after atridge -*/ -ridgeT *qh_nextridge3d(ridgeT *atridge, facetT *facet, vertexT **vertexp) { - vertexT *atvertex, *vertex, *othervertex; - ridgeT *ridge, **ridgep; - - if ((atridge->top == facet) ^ qh_ORIENTclock) - atvertex= SETsecondt_(atridge->vertices, vertexT); - else - atvertex= SETfirstt_(atridge->vertices, vertexT); - FOREACHridge_(facet->ridges) { - if (ridge == atridge) - continue; - if ((ridge->top == facet) ^ qh_ORIENTclock) { - othervertex= SETsecondt_(ridge->vertices, vertexT); - vertex= SETfirstt_(ridge->vertices, vertexT); - }else { - vertex= SETsecondt_(ridge->vertices, vertexT); - othervertex= SETfirstt_(ridge->vertices, vertexT); - } - if (vertex == atvertex) { - if (vertexp) - *vertexp= othervertex; - return ridge; - } - } - return NULL; -} /* nextridge3d */ -#else /* qh_NOmerge */ -void qh_matchduplicates(facetT *atfacet, int atskip, int hashsize, int *hashcount) { -} -ridgeT *qh_nextridge3d(ridgeT *atridge, facetT *facet, vertexT **vertexp) { - - return NULL; -} -#endif /* qh_NOmerge */ - -/*-<a href="qh-poly.htm#TOC" - >-------------------------------</a><a name="outcoplanar">-</a> - - qh_outcoplanar() - move points from all facets' outsidesets to their coplanarsets - - notes: - for post-processing under qh.NARROWhull - - design: - for each facet - for each outside point for facet - partition point into coplanar set -*/ -void qh_outcoplanar(void /* facet_list */) { - pointT *point, **pointp; - facetT *facet; - realT dist; - - trace1((qh ferr, 1033, "qh_outcoplanar: move outsideset to coplanarset for qh NARROWhull\n")); - FORALLfacets { - FOREACHpoint_(facet->outsideset) { - qh num_outside--; - if (qh KEEPcoplanar || qh KEEPnearinside) { - qh_distplane(point, facet, &dist); - zinc_(Zpartition); - qh_partitioncoplanar(point, facet, &dist); - } - } - qh_setfree(&facet->outsideset); - } -} /* outcoplanar */ - -/*-<a href="qh-poly.htm#TOC" - >-------------------------------</a><a name="point">-</a> - - qh_point( id ) - return point for a point id, or NULL if unknown - - alternative code: - return((pointT *)((unsigned long)qh.first_point - + (unsigned long)((id)*qh.normal_size))); -*/ -pointT *qh_point(int id) { - - if (id < 0) - return NULL; - if (id < qh num_points) - return qh first_point + id * qh hull_dim; - id -= qh num_points; - if (id < qh_setsize(qh other_points)) - return SETelemt_(qh other_points, id, pointT); - return NULL; -} /* point */ - -/*-<a href="qh-poly.htm#TOC" - >-------------------------------</a><a name="point_add">-</a> - - qh_point_add( set, point, elem ) - stores elem at set[point.id] - - returns: - access function for qh_pointfacet and qh_pointvertex - - notes: - checks point.id -*/ -void qh_point_add(setT *set, pointT *point, void *elem) { - int id, size; - - SETreturnsize_(set, size); - if ((id= qh_pointid(point)) < 0) - qh_fprintf(qh ferr, 7067, "qhull internal warning (point_add): unknown point %p id %d\n", - point, id); - else if (id >= size) { - qh_fprintf(qh ferr, 6160, "qhull internal errror(point_add): point p%d is out of bounds(%d)\n", - id, size); - qh_errexit(qh_ERRqhull, NULL, NULL); - }else - SETelem_(set, id)= elem; -} /* point_add */ - - -/*-<a href="qh-poly.htm#TOC" - >-------------------------------</a><a name="pointfacet">-</a> - - qh_pointfacet() - return temporary set of facet for each point - the set is indexed by point id - - notes: - vertices assigned to one of the facets - coplanarset assigned to the facet - outside set assigned to the facet - NULL if no facet for point (inside) - includes qh.GOODpointp - - access: - FOREACHfacet_i_(facets) { ... } - SETelem_(facets, i) - - design: - for each facet - add each vertex - add each coplanar point - add each outside point -*/ -setT *qh_pointfacet(void /*qh facet_list*/) { - int numpoints= qh num_points + qh_setsize(qh other_points); - setT *facets; - facetT *facet; - vertexT *vertex, **vertexp; - pointT *point, **pointp; - - facets= qh_settemp(numpoints); - qh_setzero(facets, 0, numpoints); - qh vertex_visit++; - FORALLfacets { - FOREACHvertex_(facet->vertices) { - if (vertex->visitid != qh vertex_visit) { - vertex->visitid= qh vertex_visit; - qh_point_add(facets, vertex->point, facet); - } - } - FOREACHpoint_(facet->coplanarset) - qh_point_add(facets, point, facet); - FOREACHpoint_(facet->outsideset) - qh_point_add(facets, point, facet); - } - return facets; -} /* pointfacet */ - -/*-<a href="qh-poly.htm#TOC" - >-------------------------------</a><a name="pointvertex">-</a> - - qh_pointvertex( ) - return temporary set of vertices indexed by point id - entry is NULL if no vertex for a point - this will include qh.GOODpointp - - access: - FOREACHvertex_i_(vertices) { ... } - SETelem_(vertices, i) -*/ -setT *qh_pointvertex(void /*qh facet_list*/) { - int numpoints= qh num_points + qh_setsize(qh other_points); - setT *vertices; - vertexT *vertex; - - vertices= qh_settemp(numpoints); - qh_setzero(vertices, 0, numpoints); - FORALLvertices - qh_point_add(vertices, vertex->point, vertex); - return vertices; -} /* pointvertex */ - - -/*-<a href="qh-poly.htm#TOC" - >-------------------------------</a><a name="prependfacet">-</a> - - qh_prependfacet( facet, facetlist ) - prepend facet to the start of a facetlist - - returns: - increments qh.numfacets - updates facetlist, qh.facet_list, facet_next - - notes: - be careful of prepending since it can lose a pointer. - e.g., can lose _next by deleting and then prepending before _next -*/ -void qh_prependfacet(facetT *facet, facetT **facetlist) { - facetT *prevfacet, *list; - - - trace4((qh ferr, 4061, "qh_prependfacet: prepend f%d before f%d\n", - facet->id, getid_(*facetlist))); - if (!*facetlist) - (*facetlist)= qh facet_tail; - list= *facetlist; - prevfacet= list->previous; - facet->previous= prevfacet; - if (prevfacet) - prevfacet->next= facet; - list->previous= facet; - facet->next= *facetlist; - if (qh facet_list == list) /* this may change *facetlist */ - qh facet_list= facet; - if (qh facet_next == list) - qh facet_next= facet; - *facetlist= facet; - qh num_facets++; -} /* prependfacet */ - - -/*-<a href="qh-poly.htm#TOC" - >-------------------------------</a><a name="printhashtable">-</a> - - qh_printhashtable( fp ) - print hash table to fp - - notes: - not in I/O to avoid bringing io.c in - - design: - for each hash entry - if defined - if unmatched or will merge (NULL, qh_MERGEridge, qh_DUPLICATEridge) - print entry and neighbors -*/ -void qh_printhashtable(FILE *fp) { - facetT *facet, *neighbor; - int id, facet_i, facet_n, neighbor_i= 0, neighbor_n= 0; - vertexT *vertex, **vertexp; - - FOREACHfacet_i_(qh hash_table) { - if (facet) { - FOREACHneighbor_i_(facet) { - if (!neighbor || neighbor == qh_MERGEridge || neighbor == qh_DUPLICATEridge) - break; - } - if (neighbor_i == neighbor_n) - continue; - qh_fprintf(fp, 9283, "hash %d f%d ", facet_i, facet->id); - FOREACHvertex_(facet->vertices) - qh_fprintf(fp, 9284, "v%d ", vertex->id); - qh_fprintf(fp, 9285, "\n neighbors:"); - FOREACHneighbor_i_(facet) { - if (neighbor == qh_MERGEridge) - id= -3; - else if (neighbor == qh_DUPLICATEridge) - id= -2; - else - id= getid_(neighbor); - qh_fprintf(fp, 9286, " %d", id); - } - qh_fprintf(fp, 9287, "\n"); - } - } -} /* printhashtable */ - - -/*-<a href="qh-poly.htm#TOC" - >-------------------------------</a><a name="printlists">-</a> - - qh_printlists( fp ) - print out facet and vertex list for debugging (without 'f/v' tags) -*/ -void qh_printlists(void) { - facetT *facet; - vertexT *vertex; - int count= 0; - - qh_fprintf(qh ferr, 8108, "qh_printlists: facets:"); - FORALLfacets { - if (++count % 100 == 0) - qh_fprintf(qh ferr, 8109, "\n "); - qh_fprintf(qh ferr, 8110, " %d", facet->id); - } - qh_fprintf(qh ferr, 8111, "\n new facets %d visible facets %d next facet for qh_addpoint %d\n vertices(new %d):", - getid_(qh newfacet_list), getid_(qh visible_list), getid_(qh facet_next), - getid_(qh newvertex_list)); - count = 0; - FORALLvertices { - if (++count % 100 == 0) - qh_fprintf(qh ferr, 8112, "\n "); - qh_fprintf(qh ferr, 8113, " %d", vertex->id); - } - qh_fprintf(qh ferr, 8114, "\n"); -} /* printlists */ - -/*-<a href="qh-poly.htm#TOC" - >-------------------------------</a><a name="resetlists">-</a> - - qh_resetlists( stats, qh_RESETvisible ) - reset newvertex_list, newfacet_list, visible_list - if stats, - maintains statistics - - returns: - visible_list is empty if qh_deletevisible was called -*/ -void qh_resetlists(boolT stats, boolT resetVisible /*qh newvertex_list newfacet_list visible_list*/) { - vertexT *vertex; - facetT *newfacet, *visible; - int totnew=0, totver=0; - - if (stats) { - FORALLvertex_(qh newvertex_list) - totver++; - FORALLnew_facets - totnew++; - zadd_(Zvisvertextot, totver); - zmax_(Zvisvertexmax, totver); - zadd_(Znewfacettot, totnew); - zmax_(Znewfacetmax, totnew); - } - FORALLvertex_(qh newvertex_list) - vertex->newlist= False; - qh newvertex_list= NULL; - FORALLnew_facets - newfacet->newfacet= False; - qh newfacet_list= NULL; - if (resetVisible) { - FORALLvisible_facets { - visible->f.replace= NULL; - visible->visible= False; - } - qh num_visible= 0; - } - qh visible_list= NULL; /* may still have visible facets via qh_triangulate */ - qh NEWfacets= False; -} /* resetlists */ - -/*-<a href="qh-poly.htm#TOC" - >-------------------------------</a><a name="setvoronoi_all">-</a> - - qh_setvoronoi_all() - compute Voronoi centers for all facets - includes upperDelaunay facets if qh.UPPERdelaunay ('Qu') - - returns: - facet->center is the Voronoi center - - notes: - this is unused/untested code - please email bradb@shore.net if this works ok for you - - use: - FORALLvertices {...} to locate the vertex for a point. - FOREACHneighbor_(vertex) {...} to visit the Voronoi centers for a Voronoi cell. -*/ -void qh_setvoronoi_all(void) { - facetT *facet; - - qh_clearcenters(qh_ASvoronoi); - qh_vertexneighbors(); - - FORALLfacets { - if (!facet->normal || !facet->upperdelaunay || qh UPPERdelaunay) { - if (!facet->center) - facet->center= qh_facetcenter(facet->vertices); - } - } -} /* setvoronoi_all */ - -#ifndef qh_NOmerge - -/*-<a href="qh-poly.htm#TOC" - >-------------------------------</a><a name="triangulate">-</a> - - qh_triangulate() - triangulate non-simplicial facets on qh.facet_list, - if qh VORONOI, sets Voronoi centers of non-simplicial facets - nop if hasTriangulation - - returns: - all facets simplicial - each tricoplanar facet has ->f.triowner == owner of ->center,normal,etc. - - notes: - call after qh_check_output since may switch to Voronoi centers - Output may overwrite ->f.triowner with ->f.area -*/ -void qh_triangulate(void /*qh facet_list*/) { - facetT *facet, *nextfacet, *owner; - int onlygood= qh ONLYgood; - facetT *neighbor, *visible= NULL, *facet1, *facet2, *new_facet_list= NULL; - facetT *orig_neighbor= NULL, *otherfacet; - vertexT *new_vertex_list= NULL; - mergeT *merge; - mergeType mergetype; - int neighbor_i, neighbor_n; - - if (qh hasTriangulation) - return; - trace1((qh ferr, 1034, "qh_triangulate: triangulate non-simplicial facets\n")); - if (qh hull_dim == 2) - return; - if (qh VORONOI) { /* otherwise lose Voronoi centers [could rebuild vertex set from tricoplanar] */ - qh_clearcenters(qh_ASvoronoi); - qh_vertexneighbors(); - } - qh ONLYgood= False; /* for makenew_nonsimplicial */ - qh visit_id++; - qh NEWfacets= True; - qh degen_mergeset= qh_settemp(qh TEMPsize); - qh newvertex_list= qh vertex_tail; - for (facet= qh facet_list; facet && facet->next; facet= nextfacet) { /* non-simplicial facets moved to end */ - nextfacet= facet->next; - if (facet->visible || facet->simplicial) - continue; - /* triangulate all non-simplicial facets, otherwise merging does not work, e.g., RBOX c P-0.1 P+0.1 P+0.1 D3 | QHULL d Qt Tv */ - if (!new_facet_list) - new_facet_list= facet; /* will be moved to end */ - qh_triangulate_facet(facet, &new_vertex_list); - } - trace2((qh ferr, 2047, "qh_triangulate: delete null facets from f%d -- apex same as second vertex\n", getid_(new_facet_list))); - for (facet= new_facet_list; facet && facet->next; facet= nextfacet) { /* null facets moved to end */ - nextfacet= facet->next; - if (facet->visible) - continue; - if (facet->ridges) { - if (qh_setsize(facet->ridges) > 0) { - qh_fprintf(qh ferr, 6161, "qhull error (qh_triangulate): ridges still defined for f%d\n", facet->id); - qh_errexit(qh_ERRqhull, facet, NULL); - } - qh_setfree(&facet->ridges); - } - if (SETfirst_(facet->vertices) == SETsecond_(facet->vertices)) { - zinc_(Ztrinull); - qh_triangulate_null(facet); - } - } - trace2((qh ferr, 2048, "qh_triangulate: delete %d or more mirror facets -- same vertices and neighbors\n", qh_setsize(qh degen_mergeset))); - qh visible_list= qh facet_tail; - while ((merge= (mergeT*)qh_setdellast(qh degen_mergeset))) { - facet1= merge->facet1; - facet2= merge->facet2; - mergetype= merge->type; - qh_memfree(merge, (int)sizeof(mergeT)); - if (mergetype == MRGmirror) { - zinc_(Ztrimirror); - qh_triangulate_mirror(facet1, facet2); - } - } - qh_settempfree(&qh degen_mergeset); - trace2((qh ferr, 2049, "qh_triangulate: update neighbor lists for vertices from v%d\n", getid_(new_vertex_list))); - qh newvertex_list= new_vertex_list; /* all vertices of new facets */ - qh visible_list= NULL; - qh_updatevertices(/*qh newvertex_list, empty newfacet_list and visible_list*/); - qh_resetlists(False, !qh_RESETvisible /*qh newvertex_list, empty newfacet_list and visible_list*/); - - trace2((qh ferr, 2050, "qh_triangulate: identify degenerate tricoplanar facets from f%d\n", getid_(new_facet_list))); - trace2((qh ferr, 2051, "qh_triangulate: and replace facet->f.triowner with tricoplanar facets that own center, normal, etc.\n")); - FORALLfacet_(new_facet_list) { - if (facet->tricoplanar && !facet->visible) { - FOREACHneighbor_i_(facet) { - if (neighbor_i == 0) { /* first iteration */ - if (neighbor->tricoplanar) - orig_neighbor= neighbor->f.triowner; - else - orig_neighbor= neighbor; - }else { - if (neighbor->tricoplanar) - otherfacet= neighbor->f.triowner; - else - otherfacet= neighbor; - if (orig_neighbor == otherfacet) { - zinc_(Ztridegen); - facet->degenerate= True; - break; - } - } - } - } - } - - trace2((qh ferr, 2052, "qh_triangulate: delete visible facets -- non-simplicial, null, and mirrored facets\n")); - owner= NULL; - visible= NULL; - for (facet= new_facet_list; facet && facet->next; facet= nextfacet) { /* may delete facet */ - nextfacet= facet->next; - if (facet->visible) { - if (facet->tricoplanar) { /* a null or mirrored facet */ - qh_delfacet(facet); - qh num_visible--; - }else { /* a non-simplicial facet followed by its tricoplanars */ - if (visible && !owner) { - /* RBOX 200 s D5 t1001471447 | QHULL Qt C-0.01 Qx Qc Tv Qt -- f4483 had 6 vertices/neighbors and 8 ridges */ - trace2((qh ferr, 2053, "qh_triangulate: all tricoplanar facets degenerate for non-simplicial facet f%d\n", - visible->id)); - qh_delfacet(visible); - qh num_visible--; - } - visible= facet; - owner= NULL; - } - }else if (facet->tricoplanar) { - if (facet->f.triowner != visible) { - qh_fprintf(qh ferr, 6162, "qhull error (qh_triangulate): tricoplanar facet f%d not owned by its visible, non-simplicial facet f%d\n", facet->id, getid_(visible)); - qh_errexit2 (qh_ERRqhull, facet, visible); - } - if (owner) - facet->f.triowner= owner; - else if (!facet->degenerate) { - owner= facet; - nextfacet= visible->next; /* rescan tricoplanar facets with owner */ - facet->keepcentrum= True; /* one facet owns ->normal, etc. */ - facet->coplanarset= visible->coplanarset; - facet->outsideset= visible->outsideset; - visible->coplanarset= NULL; - visible->outsideset= NULL; - if (!qh TRInormals) { /* center and normal copied to tricoplanar facets */ - visible->center= NULL; - visible->normal= NULL; - } - qh_delfacet(visible); - qh num_visible--; - } - } - } - if (visible && !owner) { - trace2((qh ferr, 2054, "qh_triangulate: all tricoplanar facets degenerate for last non-simplicial facet f%d\n", - visible->id)); - qh_delfacet(visible); - qh num_visible--; - } - qh NEWfacets= False; - qh ONLYgood= onlygood; /* restore value */ - if (qh CHECKfrequently) - qh_checkpolygon(qh facet_list); - qh hasTriangulation= True; -} /* triangulate */ - - -/*-<a href="qh-poly.htm#TOC" - >-------------------------------</a><a name="triangulate_facet">-</a> - - qh_triangulate_facet(facetA) - triangulate a non-simplicial facet - if qh.CENTERtype=qh_ASvoronoi, sets its Voronoi center - returns: - qh.newfacet_list == simplicial facets - facet->tricoplanar set and ->keepcentrum false - facet->degenerate set if duplicated apex - facet->f.trivisible set to facetA - facet->center copied from facetA (created if qh_ASvoronoi) - qh_eachvoronoi, qh_detvridge, qh_detvridge3 assume centers copied - facet->normal,offset,maxoutside copied from facetA - - notes: - qh_makenew_nonsimplicial uses neighbor->seen for the same - - see also: - qh_addpoint() -- add a point - qh_makenewfacets() -- construct a cone of facets for a new vertex - - design: - if qh_ASvoronoi, - compute Voronoi center (facet->center) - select first vertex (highest ID to preserve ID ordering of ->vertices) - triangulate from vertex to ridges - copy facet->center, normal, offset - update vertex neighbors -*/ -void qh_triangulate_facet(facetT *facetA, vertexT **first_vertex) { - facetT *newfacet; - facetT *neighbor, **neighborp; - vertexT *apex; - int numnew=0; - - trace3((qh ferr, 3020, "qh_triangulate_facet: triangulate facet f%d\n", facetA->id)); - - if (qh IStracing >= 4) - qh_printfacet(qh ferr, facetA); - FOREACHneighbor_(facetA) { - neighbor->seen= False; - neighbor->coplanar= False; - } - if (qh CENTERtype == qh_ASvoronoi && !facetA->center /* matches upperdelaunay in qh_setfacetplane() */ - && fabs_(facetA->normal[qh hull_dim -1]) >= qh ANGLEround * qh_ZEROdelaunay) { - facetA->center= qh_facetcenter(facetA->vertices); - } - qh_willdelete(facetA, NULL); - qh newfacet_list= qh facet_tail; - facetA->visitid= qh visit_id; - apex= SETfirstt_(facetA->vertices, vertexT); - qh_makenew_nonsimplicial(facetA, apex, &numnew); - SETfirst_(facetA->neighbors)= NULL; - FORALLnew_facets { - newfacet->tricoplanar= True; - newfacet->f.trivisible= facetA; - newfacet->degenerate= False; - newfacet->upperdelaunay= facetA->upperdelaunay; - newfacet->good= facetA->good; - if (qh TRInormals) { - newfacet->keepcentrum= True; - newfacet->normal= qh_copypoints(facetA->normal, 1, qh hull_dim); - if (qh CENTERtype == qh_AScentrum) - newfacet->center= qh_getcentrum(newfacet); - else - newfacet->center= qh_copypoints(facetA->center, 1, qh hull_dim); - }else { - newfacet->keepcentrum= False; - newfacet->normal= facetA->normal; - newfacet->center= facetA->center; - } - newfacet->offset= facetA->offset; -#if qh_MAXoutside - newfacet->maxoutside= facetA->maxoutside; -#endif - } - qh_matchnewfacets(/*qh newfacet_list*/); - zinc_(Ztricoplanar); - zadd_(Ztricoplanartot, numnew); - zmax_(Ztricoplanarmax, numnew); - qh visible_list= NULL; - if (!(*first_vertex)) - (*first_vertex)= qh newvertex_list; - qh newvertex_list= NULL; - qh_updatevertices(/*qh newfacet_list, empty visible_list and newvertex_list*/); - qh_resetlists(False, !qh_RESETvisible /*qh newfacet_list, empty visible_list and newvertex_list*/); -} /* triangulate_facet */ - -/*-<a href="qh-poly.htm#TOC" - >-------------------------------</a><a name="triangulate_link">-</a> - - qh_triangulate_link(oldfacetA, facetA, oldfacetB, facetB) - relink facetA to facetB via oldfacets - returns: - adds mirror facets to qh degen_mergeset (4-d and up only) - design: - if they are already neighbors, the opposing neighbors become MRGmirror facets -*/ -void qh_triangulate_link(facetT *oldfacetA, facetT *facetA, facetT *oldfacetB, facetT *facetB) { - int errmirror= False; - - trace3((qh ferr, 3021, "qh_triangulate_link: relink old facets f%d and f%d between neighbors f%d and f%d\n", - oldfacetA->id, oldfacetB->id, facetA->id, facetB->id)); - if (qh_setin(facetA->neighbors, facetB)) { - if (!qh_setin(facetB->neighbors, facetA)) - errmirror= True; - else - qh_appendmergeset(facetA, facetB, MRGmirror, NULL); - }else if (qh_setin(facetB->neighbors, facetA)) - errmirror= True; - if (errmirror) { - qh_fprintf(qh ferr, 6163, "qhull error (qh_triangulate_link): mirror facets f%d and f%d do not match for old facets f%d and f%d\n", - facetA->id, facetB->id, oldfacetA->id, oldfacetB->id); - qh_errexit2 (qh_ERRqhull, facetA, facetB); - } - qh_setreplace(facetB->neighbors, oldfacetB, facetA); - qh_setreplace(facetA->neighbors, oldfacetA, facetB); -} /* triangulate_link */ - -/*-<a href="qh-poly.htm#TOC" - >-------------------------------</a><a name="triangulate_mirror">-</a> - - qh_triangulate_mirror(facetA, facetB) - delete mirrored facets from qh_triangulate_null() and qh_triangulate_mirror - a mirrored facet shares the same vertices of a logical ridge - design: - since a null facet duplicates the first two vertices, the opposing neighbors absorb the null facet - if they are already neighbors, the opposing neighbors become MRGmirror facets -*/ -void qh_triangulate_mirror(facetT *facetA, facetT *facetB) { - facetT *neighbor, *neighborB; - int neighbor_i, neighbor_n; - - trace3((qh ferr, 3022, "qh_triangulate_mirror: delete mirrored facets f%d and f%d\n", - facetA->id, facetB->id)); - FOREACHneighbor_i_(facetA) { - neighborB= SETelemt_(facetB->neighbors, neighbor_i, facetT); - if (neighbor == neighborB) - continue; /* occurs twice */ - qh_triangulate_link(facetA, neighbor, facetB, neighborB); - } - qh_willdelete(facetA, NULL); - qh_willdelete(facetB, NULL); -} /* triangulate_mirror */ - -/*-<a href="qh-poly.htm#TOC" - >-------------------------------</a><a name="triangulate_null">-</a> - - qh_triangulate_null(facetA) - remove null facetA from qh_triangulate_facet() - a null facet has vertex #1 (apex) == vertex #2 - returns: - adds facetA to ->visible for deletion after qh_updatevertices - qh degen_mergeset contains mirror facets (4-d and up only) - design: - since a null facet duplicates the first two vertices, the opposing neighbors absorb the null facet - if they are already neighbors, the opposing neighbors become MRGmirror facets -*/ -void qh_triangulate_null(facetT *facetA) { - facetT *neighbor, *otherfacet; - - trace3((qh ferr, 3023, "qh_triangulate_null: delete null facet f%d\n", facetA->id)); - neighbor= SETfirstt_(facetA->neighbors, facetT); - otherfacet= SETsecondt_(facetA->neighbors, facetT); - qh_triangulate_link(facetA, neighbor, facetA, otherfacet); - qh_willdelete(facetA, NULL); -} /* triangulate_null */ - -#else /* qh_NOmerge */ -void qh_triangulate(void) { -} -#endif /* qh_NOmerge */ - - /*-<a href="qh-poly.htm#TOC" - >-------------------------------</a><a name="vertexintersect">-</a> - - qh_vertexintersect( vertexsetA, vertexsetB ) - intersects two vertex sets (inverse id ordered) - vertexsetA is a temporary set at the top of qhmem.tempstack - - returns: - replaces vertexsetA with the intersection - - notes: - could overwrite vertexsetA if currently too slow -*/ -void qh_vertexintersect(setT **vertexsetA,setT *vertexsetB) { - setT *intersection; - - intersection= qh_vertexintersect_new(*vertexsetA, vertexsetB); - qh_settempfree(vertexsetA); - *vertexsetA= intersection; - qh_settemppush(intersection); -} /* vertexintersect */ - -/*-<a href="qh-poly.htm#TOC" - >-------------------------------</a><a name="vertexintersect_new">-</a> - - qh_vertexintersect_new( ) - intersects two vertex sets (inverse id ordered) - - returns: - a new set -*/ -setT *qh_vertexintersect_new(setT *vertexsetA,setT *vertexsetB) { - setT *intersection= qh_setnew(qh hull_dim - 1); - vertexT **vertexA= SETaddr_(vertexsetA, vertexT); - vertexT **vertexB= SETaddr_(vertexsetB, vertexT); - - while (*vertexA && *vertexB) { - if (*vertexA == *vertexB) { - qh_setappend(&intersection, *vertexA); - vertexA++; vertexB++; - }else { - if ((*vertexA)->id > (*vertexB)->id) - vertexA++; - else - vertexB++; - } - } - return intersection; -} /* vertexintersect_new */ - -/*-<a href="qh-poly.htm#TOC" - >-------------------------------</a><a name="vertexneighbors">-</a> - - qh_vertexneighbors() - for each vertex in qh.facet_list, - determine its neighboring facets - - returns: - sets qh.VERTEXneighbors - nop if qh.VERTEXneighbors already set - qh_addpoint() will maintain them - - notes: - assumes all vertex->neighbors are NULL - - design: - for each facet - for each vertex - append facet to vertex->neighbors -*/ -void qh_vertexneighbors(void /*qh facet_list*/) { - facetT *facet; - vertexT *vertex, **vertexp; - - if (qh VERTEXneighbors) - return; - trace1((qh ferr, 1035, "qh_vertexneighbors: determing neighboring facets for each vertex\n")); - qh vertex_visit++; - FORALLfacets { - if (facet->visible) - continue; - FOREACHvertex_(facet->vertices) { - if (vertex->visitid != qh vertex_visit) { - vertex->visitid= qh vertex_visit; - vertex->neighbors= qh_setnew(qh hull_dim); - } - qh_setappend(&vertex->neighbors, facet); - } - } - qh VERTEXneighbors= True; -} /* vertexneighbors */ - -/*-<a href="qh-poly.htm#TOC" - >-------------------------------</a><a name="vertexsubset">-</a> - - qh_vertexsubset( vertexsetA, vertexsetB ) - returns True if vertexsetA is a subset of vertexsetB - assumes vertexsets are sorted - - note: - empty set is a subset of any other set -*/ -boolT qh_vertexsubset(setT *vertexsetA, setT *vertexsetB) { - vertexT **vertexA= (vertexT **) SETaddr_(vertexsetA, vertexT); - vertexT **vertexB= (vertexT **) SETaddr_(vertexsetB, vertexT); - - while (True) { - if (!*vertexA) - return True; - if (!*vertexB) - return False; - if ((*vertexA)->id > (*vertexB)->id) - return False; - if (*vertexA == *vertexB) - vertexA++; - vertexB++; - } - return False; /* avoid warnings */ -} /* vertexsubset */ diff --git a/PyMca/Object3D/Object3DQhull/src/qhull_a.h b/PyMca/Object3D/Object3DQhull/src/qhull_a.h deleted file mode 100644 index 27021b2..0000000 --- a/PyMca/Object3D/Object3DQhull/src/qhull_a.h +++ /dev/null @@ -1,151 +0,0 @@ -/*<html><pre> -<a href="qh-qhull.htm" - >-------------------------------</a><a name="TOP">-</a> - - qhull_a.h - all header files for compiling qhull - - see qh-qhull.htm - - see libqhull.h for user-level definitions - - see user.h for user-defineable constants - - defines internal functions for libqhull.c global.c - - Copyright (c) 1993-2012 The Geometry Center. - $Id: //main/2011/qhull/src/libqhull/qhull_a.h#3 $$Change: 1464 $ - $DateTime: 2012/01/25 22:58:41 $$Author: bbarber $ - - Notes: grep for ((" and (" to catch fprintf("lkasdjf"); - full parens around (x?y:z) - use '#include qhull/qhull_a.h' to avoid name clashes -*/ - -#ifndef qhDEFqhulla -#define qhDEFqhulla 1 - -#include "libqhull.h" /* Defines data types */ - -#include "stat.h" -#include "random.h" -#include "mem.h" -#include "qset.h" -#include "geom.h" -#include "merge.h" -#include "poly.h" -#include "io.h" - -#include <setjmp.h> -#include <string.h> -#include <math.h> -#include <float.h> /* some compilers will not need float.h */ -#include <limits.h> -#include <time.h> -#include <ctype.h> -#include <stdio.h> -#include <stdlib.h> -/*** uncomment here and qset.c - if string.h does not define memcpy() -#include <memory.h> -*/ - -#if qh_CLOCKtype == 2 /* defined in user.h from libqhull.h */ -#include <sys/types.h> -#include <sys/times.h> -#include <unistd.h> -#endif - -#ifdef _MSC_VER /* Microsoft Visual C++ -- warning level 4 */ -#pragma warning( disable : 4100) /* unreferenced formal parameter */ -#pragma warning( disable : 4127) /* conditional expression is constant */ -#pragma warning( disable : 4706) /* assignment within conditional function */ -#pragma warning( disable : 4996) /* function was declared deprecated(strcpy, localtime, etc.) */ -#endif - -/* ======= -macros- =========== */ - -/*-<a href="qh-qhull.htm#TOC" - >--------------------------------</a><a name="traceN">-</a> - - traceN((qh ferr, 0Nnnn, "format\n", vars)); - calls qh_fprintf if qh.IStracing >= N - - Add debugging traps to the end of qh_fprintf - - notes: - removing tracing reduces code size but doesn't change execution speed -*/ -#ifndef qh_NOtrace -#define trace0(args) {if (qh IStracing) qh_fprintf args;} -#define trace1(args) {if (qh IStracing >= 1) qh_fprintf args;} -#define trace2(args) {if (qh IStracing >= 2) qh_fprintf args;} -#define trace3(args) {if (qh IStracing >= 3) qh_fprintf args;} -#define trace4(args) {if (qh IStracing >= 4) qh_fprintf args;} -#define trace5(args) {if (qh IStracing >= 5) qh_fprintf args;} -#else /* qh_NOtrace */ -#define trace0(args) {} -#define trace1(args) {} -#define trace2(args) {} -#define trace3(args) {} -#define trace4(args) {} -#define trace5(args) {} -#endif /* qh_NOtrace */ - -/*-<a href="qh-qhull.htm#TOC" - >--------------------------------</a><a name="QHULL_UNUSED">-</a> - -*/ - -/* See Qt's qglobal.h */ -#if !defined(SAG_COM) && (defined(WIN64) || defined(_WIN64) || defined(__WIN64__) || defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__)) -# define QHULL_OS_WIN -#elif defined(__MWERKS__) && defined(__INTEL__) -# define QHULL_OS_WIN -#endif -#if defined(__INTEL_COMPILER) && !defined(QHULL_OS_WIN) -template <typename T> -inline void qhullUnused(T &x) { (void)x; } -# define QHULL_UNUSED(x) qhullUnused(x); -#else -# define QHULL_UNUSED(x) (void)x; -#endif - -/***** -libqhull.c prototypes (alphabetical after qhull) ********************/ - -void qh_qhull(void); -boolT qh_addpoint(pointT *furthest, facetT *facet, boolT checkdist); -void qh_buildhull(void); -void qh_buildtracing(pointT *furthest, facetT *facet); -void qh_build_withrestart(void); -void qh_errexit2(int exitcode, facetT *facet, facetT *otherfacet); -void qh_findhorizon(pointT *point, facetT *facet, int *goodvisible,int *goodhorizon); -pointT *qh_nextfurthest(facetT **visible); -void qh_partitionall(setT *vertices, pointT *points,int npoints); -void qh_partitioncoplanar(pointT *point, facetT *facet, realT *dist); -void qh_partitionpoint(pointT *point, facetT *facet); -void qh_partitionvisible(boolT allpoints, int *numpoints); -void qh_precision(const char *reason); -void qh_printsummary(FILE *fp); - -/***** -global.c internal prototypes (alphabetical) ***********************/ - -void qh_appendprint(qh_PRINT format); -void qh_freebuild(boolT allmem); -void qh_freebuffers(void); -void qh_initbuffers(coordT *points, int numpoints, int dim, boolT ismalloc); - -/***** -stat.c internal prototypes (alphabetical) ***********************/ - -void qh_allstatA(void); -void qh_allstatB(void); -void qh_allstatC(void); -void qh_allstatD(void); -void qh_allstatE(void); -void qh_allstatE2 (void); -void qh_allstatF(void); -void qh_allstatG(void); -void qh_allstatH(void); -void qh_freebuffers(void); -void qh_initbuffers(coordT *points, int numpoints, int dim, boolT ismalloc); - -#endif /* qhDEFqhulla */ diff --git a/PyMca/Object3D/Object3DQhull/src/qset.c b/PyMca/Object3D/Object3DQhull/src/qset.c deleted file mode 100644 index 8da46fb..0000000 --- a/PyMca/Object3D/Object3DQhull/src/qset.c +++ /dev/null @@ -1,1339 +0,0 @@ -/*<html><pre> -<a href="qh-set.htm" - >-------------------------------</a><a name="TOP">-</a> - - qset.c - implements set manipulations needed for quickhull - - see qh-set.htm and qset.h - - Be careful of strict aliasing (two pointers of different types - that reference the same location). The last slot of a set is - either the actual size of the set plus 1, or the NULL terminator - of the set (i.e., setelemT). - - Copyright (c) 1993-2012 The Geometry Center. - $Id: //main/2011/qhull/src/libqhull/qset.c#6 $$Change: 1475 $ - $DateTime: 2012/01/27 22:32:16 $$Author: bbarber $ -*/ - -#include "qset.h" -#include "mem.h" -#include <stdio.h> -#include <string.h> -/*** uncomment here and qhull_a.h - if string.h does not define memcpy() -#include <memory.h> -*/ - -#ifndef qhDEFlibqhull -typedef struct ridgeT ridgeT; -typedef struct facetT facetT; -void qh_errexit(int exitcode, facetT *, ridgeT *); -void qh_fprintf(FILE *fp, int msgcode, const char *fmt, ... ); -# ifdef _MSC_VER /* Microsoft Visual C++ -- warning level 4 */ -# pragma warning( disable : 4127) /* conditional expression is constant */ -# pragma warning( disable : 4706) /* assignment within conditional function */ -# endif -#endif - -/*=============== internal macros ===========================*/ - -/*============ functions in alphabetical order ===================*/ - -/*-<a href="qh-set.htm#TOC" - >--------------------------------<a name="setaddnth">-</a> - - qh_setaddnth( setp, nth, newelem) - adds newelem as n'th element of sorted or unsorted *setp - - notes: - *setp and newelem must be defined - *setp may be a temp set - nth=0 is first element - errors if nth is out of bounds - - design: - expand *setp if empty or full - move tail of *setp up one - insert newelem -*/ -void qh_setaddnth(setT **setp, int nth, void *newelem) { - int oldsize, i; - setelemT *sizep; /* avoid strict aliasing */ - setelemT *oldp, *newp; - - if (!*setp || (sizep= SETsizeaddr_(*setp))->i==0) { - qh_setlarger(setp); - sizep= SETsizeaddr_(*setp); - } - oldsize= sizep->i - 1; - if (nth < 0 || nth > oldsize) { - qh_fprintf(qhmem.ferr, 6171, "qhull internal error (qh_setaddnth): nth %d is out-of-bounds for set:\n", nth); - qh_setprint(qhmem.ferr, "", *setp); - qh_errexit(qhmem_ERRqhull, NULL, NULL); - } - sizep->i++; - oldp= (setelemT *)SETelemaddr_(*setp, oldsize, void); /* NULL */ - newp= oldp+1; - for (i=oldsize-nth+1; i--; ) /* move at least NULL */ - (newp--)->p= (oldp--)->p; /* may overwrite *sizep */ - newp->p= newelem; -} /* setaddnth */ - - -/*-<a href="qh-set.htm#TOC" - >--------------------------------<a name="setaddsorted">-</a> - - setaddsorted( setp, newelem ) - adds an newelem into sorted *setp - - notes: - *setp and newelem must be defined - *setp may be a temp set - nop if newelem already in set - - design: - find newelem's position in *setp - insert newelem -*/ -void qh_setaddsorted(setT **setp, void *newelem) { - int newindex=0; - void *elem, **elemp; - - FOREACHelem_(*setp) { /* could use binary search instead */ - if (elem < newelem) - newindex++; - else if (elem == newelem) - return; - else - break; - } - qh_setaddnth(setp, newindex, newelem); -} /* setaddsorted */ - - -/*-<a href="qh-set.htm#TOC" - >-------------------------------<a name="setappend">-</a> - - qh_setappend( setp, newelem) - append newelem to *setp - - notes: - *setp may be a temp set - *setp and newelem may be NULL - - design: - expand *setp if empty or full - append newelem to *setp - -*/ -void qh_setappend(setT **setp, void *newelem) { - setelemT *sizep; /* Avoid strict aliasing. Writing to *endp may overwrite *sizep */ - setelemT *endp; - int count; - - if (!newelem) - return; - if (!*setp || (sizep= SETsizeaddr_(*setp))->i==0) { - qh_setlarger(setp); - sizep= SETsizeaddr_(*setp); - } - count= (sizep->i)++ - 1; - endp= (setelemT *)SETelemaddr_(*setp, count, void); - (endp++)->p= newelem; - endp->p= NULL; -} /* setappend */ - -/*-<a href="qh-set.htm#TOC" - >-------------------------------<a name="setappend_set">-</a> - - qh_setappend_set( setp, setA) - appends setA to *setp - - notes: - *setp can not be a temp set - *setp and setA may be NULL - - design: - setup for copy - expand *setp if it is too small - append all elements of setA to *setp -*/ -void qh_setappend_set(setT **setp, setT *setA) { - int sizeA, size; - setT *oldset; - setelemT *sizep; - - if (!setA) - return; - SETreturnsize_(setA, sizeA); - if (!*setp) - *setp= qh_setnew(sizeA); - sizep= SETsizeaddr_(*setp); - if (!(size= sizep->i)) - size= (*setp)->maxsize; - else - size--; - if (size + sizeA > (*setp)->maxsize) { - oldset= *setp; - *setp= qh_setcopy(oldset, sizeA); - qh_setfree(&oldset); - sizep= SETsizeaddr_(*setp); - } - if (sizeA > 0) { - sizep->i= size+sizeA+1; /* memcpy may overwrite */ - memcpy((char *)&((*setp)->e[size].p), (char *)&(setA->e[0].p), (size_t)(sizeA+1) * SETelemsize); - } -} /* setappend_set */ - - -/*-<a href="qh-set.htm#TOC" - >-------------------------------<a name="setappend2ndlast">-</a> - - qh_setappend2ndlast( setp, newelem ) - makes newelem the next to the last element in *setp - - notes: - *setp must have at least one element - newelem must be defined - *setp may be a temp set - - design: - expand *setp if empty or full - move last element of *setp up one - insert newelem -*/ -void qh_setappend2ndlast(setT **setp, void *newelem) { - setelemT *sizep; /* Avoid strict aliasing. Writing to *endp may overwrite *sizep */ - setelemT *endp, *lastp; - int count; - - if (!*setp || (sizep= SETsizeaddr_(*setp))->i==0) { - qh_setlarger(setp); - sizep= SETsizeaddr_(*setp); - } - count= (sizep->i)++ - 1; - endp= (setelemT *)SETelemaddr_(*setp, count, void); /* NULL */ - lastp= endp-1; - *(endp++)= *lastp; - endp->p= NULL; /* may overwrite *sizep */ - lastp->p= newelem; -} /* setappend2ndlast */ - -/*-<a href="qh-set.htm#TOC" - >-------------------------------<a name="setcheck">-</a> - - qh_setcheck( set, typename, id ) - check set for validity - report errors with typename and id - - design: - checks that maxsize, actual size, and NULL terminator agree -*/ -void qh_setcheck(setT *set, const char *tname, unsigned id) { - int maxsize, size; - int waserr= 0; - - if (!set) - return; - SETreturnsize_(set, size); - maxsize= set->maxsize; - if (size > maxsize || !maxsize) { - qh_fprintf(qhmem.ferr, 6172, "qhull internal error (qh_setcheck): actual size %d of %s%d is greater than max size %d\n", - size, tname, id, maxsize); - waserr= 1; - }else if (set->e[size].p) { - qh_fprintf(qhmem.ferr, 6173, "qhull internal error (qh_setcheck): %s%d(size %d max %d) is not null terminated.\n", - tname, id, size-1, maxsize); - waserr= 1; - } - if (waserr) { - qh_setprint(qhmem.ferr, "ERRONEOUS", set); - qh_errexit(qhmem_ERRqhull, NULL, NULL); - } -} /* setcheck */ - - -/*-<a href="qh-set.htm#TOC" - >-------------------------------<a name="setcompact">-</a> - - qh_setcompact( set ) - remove internal NULLs from an unsorted set - - returns: - updated set - - notes: - set may be NULL - it would be faster to swap tail of set into holes, like qh_setdel - - design: - setup pointers into set - skip NULLs while copying elements to start of set - update the actual size -*/ -void qh_setcompact(setT *set) { - int size; - void **destp, **elemp, **endp, **firstp; - - if (!set) - return; - SETreturnsize_(set, size); - destp= elemp= firstp= SETaddr_(set, void); - endp= destp + size; - while (1) { - if (!(*destp++ = *elemp++)) { - destp--; - if (elemp > endp) - break; - } - } - qh_settruncate(set, (int)(destp-firstp)); /* WARN64 */ -} /* setcompact */ - - -/*-<a href="qh-set.htm#TOC" - >-------------------------------<a name="setcopy">-</a> - - qh_setcopy( set, extra ) - make a copy of a sorted or unsorted set with extra slots - - returns: - new set - - design: - create a newset with extra slots - copy the elements to the newset - -*/ -setT *qh_setcopy(setT *set, int extra) { - setT *newset; - int size; - - if (extra < 0) - extra= 0; - SETreturnsize_(set, size); - newset= qh_setnew(size+extra); - SETsizeaddr_(newset)->i= size+1; /* memcpy may overwrite */ - memcpy((char *)&(newset->e[0].p), (char *)&(set->e[0].p), (size_t)(size+1) * SETelemsize); - return(newset); -} /* setcopy */ - - -/*-<a href="qh-set.htm#TOC" - >-------------------------------<a name="setdel">-</a> - - qh_setdel( set, oldelem ) - delete oldelem from an unsorted set - - returns: - returns oldelem if found - returns NULL otherwise - - notes: - set may be NULL - oldelem must not be NULL; - only deletes one copy of oldelem in set - - design: - locate oldelem - update actual size if it was full - move the last element to the oldelem's location -*/ -void *qh_setdel(setT *set, void *oldelem) { - setelemT *sizep; - setelemT *elemp; - setelemT *lastp; - - if (!set) - return NULL; - elemp= (setelemT *)SETaddr_(set, void); - while (elemp->p != oldelem && elemp->p) - elemp++; - if (elemp->p) { - sizep= SETsizeaddr_(set); - if (!(sizep->i)--) /* if was a full set */ - sizep->i= set->maxsize; /* *sizep= (maxsize-1)+ 1 */ - lastp= (setelemT *)SETelemaddr_(set, sizep->i-1, void); - elemp->p= lastp->p; /* may overwrite itself */ - lastp->p= NULL; - return oldelem; - } - return NULL; -} /* setdel */ - - -/*-<a href="qh-set.htm#TOC" - >-------------------------------<a name="setdellast">-</a> - - qh_setdellast( set) - return last element of set or NULL - - notes: - deletes element from set - set may be NULL - - design: - return NULL if empty - if full set - delete last element and set actual size - else - delete last element and update actual size -*/ -void *qh_setdellast(setT *set) { - int setsize; /* actually, actual_size + 1 */ - int maxsize; - setelemT *sizep; - void *returnvalue; - - if (!set || !(set->e[0].p)) - return NULL; - sizep= SETsizeaddr_(set); - if ((setsize= sizep->i)) { - returnvalue= set->e[setsize - 2].p; - set->e[setsize - 2].p= NULL; - sizep->i--; - }else { - maxsize= set->maxsize; - returnvalue= set->e[maxsize - 1].p; - set->e[maxsize - 1].p= NULL; - sizep->i= maxsize; - } - return returnvalue; -} /* setdellast */ - - -/*-<a href="qh-set.htm#TOC" - >-------------------------------<a name="setdelnth">-</a> - - qh_setdelnth( set, nth ) - deletes nth element from unsorted set - 0 is first element - - returns: - returns the element (needs type conversion) - - notes: - errors if nth invalid - - design: - setup points and check nth - delete nth element and overwrite with last element -*/ -void *qh_setdelnth(setT *set, int nth) { - void *elem; - setelemT *sizep; - setelemT *elemp, *lastp; - - elemp= (setelemT *)SETelemaddr_(set, nth, void); - sizep= SETsizeaddr_(set); - if ((sizep->i--)==0) /* if was a full set */ - sizep->i= set->maxsize; /* *sizep= (maxsize-1)+ 1 */ - if (nth < 0 || nth >= sizep->i) { - qh_fprintf(qhmem.ferr, 6174, "qhull internal error (qh_setdelnth): nth %d is out-of-bounds for set:\n", nth); - qh_setprint(qhmem.ferr, "", set); - qh_errexit(qhmem_ERRqhull, NULL, NULL); - } - lastp= (setelemT *)SETelemaddr_(set, sizep->i-1, void); - elem= elemp->p; - elemp->p= lastp->p; /* may overwrite itself */ - lastp->p= NULL; - return elem; -} /* setdelnth */ - -/*-<a href="qh-set.htm#TOC" - >-------------------------------<a name="setdelnthsorted">-</a> - - qh_setdelnthsorted( set, nth ) - deletes nth element from sorted set - - returns: - returns the element (use type conversion) - - notes: - errors if nth invalid - - see also: - setnew_delnthsorted - - design: - setup points and check nth - copy remaining elements down one - update actual size -*/ -void *qh_setdelnthsorted(setT *set, int nth) { - void *elem; - setelemT *sizep; - setelemT *newp, *oldp; - - sizep= SETsizeaddr_(set); - if (nth < 0 || (sizep->i && nth >= sizep->i-1) || nth >= set->maxsize) { - qh_fprintf(qhmem.ferr, 6175, "qhull internal error (qh_setdelnthsorted): nth %d is out-of-bounds for set:\n", nth); - qh_setprint(qhmem.ferr, "", set); - qh_errexit(qhmem_ERRqhull, NULL, NULL); - } - newp= (setelemT *)SETelemaddr_(set, nth, void); - elem= newp->p; - oldp= newp+1; - while (((newp++)->p= (oldp++)->p)) - ; /* copy remaining elements and NULL */ - if ((sizep->i--)==0) /* if was a full set */ - sizep->i= set->maxsize; /* *sizep= (max size-1)+ 1 */ - return elem; -} /* setdelnthsorted */ - - -/*-<a href="qh-set.htm#TOC" - >-------------------------------<a name="setdelsorted">-</a> - - qh_setdelsorted( set, oldelem ) - deletes oldelem from sorted set - - returns: - returns oldelem if it was deleted - - notes: - set may be NULL - - design: - locate oldelem in set - copy remaining elements down one - update actual size -*/ -void *qh_setdelsorted(setT *set, void *oldelem) { - setelemT *sizep; - setelemT *newp, *oldp; - - if (!set) - return NULL; - newp= (setelemT *)SETaddr_(set, void); - while(newp->p != oldelem && newp->p) - newp++; - if (newp->p) { - oldp= newp+1; - while (((newp++)->p= (oldp++)->p)) - ; /* copy remaining elements */ - sizep= SETsizeaddr_(set); - if ((sizep->i--)==0) /* if was a full set */ - sizep->i= set->maxsize; /* *sizep= (max size-1)+ 1 */ - return oldelem; - } - return NULL; -} /* setdelsorted */ - - -/*-<a href="qh-set.htm#TOC" - >-------------------------------<a name="setduplicate">-</a> - - qh_setduplicate( set, elemsize ) - duplicate a set of elemsize elements - - notes: - use setcopy if retaining old elements - - design: - create a new set - for each elem of the old set - create a newelem - append newelem to newset -*/ -setT *qh_setduplicate(setT *set, int elemsize) { - void *elem, **elemp, *newElem; - setT *newSet; - int size; - - if (!(size= qh_setsize(set))) - return NULL; - newSet= qh_setnew(size); - FOREACHelem_(set) { - newElem= qh_memalloc(elemsize); - memcpy(newElem, elem, (size_t)elemsize); - qh_setappend(&newSet, newElem); - } - return newSet; -} /* setduplicate */ - - -/*-<a href="qh-set.htm#TOC" - >-------------------------------<a name="setendpointer">-</a> - - qh_setendpointer( set ) - Returns pointer to NULL terminator of a set's elements - set can not be NULL - -*/ -void **qh_setendpointer(setT *set) { - - setelemT *sizep= SETsizeaddr_(set); - int n= sizep->i; - return (n ? &set->e[n-1].p : &sizep->p); -} /* qh_setendpointer */ - -/*-<a href="qh-set.htm#TOC" - >-------------------------------<a name="setequal">-</a> - - qh_setequal( ) - returns 1 if two sorted sets are equal, otherwise returns 0 - - notes: - either set may be NULL - - design: - check size of each set - setup pointers - compare elements of each set -*/ -int qh_setequal(setT *setA, setT *setB) { - void **elemAp, **elemBp; - int sizeA= 0, sizeB= 0; - - if (setA) { - SETreturnsize_(setA, sizeA); - } - if (setB) { - SETreturnsize_(setB, sizeB); - } - if (sizeA != sizeB) - return 0; - if (!sizeA) - return 1; - elemAp= SETaddr_(setA, void); - elemBp= SETaddr_(setB, void); - if (!memcmp((char *)elemAp, (char *)elemBp, sizeA*SETelemsize)) - return 1; - return 0; -} /* setequal */ - - -/*-<a href="qh-set.htm#TOC" - >-------------------------------<a name="setequal_except">-</a> - - qh_setequal_except( setA, skipelemA, setB, skipelemB ) - returns 1 if sorted setA and setB are equal except for skipelemA & B - - returns: - false if either skipelemA or skipelemB are missing - - notes: - neither set may be NULL - - if skipelemB is NULL, - can skip any one element of setB - - design: - setup pointers - search for skipelemA, skipelemB, and mismatches - check results -*/ -int qh_setequal_except(setT *setA, void *skipelemA, setT *setB, void *skipelemB) { - void **elemA, **elemB; - int skip=0; - - elemA= SETaddr_(setA, void); - elemB= SETaddr_(setB, void); - while (1) { - if (*elemA == skipelemA) { - skip++; - elemA++; - } - if (skipelemB) { - if (*elemB == skipelemB) { - skip++; - elemB++; - } - }else if (*elemA != *elemB) { - skip++; - if (!(skipelemB= *elemB++)) - return 0; - } - if (!*elemA) - break; - if (*elemA++ != *elemB++) - return 0; - } - if (skip != 2 || *elemB) - return 0; - return 1; -} /* setequal_except */ - - -/*-<a href="qh-set.htm#TOC" - >-------------------------------<a name="setequal_skip">-</a> - - qh_setequal_skip( setA, skipA, setB, skipB ) - returns 1 if sorted setA and setB are equal except for elements skipA & B - - returns: - false if different size - - notes: - neither set may be NULL - - design: - setup pointers - search for mismatches while skipping skipA and skipB -*/ -int qh_setequal_skip(setT *setA, int skipA, setT *setB, int skipB) { - void **elemA, **elemB, **skipAp, **skipBp; - - elemA= SETaddr_(setA, void); - elemB= SETaddr_(setB, void); - skipAp= SETelemaddr_(setA, skipA, void); - skipBp= SETelemaddr_(setB, skipB, void); - while (1) { - if (elemA == skipAp) - elemA++; - if (elemB == skipBp) - elemB++; - if (!*elemA) - break; - if (*elemA++ != *elemB++) - return 0; - } - if (*elemB) - return 0; - return 1; -} /* setequal_skip */ - - -/*-<a href="qh-set.htm#TOC" - >-------------------------------<a name="setfree">-</a> - - qh_setfree( setp ) - frees the space occupied by a sorted or unsorted set - - returns: - sets setp to NULL - - notes: - set may be NULL - - design: - free array - free set -*/ -void qh_setfree(setT **setp) { - int size; - void **freelistp; /* used !qh_NOmem */ - - if (*setp) { - size= sizeof(setT) + ((*setp)->maxsize)*SETelemsize; - if (size <= qhmem.LASTsize) { - qh_memfree_(*setp, size, freelistp); - }else - qh_memfree(*setp, size); - *setp= NULL; - } -} /* setfree */ - - -/*-<a href="qh-set.htm#TOC" - >-------------------------------<a name="setfree2">-</a> - - qh_setfree2( setp, elemsize ) - frees the space occupied by a set and its elements - - notes: - set may be NULL - - design: - free each element - free set -*/ -void qh_setfree2 (setT **setp, int elemsize) { - void *elem, **elemp; - - FOREACHelem_(*setp) - qh_memfree(elem, elemsize); - qh_setfree(setp); -} /* setfree2 */ - - - -/*-<a href="qh-set.htm#TOC" - >-------------------------------<a name="setfreelong">-</a> - - qh_setfreelong( setp ) - frees a set only if it's in long memory - - returns: - sets setp to NULL if it is freed - - notes: - set may be NULL - - design: - if set is large - free it -*/ -void qh_setfreelong(setT **setp) { - int size; - - if (*setp) { - size= sizeof(setT) + ((*setp)->maxsize)*SETelemsize; - if (size > qhmem.LASTsize) { - qh_memfree(*setp, size); - *setp= NULL; - } - } -} /* setfreelong */ - - -/*-<a href="qh-set.htm#TOC" - >-------------------------------<a name="setin">-</a> - - qh_setin( set, setelem ) - returns 1 if setelem is in a set, 0 otherwise - - notes: - set may be NULL or unsorted - - design: - scans set for setelem -*/ -int qh_setin(setT *set, void *setelem) { - void *elem, **elemp; - - FOREACHelem_(set) { - if (elem == setelem) - return 1; - } - return 0; -} /* setin */ - - -/*-<a href="qh-set.htm#TOC" - >-------------------------------<a name="setindex">-</a> - - qh_setindex( set, atelem ) - returns the index of atelem in set. - returns -1, if not in set or maxsize wrong - - notes: - set may be NULL and may contain nulls. - NOerrors returned (qh_pointid, QhullPoint::id) - - design: - checks maxsize - scans set for atelem -*/ -int qh_setindex(setT *set, void *atelem) { - void **elem; - int size, i; - - if (!set) - return -1; - SETreturnsize_(set, size); - if (size > set->maxsize) - return -1; - elem= SETaddr_(set, void); - for (i=0; i < size; i++) { - if (*elem++ == atelem) - return i; - } - return -1; -} /* setindex */ - - -/*-<a href="qh-set.htm#TOC" - >-------------------------------<a name="setlarger">-</a> - - qh_setlarger( oldsetp ) - returns a larger set that contains all elements of *oldsetp - - notes: - the set is at least twice as large - if temp set, updates qhmem.tempstack - - design: - creates a new set - copies the old set to the new set - updates pointers in tempstack - deletes the old set -*/ -void qh_setlarger(setT **oldsetp) { - int size= 1; - setT *newset, *set, **setp, *oldset; - setelemT *sizep; - setelemT *newp, *oldp; - - if (*oldsetp) { - oldset= *oldsetp; - SETreturnsize_(oldset, size); - qhmem.cntlarger++; - qhmem.totlarger += size+1; - newset= qh_setnew(2 * size); - oldp= (setelemT *)SETaddr_(oldset, void); - newp= (setelemT *)SETaddr_(newset, void); - memcpy((char *)newp, (char *)oldp, (size_t)(size+1) * SETelemsize); - sizep= SETsizeaddr_(newset); - sizep->i= size+1; - FOREACHset_((setT *)qhmem.tempstack) { - if (set == oldset) - *(setp-1)= newset; - } - qh_setfree(oldsetp); - }else - newset= qh_setnew(3); - *oldsetp= newset; -} /* setlarger */ - - -/*-<a href="qh-set.htm#TOC" - >-------------------------------<a name="setlast">-</a> - - qh_setlast( ) - return last element of set or NULL (use type conversion) - - notes: - set may be NULL - - design: - return last element -*/ -void *qh_setlast(setT *set) { - int size; - - if (set) { - size= SETsizeaddr_(set)->i; - if (!size) - return SETelem_(set, set->maxsize - 1); - else if (size > 1) - return SETelem_(set, size - 2); - } - return NULL; -} /* setlast */ - - -/*-<a href="qh-set.htm#TOC" - >-------------------------------<a name="setnew">-</a> - - qh_setnew( setsize ) - creates and allocates space for a set - - notes: - setsize means the number of elements (!including the NULL terminator) - use qh_settemp/qh_setfreetemp if set is temporary - - design: - allocate memory for set - roundup memory if small set - initialize as empty set -*/ -setT *qh_setnew(int setsize) { - setT *set; - int sizereceived; /* used !qh_NOmem */ - int size; - void **freelistp; /* used !qh_NOmem */ - - if (!setsize) - setsize++; - size= sizeof(setT) + setsize * SETelemsize; - if (size>0 && size <= qhmem.LASTsize) { - qh_memalloc_(size, freelistp, set, setT); -#ifndef qh_NOmem - sizereceived= qhmem.sizetable[ qhmem.indextable[size]]; - if (sizereceived > size) - setsize += (sizereceived - size)/SETelemsize; -#endif - }else - set= (setT*)qh_memalloc(size); - set->maxsize= setsize; - set->e[setsize].i= 1; - set->e[0].p= NULL; - return(set); -} /* setnew */ - - -/*-<a href="qh-set.htm#TOC" - >-------------------------------<a name="setnew_delnthsorted">-</a> - - qh_setnew_delnthsorted( set, size, nth, prepend ) - creates a sorted set not containing nth element - if prepend, the first prepend elements are undefined - - notes: - set must be defined - checks nth - see also: setdelnthsorted - - design: - create new set - setup pointers and allocate room for prepend'ed entries - append head of old set to new set - append tail of old set to new set -*/ -setT *qh_setnew_delnthsorted(setT *set, int size, int nth, int prepend) { - setT *newset; - void **oldp, **newp; - int tailsize= size - nth -1, newsize; - - if (tailsize < 0) { - qh_fprintf(qhmem.ferr, 6176, "qhull internal error (qh_setnew_delnthsorted): nth %d is out-of-bounds for set:\n", nth); - qh_setprint(qhmem.ferr, "", set); - qh_errexit(qhmem_ERRqhull, NULL, NULL); - } - newsize= size-1 + prepend; - newset= qh_setnew(newsize); - newset->e[newset->maxsize].i= newsize+1; /* may be overwritten */ - oldp= SETaddr_(set, void); - newp= SETaddr_(newset, void) + prepend; - switch (nth) { - case 0: - break; - case 1: - *(newp++)= *oldp++; - break; - case 2: - *(newp++)= *oldp++; - *(newp++)= *oldp++; - break; - case 3: - *(newp++)= *oldp++; - *(newp++)= *oldp++; - *(newp++)= *oldp++; - break; - case 4: - *(newp++)= *oldp++; - *(newp++)= *oldp++; - *(newp++)= *oldp++; - *(newp++)= *oldp++; - break; - default: - memcpy((char *)newp, (char *)oldp, (size_t)nth * SETelemsize); - newp += nth; - oldp += nth; - break; - } - oldp++; - switch (tailsize) { - case 0: - break; - case 1: - *(newp++)= *oldp++; - break; - case 2: - *(newp++)= *oldp++; - *(newp++)= *oldp++; - break; - case 3: - *(newp++)= *oldp++; - *(newp++)= *oldp++; - *(newp++)= *oldp++; - break; - case 4: - *(newp++)= *oldp++; - *(newp++)= *oldp++; - *(newp++)= *oldp++; - *(newp++)= *oldp++; - break; - default: - memcpy((char *)newp, (char *)oldp, (size_t)tailsize * SETelemsize); - newp += tailsize; - } - *newp= NULL; - return(newset); -} /* setnew_delnthsorted */ - - -/*-<a href="qh-set.htm#TOC" - >-------------------------------<a name="setprint">-</a> - - qh_setprint( fp, string, set ) - print set elements to fp with identifying string - - notes: - never errors -*/ -void qh_setprint(FILE *fp, const char* string, setT *set) { - int size, k; - - if (!set) - qh_fprintf(fp, 9346, "%s set is null\n", string); - else { - SETreturnsize_(set, size); - qh_fprintf(fp, 9347, "%s set=%p maxsize=%d size=%d elems=", - string, set, set->maxsize, size); - if (size > set->maxsize) - size= set->maxsize+1; - for (k=0; k < size; k++) - qh_fprintf(fp, 9348, " %p", set->e[k].p); - qh_fprintf(fp, 9349, "\n"); - } -} /* setprint */ - -/*-<a href="qh-set.htm#TOC" - >-------------------------------<a name="setreplace">-</a> - - qh_setreplace( set, oldelem, newelem ) - replaces oldelem in set with newelem - - notes: - errors if oldelem not in the set - newelem may be NULL, but it turns the set into an indexed set (no FOREACH) - - design: - find oldelem - replace with newelem -*/ -void qh_setreplace(setT *set, void *oldelem, void *newelem) { - void **elemp; - - elemp= SETaddr_(set, void); - while (*elemp != oldelem && *elemp) - elemp++; - if (*elemp) - *elemp= newelem; - else { - qh_fprintf(qhmem.ferr, 6177, "qhull internal error (qh_setreplace): elem %p not found in set\n", - oldelem); - qh_setprint(qhmem.ferr, "", set); - qh_errexit(qhmem_ERRqhull, NULL, NULL); - } -} /* setreplace */ - - -/*-<a href="qh-set.htm#TOC" - >-------------------------------<a name="setsize">-</a> - - qh_setsize( set ) - returns the size of a set - - notes: - errors if set's maxsize is incorrect - same as SETreturnsize_(set) - same code for qh_setsize [qset.c] and QhullSetBase::count - - design: - determine actual size of set from maxsize -*/ -int qh_setsize(setT *set) { - int size; - setelemT *sizep; - - if (!set) - return(0); - sizep= SETsizeaddr_(set); - if ((size= sizep->i)) { - size--; - if (size > set->maxsize) { - qh_fprintf(qhmem.ferr, 6178, "qhull internal error (qh_setsize): current set size %d is greater than maximum size %d\n", - size, set->maxsize); - qh_setprint(qhmem.ferr, "set: ", set); - qh_errexit(qhmem_ERRqhull, NULL, NULL); - } - }else - size= set->maxsize; - return size; -} /* setsize */ - -/*-<a href="qh-set.htm#TOC" - >-------------------------------<a name="settemp">-</a> - - qh_settemp( setsize ) - return a stacked, temporary set of upto setsize elements - - notes: - use settempfree or settempfree_all to release from qhmem.tempstack - see also qh_setnew - - design: - allocate set - append to qhmem.tempstack - -*/ -setT *qh_settemp(int setsize) { - setT *newset; - - newset= qh_setnew(setsize); - qh_setappend(&qhmem.tempstack, newset); - if (qhmem.IStracing >= 5) - qh_fprintf(qhmem.ferr, 8123, "qh_settemp: temp set %p of %d elements, depth %d\n", - newset, newset->maxsize, qh_setsize(qhmem.tempstack)); - return newset; -} /* settemp */ - -/*-<a href="qh-set.htm#TOC" - >-------------------------------<a name="settempfree">-</a> - - qh_settempfree( set ) - free temporary set at top of qhmem.tempstack - - notes: - nop if set is NULL - errors if set not from previous qh_settemp - - to locate errors: - use 'T2' to find source and then find mis-matching qh_settemp - - design: - check top of qhmem.tempstack - free it -*/ -void qh_settempfree(setT **set) { - setT *stackedset; - - if (!*set) - return; - stackedset= qh_settemppop(); - if (stackedset != *set) { - qh_settemppush(stackedset); - qh_fprintf(qhmem.ferr, 6179, "qhull internal error (qh_settempfree): set %p(size %d) was not last temporary allocated(depth %d, set %p, size %d)\n", - *set, qh_setsize(*set), qh_setsize(qhmem.tempstack)+1, - stackedset, qh_setsize(stackedset)); - qh_errexit(qhmem_ERRqhull, NULL, NULL); - } - qh_setfree(set); -} /* settempfree */ - -/*-<a href="qh-set.htm#TOC" - >-------------------------------<a name="settempfree_all">-</a> - - qh_settempfree_all( ) - free all temporary sets in qhmem.tempstack - - design: - for each set in tempstack - free set - free qhmem.tempstack -*/ -void qh_settempfree_all(void) { - setT *set, **setp; - - FOREACHset_(qhmem.tempstack) - qh_setfree(&set); - qh_setfree(&qhmem.tempstack); -} /* settempfree_all */ - -/*-<a href="qh-set.htm#TOC" - >-------------------------------<a name="settemppop">-</a> - - qh_settemppop( ) - pop and return temporary set from qhmem.tempstack - - notes: - the returned set is permanent - - design: - pop and check top of qhmem.tempstack -*/ -setT *qh_settemppop(void) { - setT *stackedset; - - stackedset= (setT*)qh_setdellast(qhmem.tempstack); - if (!stackedset) { - qh_fprintf(qhmem.ferr, 6180, "qhull internal error (qh_settemppop): pop from empty temporary stack\n"); - qh_errexit(qhmem_ERRqhull, NULL, NULL); - } - if (qhmem.IStracing >= 5) - qh_fprintf(qhmem.ferr, 8124, "qh_settemppop: depth %d temp set %p of %d elements\n", - qh_setsize(qhmem.tempstack)+1, stackedset, qh_setsize(stackedset)); - return stackedset; -} /* settemppop */ - -/*-<a href="qh-set.htm#TOC" - >-------------------------------<a name="settemppush">-</a> - - qh_settemppush( set ) - push temporary set unto qhmem.tempstack (makes it temporary) - - notes: - duplicates settemp() for tracing - - design: - append set to tempstack -*/ -void qh_settemppush(setT *set) { - if (!set) { - fprintf (qhmem.ferr, "qhull error (qh_settemppush): can not push a NULL temp\n"); - qh_errexit (qhmem_ERRqhull, NULL, NULL); - } - qh_setappend(&qhmem.tempstack, set); - if (qhmem.IStracing >= 5) - qh_fprintf(qhmem.ferr, 8125, "qh_settemppush: depth %d temp set %p of %d elements\n", - qh_setsize(qhmem.tempstack), set, qh_setsize(set)); -} /* settemppush */ - - -/*-<a href="qh-set.htm#TOC" - >-------------------------------<a name="settruncate">-</a> - - qh_settruncate( set, size ) - truncate set to size elements - - notes: - set must be defined - - see: - SETtruncate_ - - design: - check size - update actual size of set -*/ -void qh_settruncate(setT *set, int size) { - - if (size < 0 || size > set->maxsize) { - qh_fprintf(qhmem.ferr, 6181, "qhull internal error (qh_settruncate): size %d out of bounds for set:\n", size); - qh_setprint(qhmem.ferr, "", set); - qh_errexit(qhmem_ERRqhull, NULL, NULL); - } - set->e[set->maxsize].i= size+1; /* maybe overwritten */ - set->e[size].p= NULL; -} /* settruncate */ - -/*-<a href="qh-set.htm#TOC" - >-------------------------------<a name="setunique">-</a> - - qh_setunique( set, elem ) - add elem to unsorted set unless it is already in set - - notes: - returns 1 if it is appended - - design: - if elem not in set - append elem to set -*/ -int qh_setunique(setT **set, void *elem) { - - if (!qh_setin(*set, elem)) { - qh_setappend(set, elem); - return 1; - } - return 0; -} /* setunique */ - -/*-<a href="qh-set.htm#TOC" - >-------------------------------<a name="setzero">-</a> - - qh_setzero( set, index, size ) - zero elements from index on - set actual size of set to size - - notes: - set must be defined - the set becomes an indexed set (can not use FOREACH...) - - see also: - qh_settruncate - - design: - check index and size - update actual size - zero elements starting at e[index] -*/ -void qh_setzero(setT *set, int idx, int size) { - int count; - - if (idx < 0 || idx >= size || size > set->maxsize) { - qh_fprintf(qhmem.ferr, 6182, "qhull internal error (qh_setzero): index %d or size %d out of bounds for set:\n", idx, size); - qh_setprint(qhmem.ferr, "", set); - qh_errexit(qhmem_ERRqhull, NULL, NULL); - } - set->e[set->maxsize].i= size+1; /* may be overwritten */ - count= size - idx + 1; /* +1 for NULL terminator */ - memset((char *)SETelemaddr_(set, idx, void), 0, (size_t)count * SETelemsize); -} /* setzero */ - - diff --git a/PyMca/Object3D/Object3DQhull/src/qset.h b/PyMca/Object3D/Object3DQhull/src/qset.h deleted file mode 100644 index 759b501..0000000 --- a/PyMca/Object3D/Object3DQhull/src/qset.h +++ /dev/null @@ -1,488 +0,0 @@ -/*<html><pre> -<a href="qh-set.htm" - >-------------------------------</a><a name="TOP">-</a> - - qset.h - header file for qset.c that implements set - - see qh-set.htm and qset.c - - only uses mem.c, malloc/free - - for error handling, writes message and calls - qh_errexit(qhmem_ERRqhull, NULL, NULL); - - set operations satisfy the following properties: - - sets have a max size, the actual size (if different) is stored at the end - - every set is NULL terminated - - sets may be sorted or unsorted, the caller must distinguish this - - Copyright (c) 1993-2012 The Geometry Center. - $Id: //main/2011/qhull/src/libqhull/qset.h#4 $$Change: 1464 $ - $DateTime: 2012/01/25 22:58:41 $$Author: bbarber $ -*/ - -#ifndef qhDEFset -#define qhDEFset 1 - -#include <stdio.h> - -/*================= -structures- ===============*/ - -#ifndef DEFsetT -#define DEFsetT 1 -typedef struct setT setT; /* a set is a sorted or unsorted array of pointers */ -#endif - -/*-<a href="qh-set.htm#TOC" ->----------------------------------------</a><a name="setT">-</a> - -setT - a set or list of pointers with maximum size and actual size. - -variations: - unsorted, unique -- a list of unique pointers with NULL terminator - user guarantees uniqueness - sorted -- a sorted list of unique pointers with NULL terminator - qset.c guarantees uniqueness - unsorted -- a list of pointers terminated with NULL - indexed -- an array of pointers with NULL elements - -structure for set of n elements: - - -------------- - | maxsize - -------------- - | e[0] - a pointer, may be NULL for indexed sets - -------------- - | e[1] - - -------------- - | ... - -------------- - | e[n-1] - -------------- - | e[n] = NULL - -------------- - | ... - -------------- - | e[maxsize] - n+1 or NULL (determines actual size of set) - -------------- - -*/ - -/*-- setelemT -- internal type to allow both pointers and indices -*/ -typedef union setelemT setelemT; -union setelemT { - void *p; - int i; /* integer used for e[maxSize] */ -}; - -struct setT { - int maxsize; /* maximum number of elements (except NULL) */ - setelemT e[1]; /* array of pointers, tail is NULL */ - /* last slot (unless NULL) is actual size+1 - e[maxsize]==NULL or e[e[maxsize]-1]==NULL */ - /* this may generate a warning since e[] contains - maxsize elements */ -}; - -/*=========== -constants- =========================*/ - -/*-<a href="qh-set.htm#TOC" - >-----------------------------------</a><a name="SETelemsize">-</a> - - SETelemsize - size of a set element in bytes -*/ -#define SETelemsize ((int)sizeof(setelemT)) - - -/*=========== -macros- =========================*/ - -/*-<a href="qh-set.htm#TOC" - >-----------------------------------</a><a name="FOREACHsetelement_">-</a> - - FOREACHsetelement_(type, set, variable) - define FOREACH iterator - - declare: - assumes *variable and **variablep are declared - no space in "variable)" [DEC Alpha cc compiler] - - each iteration: - variable is set element - variablep is one beyond variable. - - to repeat an element: - variablep--; / *repeat* / - - at exit: - variable is NULL at end of loop - - example: - #define FOREACHfacet_( facets ) FOREACHsetelement_( facetT, facets, facet ) - - notes: - use FOREACHsetelement_i_() if need index or include NULLs - - WARNING: - nested loops can't use the same variable (define another FOREACH) - - needs braces if nested inside another FOREACH - this includes intervening blocks, e.g. FOREACH...{ if () FOREACH...} ) -*/ -#define FOREACHsetelement_(type, set, variable) \ - if (((variable= NULL), set)) for (\ - variable##p= (type **)&((set)->e[0].p); \ - (variable= *variable##p++);) - -/*-<a href="qh-set.htm#TOC" - >----------------------------------------</a><a name="FOREACHsetelement_i_">-</a> - - FOREACHsetelement_i_(type, set, variable) - define indexed FOREACH iterator - - declare: - type *variable, variable_n, variable_i; - - each iteration: - variable is set element, may be NULL - variable_i is index, variable_n is qh_setsize() - - to repeat an element: - variable_i--; variable_n-- repeats for deleted element - - at exit: - variable==NULL and variable_i==variable_n - - example: - #define FOREACHfacet_i_( facets ) FOREACHsetelement_i_( facetT, facets, facet ) - - WARNING: - nested loops can't use the same variable (define another FOREACH) - - needs braces if nested inside another FOREACH - this includes intervening blocks, e.g. FOREACH...{ if () FOREACH...} ) -*/ -#define FOREACHsetelement_i_(type, set, variable) \ - if (((variable= NULL), set)) for (\ - variable##_i= 0, variable= (type *)((set)->e[0].p), \ - variable##_n= qh_setsize(set);\ - variable##_i < variable##_n;\ - variable= (type *)((set)->e[++variable##_i].p) ) - -/*-<a href="qh-set.htm#TOC" - >--------------------------------------</a><a name="FOREACHsetelementreverse_">-</a> - - FOREACHsetelementreverse_(type, set, variable)- - define FOREACH iterator in reverse order - - declare: - assumes *variable and **variablep are declared - also declare 'int variabletemp' - - each iteration: - variable is set element - - to repeat an element: - variabletemp++; / *repeat* / - - at exit: - variable is NULL - - example: - #define FOREACHvertexreverse_( vertices ) FOREACHsetelementreverse_( vertexT, vertices, vertex ) - - notes: - use FOREACHsetelementreverse12_() to reverse first two elements - WARNING: needs braces if nested inside another FOREACH -*/ -#define FOREACHsetelementreverse_(type, set, variable) \ - if (((variable= NULL), set)) for (\ - variable##temp= qh_setsize(set)-1, variable= qh_setlast(set);\ - variable; variable= \ - ((--variable##temp >= 0) ? SETelemt_(set, variable##temp, type) : NULL)) - -/*-<a href="qh-set.htm#TOC" - >-----------------------------------</a><a name="FOREACHsetelementreverse12_">-</a> - - FOREACHsetelementreverse12_(type, set, variable)- - define FOREACH iterator with e[1] and e[0] reversed - - declare: - assumes *variable and **variablep are declared - - each iteration: - variable is set element - variablep is one after variable. - - to repeat an element: - variablep--; / *repeat* / - - at exit: - variable is NULL at end of loop - - example - #define FOREACHvertexreverse12_( vertices ) FOREACHsetelementreverse12_( vertexT, vertices, vertex ) - - notes: - WARNING: needs braces if nested inside another FOREACH -*/ -#define FOREACHsetelementreverse12_(type, set, variable) \ - if (((variable= NULL), set)) for (\ - variable##p= (type **)&((set)->e[1].p); \ - (variable= *variable##p); \ - variable##p == ((type **)&((set)->e[0].p))?variable##p += 2: \ - (variable##p == ((type **)&((set)->e[1].p))?variable##p--:variable##p++)) - -/*-<a href="qh-set.htm#TOC" - >-----------------------------------</a><a name="FOREACHelem_">-</a> - - FOREACHelem_( set )- - iterate elements in a set - - declare: - void *elem, *elemp; - - each iteration: - elem is set element - elemp is one beyond - - to repeat an element: - elemp--; / *repeat* / - - at exit: - elem == NULL at end of loop - - example: - FOREACHelem_(set) { - - notes: - WARNING: needs braces if nested inside another FOREACH -*/ -#define FOREACHelem_(set) FOREACHsetelement_(void, set, elem) - -/*-<a href="qh-set.htm#TOC" - >-----------------------------------</a><a name="FOREACHset_">-</a> - - FOREACHset_( set )- - iterate a set of sets - - declare: - setT *set, **setp; - - each iteration: - set is set element - setp is one beyond - - to repeat an element: - setp--; / *repeat* / - - at exit: - set == NULL at end of loop - - example - FOREACHset_(sets) { - - notes: - WARNING: needs braces if nested inside another FOREACH -*/ -#define FOREACHset_(sets) FOREACHsetelement_(setT, sets, set) - -/*-<a href="qh-set.htm#TOC" - >-----------------------------------------</a><a name="SETindex_">-</a> - - SETindex_( set, elem ) - return index of elem in set - - notes: - for use with FOREACH iteration - WARN64 -- Maximum set size is 2G - - example: - i= SETindex_(ridges, ridge) -*/ -#define SETindex_(set, elem) ((int)((void **)elem##p - (void **)&(set)->e[1].p)) - -/*-<a href="qh-set.htm#TOC" - >---------------------------------------</a><a name="SETref_">-</a> - - SETref_( elem ) - l.h.s. for modifying the current element in a FOREACH iteration - - example: - SETref_(ridge)= anotherridge; -*/ -#define SETref_(elem) (elem##p[-1]) - -/*-<a href="qh-set.htm#TOC" - >---------------------------------------</a><a name="SETelem_">-</a> - - SETelem_(set, n) - return the n'th element of set - - notes: - assumes that n is valid [0..size] and that set is defined - use SETelemt_() for type cast -*/ -#define SETelem_(set, n) ((set)->e[n].p) - -/*-<a href="qh-set.htm#TOC" - >---------------------------------------</a><a name="SETelemt_">-</a> - - SETelemt_(set, n, type) - return the n'th element of set as a type - - notes: - assumes that n is valid [0..size] and that set is defined -*/ -#define SETelemt_(set, n, type) ((type*)((set)->e[n].p)) - -/*-<a href="qh-set.htm#TOC" - >---------------------------------------</a><a name="SETelemaddr_">-</a> - - SETelemaddr_(set, n, type) - return address of the n'th element of a set - - notes: - assumes that n is valid [0..size] and set is defined -*/ -#define SETelemaddr_(set, n, type) ((type **)(&((set)->e[n].p))) - -/*-<a href="qh-set.htm#TOC" - >---------------------------------------</a><a name="SETfirst_">-</a> - - SETfirst_(set) - return first element of set - -*/ -#define SETfirst_(set) ((set)->e[0].p) - -/*-<a href="qh-set.htm#TOC" - >---------------------------------------</a><a name="SETfirstt_">-</a> - - SETfirstt_(set, type) - return first element of set as a type - -*/ -#define SETfirstt_(set, type) ((type*)((set)->e[0].p)) - -/*-<a href="qh-set.htm#TOC" - >---------------------------------------</a><a name="SETsecond_">-</a> - - SETsecond_(set) - return second element of set - -*/ -#define SETsecond_(set) ((set)->e[1].p) - -/*-<a href="qh-set.htm#TOC" - >---------------------------------------</a><a name="SETsecondt_">-</a> - - SETsecondt_(set, type) - return second element of set as a type -*/ -#define SETsecondt_(set, type) ((type*)((set)->e[1].p)) - -/*-<a href="qh-set.htm#TOC" - >---------------------------------------</a><a name="SETaddr_">-</a> - - SETaddr_(set, type) - return address of set's elements -*/ -#define SETaddr_(set,type) ((type **)(&((set)->e[0].p))) - -/*-<a href="qh-set.htm#TOC" - >---------------------------------------</a><a name="SETreturnsize_">-</a> - - SETreturnsize_(set, size) - return size of a set - - notes: - set must be defined - use qh_setsize(set) unless speed is critical -*/ -#define SETreturnsize_(set, size) (((size)= ((set)->e[(set)->maxsize].i))?(--(size)):((size)= (set)->maxsize)) - -/*-<a href="qh-set.htm#TOC" - >---------------------------------------</a><a name="SETempty_">-</a> - - SETempty_(set) - return true(1) if set is empty - - notes: - set may be NULL -*/ -#define SETempty_(set) (!set || (SETfirst_(set) ? 0 : 1)) - -/*-<a href="qh-set.htm#TOC" - >-------------------------------<a name="SETsizeaddr_">-</a> - - SETsizeaddr_(set) - return pointer to 'actual size+1' of set (set CANNOT be NULL!!) - Its type is setelemT* for strict aliasing - All SETelemaddr_ must be cast to setelemT - - - notes: - *SETsizeaddr==NULL or e[*SETsizeaddr-1].p==NULL -*/ -#define SETsizeaddr_(set) (&((set)->e[(set)->maxsize])) - -/*-<a href="qh-set.htm#TOC" - >---------------------------------------</a><a name="SETtruncate_">-</a> - - SETtruncate_(set, size) - truncate set to size - - see: - qh_settruncate() - -*/ -#define SETtruncate_(set, size) {set->e[set->maxsize].i= size+1; /* maybe overwritten */ \ - set->e[size].p= NULL;} - -/*======= prototypes in alphabetical order ============*/ - -void qh_setaddsorted(setT **setp, void *elem); -void qh_setaddnth(setT **setp, int nth, void *newelem); -void qh_setappend(setT **setp, void *elem); -void qh_setappend_set(setT **setp, setT *setA); -void qh_setappend2ndlast(setT **setp, void *elem); -void qh_setcheck(setT *set, const char *tname, unsigned id); -void qh_setcompact(setT *set); -setT *qh_setcopy(setT *set, int extra); -void *qh_setdel(setT *set, void *elem); -void *qh_setdellast(setT *set); -void *qh_setdelnth(setT *set, int nth); -void *qh_setdelnthsorted(setT *set, int nth); -void *qh_setdelsorted(setT *set, void *newelem); -setT *qh_setduplicate( setT *set, int elemsize); -int qh_setequal(setT *setA, setT *setB); -int qh_setequal_except(setT *setA, void *skipelemA, setT *setB, void *skipelemB); -int qh_setequal_skip(setT *setA, int skipA, setT *setB, int skipB); -void **qh_setendpointer(setT *set); -void qh_setfree(setT **set); -void qh_setfree2( setT **setp, int elemsize); -void qh_setfreelong(setT **set); -int qh_setin(setT *set, void *setelem); -int qh_setindex(setT *set, void *setelem); -void qh_setlarger(setT **setp); -void *qh_setlast(setT *set); -setT *qh_setnew(int size); -setT *qh_setnew_delnthsorted(setT *set, int size, int nth, int prepend); -void qh_setprint(FILE *fp, const char* string, setT *set); -void qh_setreplace(setT *set, void *oldelem, void *newelem); -int qh_setsize(setT *set); -setT *qh_settemp(int setsize); -void qh_settempfree(setT **set); -void qh_settempfree_all(void); -setT *qh_settemppop(void); -void qh_settemppush(setT *set); -void qh_settruncate(setT *set, int size); -int qh_setunique(setT **set, void *elem); -void qh_setzero(setT *set, int idx, int size); - - -#endif /* qhDEFset */ diff --git a/PyMca/Object3D/Object3DQhull/src/random.c b/PyMca/Object3D/Object3DQhull/src/random.c deleted file mode 100644 index d2af5dd..0000000 --- a/PyMca/Object3D/Object3DQhull/src/random.c +++ /dev/null @@ -1,243 +0,0 @@ -/*<html><pre> -<a href="index.htm#TOC" - >-------------------------------</a><a name="TOP">-</a> - - random.c -- utilities - Park & Miller's minimimal standard random number generator - argc/argv conversion - - Used by rbox. Do not use 'qh' -*/ - -#include "libqhull.h" -#include <string.h> -#include <stdio.h> -#include <stdlib.h> - -#ifdef _MSC_VER /* Microsoft Visual C++ -- warning level 4 */ -#pragma warning( disable : 4706) /* assignment within conditional function */ -#pragma warning( disable : 4996) /* function was declared deprecated(strcpy, localtime, etc.) */ -#endif - -/*-<a href="qh-globa.htm#TOC" - >-------------------------------</a><a name="argv_to_command">-</a> - - qh_argv_to_command( argc, argv, command, max_size ) - - build command from argc/argv - max_size is at least - - returns: - a space-delimited string of options (just as typed) - returns false if max_size is too short - - notes: - silently removes - makes option string easy to input and output - matches qh_argv_to_command_size() - - argc may be 0 -*/ -int qh_argv_to_command(int argc, char *argv[], char* command, int max_size) { - int i, remaining; - char *s; - *command= '\0'; /* max_size > 0 */ - - if (argc) { - if ((s= strrchr( argv[0], '\\')) /* get filename w/o .exe extension */ - || (s= strrchr( argv[0], '/'))) - s++; - else - s= argv[0]; - if ((int)strlen(s) < max_size) /* WARN64 */ - strcpy(command, s); - else - goto error_argv; - if ((s= strstr(command, ".EXE")) - || (s= strstr(command, ".exe"))) - *s= '\0'; - } - for (i=1; i < argc; i++) { - s= argv[i]; - remaining= max_size - (int)strlen(command) - (int)strlen(s) - 2; /* WARN64 */ - if (!*s || strchr(s, ' ')) { - char *t= command + strlen(command); - remaining -= 2; - if (remaining < 0) { - goto error_argv; - } - *t++= ' '; - *t++= '"'; - while (*s) { - if (*s == '"') { - if (--remaining < 0) - goto error_argv; - *t++= '\\'; - } - *t++= *s++; - } - *t++= '"'; - *t= '\0'; - }else if (remaining < 0) { - goto error_argv; - }else - strcat(command, " "); - strcat(command, s); - } - return 1; - -error_argv: - return 0; -} /* argv_to_command */ - -/*-<a href="qh-globa.htm#TOC" ->-------------------------------</a><a name="argv_to_command_size">-</a> - -qh_argv_to_command_size( argc, argv ) - - return size to allocate for qh_argv_to_command() - -notes: - argc may be 0 - actual size is usually shorter -*/ -int qh_argv_to_command_size(int argc, char *argv[]) { - unsigned int count= 1; /* null-terminator if argc==0 */ - int i; - char *s; - - for (i=0; i<argc; i++){ - count += (int)strlen(argv[i]) + 1; /* WARN64 */ - if (i>0 && strchr(argv[i], ' ')) { - count += 2; /* quote delimiters */ - for (s=argv[i]; *s; s++) { - if (*s == '"') { - count++; - } - } - } - } - return count; -} /* argv_to_command_size */ - -/*-<a href="qh-geom.htm#TOC" - >-------------------------------</a><a name="rand">-</a> - - qh_rand() - qh_srand( seed ) - generate pseudo-random number between 1 and 2^31 -2 - - notes: - For qhull and rbox, called from qh_RANDOMint(),etc. [user.h] - - From Park & Miller's minimal standard random number generator - Communications of the ACM, 31:1192-1201, 1988. - Does not use 0 or 2^31 -1 - this is silently enforced by qh_srand() - Can make 'Rn' much faster by moving qh_rand to qh_distplane -*/ - -/* Global variables and constants */ - -int qh_rand_seed= 1; /* define as global variable instead of using qh */ - -#define qh_rand_a 16807 -#define qh_rand_m 2147483647 -#define qh_rand_q 127773 /* m div a */ -#define qh_rand_r 2836 /* m mod a */ - -int qh_rand( void) { - int lo, hi, test; - int seed = qh_rand_seed; - - hi = seed / qh_rand_q; /* seed div q */ - lo = seed % qh_rand_q; /* seed mod q */ - test = qh_rand_a * lo - qh_rand_r * hi; - if (test > 0) - seed= test; - else - seed= test + qh_rand_m; - qh_rand_seed= seed; - /* seed = seed < qh_RANDOMmax/2 ? 0 : qh_RANDOMmax; for testing */ - /* seed = qh_RANDOMmax; for testing */ - return seed; -} /* rand */ - -void qh_srand( int seed) { - if (seed < 1) - qh_rand_seed= 1; - else if (seed >= qh_rand_m) - qh_rand_seed= qh_rand_m - 1; - else - qh_rand_seed= seed; -} /* qh_srand */ - -/*-<a href="qh-geom.htm#TOC" ->-------------------------------</a><a name="randomfactor">-</a> - -qh_randomfactor( scale, offset ) -return a random factor r * scale + offset - -notes: -qh.RANDOMa/b are defined in global.c -*/ -realT qh_randomfactor(realT scale, realT offset) { - realT randr; - - randr= qh_RANDOMint; - return randr * scale + offset; -} /* randomfactor */ - -/*-<a href="qh-geom.htm#TOC" ->-------------------------------</a><a name="randommatrix">-</a> - -qh_randommatrix( buffer, dim, rows ) -generate a random dim X dim matrix in range [-1,1] -assumes buffer is [dim+1, dim] - -returns: -sets buffer to random numbers -sets rows to rows of buffer -sets row[dim] as scratch row -*/ -void qh_randommatrix(realT *buffer, int dim, realT **rows) { - int i, k; - realT **rowi, *coord, realr; - - coord= buffer; - rowi= rows; - for (i=0; i < dim; i++) { - *(rowi++)= coord; - for (k=0; k < dim; k++) { - realr= qh_RANDOMint; - *(coord++)= 2.0 * realr/(qh_RANDOMmax+1) - 1.0; - } - } - *rowi= coord; -} /* randommatrix */ - -/*-<a href="qh-globa.htm#TOC" - >-------------------------------</a><a name="strtol">-</a> - - qh_strtol( s, endp) qh_strtod( s, endp) - internal versions of strtol() and strtod() - does not skip trailing spaces - notes: - some implementations of strtol()/strtod() skip trailing spaces -*/ -double qh_strtod(const char *s, char **endp) { - double result; - - result= strtod(s, endp); - if (s < (*endp) && (*endp)[-1] == ' ') - (*endp)--; - return result; -} /* strtod */ - -int qh_strtol(const char *s, char **endp) { - int result; - - result= (int) strtol(s, endp, 10); /* WARN64 */ - if (s< (*endp) && (*endp)[-1] == ' ') - (*endp)--; - return result; -} /* strtol */ diff --git a/PyMca/Object3D/Object3DQhull/src/random.h b/PyMca/Object3D/Object3DQhull/src/random.h deleted file mode 100644 index 87371db..0000000 --- a/PyMca/Object3D/Object3DQhull/src/random.h +++ /dev/null @@ -1,34 +0,0 @@ -/*<html><pre> -<a href="qh-geom.htm" - >-------------------------------</a><a name="TOP">-</a> - - random.h - header file for random routines - - see qh-geom.htm and random.c - - Copyright (c) 1993-2012 The Geometry Center. - $Id: //main/2011/qhull/src/libqhull/random.h#3 $$Change: 1464 $ - $DateTime: 2012/01/25 22:58:41 $$Author: bbarber $ -*/ - -#ifndef qhDEFrandom -#define qhDEFrandom 1 - -#include "libqhull.h" - -/*============= prototypes in alphabetical order ======= */ - - -int qh_argv_to_command(int argc, char *argv[], char* command, int max_size); -int qh_argv_to_command_size(int argc, char *argv[]); -int qh_rand( void); -void qh_srand( int seed); -realT qh_randomfactor(realT scale, realT offset); -void qh_randommatrix(realT *buffer, int dim, realT **row); -int qh_strtol(const char *s, char **endp); -double qh_strtod(const char *s, char **endp); - -#endif /* qhDEFrandom */ - - - diff --git a/PyMca/Object3D/Object3DQhull/src/stat.c b/PyMca/Object3D/Object3DQhull/src/stat.c deleted file mode 100644 index 7dc60b9..0000000 --- a/PyMca/Object3D/Object3DQhull/src/stat.c +++ /dev/null @@ -1,714 +0,0 @@ -/*<html><pre> -<a href="qh-stat.htm" - >-------------------------------</a><a name="TOP">-</a> - - stat.c - contains all statistics that are collected for qhull - - see qh-stat.htm and stat.h - - Copyright (c) 1993-2012 The Geometry Center. - $Id: //main/2011/qhull/src/libqhull/stat.c#3 $$Change: 1464 $ - $DateTime: 2012/01/25 22:58:41 $$Author: bbarber $ -*/ - -#include "qhull_a.h" - -/*============ global data structure ==========*/ - -#if qh_QHpointer -qhstatT *qh_qhstat=NULL; /* global data structure */ -#else -qhstatT qh_qhstat; /* add "={0}" if this causes a compiler error */ -#endif - -/*========== functions in alphabetic order ================*/ - -/*-<a href="qh-stat.htm#TOC" - >-------------------------------</a><a name="allstatA">-</a> - - qh_allstatA() - define statistics in groups of 20 - - notes: - (otherwise, 'gcc -O2' uses too much memory) - uses qhstat.next -*/ -void qh_allstatA(void) { - - /* zdef_(type,name,doc,average) */ - zzdef_(zdoc, Zdoc2, "precision statistics", -1); - zdef_(zinc, Znewvertex, NULL, -1); - zdef_(wadd, Wnewvertex, "ave. distance of a new vertex to a facet(!0s)", Znewvertex); - zzdef_(wmax, Wnewvertexmax, "max. distance of a new vertex to a facet", -1); - zdef_(wmax, Wvertexmax, "max. distance of an output vertex to a facet", -1); - zdef_(wmin, Wvertexmin, "min. distance of an output vertex to a facet", -1); - zdef_(wmin, Wmindenom, "min. denominator in hyperplane computation", -1); - - qhstat precision= qhstat next; /* call qh_precision for each of these */ - zzdef_(zdoc, Zdoc3, "precision problems (corrected unless 'Q0' or an error)", -1); - zzdef_(zinc, Zcoplanarridges, "coplanar half ridges in output", -1); - zzdef_(zinc, Zconcaveridges, "concave half ridges in output", -1); - zzdef_(zinc, Zflippedfacets, "flipped facets", -1); - zzdef_(zinc, Zcoplanarhorizon, "coplanar horizon facets for new vertices", -1); - zzdef_(zinc, Zcoplanarpart, "coplanar points during partitioning", -1); - zzdef_(zinc, Zminnorm, "degenerate hyperplanes recomputed with gaussian elimination", -1); - zzdef_(zinc, Znearlysingular, "nearly singular or axis-parallel hyperplanes", -1); - zzdef_(zinc, Zback0, "zero divisors during back substitute", -1); - zzdef_(zinc, Zgauss0, "zero divisors during gaussian elimination", -1); - zzdef_(zinc, Zmultiridge, "ridges with multiple neighbors", -1); -} -void qh_allstatB(void) { - zzdef_(zdoc, Zdoc1, "summary information", -1); - zdef_(zinc, Zvertices, "number of vertices in output", -1); - zdef_(zinc, Znumfacets, "number of facets in output", -1); - zdef_(zinc, Znonsimplicial, "number of non-simplicial facets in output", -1); - zdef_(zinc, Znowsimplicial, "number of simplicial facets that were merged", -1); - zdef_(zinc, Znumridges, "number of ridges in output", -1); - zdef_(zadd, Znumridges, "average number of ridges per facet", Znumfacets); - zdef_(zmax, Zmaxridges, "maximum number of ridges", -1); - zdef_(zadd, Znumneighbors, "average number of neighbors per facet", Znumfacets); - zdef_(zmax, Zmaxneighbors, "maximum number of neighbors", -1); - zdef_(zadd, Znumvertices, "average number of vertices per facet", Znumfacets); - zdef_(zmax, Zmaxvertices, "maximum number of vertices", -1); - zdef_(zadd, Znumvneighbors, "average number of neighbors per vertex", Zvertices); - zdef_(zmax, Zmaxvneighbors, "maximum number of neighbors", -1); - zdef_(wadd, Wcpu, "cpu seconds for qhull after input", -1); - zdef_(zinc, Ztotvertices, "vertices created altogether", -1); - zzdef_(zinc, Zsetplane, "facets created altogether", -1); - zdef_(zinc, Ztotridges, "ridges created altogether", -1); - zdef_(zinc, Zpostfacets, "facets before post merge", -1); - zdef_(zadd, Znummergetot, "average merges per facet(at most 511)", Znumfacets); - zdef_(zmax, Znummergemax, " maximum merges for a facet(at most 511)", -1); - zdef_(zinc, Zangle, NULL, -1); - zdef_(wadd, Wangle, "average angle(cosine) of facet normals for all ridges", Zangle); - zdef_(wmax, Wanglemax, " maximum angle(cosine) of facet normals across a ridge", -1); - zdef_(wmin, Wanglemin, " minimum angle(cosine) of facet normals across a ridge", -1); - zdef_(wadd, Wareatot, "total area of facets", -1); - zdef_(wmax, Wareamax, " maximum facet area", -1); - zdef_(wmin, Wareamin, " minimum facet area", -1); -} -void qh_allstatC(void) { - zdef_(zdoc, Zdoc9, "build hull statistics", -1); - zzdef_(zinc, Zprocessed, "points processed", -1); - zzdef_(zinc, Zretry, "retries due to precision problems", -1); - zdef_(wmax, Wretrymax, " max. random joggle", -1); - zdef_(zmax, Zmaxvertex, "max. vertices at any one time", -1); - zdef_(zinc, Ztotvisible, "ave. visible facets per iteration", Zprocessed); - zdef_(zinc, Zinsidevisible, " ave. visible facets without an horizon neighbor", Zprocessed); - zdef_(zadd, Zvisfacettot, " ave. facets deleted per iteration", Zprocessed); - zdef_(zmax, Zvisfacetmax, " maximum", -1); - zdef_(zadd, Zvisvertextot, "ave. visible vertices per iteration", Zprocessed); - zdef_(zmax, Zvisvertexmax, " maximum", -1); - zdef_(zinc, Ztothorizon, "ave. horizon facets per iteration", Zprocessed); - zdef_(zadd, Znewfacettot, "ave. new or merged facets per iteration", Zprocessed); - zdef_(zmax, Znewfacetmax, " maximum(includes initial simplex)", -1); - zdef_(wadd, Wnewbalance, "average new facet balance", Zprocessed); - zdef_(wadd, Wnewbalance2, " standard deviation", -1); - zdef_(wadd, Wpbalance, "average partition balance", Zpbalance); - zdef_(wadd, Wpbalance2, " standard deviation", -1); - zdef_(zinc, Zpbalance, " number of trials", -1); - zdef_(zinc, Zsearchpoints, "searches of all points for initial simplex", -1); - zdef_(zinc, Zdetsimplex, "determinants computed(area & initial hull)", -1); - zdef_(zinc, Znoarea, "determinants not computed because vertex too low", -1); - zdef_(zinc, Znotmax, "points ignored(!above max_outside)", -1); - zdef_(zinc, Znotgood, "points ignored(!above a good facet)", -1); - zdef_(zinc, Znotgoodnew, "points ignored(didn't create a good new facet)", -1); - zdef_(zinc, Zgoodfacet, "good facets found", -1); - zzdef_(zinc, Znumvisibility, "distance tests for facet visibility", -1); - zdef_(zinc, Zdistvertex, "distance tests to report minimum vertex", -1); - zzdef_(zinc, Ztotcheck, "points checked for facets' outer planes", -1); - zzdef_(zinc, Zcheckpart, " ave. distance tests per check", Ztotcheck); -} -void qh_allstatD(void) { - zdef_(zinc, Zvisit, "resets of visit_id", -1); - zdef_(zinc, Zvvisit, " resets of vertex_visit", -1); - zdef_(zmax, Zvisit2max, " max visit_id/2", -1); - zdef_(zmax, Zvvisit2max, " max vertex_visit/2", -1); - - zdef_(zdoc, Zdoc4, "partitioning statistics(see previous for outer planes)", -1); - zzdef_(zadd, Zdelvertextot, "total vertices deleted", -1); - zdef_(zmax, Zdelvertexmax, " maximum vertices deleted per iteration", -1); - zdef_(zinc, Zfindbest, "calls to findbest", -1); - zdef_(zadd, Zfindbesttot, " ave. facets tested", Zfindbest); - zdef_(zmax, Zfindbestmax, " max. facets tested", -1); - zdef_(zadd, Zfindcoplanar, " ave. coplanar search", Zfindbest); - zdef_(zinc, Zfindnew, "calls to findbestnew", -1); - zdef_(zadd, Zfindnewtot, " ave. facets tested", Zfindnew); - zdef_(zmax, Zfindnewmax, " max. facets tested", -1); - zdef_(zinc, Zfindnewjump, " ave. clearly better", Zfindnew); - zdef_(zinc, Zfindnewsharp, " calls due to qh_sharpnewfacets", -1); - zdef_(zinc, Zfindhorizon, "calls to findhorizon", -1); - zdef_(zadd, Zfindhorizontot, " ave. facets tested", Zfindhorizon); - zdef_(zmax, Zfindhorizonmax, " max. facets tested", -1); - zdef_(zinc, Zfindjump, " ave. clearly better", Zfindhorizon); - zdef_(zinc, Zparthorizon, " horizon facets better than bestfacet", -1); - zdef_(zinc, Zpartangle, "angle tests for repartitioned coplanar points", -1); - zdef_(zinc, Zpartflip, " repartitioned coplanar points for flipped orientation", -1); -} -void qh_allstatE(void) { - zdef_(zinc, Zpartinside, "inside points", -1); - zdef_(zinc, Zpartnear, " inside points kept with a facet", -1); - zdef_(zinc, Zcoplanarinside, " inside points that were coplanar with a facet", -1); - zdef_(zinc, Zbestlower, "calls to findbestlower", -1); - zdef_(zinc, Zbestlowerv, " with search of vertex neighbors", -1); - zdef_(wadd, Wmaxout, "difference in max_outside at final check", -1); - zzdef_(zinc, Zpartitionall, "distance tests for initial partition", -1); - zdef_(zinc, Ztotpartition, "partitions of a point", -1); - zzdef_(zinc, Zpartition, "distance tests for partitioning", -1); - zzdef_(zinc, Zdistcheck, "distance tests for checking flipped facets", -1); - zzdef_(zinc, Zdistconvex, "distance tests for checking convexity", -1); - zdef_(zinc, Zdistgood, "distance tests for checking good point", -1); - zdef_(zinc, Zdistio, "distance tests for output", -1); - zdef_(zinc, Zdiststat, "distance tests for statistics", -1); - zdef_(zinc, Zdistplane, "total number of distance tests", -1); - zdef_(zinc, Ztotpartcoplanar, "partitions of coplanar points or deleted vertices", -1); - zzdef_(zinc, Zpartcoplanar, " distance tests for these partitions", -1); - zdef_(zinc, Zcomputefurthest, "distance tests for computing furthest", -1); -} -void qh_allstatE2(void) { - zdef_(zdoc, Zdoc5, "statistics for matching ridges", -1); - zdef_(zinc, Zhashlookup, "total lookups for matching ridges of new facets", -1); - zdef_(zinc, Zhashtests, "average number of tests to match a ridge", Zhashlookup); - zdef_(zinc, Zhashridge, "total lookups of subridges(duplicates and boundary)", -1); - zdef_(zinc, Zhashridgetest, "average number of tests per subridge", Zhashridge); - zdef_(zinc, Zdupsame, "duplicated ridges in same merge cycle", -1); - zdef_(zinc, Zdupflip, "duplicated ridges with flipped facets", -1); - - zdef_(zdoc, Zdoc6, "statistics for determining merges", -1); - zdef_(zinc, Zangletests, "angles computed for ridge convexity", -1); - zdef_(zinc, Zbestcentrum, "best merges used centrum instead of vertices",-1); - zzdef_(zinc, Zbestdist, "distance tests for best merge", -1); - zzdef_(zinc, Zcentrumtests, "distance tests for centrum convexity", -1); - zzdef_(zinc, Zdistzero, "distance tests for checking simplicial convexity", -1); - zdef_(zinc, Zcoplanarangle, "coplanar angles in getmergeset", -1); - zdef_(zinc, Zcoplanarcentrum, "coplanar centrums in getmergeset", -1); - zdef_(zinc, Zconcaveridge, "concave ridges in getmergeset", -1); -} -void qh_allstatF(void) { - zdef_(zdoc, Zdoc7, "statistics for merging", -1); - zdef_(zinc, Zpremergetot, "merge iterations", -1); - zdef_(zadd, Zmergeinittot, "ave. initial non-convex ridges per iteration", Zpremergetot); - zdef_(zadd, Zmergeinitmax, " maximum", -1); - zdef_(zadd, Zmergesettot, " ave. additional non-convex ridges per iteration", Zpremergetot); - zdef_(zadd, Zmergesetmax, " maximum additional in one pass", -1); - zdef_(zadd, Zmergeinittot2, "initial non-convex ridges for post merging", -1); - zdef_(zadd, Zmergesettot2, " additional non-convex ridges", -1); - zdef_(wmax, Wmaxoutside, "max distance of vertex or coplanar point above facet(w/roundoff)", -1); - zdef_(wmin, Wminvertex, "max distance of merged vertex below facet(or roundoff)", -1); - zdef_(zinc, Zwidefacet, "centrums frozen due to a wide merge", -1); - zdef_(zinc, Zwidevertices, "centrums frozen due to extra vertices", -1); - zzdef_(zinc, Ztotmerge, "total number of facets or cycles of facets merged", -1); - zdef_(zinc, Zmergesimplex, "merged a simplex", -1); - zdef_(zinc, Zonehorizon, "simplices merged into coplanar horizon", -1); - zzdef_(zinc, Zcyclehorizon, "cycles of facets merged into coplanar horizon", -1); - zzdef_(zadd, Zcyclefacettot, " ave. facets per cycle", Zcyclehorizon); - zdef_(zmax, Zcyclefacetmax, " max. facets", -1); - zdef_(zinc, Zmergeintohorizon, "new facets merged into horizon", -1); - zdef_(zinc, Zmergenew, "new facets merged", -1); - zdef_(zinc, Zmergehorizon, "horizon facets merged into new facets", -1); - zdef_(zinc, Zmergevertex, "vertices deleted by merging", -1); - zdef_(zinc, Zcyclevertex, "vertices deleted by merging into coplanar horizon", -1); - zdef_(zinc, Zdegenvertex, "vertices deleted by degenerate facet", -1); - zdef_(zinc, Zmergeflipdup, "merges due to flipped facets in duplicated ridge", -1); - zdef_(zinc, Zneighbor, "merges due to redundant neighbors", -1); - zdef_(zadd, Ztestvneighbor, "non-convex vertex neighbors", -1); -} -void qh_allstatG(void) { - zdef_(zinc, Zacoplanar, "merges due to angle coplanar facets", -1); - zdef_(wadd, Wacoplanartot, " average merge distance", Zacoplanar); - zdef_(wmax, Wacoplanarmax, " maximum merge distance", -1); - zdef_(zinc, Zcoplanar, "merges due to coplanar facets", -1); - zdef_(wadd, Wcoplanartot, " average merge distance", Zcoplanar); - zdef_(wmax, Wcoplanarmax, " maximum merge distance", -1); - zdef_(zinc, Zconcave, "merges due to concave facets", -1); - zdef_(wadd, Wconcavetot, " average merge distance", Zconcave); - zdef_(wmax, Wconcavemax, " maximum merge distance", -1); - zdef_(zinc, Zavoidold, "coplanar/concave merges due to avoiding old merge", -1); - zdef_(wadd, Wavoidoldtot, " average merge distance", Zavoidold); - zdef_(wmax, Wavoidoldmax, " maximum merge distance", -1); - zdef_(zinc, Zdegen, "merges due to degenerate facets", -1); - zdef_(wadd, Wdegentot, " average merge distance", Zdegen); - zdef_(wmax, Wdegenmax, " maximum merge distance", -1); - zdef_(zinc, Zflipped, "merges due to removing flipped facets", -1); - zdef_(wadd, Wflippedtot, " average merge distance", Zflipped); - zdef_(wmax, Wflippedmax, " maximum merge distance", -1); - zdef_(zinc, Zduplicate, "merges due to duplicated ridges", -1); - zdef_(wadd, Wduplicatetot, " average merge distance", Zduplicate); - zdef_(wmax, Wduplicatemax, " maximum merge distance", -1); -} -void qh_allstatH(void) { - zdef_(zdoc, Zdoc8, "renamed vertex statistics", -1); - zdef_(zinc, Zrenameshare, "renamed vertices shared by two facets", -1); - zdef_(zinc, Zrenamepinch, "renamed vertices in a pinched facet", -1); - zdef_(zinc, Zrenameall, "renamed vertices shared by multiple facets", -1); - zdef_(zinc, Zfindfail, "rename failures due to duplicated ridges", -1); - zdef_(zinc, Zdupridge, " duplicate ridges detected", -1); - zdef_(zinc, Zdelridge, "deleted ridges due to renamed vertices", -1); - zdef_(zinc, Zdropneighbor, "dropped neighbors due to renamed vertices", -1); - zdef_(zinc, Zdropdegen, "degenerate facets due to dropped neighbors", -1); - zdef_(zinc, Zdelfacetdup, " facets deleted because of no neighbors", -1); - zdef_(zinc, Zremvertex, "vertices removed from facets due to no ridges", -1); - zdef_(zinc, Zremvertexdel, " deleted", -1); - zdef_(zinc, Zintersectnum, "vertex intersections for locating redundant vertices", -1); - zdef_(zinc, Zintersectfail, "intersections failed to find a redundant vertex", -1); - zdef_(zinc, Zintersect, "intersections found redundant vertices", -1); - zdef_(zadd, Zintersecttot, " ave. number found per vertex", Zintersect); - zdef_(zmax, Zintersectmax, " max. found for a vertex", -1); - zdef_(zinc, Zvertexridge, NULL, -1); - zdef_(zadd, Zvertexridgetot, " ave. number of ridges per tested vertex", Zvertexridge); - zdef_(zmax, Zvertexridgemax, " max. number of ridges per tested vertex", -1); - - zdef_(zdoc, Zdoc10, "memory usage statistics(in bytes)", -1); - zdef_(zadd, Zmemfacets, "for facets and their normals, neighbor and vertex sets", -1); - zdef_(zadd, Zmemvertices, "for vertices and their neighbor sets", -1); - zdef_(zadd, Zmempoints, "for input points and outside and coplanar sets",-1); - zdef_(zadd, Zmemridges, "for ridges and their vertex sets", -1); -} /* allstat */ - -void qh_allstatI(void) { - qhstat vridges= qhstat next; - zzdef_(zdoc, Zdoc11, "Voronoi ridge statistics", -1); - zzdef_(zinc, Zridge, "non-simplicial Voronoi vertices for all ridges", -1); - zzdef_(wadd, Wridge, " ave. distance to ridge", Zridge); - zzdef_(wmax, Wridgemax, " max. distance to ridge", -1); - zzdef_(zinc, Zridgemid, "bounded ridges", -1); - zzdef_(wadd, Wridgemid, " ave. distance of midpoint to ridge", Zridgemid); - zzdef_(wmax, Wridgemidmax, " max. distance of midpoint to ridge", -1); - zzdef_(zinc, Zridgeok, "bounded ridges with ok normal", -1); - zzdef_(wadd, Wridgeok, " ave. angle to ridge", Zridgeok); - zzdef_(wmax, Wridgeokmax, " max. angle to ridge", -1); - zzdef_(zinc, Zridge0, "bounded ridges with near-zero normal", -1); - zzdef_(wadd, Wridge0, " ave. angle to ridge", Zridge0); - zzdef_(wmax, Wridge0max, " max. angle to ridge", -1); - - zdef_(zdoc, Zdoc12, "Triangulation statistics(Qt)", -1); - zdef_(zinc, Ztricoplanar, "non-simplicial facets triangulated", -1); - zdef_(zadd, Ztricoplanartot, " ave. new facets created(may be deleted)", Ztricoplanar); - zdef_(zmax, Ztricoplanarmax, " max. new facets created", -1); - zdef_(zinc, Ztrinull, "null new facets deleted(duplicated vertex)", -1); - zdef_(zinc, Ztrimirror, "mirrored pairs of new facets deleted(same vertices)", -1); - zdef_(zinc, Ztridegen, "degenerate new facets in output(same ridge)", -1); -} /* allstat */ - -/*-<a href="qh-stat.htm#TOC" - >-------------------------------</a><a name="allstatistics">-</a> - - qh_allstatistics() - reset printed flag for all statistics -*/ -void qh_allstatistics(void) { - int i; - - for(i=ZEND; i--; ) - qhstat printed[i]= False; -} /* allstatistics */ - -#if qh_KEEPstatistics -/*-<a href="qh-stat.htm#TOC" - >-------------------------------</a><a name="collectstatistics">-</a> - - qh_collectstatistics() - collect statistics for qh.facet_list - -*/ -void qh_collectstatistics(void) { - facetT *facet, *neighbor, **neighborp; - vertexT *vertex, **vertexp; - realT dotproduct, dist; - int sizneighbors, sizridges, sizvertices, i; - - qh old_randomdist= qh RANDOMdist; - qh RANDOMdist= False; - zval_(Zmempoints)= qh num_points * qh normal_size + - sizeof(qhT) + sizeof(qhstatT); - zval_(Zmemfacets)= 0; - zval_(Zmemridges)= 0; - zval_(Zmemvertices)= 0; - zval_(Zangle)= 0; - wval_(Wangle)= 0.0; - zval_(Znumridges)= 0; - zval_(Znumfacets)= 0; - zval_(Znumneighbors)= 0; - zval_(Znumvertices)= 0; - zval_(Znumvneighbors)= 0; - zval_(Znummergetot)= 0; - zval_(Znummergemax)= 0; - zval_(Zvertices)= qh num_vertices - qh_setsize(qh del_vertices); - if (qh MERGING || qh APPROXhull || qh JOGGLEmax < REALmax/2) - wmax_(Wmaxoutside, qh max_outside); - if (qh MERGING) - wmin_(Wminvertex, qh min_vertex); - FORALLfacets - facet->seen= False; - if (qh DELAUNAY) { - FORALLfacets { - if (facet->upperdelaunay != qh UPPERdelaunay) - facet->seen= True; /* remove from angle statistics */ - } - } - FORALLfacets { - if (facet->visible && qh NEWfacets) - continue; - sizvertices= qh_setsize(facet->vertices); - sizneighbors= qh_setsize(facet->neighbors); - sizridges= qh_setsize(facet->ridges); - zinc_(Znumfacets); - zadd_(Znumvertices, sizvertices); - zmax_(Zmaxvertices, sizvertices); - zadd_(Znumneighbors, sizneighbors); - zmax_(Zmaxneighbors, sizneighbors); - zadd_(Znummergetot, facet->nummerge); - i= facet->nummerge; /* avoid warnings */ - zmax_(Znummergemax, i); - if (!facet->simplicial) { - if (sizvertices == qh hull_dim) { - zinc_(Znowsimplicial); - }else { - zinc_(Znonsimplicial); - } - } - if (sizridges) { - zadd_(Znumridges, sizridges); - zmax_(Zmaxridges, sizridges); - } - zadd_(Zmemfacets, sizeof(facetT) + qh normal_size + 2*sizeof(setT) - + SETelemsize * (sizneighbors + sizvertices)); - if (facet->ridges) { - zadd_(Zmemridges, - sizeof(setT) + SETelemsize * sizridges + sizridges * - (sizeof(ridgeT) + sizeof(setT) + SETelemsize * (qh hull_dim-1))/2); - } - if (facet->outsideset) - zadd_(Zmempoints, sizeof(setT) + SETelemsize * qh_setsize(facet->outsideset)); - if (facet->coplanarset) - zadd_(Zmempoints, sizeof(setT) + SETelemsize * qh_setsize(facet->coplanarset)); - if (facet->seen) /* Delaunay upper envelope */ - continue; - facet->seen= True; - FOREACHneighbor_(facet) { - if (neighbor == qh_DUPLICATEridge || neighbor == qh_MERGEridge - || neighbor->seen || !facet->normal || !neighbor->normal) - continue; - dotproduct= qh_getangle(facet->normal, neighbor->normal); - zinc_(Zangle); - wadd_(Wangle, dotproduct); - wmax_(Wanglemax, dotproduct) - wmin_(Wanglemin, dotproduct) - } - if (facet->normal) { - FOREACHvertex_(facet->vertices) { - zinc_(Zdiststat); - qh_distplane(vertex->point, facet, &dist); - wmax_(Wvertexmax, dist); - wmin_(Wvertexmin, dist); - } - } - } - FORALLvertices { - if (vertex->deleted) - continue; - zadd_(Zmemvertices, sizeof(vertexT)); - if (vertex->neighbors) { - sizneighbors= qh_setsize(vertex->neighbors); - zadd_(Znumvneighbors, sizneighbors); - zmax_(Zmaxvneighbors, sizneighbors); - zadd_(Zmemvertices, sizeof(vertexT) + SETelemsize * sizneighbors); - } - } - qh RANDOMdist= qh old_randomdist; -} /* collectstatistics */ -#endif /* qh_KEEPstatistics */ - -/*-<a href="qh-stat.htm#TOC" - >-------------------------------</a><a name="freestatistics">-</a> - - qh_freestatistics( ) - free memory used for statistics -*/ -void qh_freestatistics(void) { - -#if qh_QHpointer - qh_free(qh_qhstat); - qh_qhstat= NULL; -#endif -} /* freestatistics */ - -/*-<a href="qh-stat.htm#TOC" - >-------------------------------</a><a name="initstatistics">-</a> - - qh_initstatistics( ) - allocate and initialize statistics - - notes: - uses qh_malloc() instead of qh_memalloc() since mem.c not set up yet - NOerrors -- qh_initstatistics can not use qh_errexit(). One first call, qh_memalloc is not initialized. Also invoked by QhullQh(). -*/ -void qh_initstatistics(void) { - int i; - realT realx; - int intx; - -#if qh_QHpointer - if(qh_qhstat){ /* qh_initstatistics may be called from Qhull::resetStatistics() */ - qh_free(qh_qhstat); - qh_qhstat= 0; - } - if (!(qh_qhstat= (qhstatT *)qh_malloc(sizeof(qhstatT)))) { - qh_fprintf(qhmem.ferr, 6183, "qhull error (qh_initstatistics): insufficient memory\n"); - qh_exit(qh_ERRmem); /* can not use qh_errexit() */ - } -#endif - - qhstat next= 0; - qh_allstatA(); - qh_allstatB(); - qh_allstatC(); - qh_allstatD(); - qh_allstatE(); - qh_allstatE2(); - qh_allstatF(); - qh_allstatG(); - qh_allstatH(); - qh_allstatI(); - if (qhstat next > (int)sizeof(qhstat id)) { - qh_fprintf(qhmem.ferr, 6184, "qhull error (qh_initstatistics): increase size of qhstat.id[].\n\ - qhstat.next %d should be <= sizeof(qhstat id) %d\n", qhstat next, (int)sizeof(qhstat id)); -#if 0 /* for locating error, Znumridges should be duplicated */ - for(i=0; i < ZEND; i++) { - int j; - for(j=i+1; j < ZEND; j++) { - if (qhstat id[i] == qhstat id[j]) { - qh_fprintf(qhmem.ferr, 6185, "qhull error (qh_initstatistics): duplicated statistic %d at indices %d and %d\n", - qhstat id[i], i, j); - } - } - } -#endif - qh_exit(qh_ERRqhull); /* can not use qh_errexit() */ - } - qhstat init[zinc].i= 0; - qhstat init[zadd].i= 0; - qhstat init[zmin].i= INT_MAX; - qhstat init[zmax].i= INT_MIN; - qhstat init[wadd].r= 0; - qhstat init[wmin].r= REALmax; - qhstat init[wmax].r= -REALmax; - for(i=0; i < ZEND; i++) { - if (qhstat type[i] > ZTYPEreal) { - realx= qhstat init[(unsigned char)(qhstat type[i])].r; - qhstat stats[i].r= realx; - }else if (qhstat type[i] != zdoc) { - intx= qhstat init[(unsigned char)(qhstat type[i])].i; - qhstat stats[i].i= intx; - } - } -} /* initstatistics */ - -/*-<a href="qh-stat.htm#TOC" - >-------------------------------</a><a name="newstats">-</a> - - qh_newstats( ) - returns True if statistics for zdoc - - returns: - next zdoc -*/ -boolT qh_newstats(int idx, int *nextindex) { - boolT isnew= False; - int start, i; - - if (qhstat type[qhstat id[idx]] == zdoc) - start= idx+1; - else - start= idx; - for(i= start; i < qhstat next && qhstat type[qhstat id[i]] != zdoc; i++) { - if (!qh_nostatistic(qhstat id[i]) && !qhstat printed[qhstat id[i]]) - isnew= True; - } - *nextindex= i; - return isnew; -} /* newstats */ - -/*-<a href="qh-stat.htm#TOC" - >-------------------------------</a><a name="nostatistic">-</a> - - qh_nostatistic( index ) - true if no statistic to print -*/ -boolT qh_nostatistic(int i) { - - if ((qhstat type[i] > ZTYPEreal - &&qhstat stats[i].r == qhstat init[(unsigned char)(qhstat type[i])].r) - || (qhstat type[i] < ZTYPEreal - &&qhstat stats[i].i == qhstat init[(unsigned char)(qhstat type[i])].i)) - return True; - return False; -} /* nostatistic */ - -#if qh_KEEPstatistics -/*-<a href="qh-stat.htm#TOC" - >-------------------------------</a><a name="printallstatistics">-</a> - - qh_printallstatistics( fp, string ) - print all statistics with header 'string' -*/ -void qh_printallstatistics(FILE *fp, const char *string) { - - qh_allstatistics(); - qh_collectstatistics(); - qh_printstatistics(fp, string); - qh_memstatistics(fp); -} - - -/*-<a href="qh-stat.htm#TOC" - >-------------------------------</a><a name="printstatistics">-</a> - - qh_printstatistics( fp, string ) - print statistics to a file with header 'string' - skips statistics with qhstat.printed[] (reset with qh_allstatistics) - - see: - qh_printallstatistics() -*/ -void qh_printstatistics(FILE *fp, const char *string) { - int i, k; - realT ave; - - if (qh num_points != qh num_vertices) { - wval_(Wpbalance)= 0; - wval_(Wpbalance2)= 0; - }else - wval_(Wpbalance2)= qh_stddev(zval_(Zpbalance), wval_(Wpbalance), - wval_(Wpbalance2), &ave); - wval_(Wnewbalance2)= qh_stddev(zval_(Zprocessed), wval_(Wnewbalance), - wval_(Wnewbalance2), &ave); - qh_fprintf(fp, 9350, "\n\ -%s\n\ - qhull invoked by: %s | %s\n%s with options:\n%s\n", string, qh rbox_command, - qh qhull_command, qh_version, qh qhull_options); - qh_fprintf(fp, 9351, "\nprecision constants:\n\ - %6.2g max. abs. coordinate in the (transformed) input('Qbd:n')\n\ - %6.2g max. roundoff error for distance computation('En')\n\ - %6.2g max. roundoff error for angle computations\n\ - %6.2g min. distance for outside points ('Wn')\n\ - %6.2g min. distance for visible facets ('Vn')\n\ - %6.2g max. distance for coplanar facets ('Un')\n\ - %6.2g max. facet width for recomputing centrum and area\n\ -", - qh MAXabs_coord, qh DISTround, qh ANGLEround, qh MINoutside, - qh MINvisible, qh MAXcoplanar, qh WIDEfacet); - if (qh KEEPnearinside) - qh_fprintf(fp, 9352, "\ - %6.2g max. distance for near-inside points\n", qh NEARinside); - if (qh premerge_cos < REALmax/2) qh_fprintf(fp, 9353, "\ - %6.2g max. cosine for pre-merge angle\n", qh premerge_cos); - if (qh PREmerge) qh_fprintf(fp, 9354, "\ - %6.2g radius of pre-merge centrum\n", qh premerge_centrum); - if (qh postmerge_cos < REALmax/2) qh_fprintf(fp, 9355, "\ - %6.2g max. cosine for post-merge angle\n", qh postmerge_cos); - if (qh POSTmerge) qh_fprintf(fp, 9356, "\ - %6.2g radius of post-merge centrum\n", qh postmerge_centrum); - qh_fprintf(fp, 9357, "\ - %6.2g max. distance for merging two simplicial facets\n\ - %6.2g max. roundoff error for arithmetic operations\n\ - %6.2g min. denominator for divisions\n\ - zero diagonal for Gauss: ", qh ONEmerge, REALepsilon, qh MINdenom); - for(k=0; k < qh hull_dim; k++) - qh_fprintf(fp, 9358, "%6.2e ", qh NEARzero[k]); - qh_fprintf(fp, 9359, "\n\n"); - for(i=0 ; i < qhstat next; ) - qh_printstats(fp, i, &i); -} /* printstatistics */ -#endif /* qh_KEEPstatistics */ - -/*-<a href="qh-stat.htm#TOC" - >-------------------------------</a><a name="printstatlevel">-</a> - - qh_printstatlevel( fp, id ) - print level information for a statistic - - notes: - nop if id >= ZEND, printed, or same as initial value -*/ -void qh_printstatlevel(FILE *fp, int id, int start) { -#define NULLfield " " - - if (id >= ZEND || qhstat printed[id]) - return; - if (qhstat type[id] == zdoc) { - qh_fprintf(fp, 9360, "%s\n", qhstat doc[id]); - return; - } - start= 0; /* not used */ - if (qh_nostatistic(id) || !qhstat doc[id]) - return; - qhstat printed[id]= True; - if (qhstat count[id] != -1 - && qhstat stats[(unsigned char)(qhstat count[id])].i == 0) - qh_fprintf(fp, 9361, " *0 cnt*"); - else if (qhstat type[id] >= ZTYPEreal && qhstat count[id] == -1) - qh_fprintf(fp, 9362, "%7.2g", qhstat stats[id].r); - else if (qhstat type[id] >= ZTYPEreal && qhstat count[id] != -1) - qh_fprintf(fp, 9363, "%7.2g", qhstat stats[id].r/ qhstat stats[(unsigned char)(qhstat count[id])].i); - else if (qhstat type[id] < ZTYPEreal && qhstat count[id] == -1) - qh_fprintf(fp, 9364, "%7d", qhstat stats[id].i); - else if (qhstat type[id] < ZTYPEreal && qhstat count[id] != -1) - qh_fprintf(fp, 9365, "%7.3g", (realT) qhstat stats[id].i / qhstat stats[(unsigned char)(qhstat count[id])].i); - qh_fprintf(fp, 9366, " %s\n", qhstat doc[id]); -} /* printstatlevel */ - - -/*-<a href="qh-stat.htm#TOC" - >-------------------------------</a><a name="printstats">-</a> - - qh_printstats( fp, index, nextindex ) - print statistics for a zdoc group - - returns: - next zdoc if non-null -*/ -void qh_printstats(FILE *fp, int idx, int *nextindex) { - int j, nexti; - - if (qh_newstats(idx, &nexti)) { - qh_fprintf(fp, 9367, "\n"); - for (j=idx; j<nexti; j++) - qh_printstatlevel(fp, qhstat id[j], 0); - } - if (nextindex) - *nextindex= nexti; -} /* printstats */ - -#if qh_KEEPstatistics - -/*-<a href="qh-stat.htm#TOC" - >-------------------------------</a><a name="stddev">-</a> - - qh_stddev( num, tot, tot2, ave ) - compute the standard deviation and average from statistics - - tot2 is the sum of the squares - notes: - computes r.m.s.: - (x-ave)^2 - == x^2 - 2x tot/num + (tot/num)^2 - == tot2 - 2 tot tot/num + tot tot/num - == tot2 - tot ave -*/ -realT qh_stddev(int num, realT tot, realT tot2, realT *ave) { - realT stddev; - - *ave= tot/num; - stddev= sqrt(tot2/num - *ave * *ave); - return stddev; -} /* stddev */ - -#endif /* qh_KEEPstatistics */ - -#if !qh_KEEPstatistics -void qh_collectstatistics(void) {} -void qh_printallstatistics(FILE *fp, char *string) {}; -void qh_printstatistics(FILE *fp, char *string) {} -#endif - diff --git a/PyMca/Object3D/Object3DQhull/src/stat.h b/PyMca/Object3D/Object3DQhull/src/stat.h deleted file mode 100644 index 97d8efa..0000000 --- a/PyMca/Object3D/Object3DQhull/src/stat.h +++ /dev/null @@ -1,541 +0,0 @@ -/*<html><pre> -<a href="qh-stat.htm" - >-------------------------------</a><a name="TOP">-</a> - - stat.h - contains all statistics that are collected for qhull - - see qh-stat.htm and stat.c - - Copyright (c) 1993-2012 The Geometry Center. - $Id: //main/2011/qhull/src/libqhull/stat.h#5 $$Change: 1464 $ - $DateTime: 2012/01/25 22:58:41 $$Author: bbarber $ - - recompile qhull if you change this file - - Integer statistics are Z* while real statistics are W*. - - define maydebugx to call a routine at every statistic event - -*/ - -#ifndef qhDEFstat -#define qhDEFstat 1 - -#include "libqhull.h" - -/*-<a href="qh-stat.htm#TOC" - >-------------------------------</a><a name="KEEPstatistics">-</a> - - qh_KEEPstatistics - 0 turns off statistic gathering (except zzdef/zzinc/zzadd/zzval/wwval) -*/ -#ifndef qh_KEEPstatistics -#define qh_KEEPstatistics 1 -#endif - -/*-<a href="qh-stat.htm#TOC" - >-------------------------------</a><a name="statistics">-</a> - - Zxxx for integers, Wxxx for reals - - notes: - be sure that all statistics are defined in stat.c - otherwise initialization may core dump - can pick up all statistics by: - grep '[zw].*_[(][ZW]' *.c >z.x - remove trailers with query">-</a> - remove leaders with query-replace-regexp [ ^I]+ ( -*/ -#if qh_KEEPstatistics -enum statistics { /* alphabetical after Z/W */ - Zacoplanar, - Wacoplanarmax, - Wacoplanartot, - Zangle, - Wangle, - Wanglemax, - Wanglemin, - Zangletests, - Wareatot, - Wareamax, - Wareamin, - Zavoidold, - Wavoidoldmax, - Wavoidoldtot, - Zback0, - Zbestcentrum, - Zbestdist, - Zbestlower, - Zbestlowerv, - Zcentrumtests, - Zcheckpart, - Zcomputefurthest, - Zconcave, - Wconcavemax, - Wconcavetot, - Zconcaveridges, - Zconcaveridge, - Zcoplanar, - Wcoplanarmax, - Wcoplanartot, - Zcoplanarangle, - Zcoplanarcentrum, - Zcoplanarhorizon, - Zcoplanarinside, - Zcoplanarpart, - Zcoplanarridges, - Wcpu, - Zcyclefacetmax, - Zcyclefacettot, - Zcyclehorizon, - Zcyclevertex, - Zdegen, - Wdegenmax, - Wdegentot, - Zdegenvertex, - Zdelfacetdup, - Zdelridge, - Zdelvertextot, - Zdelvertexmax, - Zdetsimplex, - Zdistcheck, - Zdistconvex, - Zdistgood, - Zdistio, - Zdistplane, - Zdiststat, - Zdistvertex, - Zdistzero, - Zdoc1, - Zdoc2, - Zdoc3, - Zdoc4, - Zdoc5, - Zdoc6, - Zdoc7, - Zdoc8, - Zdoc9, - Zdoc10, - Zdoc11, - Zdoc12, - Zdropdegen, - Zdropneighbor, - Zdupflip, - Zduplicate, - Wduplicatemax, - Wduplicatetot, - Zdupridge, - Zdupsame, - Zflipped, - Wflippedmax, - Wflippedtot, - Zflippedfacets, - Zfindbest, - Zfindbestmax, - Zfindbesttot, - Zfindcoplanar, - Zfindfail, - Zfindhorizon, - Zfindhorizonmax, - Zfindhorizontot, - Zfindjump, - Zfindnew, - Zfindnewmax, - Zfindnewtot, - Zfindnewjump, - Zfindnewsharp, - Zgauss0, - Zgoodfacet, - Zhashlookup, - Zhashridge, - Zhashridgetest, - Zhashtests, - Zinsidevisible, - Zintersect, - Zintersectfail, - Zintersectmax, - Zintersectnum, - Zintersecttot, - Zmaxneighbors, - Wmaxout, - Wmaxoutside, - Zmaxridges, - Zmaxvertex, - Zmaxvertices, - Zmaxvneighbors, - Zmemfacets, - Zmempoints, - Zmemridges, - Zmemvertices, - Zmergeflipdup, - Zmergehorizon, - Zmergeinittot, - Zmergeinitmax, - Zmergeinittot2, - Zmergeintohorizon, - Zmergenew, - Zmergesettot, - Zmergesetmax, - Zmergesettot2, - Zmergesimplex, - Zmergevertex, - Wmindenom, - Wminvertex, - Zminnorm, - Zmultiridge, - Znearlysingular, - Zneighbor, - Wnewbalance, - Wnewbalance2, - Znewfacettot, - Znewfacetmax, - Znewvertex, - Wnewvertex, - Wnewvertexmax, - Znoarea, - Znonsimplicial, - Znowsimplicial, - Znotgood, - Znotgoodnew, - Znotmax, - Znumfacets, - Znummergemax, - Znummergetot, - Znumneighbors, - Znumridges, - Znumvertices, - Znumvisibility, - Znumvneighbors, - Zonehorizon, - Zpartangle, - Zpartcoplanar, - Zpartflip, - Zparthorizon, - Zpartinside, - Zpartition, - Zpartitionall, - Zpartnear, - Zpbalance, - Wpbalance, - Wpbalance2, - Zpostfacets, - Zpremergetot, - Zprocessed, - Zremvertex, - Zremvertexdel, - Zrenameall, - Zrenamepinch, - Zrenameshare, - Zretry, - Wretrymax, - Zridge, - Wridge, - Wridgemax, - Zridge0, - Wridge0, - Wridge0max, - Zridgemid, - Wridgemid, - Wridgemidmax, - Zridgeok, - Wridgeok, - Wridgeokmax, - Zsearchpoints, - Zsetplane, - Ztestvneighbor, - Ztotcheck, - Ztothorizon, - Ztotmerge, - Ztotpartcoplanar, - Ztotpartition, - Ztotridges, - Ztotvertices, - Ztotvisible, - Ztricoplanar, - Ztricoplanarmax, - Ztricoplanartot, - Ztridegen, - Ztrimirror, - Ztrinull, - Wvertexmax, - Wvertexmin, - Zvertexridge, - Zvertexridgetot, - Zvertexridgemax, - Zvertices, - Zvisfacettot, - Zvisfacetmax, - Zvisit, - Zvisit2max, - Zvisvertextot, - Zvisvertexmax, - Zvvisit, - Zvvisit2max, - Zwidefacet, - Zwidevertices, - ZEND}; - -/*-<a href="qh-stat.htm#TOC" - >-------------------------------</a><a name="ZZstat">-</a> - - Zxxx/Wxxx statistics that remain defined if qh_KEEPstatistics=0 - - notes: - be sure to use zzdef, zzinc, etc. with these statistics (no double checking!) -*/ -#else -enum statistics { /* for zzdef etc. macros */ - Zback0, - Zbestdist, - Zcentrumtests, - Zcheckpart, - Zconcaveridges, - Zcoplanarhorizon, - Zcoplanarpart, - Zcoplanarridges, - Zcyclefacettot, - Zcyclehorizon, - Zdelvertextot, - Zdistcheck, - Zdistconvex, - Zdistzero, - Zdoc1, - Zdoc2, - Zdoc3, - Zdoc11, - Zflippedfacets, - Zgauss0, - Zminnorm, - Zmultiridge, - Znearlysingular, - Wnewvertexmax, - Znumvisibility, - Zpartcoplanar, - Zpartition, - Zpartitionall, - Zprocessed, - Zretry, - Zridge, - Wridge, - Wridgemax, - Zridge0, - Wridge0, - Wridge0max, - Zridgemid, - Wridgemid, - Wridgemidmax, - Zridgeok, - Wridgeok, - Wridgeokmax, - Zsetplane, - Ztotcheck, - Ztotmerge, - ZEND}; -#endif - -/*-<a href="qh-stat.htm#TOC" - >-------------------------------</a><a name="ztype">-</a> - - ztype - the type of a statistic sets its initial value. - - notes: - The type should be the same as the macro for collecting the statistic -*/ -enum ztypes {zdoc,zinc,zadd,zmax,zmin,ZTYPEreal,wadd,wmax,wmin,ZTYPEend}; - -/*========== macros and constants =============*/ - -/*-<a href="qh-stat.htm#TOC" - >--------------------------------</a><a name="MAYdebugx">-</a> - - MAYdebugx - define as maydebug() to be called frequently for error trapping -*/ -#define MAYdebugx - -/*-<a href="qh-stat.htm#TOC" - >--------------------------------</a><a name="zdef_">-</a> - - zzdef_, zdef_( type, name, doc, -1) - define a statistic (assumes 'qhstat.next= 0;') - - zdef_( type, name, doc, count) - define an averaged statistic - printed as name/count -*/ -#define zzdef_(stype,name,string,cnt) qhstat id[qhstat next++]=name; \ - qhstat doc[name]= string; qhstat count[name]= cnt; qhstat type[name]= stype -#if qh_KEEPstatistics -#define zdef_(stype,name,string,cnt) qhstat id[qhstat next++]=name; \ - qhstat doc[name]= string; qhstat count[name]= cnt; qhstat type[name]= stype -#else -#define zdef_(type,name,doc,count) -#endif - -/*-<a href="qh-stat.htm#TOC" - >--------------------------------</a><a name="zinc_">-</a> - - zzinc_( name ), zinc_( name) - increment an integer statistic -*/ -#define zzinc_(id) {MAYdebugx; qhstat stats[id].i++;} -#if qh_KEEPstatistics -#define zinc_(id) {MAYdebugx; qhstat stats[id].i++;} -#else -#define zinc_(id) {} -#endif - -/*-<a href="qh-stat.htm#TOC" - >--------------------------------</a><a name="zadd_">-</a> - - zzadd_( name, value ), zadd_( name, value ), wadd_( name, value ) - add value to an integer or real statistic -*/ -#define zzadd_(id, val) {MAYdebugx; qhstat stats[id].i += (val);} -#define wwadd_(id, val) {MAYdebugx; qhstat stats[id].r += (val);} -#if qh_KEEPstatistics -#define zadd_(id, val) {MAYdebugx; qhstat stats[id].i += (val);} -#define wadd_(id, val) {MAYdebugx; qhstat stats[id].r += (val);} -#else -#define zadd_(id, val) {} -#define wadd_(id, val) {} -#endif - -/*-<a href="qh-stat.htm#TOC" - >--------------------------------</a><a name="zval_">-</a> - - zzval_( name ), zval_( name ), wwval_( name ) - set or return value of a statistic -*/ -#define zzval_(id) ((qhstat stats[id]).i) -#define wwval_(id) ((qhstat stats[id]).r) -#if qh_KEEPstatistics -#define zval_(id) ((qhstat stats[id]).i) -#define wval_(id) ((qhstat stats[id]).r) -#else -#define zval_(id) qhstat tempi -#define wval_(id) qhstat tempr -#endif - -/*-<a href="qh-stat.htm#TOC" - >--------------------------------</a><a name="zmax_">-</a> - - zmax_( id, val ), wmax_( id, value ) - maximize id with val -*/ -#define wwmax_(id, val) {MAYdebugx; maximize_(qhstat stats[id].r,(val));} -#if qh_KEEPstatistics -#define zmax_(id, val) {MAYdebugx; maximize_(qhstat stats[id].i,(val));} -#define wmax_(id, val) {MAYdebugx; maximize_(qhstat stats[id].r,(val));} -#else -#define zmax_(id, val) {} -#define wmax_(id, val) {} -#endif - -/*-<a href="qh-stat.htm#TOC" - >--------------------------------</a><a name="zmin_">-</a> - - zmin_( id, val ), wmin_( id, value ) - minimize id with val -*/ -#if qh_KEEPstatistics -#define zmin_(id, val) {MAYdebugx; minimize_(qhstat stats[id].i,(val));} -#define wmin_(id, val) {MAYdebugx; minimize_(qhstat stats[id].r,(val));} -#else -#define zmin_(id, val) {} -#define wmin_(id, val) {} -#endif - -/*================== stat.h types ==============*/ - - -/*-<a href="qh-stat.htm#TOC" - >--------------------------------</a><a name="intrealT">-</a> - - intrealT - union of integer and real, used for statistics -*/ -typedef union intrealT intrealT; /* union of int and realT */ -union intrealT { - int i; - realT r; -}; - -/*-<a href="qh-stat.htm#TOC" - >--------------------------------</a><a name="qhstat">-</a> - - qhstat - global data structure for statistics, similar to qh and qhrbox - - notes: - access to qh_qhstat is via the "qhstat" macro. There are two choices - qh_QHpointer = 1 access globals via a pointer - enables qh_saveqhull() and qh_restoreqhull() - = 0 qh_qhstat is a static data structure - only one instance of qhull() can be active at a time - default value - qh_QHpointer is defined in libqhull.h - qh_QHpointer_dllimport and qh_dllimport define qh_qh as __declspec(dllimport) [libqhull.h] - - allocated in stat.c using qh_malloc() -*/ -#ifndef DEFqhstatT -#define DEFqhstatT 1 -typedef struct qhstatT qhstatT; -#endif - -#if qh_QHpointer_dllimport -#define qhstat qh_qhstat-> -__declspec(dllimport) extern qhstatT *qh_qhstat; -#elif qh_QHpointer -#define qhstat qh_qhstat-> -extern qhstatT *qh_qhstat; -#elif qh_dllimport -#define qhstat qh_qhstat. -__declspec(dllimport) extern qhstatT qh_qhstat; -#else -#define qhstat qh_qhstat. -extern qhstatT qh_qhstat; -#endif -struct qhstatT { - intrealT stats[ZEND]; /* integer and real statistics */ - unsigned char id[ZEND+10]; /* id's in print order */ - const char *doc[ZEND]; /* array of documentation strings */ - short int count[ZEND]; /* -1 if none, else index of count to use */ - char type[ZEND]; /* type, see ztypes above */ - char printed[ZEND]; /* true, if statistic has been printed */ - intrealT init[ZTYPEend]; /* initial values by types, set initstatistics */ - - int next; /* next index for zdef_ */ - int precision; /* index for precision problems */ - int vridges; /* index for Voronoi ridges */ - int tempi; - realT tempr; -}; - -/*========== function prototypes ===========*/ - -void qh_allstatA(void); -void qh_allstatB(void); -void qh_allstatC(void); -void qh_allstatD(void); -void qh_allstatE(void); -void qh_allstatE2(void); -void qh_allstatF(void); -void qh_allstatG(void); -void qh_allstatH(void); -void qh_allstatI(void); -void qh_allstatistics(void); -void qh_collectstatistics(void); -void qh_freestatistics(void); -void qh_initstatistics(void); -boolT qh_newstats(int idx, int *nextindex); -boolT qh_nostatistic(int i); -void qh_printallstatistics(FILE *fp, const char *string); -void qh_printstatistics(FILE *fp, const char *string); -void qh_printstatlevel(FILE *fp, int id, int start); -void qh_printstats(FILE *fp, int idx, int *nextindex); -realT qh_stddev(int num, realT tot, realT tot2, realT *ave); - -#endif /* qhDEFstat */ diff --git a/PyMca/Object3D/Object3DQhull/src/user.c b/PyMca/Object3D/Object3DQhull/src/user.c deleted file mode 100644 index 653c5a4..0000000 --- a/PyMca/Object3D/Object3DQhull/src/user.c +++ /dev/null @@ -1,527 +0,0 @@ -/*<html><pre> -<a href="qh-user.htm" - >-------------------------------</a><a name="TOP">-</a> - - user.c - user redefinable functions - - see user2.c for qh_fprintf, qh_malloc, qh_free - - see README.txt see COPYING.txt for copyright information. - - see libqhull.h for data structures, macros, and user-callable functions. - - see user_eg.c, unix.c, and qhull_interface.cpp for examples. - - see user.h for user-definable constants - - use qh_NOmem in mem.h to turn off memory management - use qh_NOmerge in user.h to turn off facet merging - set qh_KEEPstatistics in user.h to 0 to turn off statistics - - This is unsupported software. You're welcome to make changes, - but you're on your own if something goes wrong. Use 'Tc' to - check frequently. Usually qhull will report an error if - a data structure becomes inconsistent. If so, it also reports - the last point added to the hull, e.g., 102. You can then trace - the execution of qhull with "T4P102". - - Please report any errors that you fix to qhull@qhull.org - - call_qhull is a template for calling qhull from within your application - - if you recompile and load this module, then user.o will not be loaded - from qhull.a - - you can add additional quick allocation sizes in qh_user_memsizes - - if the other functions here are redefined to not use qh_print..., - then io.o will not be loaded from qhull.a. See user_eg.c for an - example. We recommend keeping io.o for the extra debugging - information it supplies. -*/ - -#include "qhull_a.h" - -#include <stdarg.h> - -/*-<a href="qh-user.htm#TOC" - >-------------------------------</a><a name="call_qhull">-</a> - - qh_call_qhull( void ) - template for calling qhull from inside your program - remove #if 0, #endif to compile - - returns: - exit code(see qh_ERR... in libqhull.h) - all memory freed - - notes: - This can be called any number of times. - - see: - qh_call_qhull_once() - -*/ -#if 0 -{ - int dim; /* dimension of points */ - int numpoints; /* number of points */ - coordT *points; /* array of coordinates for each point */ - boolT ismalloc; /* True if qhull should free points in qh_freeqhull() or reallocation */ - char flags[]= "qhull Tv"; /* option flags for qhull, see qh_opt.htm */ - FILE *outfile= stdout; /* output from qh_produce_output() - use NULL to skip qh_produce_output() */ - FILE *errfile= stderr; /* error messages from qhull code */ - int exitcode; /* 0 if no error from qhull */ - facetT *facet; /* set by FORALLfacets */ - int curlong, totlong; /* memory remaining after qh_memfreeshort */ - -#if qh_QHpointer /* see user.h */ - if (qh_qh){ - printf ("QH6238: Qhull link error. The global variable qh_qh was not initialized\n\ - to NULL by global.c. Please compile this program with -Dqh_QHpointer_dllimport\n\ - as well as -Dqh_QHpointer, or use libqhullstatic, or use a different tool chain.\n\n"); - exit -1; - } -#endif - - /* initialize dim, numpoints, points[], ismalloc here */ - exitcode= qh_new_qhull(dim, numpoints, points, ismalloc, - flags, outfile, errfile); - if (!exitcode) { /* if no error */ - /* 'qh facet_list' contains the convex hull */ - FORALLfacets { - /* ... your code ... */ - } - } - qh_freeqhull(!qh_ALL); - qh_memfreeshort(&curlong, &totlong); - if (curlong || totlong) - qh_fprintf(errfile, 7068, "qhull internal warning (main): did not free %d bytes of long memory(%d pieces)\n", totlong, curlong); -} -#endif - -/*-<a href="qh-user.htm#TOC" - >-------------------------------</a><a name="new_qhull">-</a> - - qh_new_qhull( dim, numpoints, points, ismalloc, qhull_cmd, outfile, errfile ) - build new qhull data structure and return exitcode (0 if no errors) - - notes: - do not modify points until finished with results. - The qhull data structure contains pointers into the points array. - do not call qhull functions before qh_new_qhull(). - The qhull data structure is not initialized until qh_new_qhull(). - - outfile may be null - qhull_cmd must start with "qhull " - projects points to a new point array for Delaunay triangulations ('d' and 'v') - transforms points into a new point array for halfspace intersection ('H') - - - To allow multiple, concurrent calls to qhull() - - set qh_QHpointer in user.h - - use qh_save_qhull and qh_restore_qhull to swap the global data structure between calls. - - use qh_freeqhull(qh_ALL) to free intermediate convex hulls - - see: - user_eg.c for an example -*/ -int qh_new_qhull(int dim, int numpoints, coordT *points, boolT ismalloc, - char *qhull_cmd, FILE *outfile, FILE *errfile) { - int exitcode, hulldim; - boolT new_ismalloc; - static boolT firstcall = True; - coordT *new_points; - - if (firstcall) { - qh_meminit(errfile); - firstcall= False; - } - if (strncmp(qhull_cmd,"qhull ", (size_t)6)) { - qh_fprintf(errfile, 6186, "qhull error (qh_new_qhull): start qhull_cmd argument with \"qhull \"\n"); - qh_exit(qh_ERRinput); - } - qh_initqhull_start(NULL, outfile, errfile); - trace1((qh ferr, 1044, "qh_new_qhull: build new Qhull for %d %d-d points with %s\n", numpoints, dim, qhull_cmd)); - exitcode = setjmp(qh errexit); - if (!exitcode) - { - qh NOerrexit = False; - qh_initflags(qhull_cmd); - if (qh DELAUNAY) - qh PROJECTdelaunay= True; - if (qh HALFspace) { - /* points is an array of halfspaces, - the last coordinate of each halfspace is its offset */ - hulldim= dim-1; - qh_setfeasible(hulldim); - new_points= qh_sethalfspace_all(dim, numpoints, points, qh feasible_point); - new_ismalloc= True; - if (ismalloc) - qh_free(points); - }else { - hulldim= dim; - new_points= points; - new_ismalloc= ismalloc; - } - qh_init_B(new_points, numpoints, hulldim, new_ismalloc); - qh_qhull(); - qh_check_output(); - if (outfile) { - qh_produce_output(); - }else { - qh_prepare_output(); - } - if (qh VERIFYoutput && !qh STOPpoint && !qh STOPcone) - qh_check_points(); - } - qh NOerrexit = True; - return exitcode; -} /* new_qhull */ - -/*-<a href="qh-user.htm#TOC" - >-------------------------------</a><a name="errexit">-</a> - - qh_errexit( exitcode, facet, ridge ) - report and exit from an error - report facet and ridge if non-NULL - reports useful information such as last point processed - set qh.FORCEoutput to print neighborhood of facet - - see: - qh_errexit2() in libqhull.c for printing 2 facets - - design: - check for error within error processing - compute qh.hulltime - print facet and ridge (if any) - report commandString, options, qh.furthest_id - print summary and statistics (including precision statistics) - if qh_ERRsingular - print help text for singular data set - exit program via long jump (if defined) or exit() -*/ -void qh_errexit(int exitcode, facetT *facet, ridgeT *ridge) { - - if (qh ERREXITcalled) { - qh_fprintf(qh ferr, 8126, "\nqhull error while processing previous error. Exit program\n"); - qh_exit(qh_ERRqhull); - } - qh ERREXITcalled= True; - if (!qh QHULLfinished) - qh hulltime= qh_CPUclock - qh hulltime; - qh_errprint("ERRONEOUS", facet, NULL, ridge, NULL); - qh_fprintf(qh ferr, 8127, "\nWhile executing: %s | %s\n", qh rbox_command, qh qhull_command); - qh_fprintf(qh ferr, 8128, "Options selected for Qhull %s:\n%s\n", qh_version, qh qhull_options); - if (qh furthest_id >= 0) { - qh_fprintf(qh ferr, 8129, "Last point added to hull was p%d.", qh furthest_id); - if (zzval_(Ztotmerge)) - qh_fprintf(qh ferr, 8130, " Last merge was #%d.", zzval_(Ztotmerge)); - if (qh QHULLfinished) - qh_fprintf(qh ferr, 8131, "\nQhull has finished constructing the hull."); - else if (qh POSTmerging) - qh_fprintf(qh ferr, 8132, "\nQhull has started post-merging."); - qh_fprintf(qh ferr, 8133, "\n"); - } - if (qh FORCEoutput && (qh QHULLfinished || (!facet && !ridge))) - qh_produce_output(); - else if (exitcode != qh_ERRinput) { - if (exitcode != qh_ERRsingular && zzval_(Zsetplane) > qh hull_dim+1) { - qh_fprintf(qh ferr, 8134, "\nAt error exit:\n"); - qh_printsummary(qh ferr); - if (qh PRINTstatistics) { - qh_collectstatistics(); - qh_printstatistics(qh ferr, "at error exit"); - qh_memstatistics(qh ferr); - } - } - if (qh PRINTprecision) - qh_printstats(qh ferr, qhstat precision, NULL); - } - if (!exitcode) - exitcode= qh_ERRqhull; - else if (exitcode == qh_ERRsingular) - qh_printhelp_singular(qh ferr); - else if (exitcode == qh_ERRprec && !qh PREmerge) - qh_printhelp_degenerate(qh ferr); - if (qh NOerrexit) { - qh_fprintf(qh ferr, 6187, "qhull error while ending program. Exit program\n"); - qh_exit(qh_ERRqhull); - } - qh ERREXITcalled= False; - qh NOerrexit= True; - longjmp(qh errexit, exitcode); -} /* errexit */ - - -/*-<a href="qh-user.htm#TOC" - >-------------------------------</a><a name="errprint">-</a> - - qh_errprint( fp, string, atfacet, otherfacet, atridge, atvertex ) - prints out the information of facets and ridges to fp - also prints neighbors and geomview output - - notes: - except for string, any parameter may be NULL -*/ -void qh_errprint(const char *string, facetT *atfacet, facetT *otherfacet, ridgeT *atridge, vertexT *atvertex) { - int i; - - if (atfacet) { - qh_fprintf(qh ferr, 8135, "%s FACET:\n", string); - qh_printfacet(qh ferr, atfacet); - } - if (otherfacet) { - qh_fprintf(qh ferr, 8136, "%s OTHER FACET:\n", string); - qh_printfacet(qh ferr, otherfacet); - } - if (atridge) { - qh_fprintf(qh ferr, 8137, "%s RIDGE:\n", string); - qh_printridge(qh ferr, atridge); - if (atridge->top && atridge->top != atfacet && atridge->top != otherfacet) - qh_printfacet(qh ferr, atridge->top); - if (atridge->bottom - && atridge->bottom != atfacet && atridge->bottom != otherfacet) - qh_printfacet(qh ferr, atridge->bottom); - if (!atfacet) - atfacet= atridge->top; - if (!otherfacet) - otherfacet= otherfacet_(atridge, atfacet); - } - if (atvertex) { - qh_fprintf(qh ferr, 8138, "%s VERTEX:\n", string); - qh_printvertex(qh ferr, atvertex); - } - if (qh fout && qh FORCEoutput && atfacet && !qh QHULLfinished && !qh IStracing) { - qh_fprintf(qh ferr, 8139, "ERRONEOUS and NEIGHBORING FACETS to output\n"); - for (i=0; i < qh_PRINTEND; i++) /* use fout for geomview output */ - qh_printneighborhood(qh fout, qh PRINTout[i], atfacet, otherfacet, - !qh_ALL); - } -} /* errprint */ - - -/*-<a href="qh-user.htm#TOC" - >-------------------------------</a><a name="printfacetlist">-</a> - - qh_printfacetlist( fp, facetlist, facets, printall ) - print all fields for a facet list and/or set of facets to fp - if !printall, - only prints good facets - - notes: - also prints all vertices -*/ -void qh_printfacetlist(facetT *facetlist, setT *facets, boolT printall) { - facetT *facet, **facetp; - - qh_printbegin(qh ferr, qh_PRINTfacets, facetlist, facets, printall); - FORALLfacet_(facetlist) - qh_printafacet(qh ferr, qh_PRINTfacets, facet, printall); - FOREACHfacet_(facets) - qh_printafacet(qh ferr, qh_PRINTfacets, facet, printall); - qh_printend(qh ferr, qh_PRINTfacets, facetlist, facets, printall); -} /* printfacetlist */ - - -/*-<a href="qh-io.htm#TOC" - >-------------------------------</a><a name="printhelp_degenerate">-</a> - - qh_printhelp_degenerate( fp ) - prints descriptive message for precision error - - notes: - no message if qh_QUICKhelp -*/ -void qh_printhelp_degenerate(FILE *fp) { - - if (qh MERGEexact || qh PREmerge || qh JOGGLEmax < REALmax/2) - qh_fprintf(fp, 9368, "\n\ -A Qhull error has occurred. Qhull should have corrected the above\n\ -precision error. Please send the input and all of the output to\n\ -qhull_bug@qhull.org\n"); - else if (!qh_QUICKhelp) { - qh_fprintf(fp, 9369, "\n\ -Precision problems were detected during construction of the convex hull.\n\ -This occurs because convex hull algorithms assume that calculations are\n\ -exact, but floating-point arithmetic has roundoff errors.\n\ -\n\ -To correct for precision problems, do not use 'Q0'. By default, Qhull\n\ -selects 'C-0' or 'Qx' and merges non-convex facets. With option 'QJ',\n\ -Qhull joggles the input to prevent precision problems. See \"Imprecision\n\ -in Qhull\" (qh-impre.htm).\n\ -\n\ -If you use 'Q0', the output may include\n\ -coplanar ridges, concave ridges, and flipped facets. In 4-d and higher,\n\ -Qhull may produce a ridge with four neighbors or two facets with the same \n\ -vertices. Qhull reports these events when they occur. It stops when a\n\ -concave ridge, flipped facet, or duplicate facet occurs.\n"); -#if REALfloat - qh_fprintf(fp, 9370, "\ -\n\ -Qhull is currently using single precision arithmetic. The following\n\ -will probably remove the precision problems:\n\ - - recompile qhull for realT precision(#define REALfloat 0 in user.h).\n"); -#endif - if (qh DELAUNAY && !qh SCALElast && qh MAXabs_coord > 1e4) - qh_fprintf(fp, 9371, "\ -\n\ -When computing the Delaunay triangulation of coordinates > 1.0,\n\ - - use 'Qbb' to scale the last coordinate to [0,m] (max previous coordinate)\n"); - if (qh DELAUNAY && !qh ATinfinity) - qh_fprintf(fp, 9372, "\ -When computing the Delaunay triangulation:\n\ - - use 'Qz' to add a point at-infinity. This reduces precision problems.\n"); - - qh_fprintf(fp, 9373, "\ -\n\ -If you need triangular output:\n\ - - use option 'Qt' to triangulate the output\n\ - - use option 'QJ' to joggle the input points and remove precision errors\n\ - - use option 'Ft'. It triangulates non-simplicial facets with added points.\n\ -\n\ -If you must use 'Q0',\n\ -try one or more of the following options. They can not guarantee an output.\n\ - - use 'QbB' to scale the input to a cube.\n\ - - use 'Po' to produce output and prevent partitioning for flipped facets\n\ - - use 'V0' to set min. distance to visible facet as 0 instead of roundoff\n\ - - use 'En' to specify a maximum roundoff error less than %2.2g.\n\ - - options 'Qf', 'Qbb', and 'QR0' may also help\n", - qh DISTround); - qh_fprintf(fp, 9374, "\ -\n\ -To guarantee simplicial output:\n\ - - use option 'Qt' to triangulate the output\n\ - - use option 'QJ' to joggle the input points and remove precision errors\n\ - - use option 'Ft' to triangulate the output by adding points\n\ - - use exact arithmetic (see \"Imprecision in Qhull\", qh-impre.htm)\n\ -"); - } -} /* printhelp_degenerate */ - - -/*-<a href="qh-globa.htm#TOC" - >-------------------------------</a><a name="printhelp_narrowhull">-</a> - - qh_printhelp_narrowhull( minangle ) - Warn about a narrow hull - - notes: - Alternatively, reduce qh_WARNnarrow in user.h - -*/ -void qh_printhelp_narrowhull(FILE *fp, realT minangle) { - - qh_fprintf(fp, 9375, "qhull precision warning: \n\ -The initial hull is narrow (cosine of min. angle is %.16f).\n\ -Is the input lower dimensional (e.g., on a plane in 3-d)? Qhull may\n\ -produce a wide facet. Options 'QbB' (scale to unit box) or 'Qbb' (scale\n\ -last coordinate) may remove this warning. Use 'Pp' to skip this warning.\n\ -See 'Limitations' in qh-impre.htm.\n", - -minangle); /* convert from angle between normals to angle between facets */ -} /* printhelp_narrowhull */ - -/*-<a href="qh-io.htm#TOC" - >-------------------------------</a><a name="printhelp_singular">-</a> - - qh_printhelp_singular( fp ) - prints descriptive message for singular input -*/ -void qh_printhelp_singular(FILE *fp) { - facetT *facet; - vertexT *vertex, **vertexp; - realT min, max, *coord, dist; - int i,k; - - qh_fprintf(fp, 9376, "\n\ -The input to qhull appears to be less than %d dimensional, or a\n\ -computation has overflowed.\n\n\ -Qhull could not construct a clearly convex simplex from points:\n", - qh hull_dim); - qh_printvertexlist(fp, "", qh facet_list, NULL, qh_ALL); - if (!qh_QUICKhelp) - qh_fprintf(fp, 9377, "\n\ -The center point is coplanar with a facet, or a vertex is coplanar\n\ -with a neighboring facet. The maximum round off error for\n\ -computing distances is %2.2g. The center point, facets and distances\n\ -to the center point are as follows:\n\n", qh DISTround); - qh_printpointid(fp, "center point", qh hull_dim, qh interior_point, -1); - qh_fprintf(fp, 9378, "\n"); - FORALLfacets { - qh_fprintf(fp, 9379, "facet"); - FOREACHvertex_(facet->vertices) - qh_fprintf(fp, 9380, " p%d", qh_pointid(vertex->point)); - zinc_(Zdistio); - qh_distplane(qh interior_point, facet, &dist); - qh_fprintf(fp, 9381, " distance= %4.2g\n", dist); - } - if (!qh_QUICKhelp) { - if (qh HALFspace) - qh_fprintf(fp, 9382, "\n\ -These points are the dual of the given halfspaces. They indicate that\n\ -the intersection is degenerate.\n"); - qh_fprintf(fp, 9383,"\n\ -These points either have a maximum or minimum x-coordinate, or\n\ -they maximize the determinant for k coordinates. Trial points\n\ -are first selected from points that maximize a coordinate.\n"); - if (qh hull_dim >= qh_INITIALmax) - qh_fprintf(fp, 9384, "\n\ -Because of the high dimension, the min x-coordinate and max-coordinate\n\ -points are used if the determinant is non-zero. Option 'Qs' will\n\ -do a better, though much slower, job. Instead of 'Qs', you can change\n\ -the points by randomly rotating the input with 'QR0'.\n"); - } - qh_fprintf(fp, 9385, "\nThe min and max coordinates for each dimension are:\n"); - for (k=0; k < qh hull_dim; k++) { - min= REALmax; - max= -REALmin; - for (i=qh num_points, coord= qh first_point+k; i--; coord += qh hull_dim) { - maximize_(max, *coord); - minimize_(min, *coord); - } - qh_fprintf(fp, 9386, " %d: %8.4g %8.4g difference= %4.4g\n", k, min, max, max-min); - } - if (!qh_QUICKhelp) { - qh_fprintf(fp, 9387, "\n\ -If the input should be full dimensional, you have several options that\n\ -may determine an initial simplex:\n\ - - use 'QJ' to joggle the input and make it full dimensional\n\ - - use 'QbB' to scale the points to the unit cube\n\ - - use 'QR0' to randomly rotate the input for different maximum points\n\ - - use 'Qs' to search all points for the initial simplex\n\ - - use 'En' to specify a maximum roundoff error less than %2.2g.\n\ - - trace execution with 'T3' to see the determinant for each point.\n", - qh DISTround); -#if REALfloat - qh_fprintf(fp, 9388, "\ - - recompile qhull for realT precision(#define REALfloat 0 in libqhull.h).\n"); -#endif - qh_fprintf(fp, 9389, "\n\ -If the input is lower dimensional:\n\ - - use 'QJ' to joggle the input and make it full dimensional\n\ - - use 'Qbk:0Bk:0' to delete coordinate k from the input. You should\n\ - pick the coordinate with the least range. The hull will have the\n\ - correct topology.\n\ - - determine the flat containing the points, rotate the points\n\ - into a coordinate plane, and delete the other coordinates.\n\ - - add one or more points to make the input full dimensional.\n\ -"); - } -} /* printhelp_singular */ - -/*-<a href="qh-globa.htm#TOC" - >-------------------------------</a><a name="user_memsizes">-</a> - - qh_user_memsizes() - allocate up to 10 additional, quick allocation sizes - - notes: - increase maximum number of allocations in qh_initqhull_mem() -*/ -void qh_user_memsizes(void) { - - /* qh_memsize(size); */ -} /* user_memsizes */ - - diff --git a/PyMca/Object3D/Object3DQhull/src/user.h b/PyMca/Object3D/Object3DQhull/src/user.h deleted file mode 100644 index a3322aa..0000000 --- a/PyMca/Object3D/Object3DQhull/src/user.h +++ /dev/null @@ -1,858 +0,0 @@ -/*<html><pre> -<a href="qh-user.htm" - >-------------------------------</a><a name="TOP">-</a> - - user.h - user redefinable constants - - see qh-user.htm. see COPYING for copyright information. - - before reading any code, review libqhull.h for data structure definitions and - the "qh" macro. - -Sections: - ============= qhull library constants ====================== - ============= data types and configuration macros ========== - ============= performance related constants ================ - ============= memory constants ============================= - ============= joggle constants ============================= - ============= conditional compilation ====================== - ============= -merge constants- ============================ - -Code flags -- - NOerrors -- the code does not call qh_errexit() - WARN64 -- the code may be incompatible with 64-bit pointers - -*/ - -#include <time.h> - -#ifndef qhDEFuser -#define qhDEFuser 1 - -/*============================================================*/ -/*============= qhull library constants ======================*/ -/*============================================================*/ - -/*-<a href="qh-user.htm#TOC" - >--------------------------------</a><a name="filenamelen">-</a> - - FILENAMElen -- max length for TI and TO filenames - -*/ - -#define qh_FILENAMElen 500 - -/*-<a href="qh-user.htm#TOC" - >--------------------------------</a><a name="msgcode">-</a> - - msgcode -- Unique message codes for qh_fprintf - - If add new messages, assign these values and increment. - - def counters = [27, 1047, 2059, 3025, 4068, 5003, - 6241, 7079, 8143, 9410, 10000, 11026] - - See: qh_ERR* [libqhull.h] -*/ - -#define MSG_TRACE0 0 -#define MSG_TRACE1 1000 -#define MSG_TRACE2 2000 -#define MSG_TRACE3 3000 -#define MSG_TRACE4 4000 -#define MSG_TRACE5 5000 -#define MSG_ERROR 6000 /* errors written to qh.ferr */ -#define MSG_WARNING 7000 -#define MSG_STDERR 8000 /* log messages Written to qh.ferr */ -#define MSG_OUTPUT 9000 -#define MSG_QHULL_ERROR 10000 /* errors thrown by QhullError [QhullError.h] */ -#define MSG_FIXUP 11000 /* FIXUP QH11... */ -#define MSG_MAXLEN 3000 /* qh_printhelp_degenerate() in user.c */ - - -/*-<a href="qh-user.htm#TOC" - >--------------------------------</a><a name="qh_OPTIONline">-</a> - - qh_OPTIONline -- max length of an option line 'FO' -*/ -#define qh_OPTIONline 80 - -/*============================================================*/ -/*============= data types and configuration macros ==========*/ -/*============================================================*/ - -/*-<a href="qh-user.htm#TOC" - >--------------------------------</a><a name="realT">-</a> - - realT - set the size of floating point numbers - - qh_REALdigits - maximimum number of significant digits - - qh_REAL_1, qh_REAL_2n, qh_REAL_3n - format strings for printf - - qh_REALmax, qh_REALmin - maximum and minimum (near zero) values - - qh_REALepsilon - machine roundoff. Maximum roundoff error for addition and multiplication. - - notes: - Select whether to store floating point numbers in single precision (float) - or double precision (double). - - Use 'float' to save about 8% in time and 25% in space. This is particularly - helpful if high-d where convex hulls are space limited. Using 'float' also - reduces the printed size of Qhull's output since numbers have 8 digits of - precision. - - Use 'double' when greater arithmetic precision is needed. This is needed - for Delaunay triangulations and Voronoi diagrams when you are not merging - facets. - - If 'double' gives insufficient precision, your data probably includes - degeneracies. If so you should use facet merging (done by default) - or exact arithmetic (see imprecision section of manual, qh-impre.htm). - You may also use option 'Po' to force output despite precision errors. - - You may use 'long double', but many format statements need to be changed - and you may need a 'long double' square root routine. S. Grundmann - (sg@eeiwzb.et.tu-dresden.de) has done this. He reports that the code runs - much slower with little gain in precision. - - WARNING: on some machines, int f(){realT a= REALmax;return (a == REALmax);} - returns False. Use (a > REALmax/2) instead of (a == REALmax). - - REALfloat = 1 all numbers are 'float' type - = 0 all numbers are 'double' type -*/ -#define REALfloat 0 - -#if (REALfloat == 1) -#define realT float -#define REALmax FLT_MAX -#define REALmin FLT_MIN -#define REALepsilon FLT_EPSILON -#define qh_REALdigits 8 /* maximum number of significant digits */ -#define qh_REAL_1 "%6.8g " -#define qh_REAL_2n "%6.8g %6.8g\n" -#define qh_REAL_3n "%6.8g %6.8g %6.8g\n" - -#elif (REALfloat == 0) -#define realT double -#define REALmax DBL_MAX -#define REALmin DBL_MIN -#define REALepsilon DBL_EPSILON -#define qh_REALdigits 16 /* maximum number of significant digits */ -#define qh_REAL_1 "%6.16g " -#define qh_REAL_2n "%6.16g %6.16g\n" -#define qh_REAL_3n "%6.16g %6.16g %6.16g\n" - -#else -#error unknown float option -#endif - -/*-<a href="qh-user.htm#TOC" - >--------------------------------</a><a name="CPUclock">-</a> - - qh_CPUclock - define the clock() function for reporting the total time spent by Qhull - returns CPU ticks as a 'long int' - qh_CPUclock is only used for reporting the total time spent by Qhull - - qh_SECticks - the number of clock ticks per second - - notes: - looks for CLOCKS_PER_SEC, CLOCKS_PER_SECOND, or assumes microseconds - to define a custom clock, set qh_CLOCKtype to 0 - - if your system does not use clock() to return CPU ticks, replace - qh_CPUclock with the corresponding function. It is converted - to 'unsigned long' to prevent wrap-around during long runs. By default, - <time.h> defines clock_t as 'long' - - Set qh_CLOCKtype to - - 1 for CLOCKS_PER_SEC, CLOCKS_PER_SECOND, or microsecond - Note: may fail if more than 1 hour elapsed time - - 2 use qh_clock() with POSIX times() (see global.c) -*/ -#define qh_CLOCKtype 1 /* change to the desired number */ - -#if (qh_CLOCKtype == 1) - -#if defined(CLOCKS_PER_SECOND) -#define qh_CPUclock ((unsigned long)clock()) /* return CPU clock */ -#define qh_SECticks CLOCKS_PER_SECOND - -#elif defined(CLOCKS_PER_SEC) -#define qh_CPUclock ((unsigned long)clock()) /* return CPU clock */ -#define qh_SECticks CLOCKS_PER_SEC - -#elif defined(CLK_TCK) -#define qh_CPUclock ((unsigned long)clock()) /* return CPU clock */ -#define qh_SECticks CLK_TCK - -#else -#define qh_CPUclock ((unsigned long)clock()) /* return CPU clock */ -#define qh_SECticks 1E6 -#endif - -#elif (qh_CLOCKtype == 2) -#define qh_CPUclock qh_clock() /* return CPU clock */ -#define qh_SECticks 100 - -#else /* qh_CLOCKtype == ? */ -#error unknown clock option -#endif - -/*-<a href="qh-user.htm#TOC" - >--------------------------------</a><a name="RANDOM">-</a> - - qh_RANDOMtype, qh_RANDOMmax, qh_RANDOMseed - define random number generator - - qh_RANDOMint generates a random integer between 0 and qh_RANDOMmax. - qh_RANDOMseed sets the random number seed for qh_RANDOMint - - Set qh_RANDOMtype (default 5) to: - 1 for random() with 31 bits (UCB) - 2 for rand() with RAND_MAX or 15 bits (system 5) - 3 for rand() with 31 bits (Sun) - 4 for lrand48() with 31 bits (Solaris) - 5 for qh_rand() with 31 bits (included with Qhull) - - notes: - Random numbers are used by rbox to generate point sets. Random - numbers are used by Qhull to rotate the input ('QRn' option), - simulate a randomized algorithm ('Qr' option), and to simulate - roundoff errors ('Rn' option). - - Random number generators differ between systems. Most systems provide - rand() but the period varies. The period of rand() is not critical - since qhull does not normally use random numbers. - - The default generator is Park & Miller's minimal standard random - number generator [CACM 31:1195 '88]. It is included with Qhull. - - If qh_RANDOMmax is wrong, qhull will report a warning and Geomview - output will likely be invisible. -*/ -#define qh_RANDOMtype 5 /* *** change to the desired number *** */ - -#if (qh_RANDOMtype == 1) -#define qh_RANDOMmax ((realT)0x7fffffffUL) /* 31 bits, random()/MAX */ -#define qh_RANDOMint random() -#define qh_RANDOMseed_(seed) srandom(seed); - -#elif (qh_RANDOMtype == 2) -#ifdef RAND_MAX -#define qh_RANDOMmax ((realT)RAND_MAX) -#else -#define qh_RANDOMmax ((realT)32767) /* 15 bits (System 5) */ -#endif -#define qh_RANDOMint rand() -#define qh_RANDOMseed_(seed) srand((unsigned)seed); - -#elif (qh_RANDOMtype == 3) -#define qh_RANDOMmax ((realT)0x7fffffffUL) /* 31 bits, Sun */ -#define qh_RANDOMint rand() -#define qh_RANDOMseed_(seed) srand((unsigned)seed); - -#elif (qh_RANDOMtype == 4) -#define qh_RANDOMmax ((realT)0x7fffffffUL) /* 31 bits, lrand38()/MAX */ -#define qh_RANDOMint lrand48() -#define qh_RANDOMseed_(seed) srand48(seed); - -#elif (qh_RANDOMtype == 5) -#define qh_RANDOMmax ((realT)2147483646UL) /* 31 bits, qh_rand/MAX */ -#define qh_RANDOMint qh_rand() -#define qh_RANDOMseed_(seed) qh_srand(seed); -/* unlike rand(), never returns 0 */ - -#else -#error: unknown random option -#endif - -/*-<a href="qh-user.htm#TOC" - >--------------------------------</a><a name="ORIENTclock">-</a> - - qh_ORIENTclock - 0 for inward pointing normals by Geomview convention -*/ -#define qh_ORIENTclock 0 - - -/*============================================================*/ -/*============= joggle constants =============================*/ -/*============================================================*/ - -/*-<a href="qh-user.htm#TOC" ->--------------------------------</a><a name="JOGGLEdefault">-</a> - -qh_JOGGLEdefault -default qh.JOGGLEmax is qh.DISTround * qh_JOGGLEdefault - -notes: -rbox s r 100 | qhull QJ1e-15 QR0 generates 90% faults at distround 7e-16 -rbox s r 100 | qhull QJ1e-14 QR0 generates 70% faults -rbox s r 100 | qhull QJ1e-13 QR0 generates 35% faults -rbox s r 100 | qhull QJ1e-12 QR0 generates 8% faults -rbox s r 100 | qhull QJ1e-11 QR0 generates 1% faults -rbox s r 100 | qhull QJ1e-10 QR0 generates 0% faults -rbox 1000 W0 | qhull QJ1e-12 QR0 generates 86% faults -rbox 1000 W0 | qhull QJ1e-11 QR0 generates 20% faults -rbox 1000 W0 | qhull QJ1e-10 QR0 generates 2% faults -the later have about 20 points per facet, each of which may interfere - -pick a value large enough to avoid retries on most inputs -*/ -#define qh_JOGGLEdefault 30000.0 - -/*-<a href="qh-user.htm#TOC" ->--------------------------------</a><a name="JOGGLEincrease">-</a> - -qh_JOGGLEincrease -factor to increase qh.JOGGLEmax on qh_JOGGLEretry or qh_JOGGLEagain -*/ -#define qh_JOGGLEincrease 10.0 - -/*-<a href="qh-user.htm#TOC" ->--------------------------------</a><a name="JOGGLEretry">-</a> - -qh_JOGGLEretry -if ZZretry = qh_JOGGLEretry, increase qh.JOGGLEmax - -notes: -try twice at the original value in case of bad luck the first time -*/ -#define qh_JOGGLEretry 2 - -/*-<a href="qh-user.htm#TOC" ->--------------------------------</a><a name="JOGGLEagain">-</a> - -qh_JOGGLEagain -every following qh_JOGGLEagain, increase qh.JOGGLEmax - -notes: -1 is OK since it's already failed qh_JOGGLEretry times -*/ -#define qh_JOGGLEagain 1 - -/*-<a href="qh-user.htm#TOC" ->--------------------------------</a><a name="JOGGLEmaxincrease">-</a> - -qh_JOGGLEmaxincrease -maximum qh.JOGGLEmax due to qh_JOGGLEincrease -relative to qh.MAXwidth - -notes: -qh.joggleinput will retry at this value until qh_JOGGLEmaxretry -*/ -#define qh_JOGGLEmaxincrease 1e-2 - -/*-<a href="qh-user.htm#TOC" ->--------------------------------</a><a name="JOGGLEmaxretry">-</a> - -qh_JOGGLEmaxretry -stop after qh_JOGGLEmaxretry attempts -*/ -#define qh_JOGGLEmaxretry 100 - -/*============================================================*/ -/*============= performance related constants ================*/ -/*============================================================*/ - -/*-<a href="qh-user.htm#TOC" - >--------------------------------</a><a name="HASHfactor">-</a> - - qh_HASHfactor - total hash slots / used hash slots. Must be at least 1.1. - - notes: - =2 for at worst 50% occupancy for qh hash_table and normally 25% occupancy -*/ -#define qh_HASHfactor 2 - -/*-<a href="qh-user.htm#TOC" - >--------------------------------</a><a name="VERIFYdirect">-</a> - - qh_VERIFYdirect - with 'Tv' verify all points against all facets if op count is smaller - - notes: - if greater, calls qh_check_bestdist() instead -*/ -#define qh_VERIFYdirect 1000000 - -/*-<a href="qh-user.htm#TOC" - >--------------------------------</a><a name="INITIALsearch">-</a> - - qh_INITIALsearch - if qh_INITIALmax, search points up to this dimension -*/ -#define qh_INITIALsearch 6 - -/*-<a href="qh-user.htm#TOC" - >--------------------------------</a><a name="INITIALmax">-</a> - - qh_INITIALmax - if dim >= qh_INITIALmax, use min/max coordinate points for initial simplex - - notes: - from points with non-zero determinants - use option 'Qs' to override (much slower) -*/ -#define qh_INITIALmax 8 - -/*============================================================*/ -/*============= memory constants =============================*/ -/*============================================================*/ - -/*-<a href="qh-user.htm#TOC" - >--------------------------------</a><a name="MEMalign">-</a> - - qh_MEMalign - memory alignment for qh_meminitbuffers() in global.c - - notes: - to avoid bus errors, memory allocation must consider alignment requirements. - malloc() automatically takes care of alignment. Since mem.c manages - its own memory, we need to explicitly specify alignment in - qh_meminitbuffers(). - - A safe choice is sizeof(double). sizeof(float) may be used if doubles - do not occur in data structures and pointers are the same size. Be careful - of machines (e.g., DEC Alpha) with large pointers. - - If using gcc, best alignment is - #define qh_MEMalign fmax_(__alignof__(realT),__alignof__(void *)) -*/ -#define qh_MEMalign ((int)(fmax_(sizeof(realT), sizeof(void *)))) - -/*-<a href="qh-user.htm#TOC" - >--------------------------------</a><a name="MEMbufsize">-</a> - - qh_MEMbufsize - size of additional memory buffers - - notes: - used for qh_meminitbuffers() in global.c -*/ -#define qh_MEMbufsize 0x10000 /* allocate 64K memory buffers */ - -/*-<a href="qh-user.htm#TOC" - >--------------------------------</a><a name="MEMinitbuf">-</a> - - qh_MEMinitbuf - size of initial memory buffer - - notes: - use for qh_meminitbuffers() in global.c -*/ -#define qh_MEMinitbuf 0x20000 /* initially allocate 128K buffer */ - -/*-<a href="qh-user.htm#TOC" - >--------------------------------</a><a name="INFINITE">-</a> - - qh_INFINITE - on output, indicates Voronoi center at infinity -*/ -#define qh_INFINITE -10.101 - -/*-<a href="qh-user.htm#TOC" - >--------------------------------</a><a name="DEFAULTbox">-</a> - - qh_DEFAULTbox - default box size (Geomview expects 0.5) - - qh_DEFAULTbox - default box size for integer coorindate (rbox only) -*/ -#define qh_DEFAULTbox 0.5 -#define qh_DEFAULTzbox 1e6 - -/*============================================================*/ -/*============= conditional compilation ======================*/ -/*============================================================*/ - -/*-<a href="qh-user.htm#TOC" - >--------------------------------</a><a name="compiler">-</a> - - __cplusplus - defined by C++ compilers - - __MSC_VER - defined by Microsoft Visual C++ - - __MWERKS__ && __POWERPC__ - defined by Metrowerks when compiling for the Power Macintosh - - __STDC__ - defined for strict ANSI C -*/ - -/*-<a href="qh-user.htm#TOC" - >--------------------------------</a><a name="COMPUTEfurthest">-</a> - - qh_COMPUTEfurthest - compute furthest distance to an outside point instead of storing it with the facet - =1 to compute furthest - - notes: - computing furthest saves memory but costs time - about 40% more distance tests for partitioning - removes facet->furthestdist -*/ -#define qh_COMPUTEfurthest 0 - -/*-<a href="qh-user.htm#TOC" - >--------------------------------</a><a name="KEEPstatistics">-</a> - - qh_KEEPstatistics - =0 removes most of statistic gathering and reporting - - notes: - if 0, code size is reduced by about 4%. -*/ -#define qh_KEEPstatistics 1 - -/*-<a href="qh-user.htm#TOC" - >--------------------------------</a><a name="MAXoutside">-</a> - - qh_MAXoutside - record outer plane for each facet - =1 to record facet->maxoutside - - notes: - this takes a realT per facet and slightly slows down qhull - it produces better outer planes for geomview output -*/ -#define qh_MAXoutside 1 - -/*-<a href="qh-user.htm#TOC" - >--------------------------------</a><a name="NOmerge">-</a> - - qh_NOmerge - disables facet merging if defined - - notes: - This saves about 10% space. - - Unless 'Q0' - qh_NOmerge sets 'QJ' to avoid precision errors - - #define qh_NOmerge - - see: - <a href="mem.h#NOmem">qh_NOmem</a> in mem.c - - see user.c/user_eg.c for removing io.o -*/ - -/*-<a href="qh-user.htm#TOC" - >--------------------------------</a><a name="NOtrace">-</a> - - qh_NOtrace - no tracing if defined - - notes: - This saves about 5% space. - - #define qh_NOtrace -*/ - -/*-<a href="qh-user.htm#TOC" - >--------------------------------</a><a name="QHpointer">-</a> - - qh_QHpointer - access global data with pointer or static structure - - qh_QHpointer = 1 access globals via a pointer to allocated memory - enables qh_saveqhull() and qh_restoreqhull() - [2010, gcc] costs about 4% in time and 4% in space - [2003, msvc] costs about 8% in time and 2% in space - - = 0 qh_qh and qh_qhstat are static data structures - only one instance of qhull() can be active at a time - default value - - qh_QHpointer_dllimport and qh_dllimport define qh_qh as __declspec(dllimport) [libqhull.h] - It is required for msvc-2005. It is not needed for gcc. - - notes: - all global variables for qhull are in qh, qhmem, and qhstat - qh is defined in libqhull.h - qhmem is defined in mem.h - qhstat is defined in stat.h - C++ build defines qh_QHpointer [libqhullp.pro, libqhullcpp.pro] - - see: - user_eg.c for an example -*/ -#ifdef qh_QHpointer -#if qh_dllimport -#error QH6207 Qhull error: Use qh_QHpointer_dllimport instead of qh_dllimport with qh_QHpointer -#endif -#else -#define qh_QHpointer 0 -#if qh_QHpointer_dllimport -#error QH6234 Qhull error: Use qh_dllimport instead of qh_QHpointer_dllimport when qh_QHpointer is not defined -#endif -#endif -#if 0 /* sample code */ - qhT *oldqhA, *oldqhB; - - exitcode= qh_new_qhull(dim, numpoints, points, ismalloc, - flags, outfile, errfile); - /* use results from first call to qh_new_qhull */ - oldqhA= qh_save_qhull(); - exitcode= qh_new_qhull(dimB, numpointsB, pointsB, ismalloc, - flags, outfile, errfile); - /* use results from second call to qh_new_qhull */ - oldqhB= qh_save_qhull(); - qh_restore_qhull(&oldqhA); - /* use results from first call to qh_new_qhull */ - qh_freeqhull(qh_ALL); /* frees all memory used by first call */ - qh_restore_qhull(&oldqhB); - /* use results from second call to qh_new_qhull */ - qh_freeqhull(!qh_ALL); /* frees long memory used by second call */ - qh_memfreeshort(&curlong, &totlong); /* frees short memory and memory allocator */ -#endif - -/*-<a href="qh-user.htm#TOC" - >--------------------------------</a><a name="QUICKhelp">-</a> - - qh_QUICKhelp - =1 to use abbreviated help messages, e.g., for degenerate inputs -*/ -#define qh_QUICKhelp 0 - -/*============================================================*/ -/*============= -merge constants- ============================*/ -/*============================================================*/ -/* - These constants effect facet merging. You probably will not need - to modify them. They effect the performance of facet merging. -*/ - -/*-<a href="qh-user.htm#TOC" - >--------------------------------</a><a name="DIMmergeVertex">-</a> - - qh_DIMmergeVertex - max dimension for vertex merging (it is not effective in high-d) -*/ -#define qh_DIMmergeVertex 6 - -/*-<a href="qh-user.htm#TOC" - >--------------------------------</a><a name="DIMreduceBuild">-</a> - - qh_DIMreduceBuild - max dimension for vertex reduction during build (slow in high-d) -*/ -#define qh_DIMreduceBuild 5 - -/*-<a href="qh-user.htm#TOC" - >--------------------------------</a><a name="BESTcentrum">-</a> - - qh_BESTcentrum - if > 2*dim+n vertices, qh_findbestneighbor() tests centrums (faster) - else, qh_findbestneighbor() tests all vertices (much better merges) - - qh_BESTcentrum2 - if qh_BESTcentrum2 * DIM3 + BESTcentrum < #vertices tests centrums -*/ -#define qh_BESTcentrum 20 -#define qh_BESTcentrum2 2 - -/*-<a href="qh-user.htm#TOC" - >--------------------------------</a><a name="BESTnonconvex">-</a> - - qh_BESTnonconvex - if > dim+n neighbors, qh_findbestneighbor() tests nonconvex ridges. - - notes: - It is needed because qh_findbestneighbor is slow for large facets -*/ -#define qh_BESTnonconvex 15 - -/*-<a href="qh-user.htm#TOC" - >--------------------------------</a><a name="MAXnewmerges">-</a> - - qh_MAXnewmerges - if >n newmerges, qh_merge_nonconvex() calls qh_reducevertices_centrums. - - notes: - It is needed because postmerge can merge many facets at once -*/ -#define qh_MAXnewmerges 2 - -/*-<a href="qh-user.htm#TOC" - >--------------------------------</a><a name="MAXnewcentrum">-</a> - - qh_MAXnewcentrum - if <= dim+n vertices (n approximates the number of merges), - reset the centrum in qh_updatetested() and qh_mergecycle_facets() - - notes: - needed to reduce cost and because centrums may move too much if - many vertices in high-d -*/ -#define qh_MAXnewcentrum 5 - -/*-<a href="qh-user.htm#TOC" - >--------------------------------</a><a name="COPLANARratio">-</a> - - qh_COPLANARratio - for 3-d+ merging, qh.MINvisible is n*premerge_centrum - - notes: - for non-merging, it's DISTround -*/ -#define qh_COPLANARratio 3 - -/*-<a href="qh-user.htm#TOC" - >--------------------------------</a><a name="DISToutside">-</a> - - qh_DISToutside - When is a point clearly outside of a facet? - Stops search in qh_findbestnew or qh_partitionall - qh_findbest uses qh.MINoutside since since it is only called if no merges. - - notes: - 'Qf' always searches for best facet - if !qh.MERGING, same as qh.MINoutside. - if qh_USEfindbestnew, increase value since neighboring facets may be ill-behaved - [Note: Zdelvertextot occurs normally with interior points] - RBOX 1000 s Z1 G1e-13 t1001188774 | QHULL Tv - When there is a sharp edge, need to move points to a - clearly good facet; otherwise may be lost in another partitioning. - if too big then O(n^2) behavior for partitioning in cone - if very small then important points not processed - Needed in qh_partitionall for - RBOX 1000 s Z1 G1e-13 t1001032651 | QHULL Tv - Needed in qh_findbestnew for many instances of - RBOX 1000 s Z1 G1e-13 t | QHULL Tv - - See: - qh_DISToutside -- when is a point clearly outside of a facet - qh_SEARCHdist -- when is facet coplanar with the best facet? - qh_USEfindbestnew -- when to use qh_findbestnew for qh_partitionpoint() -*/ -#define qh_DISToutside ((qh_USEfindbestnew ? 2 : 1) * \ - fmax_((qh MERGING ? 2 : 1)*qh MINoutside, qh max_outside)) - -/*-<a href="qh-user.htm#TOC" - >--------------------------------</a><a name="RATIOnearinside">-</a> - - qh_RATIOnearinside - ratio of qh.NEARinside to qh.ONEmerge for retaining inside points for - qh_check_maxout(). - - notes: - This is overkill since do not know the correct value. - It effects whether 'Qc' reports all coplanar points - Not used for 'd' since non-extreme points are coplanar -*/ -#define qh_RATIOnearinside 5 - -/*-<a href="qh-user.htm#TOC" - >--------------------------------</a><a name="SEARCHdist">-</a> - - qh_SEARCHdist - When is a facet coplanar with the best facet? - qh_findbesthorizon: all coplanar facets of the best facet need to be searched. - - See: - qh_DISToutside -- when is a point clearly outside of a facet - qh_SEARCHdist -- when is facet coplanar with the best facet? - qh_USEfindbestnew -- when to use qh_findbestnew for qh_partitionpoint() -*/ -#define qh_SEARCHdist ((qh_USEfindbestnew ? 2 : 1) * \ - (qh max_outside + 2 * qh DISTround + fmax_( qh MINvisible, qh MAXcoplanar))); - -/*-<a href="qh-user.htm#TOC" - >--------------------------------</a><a name="USEfindbestnew">-</a> - - qh_USEfindbestnew - Always use qh_findbestnew for qh_partitionpoint, otherwise use - qh_findbestnew if merged new facet or sharpnewfacets. - - See: - qh_DISToutside -- when is a point clearly outside of a facet - qh_SEARCHdist -- when is facet coplanar with the best facet? - qh_USEfindbestnew -- when to use qh_findbestnew for qh_partitionpoint() -*/ -#define qh_USEfindbestnew (zzval_(Ztotmerge) > 50) - -/*-<a href="qh-user.htm#TOC" - >--------------------------------</a><a name="WIDEcoplanar">-</a> - - qh_WIDEcoplanar - n*MAXcoplanar or n*MINvisible for a WIDEfacet - - if vertex is further than qh.WIDEfacet from the hyperplane - then its ridges are not counted in computing the area, and - the facet's centrum is frozen. - - notes: - qh.WIDEfacet= max(qh.MAXoutside,qh_WIDEcoplanar*qh.MAXcoplanar, - qh_WIDEcoplanar * qh.MINvisible); -*/ -#define qh_WIDEcoplanar 6 - -/*-<a href="qh-user.htm#TOC" - >--------------------------------</a><a name="MAXnarrow">-</a> - - qh_MAXnarrow - max. cosine in initial hull that sets qh.NARROWhull - - notes: - If qh.NARROWhull, the initial partition does not make - coplanar points. If narrow, a coplanar point can be - coplanar to two facets of opposite orientations and - distant from the exact convex hull. - - Conservative estimate. Don't actually see problems until it is -1.0 -*/ -#define qh_MAXnarrow -0.99999999 - -/*-<a href="qh-user.htm#TOC" - >--------------------------------</a><a name="WARNnarrow">-</a> - - qh_WARNnarrow - max. cosine in initial hull to warn about qh.NARROWhull - - notes: - this is a conservative estimate. - Don't actually see problems until it is -1.0. See qh-impre.htm -*/ -#define qh_WARNnarrow -0.999999999999999 - -/*-<a href="qh-user.htm#TOC" - >--------------------------------</a><a name="ZEROdelaunay">-</a> - - qh_ZEROdelaunay - a zero Delaunay facet occurs for input sites coplanar with their convex hull - the last normal coefficient of a zero Delaunay facet is within - qh_ZEROdelaunay * qh.ANGLEround of 0 - - notes: - qh_ZEROdelaunay does not allow for joggled input ('QJ'). - - You can avoid zero Delaunay facets by surrounding the input with a box. - - Use option 'PDk:-n' to explicitly define zero Delaunay facets - k= dimension of input sites (e.g., 3 for 3-d Delaunay triangulation) - n= the cutoff for zero Delaunay facets (e.g., 'PD3:-1e-12') -*/ -#define qh_ZEROdelaunay 2 - -#endif /* qh_DEFuser */ - - - diff --git a/PyMca/Object3D/Object3DQhull/src/usermem.c b/PyMca/Object3D/Object3DQhull/src/usermem.c deleted file mode 100644 index 8cb6ba4..0000000 --- a/PyMca/Object3D/Object3DQhull/src/usermem.c +++ /dev/null @@ -1,64 +0,0 @@ -/*<html><pre> -<a href="qh-user.htm" - >-------------------------------</a><a name="TOP">-</a> - - usermem.c - qh_exit(), qh_free(), and qh_malloc() - - See README.txt. - - If you redefine one of these functions you must redefine all of them. - If you recompile and load this file, then usermem.o will not be loaded - from qhull.a or qhull.lib - - See libqhull.h for data structures, macros, and user-callable functions. - See user.c for qhull-related, redefinable functions - see user.h for user-definable constants - See userprintf.c for qh_fprintf and userprintf_rbox,c for qh_fprintf_rbox - - Please report any errors that you fix to qhull@qhull.org -*/ - -#include "libqhull.h" - -#include <stdlib.h> - -/*-<a href="qh-user.htm#TOC" - >-------------------------------</a><a name="qh_exit">-</a> - - qh_exit( exitcode ) - exit program - - notes: - same as exit() -*/ -void qh_exit(int exitcode) { - exit(exitcode); -} /* exit */ - -/*-<a href="qh-user.htm#TOC" ->-------------------------------</a><a name="qh_free">-</a> - -qh_free( mem ) -free memory - -notes: -same as free() -*/ -void qh_free(void *mem) { - free(mem); -} /* free */ - -/*-<a href="qh-user.htm#TOC" - >-------------------------------</a><a name="qh_malloc">-</a> - - qh_malloc( mem ) - allocate memory - - notes: - same as malloc() -*/ -void *qh_malloc(size_t size) { - return malloc(size); -} /* malloc */ - - diff --git a/PyMca/Object3D/Object3DQhull/src/userprintf.c b/PyMca/Object3D/Object3DQhull/src/userprintf.c deleted file mode 100644 index 88ead2f..0000000 --- a/PyMca/Object3D/Object3DQhull/src/userprintf.c +++ /dev/null @@ -1,63 +0,0 @@ -/*<html><pre> -<a href="qh-user.htm" - >-------------------------------</a><a name="TOP">-</a> - - userprintf.c - qh_fprintf() - - see README.txt see COPYING.txt for copyright information. - - If you recompile and load this file, then userprintf.o will not be loaded - from qhull.a or qhull.lib - - See libqhull.h for data structures, macros, and user-callable functions. - See user.c for qhull-related, redefinable functions - see user.h for user-definable constants - See usermem.c for qh_exit(), qh_free(), and qh_malloc() - see Qhull.cpp and RboxPoints.cpp for examples. - - Please report any errors that you fix to qhull@qhull.org -*/ - -#include "libqhull.h" - -#include <stdarg.h> -#include <stdio.h> -#include <stdlib.h> - -/*-<a href="qh-user.htm#TOC" - >-------------------------------</a><a name="qh_fprintf">-</a> - - qh_fprintf(fp, msgcode, format, list of args ) - print arguments to *fp according to format - Use qh_fprintf_rbox() for rboxlib.c - - notes: - same as fprintf() - fgets() is not trapped like fprintf() - exit qh_fprintf via qh_errexit() -*/ - -void qh_fprintf(FILE *fp, int msgcode, const char *fmt, ... ) { - va_list args; - - if (!fp) { - fprintf(stderr, "QH6232 Qhull internal error (userprintf.c): fp is 0. Wrong qh_fprintf called.\n"); - qh_errexit(6232, NULL, NULL); - } - va_start(args, fmt); -#if qh_QHpointer - if (qh_qh && qh ANNOTATEoutput) { -#else - if (qh ANNOTATEoutput) { -#endif - fprintf(fp, "[QH%.4d]", msgcode); - }else if (msgcode >= MSG_ERROR && msgcode < MSG_STDERR ) { - fprintf(fp, "QH%.4d ", msgcode); - } - vfprintf(fp, fmt, args); - va_end(args); - - /* Place debugging traps here. Use with option 'Tn' */ - -} /* qh_fprintf */ - diff --git a/PyMca/OmnicMap.py b/PyMca/OmnicMap.py index 97cc71d..67e958e 100644 --- a/PyMca/OmnicMap.py +++ b/PyMca/OmnicMap.py @@ -33,7 +33,7 @@ class OmnicMap(DataObject.DataObject): It reads the spectra into a DataObject instance. This class info member contains all the parsed information. - This calss data member contains the map itself as a 3D array. + This class data member contains the map itself as a 3D array. ''' def __init__(self, filename): ''' diff --git a/PyMca/PhysicalMemory.py b/PyMca/PhysicalMemory.py index 57b12d8..b4dc3da 100644 --- a/PyMca/PhysicalMemory.py +++ b/PyMca/PhysicalMemory.py @@ -1,82 +1,107 @@ -import sys
-import os
-import ctypes
-import traceback
-
-def loadCLibrary(name="libc.so"):
- try:
- libc = ctypes.CDLL(name)
- except OSError:
- text = traceback.format_exc()
- if "invalid ELF header" in text:
- library = text.split(": ")
- if len(library) > 1:
- libraryFile = library[1]
- if os.path.exists(libraryFile):
- # to read some line
- f = open(libraryFile, 'r')
- for i in range(10):
- line = f.readline()
- if name in line:
- f.close()
- lineSplit = line.split(name)
- libraryFile = lineSplit[0].split()[-1] +\
- name+\
- lineSplit[1].split()[0]
- break
- libraryFile = line[line.index(libraryFile):].split()[0]
- libc = ctypes.CDLL(libraryFile)
- else:
- raise
- return libc
-
-if sys.platform == 'win32':
- class MEMORYSTATUSEX(ctypes.Structure):
- _fields_ = [
- ("dwLength", ctypes.c_ulong),
- ("dwMemoryLoad", ctypes.c_ulong),
- ("ullTotalPhys", ctypes.c_ulonglong),
- ("ullAvailPhys", ctypes.c_ulonglong),
- ("ullTotalPageFile", ctypes.c_ulonglong),
- ("ullAvailPageFile", ctypes.c_ulonglong),
- ("ullTotalVirtual", ctypes.c_ulonglong),
- ("ullAvailVirtual", ctypes.c_ulonglong),
- ("sullAvailExtendedVirtual", ctypes.c_ulonglong),
- ]
-
- def __init__(self):
- # have to initialize this to the size of MEMORYSTATUSEX
- self.dwLength = ctypes.sizeof(self)
- super(MEMORYSTATUSEX, self).__init__()
-
- #print("MemoryLoad: %d%%" % (stat.dwMemoryLoad))
- #print("Physical memory = %d" % stat.ullTotalPhys)
- #print(stat.ullAvailPhys)
- def getPhysicalMemory():
- stat = MEMORYSTATUSEX()
- ctypes.windll.kernel32.GlobalMemoryStatusEx(ctypes.byref(stat))
- return stat.ullTotalPhys
-
-elif sys.platform.startswith('linux'):
- def getPhysicalMemory():
- return os.sysconf('SC_PAGESIZE') * os.sysconf('SC_PHYS_PAGES')
-
-elif sys.platform == 'darwin':
- def getPhysicalMemory():
- libc = loadCLibrary("libc.dylib")
- memsize = ctypes.c_uint64(0)
- length = ctypes.c_size_t(ctypes.sizeof(memsize))
- libc.sysctlbyname("hw.memsize", ctypes.byref(memsize), ctypes.byref(length), None, 0)
- return memsize.value
-else:
- def getPhysicalMemory():
- return None
-
-def getPhysicalMemoryOrNone():
- try:
- return getPhysicalMemory()
- except:
- return None
-
-if __name__ == "__main__":
- print("Physical memory = %d" % getPhysicalMemory())
+# +# Copyright (C) 2012 V. Armando Sole - ESRF +# +# Permission is hereby granted, free of charge, to any person +# obtaining a copy of this software and associated documentation +# files (the "Software"), to deal in the Software without +# restriction, including without limitation the rights to use, +# copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following +# conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +# OTHER DEALINGS IN THE SOFTWARE. +# +__license__ = "MIT" +import sys +import os +import ctypes +import traceback + +def loadCLibrary(name="libc.so"): + try: + libc = ctypes.CDLL(name) + except OSError: + text = traceback.format_exc() + if "invalid ELF header" in text: + library = text.split(": ") + if len(library) > 1: + libraryFile = library[1] + if os.path.exists(libraryFile): + # to read some line + f = open(libraryFile, 'r') + for i in range(10): + line = f.readline() + if name in line: + f.close() + lineSplit = line.split(name) + libraryFile = lineSplit[0].split()[-1] +\ + name+\ + lineSplit[1].split()[0] + break + libraryFile = line[line.index(libraryFile):].split()[0] + libc = ctypes.CDLL(libraryFile) + else: + raise + return libc + +if sys.platform == 'win32': + class MEMORYSTATUSEX(ctypes.Structure): + _fields_ = [ + ("dwLength", ctypes.c_ulong), + ("dwMemoryLoad", ctypes.c_ulong), + ("ullTotalPhys", ctypes.c_ulonglong), + ("ullAvailPhys", ctypes.c_ulonglong), + ("ullTotalPageFile", ctypes.c_ulonglong), + ("ullAvailPageFile", ctypes.c_ulonglong), + ("ullTotalVirtual", ctypes.c_ulonglong), + ("ullAvailVirtual", ctypes.c_ulonglong), + ("sullAvailExtendedVirtual", ctypes.c_ulonglong), + ] + + def __init__(self): + # have to initialize this to the size of MEMORYSTATUSEX + self.dwLength = ctypes.sizeof(self) + super(MEMORYSTATUSEX, self).__init__() + + #print("MemoryLoad: %d%%" % (stat.dwMemoryLoad)) + #print("Physical memory = %d" % stat.ullTotalPhys) + #print(stat.ullAvailPhys) + def getPhysicalMemory(): + stat = MEMORYSTATUSEX() + ctypes.windll.kernel32.GlobalMemoryStatusEx(ctypes.byref(stat)) + return stat.ullTotalPhys + +elif sys.platform.startswith('linux'): + def getPhysicalMemory(): + return os.sysconf('SC_PAGESIZE') * os.sysconf('SC_PHYS_PAGES') + +elif sys.platform == 'darwin': + def getPhysicalMemory(): + libc = loadCLibrary("libc.dylib") + memsize = ctypes.c_uint64(0) + length = ctypes.c_size_t(ctypes.sizeof(memsize)) + libc.sysctlbyname("hw.memsize", ctypes.byref(memsize), ctypes.byref(length), None, 0) + return memsize.value +else: + def getPhysicalMemory(): + return None + +def getPhysicalMemoryOrNone(): + try: + return getPhysicalMemory() + except: + return None + +if __name__ == "__main__": + print("Physical memory = %d" % getPhysicalMemory()) diff --git a/PyMca/Plot1D.py b/PyMca/Plot1D.py index 1371a1d..60e5ec2 100644 --- a/PyMca/Plot1D.py +++ b/PyMca/Plot1D.py @@ -20,7 +20,7 @@ __author__ = "V.A. Sole - ESRF Data Analysis" This module can be used for plugin testing purposes as well as for doing the bookkeeping of actual plot windows. -It implements the Plot1D interface: +It implements the Plot1DBase interface: addCurve(self, x, y, legend=None, info=None, replace=False, replot=True) getActiveCurve(self, just_legend=False) @@ -44,6 +44,18 @@ class Plot1D(Plot1DBase.Plot1DBase): replot=True): """ Add the 1D curve given by x an y to the graph. + :param x: The data corresponding to the x axis + :type x: list or numpy.ndarray + :param y: The data corresponding to the y axis + :type y: list or numpy.ndarray + :param legend: The legend to be associated to the curve + :type legend: string or None + :param info: Dictionary of information associated to the curve + :type info: dict or None + :param replace: Flag to indicate if already existing curves are to be deleted + :type replace: boolean default False + :param replot: Flag to indicate plot is to be immediately updated + :type replot: boolean default True """ if legend is None: key = "Unnamed curve 1.1" @@ -74,6 +86,10 @@ class Plot1D(Plot1DBase.Plot1DBase): """ Remove the curve associated to the supplied legend from the graph. The graph will be updated if replot is true. + :param legend: The legend associated to the curve to be deleted + :type legend: string or None + :param replot: Flag to indicate plot is to be immediately updated + :type replot: boolean default True """ if legend is None: return @@ -86,7 +102,11 @@ class Plot1D(Plot1DBase.Plot1DBase): def getActiveCurve(self, just_legend=False): """ - Function to access the currently active curve. + :param just_legend: Flag to specify the type of output required + :type just_legend: boolean + :return: legend of the active curve or list [x, y, legend, info] + :rtype: string or list + Function to access the graph currently active curve. It returns None in case of not having an active curve. Default output has the form: @@ -109,6 +129,12 @@ class Plot1D(Plot1DBase.Plot1DBase): def getAllCurves(self, just_legend=False): """ + :param just_legend: Flag to specify the type of output required + :type just_legend: boolean + :return: legend of the curves or list [[x, y, legend, info], ...] + :rtype: list of strings or list of curves + + It returns an empty list in case of not having any curve. If just_legend is False: It returns a list of the form: [[xvalues0, yvalues0, legend0, dict0], @@ -125,10 +151,13 @@ class Plot1D(Plot1DBase.Plot1DBase): keys = self.curveDict.keys() for key in self.curveList: if key in keys: - output.append(self.curveDict[key]) + if just_legend: + output.append(key) + else: + output.append(self.curveDict[key]) return output - def __getAllLimits(self): + def _getAllLimits(self): keys = self.curveDict.keys() if not len(keys): return 0.0, 0.0, 100., 100. @@ -159,23 +188,36 @@ class Plot1D(Plot1DBase.Plot1DBase): def getGraphXLimits(self): """ - Get the graph X limits. + Set the graph X limits. + :param xmin: minimum value of the axis + :type xmin: float + :param xmax: minimum value of the axis + :type xmax: float + :param replot: Flag to indicate plot is to be immediately updated + :type replot: boolean default False """ - xmin, ymin, xmax, ymax = self.__getAllLimits() + xmin, ymin, xmax, ymax = self._getAllLimits() return xmin, xmax def getGraphYLimits(self): """ - Get the graph Y (left) limits. + Set the graph Y (left) limits. + :param ymin: minimum value of the axis + :type ymin: float + :param ymax: minimum value of the axis + :type ymax: float + :param replot: Flag to indicate plot is to be immediately updated + :type replot: boolean default False """ - xmin, ymin, xmax, ymax = self.__getAllLimits() + xmin, ymin, xmax, ymax = self._getAllLimits() return ymin, ymax def setActiveCurve(self, legend): """ - Funtion to request the plot window to set the curve with the specified - legend as the active curve. - It returns the active curve legend. + Funtion to request the plot window to set the curve with the specified legend + as the active curve. + :param legend: The legend associated to the curve + :type legend: string """ key = str(legend) if key in self.curveDict.keys(): @@ -185,7 +227,6 @@ class Plot1D(Plot1DBase.Plot1DBase): def main(): import numpy - x = numpy.arange(100.) y = x * x plot = Plot1D() diff --git a/PyMca/Plot1DBase.py b/PyMca/Plot1DBase.py index c7a001a..79885aa 100644 --- a/PyMca/Plot1DBase.py +++ b/PyMca/Plot1DBase.py @@ -16,7 +16,8 @@ # #############################################################################*/ __author__ = "V.A. Sole - ESRF Software Group" -""" +__license__ = "LGPL" +__doc__ = """ Any window willing to accept 1D plugins should implement the methods defined in this class. @@ -26,8 +27,11 @@ The plugins will be compatible with any 1D-plot window that provides the methods removeCurve getActiveCurve getAllCurves + setGraphTitle getGraphXLimits getGraphYLimits + setGraphXLimits + setGraphYLimits setActiveCurve On instantiation, this clase imports all the plugins found in the PyMcaPlugins @@ -63,6 +67,10 @@ class Plot1DBase(object): self.getPlugins() def setPluginDirectoryList(self, dirlist): + """ + :param dirlist: Set directories to search for Plot1D plugins + :type dirlist: list + """ for directory in dirlist: if not os.path.exists(directory): raise IOError("Directory:\n%s\ndoes not exist." % directory) @@ -70,12 +78,15 @@ class Plot1DBase(object): self.__pluginDirList = dirlist def getPluginDirectoryList(self): + """ + :return dirlist: List of directories to search for Plot1D plugins + """ return self.__pluginDirList def getPlugins(self): """ Import or reloads all the available plugins. - It returns the number of plugins loaded. + :return: The number of plugins loaded. """ if self.__pluginDirList == []: self.__pluginDirList = [PLUGINS_DIR] @@ -137,6 +148,18 @@ class Plot1DBase(object): def addCurve(self, x, y, legend=None, info=None, replace=False, replot=True): """ Add the 1D curve given by x an y to the graph. + :param x: The data corresponding to the x axis + :type x: list or numpy.ndarray + :param y: The data corresponding to the y axis + :type y: list or numpy.ndarray + :param legend: The legend to be associated to the curve + :type legend: string or None + :param info: Dictionary of information associated to the curve + :type info: dict or None + :param replace: Flag to indicate if already existing curves are to be deleted + :type replace: boolean default False + :param replot: Flag to indicate plot is to be immediately updated + :type replot: boolean default True """ print("addCurve not implemented") return None @@ -145,13 +168,21 @@ class Plot1DBase(object): """ Remove the curve associated to the supplied legend from the graph. The graph will be updated if replot is true. + :param legend: The legend associated to the curve to be deleted + :type legend: string or None + :param replot: Flag to indicate plot is to be immediately updated + :type replot: boolean default True """ print("removeCurve not implemented") return None def getActiveCurve(self, just_legend=False): """ - Function to access the currently active curve. + :param just_legend: Flag to specify the type of output required + :type just_legend: boolean + :return: legend of the active curve or list [x, y, legend, info] + :rtype: string or list + Function to access the graph currently active curve. It returns None in case of not having an active curve. Default output has the form: @@ -168,6 +199,12 @@ class Plot1DBase(object): def getAllCurves(self, just_legend=False): """ + :param just_legend: Flag to specify the type of output required + :type just_legend: boolean + :return: legend of the curves or list [[x, y, legend, info], ...] + :rtype: list of strings or list of curves + + It returns an empty list in case of not having any curve. If just_legend is False: It returns a list of the form: [[xvalues0, yvalues0, legend0, dict0], @@ -185,7 +222,8 @@ class Plot1DBase(object): def getGraphXLimits(self): """ - Get the graph X limits. + :return: Two floats with the X axis limits + Get the graph X limits. """ print("getGraphXLimits not implemented") return 0.0, 100.0 @@ -193,35 +231,88 @@ class Plot1DBase(object): def getGraphYLimits(self): """ Get the graph Y (left) limits. + :return: Two floats with the Y (left) axis limits """ print("getGraphYLimits not implemented") return 0.0, 100.0 + def setGraphXLimits(self, xmin, xmax, replot=False): + """ + Set the graph X limits. + :param xmin: minimum value of the axis + :type xmin: float + :param xmax: minimum value of the axis + :type xmax: float + :param replot: Flag to indicate plot is to be immediately updated + :type replot: boolean default False + """ + print("setGraphXLimits not implemented") + return + + def getGraphYLimits(self, ymin, ymax, replot=False): + """ + Set the graph Y (left) limits. + :param ymin: minimum value of the axis + :type ymin: float + :param ymax: minimum value of the axis + :type ymax: float + :param replot: Flag to indicate plot is to be immediately updated + :type replot: boolean default False + """ + print("setGraphYLimits not implemented") + return + def setActiveCurve(self, legend): """ Funtion to request the plot window to set the curve with the specified legend as the active curve. + :param legend: The legend associated to the curve + :type legend: string """ print("setActiveCurve not implemented") return None def setGraphTitle(self, title): + """ + :param title: The title to be set + :type title: string + """ print("setGraphTitle not implemented") def setGraphXTitle(self, title): + """ + :param title: The title to be associated to the X axis + :type title: string + """ print("setGraphXTitle not implemented") def setGraphYTitle(self, title): + """ + :param title: The title to be associated to the X axis + :type title: string + """ print("setGraphYTitle not implemented") + def getGraphTitle(self): + """ + :return: The graph title + :rtype: string + """ print("getGraphTitle not implemented") return "Title" def getGraphXTitle(self): + """ + :return: The graph X axis label + :rtype: string + """ print("getGraphXTitle not implemented") return "X" def getGraphYTitle(self): - print("getGraphYTitle not implemented") + """ + :return: The graph Y axis label + :rtype: string + """ return "Y" diff --git a/PyMca/PyMcaData/HTML/AdvancedAlignmentScanPlugin.html b/PyMca/PyMcaData/HTML/AdvancedAlignmentScanPlugin.html new file mode 100644 index 0000000..40c4d44 --- /dev/null +++ b/PyMca/PyMcaData/HTML/AdvancedAlignmentScanPlugin.html @@ -0,0 +1,246 @@ +<html> +<head> + <style type="text/css"> + body { + background-color:white; + width:400px + } + th, tr, td { + text-align:left; + vertical-align:bottom; + border: 2px solid #CCCCCC; + border-style:solid; + } + table { + font-family:"Monospace"; + font-size:75%; + border: 2px solid grey; + border-collapse:collapse; + width:390px; + margin-left:0px; + margin-right:0px; + margin-top:10px; + margin-bottom:10px; + } + div.indent { + color:#333333; + text-align:justify; + margin-left:20px; + margin-right:20px; + margin-top:20px; + margin-bottom:20px; + } + div.main { + text-align:justify; + margin-left:5px; + margin-right:5px; + margin-top:5px; + margin-bottom:20px; + } + div.elem { + text-align:left; + margin-left:5px; + margin-right:5px; + margin-top:5px; + margin-bottom:5px; + } + div.code { + color:#333333; + background:#EEEEEE; + text-align:left; + margin-left:20px; + margin-right:20px; + margin-top:20px; + margin-bottom:20px; + } + div.highlight { + background: #f8f8f8; + font-size:80%; + } + div.highlight .hll { background-color: #ffffcc } + div.highlight .c { color: #408080; font-style: italic } /* Comment */ + div.highlight .err { border: 1px solid #FF0000 } /* Error */ + div.highlight .k { color: #008000; font-weight: bold } /* Keyword */ + div.highlight .o { color: #666666 } /* Operator */ + div.highlight .cm { color: #408080; font-style: italic } /* Comment.Multiline */ + div.highlight .cp { color: #BC7A00 } /* Comment.Preproc */ + div.highlight .c1 { color: #408080; font-style: italic } /* Comment.Single */ + div.highlight .cs { color: #408080; font-style: italic } /* Comment.Special */ + div.highlight .gd { color: #A00000 } /* Generic.Deleted */ + div.highlight .ge { font-style: italic } /* Generic.Emph */ + div.highlight .gr { color: #FF0000 } /* Generic.Error */ + div.highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */ + div.highlight .gi { color: #00A000 } /* Generic.Inserted */ + div.highlight .go { color: #808080 } /* Generic.Output */ + div.highlight .gp { color: #000080; font-weight: bold } /* Generic.Prompt */ + div.highlight .gs { font-weight: bold } /* Generic.Strong */ + div.highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */ + div.highlight .gt { color: #0040D0 } /* Generic.Traceback */ + div.highlight .kc { color: #008000; font-weight: bold } /* Keyword.Constant */ + div.highlight .kd { color: #008000; font-weight: bold } /* Keyword.Declaration */ + div.highlight .kn { color: #008000; font-weight: bold } /* Keyword.Namespace */ + div.highlight .kp { color: #008000 } /* Keyword.Pseudo */ + div.highlight .kr { color: #008000; font-weight: bold } /* Keyword.Reserved */ + div.highlight .kt { color: #B00040 } /* Keyword.Type */ + div.highlight .m { color: #666666 } /* Literal.Number */ + div.highlight .s { color: #BA2121 } /* Literal.String */ + div.highlight .na { color: #7D9029 } /* Name.Attribute */ + div.highlight .nb { color: #008000 } /* Name.Builtin */ + div.highlight .nc { color: #0000FF; font-weight: bold } /* Name.Class */ + div.highlight .no { color: #880000 } /* Name.Constant */ + div.highlight .nd { color: #AA22FF } /* Name.Decorator */ + div.highlight .ni { color: #999999; font-weight: bold } /* Name.Entity */ + div.highlight .ne { color: #D2413A; font-weight: bold } /* Name.Exception */ + div.highlight .nf { color: #0000FF } /* Name.Function */ + div.highlight .nl { color: #A0A000 } /* Name.Label */ + div.highlight .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */ + div.highlight .nt { color: #008000; font-weight: bold } /* Name.Tag */ + div.highlight .nv { color: #19177C } /* Name.Variable */ + div.highlight .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */ + div.highlight .w { color: #bbbbbb } /* Text.Whitespace */ + div.highlight .mf { color: #666666 } /* Literal.Number.Float */ + div.highlight .mh { color: #666666 } /* Literal.Number.Hex */ + div.highlight .mi { color: #666666 } /* Literal.Number.Integer */ + div.highlight .mo { color: #666666 } /* Literal.Number.Oct */ + div.highlight .sb { color: #BA2121 } /* Literal.String.Backtick */ + div.highlight .sc { color: #BA2121 } /* Literal.String.Char */ + div.highlight .sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */ + div.highlight .s2 { color: #BA2121 } /* Literal.String.Double */ + div.highlight .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */ + div.highlight .sh { color: #BA2121 } /* Literal.String.Heredoc */ + div.highlight .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */ + div.highlight .sx { color: #008000 } /* Literal.String.Other */ + div.highlight .sr { color: #BB6688 } /* Literal.String.Regex */ + div.highlight .s1 { color: #BA2121 } /* Literal.String.Single */ + div.highlight .ss { color: #19177C } /* Literal.String.Symbol */ + div.highlight .bp { color: #008000 } /* Name.Builtin.Pseudo */ + div.highlight .vc { color: #19177C } /* Name.Variable.Class */ + div.highlight .vg { color: #19177C } /* Name.Variable.Global */ + div.highlight .vi { color: #19177C } /* Name.Variable.Instance */ + div.highlight .il { color: #666666 } /* Literal.Number.Integer.Long */ + </style> +</head> + +<body TEXT=#000000 BGCOLOR=#FFFFFF ALINK=#ff6600 LINK=#0000cc VLINK=#0000cc +marginwidth=10 marginheight=10 topmargin=10 leftmargin=10> + +<a NAME=Up></a> +<H3>Alignment plug-in Documentation</H3> + +<H4> +Contents +</H4> +<br> +<a href=#Description>1. Usage and Description</a><br> +<a href=#Methods>2. Methods used by the plug-in</a><br> +<br> + +<H4> +Synopsis +</H4> + +Due to uncertainties in the experimental set-up, recorded data might be shifted unrelated +to physical effects probed in the experiment. The present plug-in calculates this shift and +corrects the data using a variety of different methods. + +<H3><a NAME=Description> +1. Usage and Description +</a></H3> + +<div class='main'> +Data that is subject to a shift must be loaded into the plot window of the main application. +The plug-in offers two ways to treat the data: a shortcut options called 'Perform FFT Shift' +calculates the shift and directly corrects the data and the 'Show Alignment Window' option +showing a window that allows for specification of the shift and alignment methods as well as +offering the possibility to safe calculated shifts respectively load previously calculated +shifts from a file. It is also possible to enter shift values by hand.</br> +</br> +Once the Alignment Window is opened, the alignment method and the shift method must be specified. +The alignment method specifies how the shift is calculated while the shift method determines +how the shift is applied to the data.</br> +</br> +The table shows three columns: The first one shows the plot legend of the data that will be +corrected by the shift method. The second column shows the plot legend from which the shift +is calculated. The third column shows the shift values calculated by the alignment method in +units of the plot windows x-axis. While columns one and two can not be edited, shift values +can be entered by hand. Another way of setting the shift values is to load them from a existing +*.shift file using the Load button.</br> +</br> +Once the shift values are set, they can either be directly applied to the data present in the +plot window using the Apply button or the data can be stored in memory. The latter options allow +to use a reference signal recorded during the experiment to determine the shift and then apply +the shift values to a different set of data.</br> +</br> +Notice: In order to match different sets of data to another, as necessary in the case of a +reference signal, the order in which the data is added to the plot window is crucial. If one +switches between two sets of data where one set aligns the other one it is highly encouraged +to consult the table in the Alignment window to check if every element in the two different +sets of data is assigned to its correct counterpart before applying the shift.</br> +</br> +If the data in the plot window is zoomed in to a distinct feature, only of the data is used to +calculate the shift. +</div> + +<br><a href=#Up>up</a> + +<H3><a NAME=Methods> +1. Usage and Description +</a></H3> + +<div class='main'> +Alignment methods are used to calculate the shift. Present methods include FFT, MAX, FIT and +FIT DRV. +</div> + +<div class=elem><i>FFT</i></div> + <div class='indent'> + Uses the Fourier Transform of the curves to calculated their cross-correlation. The maximum + of the correlation is determined and yields the shift value. This method is the default option, + since it is not affected by the peak shape, fast and numerically robust. Notice: the shifts + are given in real space values. + </div> + +<div class=elem><i>MAX</i></div> + <div class='indent'> + Determines the maximum of each curve, the shift is given by its the differences in the x-position + of the maxima. Notice that this method is highly vulnerable to noise in the data and spikes. + </div> + +<div class=elem><i>FIT</i></div> + <div class='indent'> + Method subtracts a background from the data using the SNIP algorithm (c.f. plug-in section, + Background subtraction tools) and searches for peaks in the data. For every curve, the single + most pronounced feature is selected. The peak is fitted by a Gaussian model, the shifts are then + given by differences in the x-offsets of the fitted Gaussians. + </div> + +<div class=elem><i>FIT</i></div> + <div class='indent'> + Uses the same procedure as the FIT method, however the fit is applied to the first derivative of + the data. This method only recommended for X-ray absorption data. + </div> + +<div class='main'> +Shift methods are used to apply the calculated shift to the data. Present methods include 'Shift x-range' +and 'Inverse FFT shift'. +</div> + +<div class=elem><i>Shift x-range</i></div> + <div class='indent'> + This method takes the x-range of the respective curve and adds the calculated shift value to every + point. + </div> + +<div class=elem><i>Inverse FFT shift</i></div> + <div class='indent'> + Takes the Fourier Transform of a curve and multiplies the shift as a phase factor. The multiplication + of a phase factor in Fourier space translates to a shift in the x-range in real space. The shifted data + is given by the inverse Fourier transform. + + Notice: In the process, the data needs to have a equidistant x-range. If this is not the case, the data + will be interpolated on a equidistant x-range. Due to the cyclic nature of the Fourier transform, this + method is recommended for data that has linear background. + </div> + +<br><a href=#Up>up</a> +</body> diff --git a/PyMca/PyMcaData/HTML/XMCDInfotext.html b/PyMca/PyMcaData/HTML/XMCDInfotext.html new file mode 100644 index 0000000..7602cfc --- /dev/null +++ b/PyMca/PyMcaData/HTML/XMCDInfotext.html @@ -0,0 +1,702 @@ +<html> +<head> + <style type="text/css"> + body { + background-color:white; + width:400px + } + th, tr, td { + text-align:left; + vertical-align:bottom; + border: 2px solid #CCCCCC; + border-style:solid; + } + table { + font-family:"Monospace"; + font-size:75%; + border: 2px solid grey; + border-collapse:collapse; + width:390px; + margin-left:0px; + margin-right:0px; + margin-top:10px; + margin-bottom:10px; + } + div.indent { + color:#333333; + text-align:justify; + margin-left:20px; + margin-right:20px; + margin-top:20px; + margin-bottom:20px; + } + div.main { + text-align:justify; + margin-left:5px; + margin-right:5px; + margin-top:5px; + margin-bottom:20px; + } + div.elem { + text-align:left; + margin-left:5px; + margin-right:5px; + margin-top:5px; + margin-bottom:5px; + } + div.code { + color:#333333; + background:#EEEEEE; + text-align:left; + margin-left:20px; + margin-right:20px; + margin-top:20px; + margin-bottom:20px; + } + div.highlight { + background: #f8f8f8; + font-size:80%; + } + div.highlight .hll { background-color: #ffffcc } + div.highlight .c { color: #408080; font-style: italic } /* Comment */ + div.highlight .err { border: 1px solid #FF0000 } /* Error */ + div.highlight .k { color: #008000; font-weight: bold } /* Keyword */ + div.highlight .o { color: #666666 } /* Operator */ + div.highlight .cm { color: #408080; font-style: italic } /* Comment.Multiline */ + div.highlight .cp { color: #BC7A00 } /* Comment.Preproc */ + div.highlight .c1 { color: #408080; font-style: italic } /* Comment.Single */ + div.highlight .cs { color: #408080; font-style: italic } /* Comment.Special */ + div.highlight .gd { color: #A00000 } /* Generic.Deleted */ + div.highlight .ge { font-style: italic } /* Generic.Emph */ + div.highlight .gr { color: #FF0000 } /* Generic.Error */ + div.highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */ + div.highlight .gi { color: #00A000 } /* Generic.Inserted */ + div.highlight .go { color: #808080 } /* Generic.Output */ + div.highlight .gp { color: #000080; font-weight: bold } /* Generic.Prompt */ + div.highlight .gs { font-weight: bold } /* Generic.Strong */ + div.highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */ + div.highlight .gt { color: #0040D0 } /* Generic.Traceback */ + div.highlight .kc { color: #008000; font-weight: bold } /* Keyword.Constant */ + div.highlight .kd { color: #008000; font-weight: bold } /* Keyword.Declaration */ + div.highlight .kn { color: #008000; font-weight: bold } /* Keyword.Namespace */ + div.highlight .kp { color: #008000 } /* Keyword.Pseudo */ + div.highlight .kr { color: #008000; font-weight: bold } /* Keyword.Reserved */ + div.highlight .kt { color: #B00040 } /* Keyword.Type */ + div.highlight .m { color: #666666 } /* Literal.Number */ + div.highlight .s { color: #BA2121 } /* Literal.String */ + div.highlight .na { color: #7D9029 } /* Name.Attribute */ + div.highlight .nb { color: #008000 } /* Name.Builtin */ + div.highlight .nc { color: #0000FF; font-weight: bold } /* Name.Class */ + div.highlight .no { color: #880000 } /* Name.Constant */ + div.highlight .nd { color: #AA22FF } /* Name.Decorator */ + div.highlight .ni { color: #999999; font-weight: bold } /* Name.Entity */ + div.highlight .ne { color: #D2413A; font-weight: bold } /* Name.Exception */ + div.highlight .nf { color: #0000FF } /* Name.Function */ + div.highlight .nl { color: #A0A000 } /* Name.Label */ + div.highlight .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */ + div.highlight .nt { color: #008000; font-weight: bold } /* Name.Tag */ + div.highlight .nv { color: #19177C } /* Name.Variable */ + div.highlight .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */ + div.highlight .w { color: #bbbbbb } /* Text.Whitespace */ + div.highlight .mf { color: #666666 } /* Literal.Number.Float */ + div.highlight .mh { color: #666666 } /* Literal.Number.Hex */ + div.highlight .mi { color: #666666 } /* Literal.Number.Integer */ + div.highlight .mo { color: #666666 } /* Literal.Number.Oct */ + div.highlight .sb { color: #BA2121 } /* Literal.String.Backtick */ + div.highlight .sc { color: #BA2121 } /* Literal.String.Char */ + div.highlight .sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */ + div.highlight .s2 { color: #BA2121 } /* Literal.String.Double */ + div.highlight .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */ + div.highlight .sh { color: #BA2121 } /* Literal.String.Heredoc */ + div.highlight .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */ + div.highlight .sx { color: #008000 } /* Literal.String.Other */ + div.highlight .sr { color: #BB6688 } /* Literal.String.Regex */ + div.highlight .s1 { color: #BA2121 } /* Literal.String.Single */ + div.highlight .ss { color: #19177C } /* Literal.String.Symbol */ + div.highlight .bp { color: #008000 } /* Name.Builtin.Pseudo */ + div.highlight .vc { color: #19177C } /* Name.Variable.Class */ + div.highlight .vg { color: #19177C } /* Name.Variable.Global */ + div.highlight .vi { color: #19177C } /* Name.Variable.Instance */ + div.highlight .il { color: #666666 } /* Literal.Number.Integer.Long */ + </style> +</head> + +<body TEXT=#000000 BGCOLOR=#FFFFFF ALINK=#ff6600 LINK=#0000cc VLINK=#0000cc +marginwidth=10 marginheight=10 topmargin=10 leftmargin=10> + +<a NAME=Up></a> +<H3>XLD/XMCD Analysis HOWTO</H3> + +<H4> +Contents +</H4> +<br> +<a href=#Usage>1. Usage</a><br> +<a href=#Description>2. Description</a><br> + <a href=#Toprow>2.1 Top row</a><br> + <a href=#OptionsWindow>2.2 Options window</a><br> + <a href=#OptionsWindowNorm>2.2.1 Normalization</a><br> + <a href=#OptionsWindowInterp>2.2.2 Interpolation</a><br> + <a href=#OptionsWindowMotors>2.2.3 Motor selection</a><br> + <a href=#Table>2.3 Table</a><br> + <a href=#AnalysisWindow>2.4 Analysis window</a><br> +<a href=#EditAutoAssign>3. Extend the automatic assignment</a><br> + <a href=#EditExpDict>3.1 Edit the experiments dictionary</a><br> + <a href=#EditComboBox>3.2 Edit the drop down menu</a><br> + <a href=#EditSelectExp>3.3 Edit the selectExperiment function</a><br> +<br> + +<H4> +Synopsis +</H4> + +<div class='main'> +Xray linear dichorism (XLD) and Xray magnetic circular dichorism (XMCD) +measurements as performed at Beamlines ID08 and ID12 of the ESRF +probe the sample with x-rays of two different polarizations. From two spectra +with different polarizations, one calculates the difference spectrum (the +XLD/XMCD spectrum) as well as the average spectrum (XAS spectrum). The present +plug-in aims to ease the evaluation process.<br> +<br> +To assign the recorded spectra into two groups (labeled 'A' and 'B') depending +on their polarization, the plug-in displays meta data obtained from the spec file +and provides methods to automate the assignment process. A separate plot +window allows a preview on calculated XLD/XMCD spectra. Several options relevant +to the treatment of the data can be specified and saved. The results of an analysis +can be exported into spec-files. +</div> + +<br><a href=#Up>up</a> + +<H3><a NAME=Usage> +1. Usage +</a></H3> + +<div class='main'> +From the open spec-File, select the relevant scans in the scan selection window +on the left side of your PyMca session. Assign the relevant counters to the +respective axes and load the scans in the plot window on the right. Load the plug-in +from the plug-in menu (gearbox item in the top row of the plot window). +Notice that if one selects a section of the data by zooming in before starting the +plug-in, only the data within that energy range is used for the analysis.<br> +<br> +The selected spectra now appears in the table of the plug-in. +Per default, the spectra remain unassigned as indicated by the drop down menu showing +the entry 'Generic dichorism'. Either one selects an existing experiment from the +drop down menu (which also provides automatic division of spectra into groups) or does all +settings by hand using the options menu. The options menu also allows to determine +if and when a normalization is applied to the spectra and the specifics of the interpolation +carried out during the calculation.<br> +If all necessary information is displayed in the table, the assignment of spectra to +either group 'A' or 'B' can be done by right-clicking on the table. A context menu appears +offering several ways to assign a selected spectrum a group.<br> +<br> +Once a selection is made, the result of calculations is displayed immediately in the analysis window. +An average is calculated on the spectra that belong to groups 'A' and 'B' (curves labeled +avg_A resp. avg_B). The difference spectrum (curve labeled XMCD) is calculated as Avg(B)- Avg(A). +The XAS spectrum is calculated as the average of both groups: (Avg(A) + Avg(B))/2<br> +The finished analysis can be saved in a spec file using the Save Button in the top button row +of the analysis window. +</div> + +<br><a href=#Up>up</a> + +<H3><a NAME=Description> +2. Description +</a></H3> + +<div class='main'> +The plug-in consists of four elements: the top row of buttons, the table +listing the spectra and the analysis window. Another important element is the options +window. +</div> + +<H4><a NAME=Toprow> +2.1 Top row +</a></H4> + +<div class='main'> +The top row contains the following buttons in order from left to right: the Update +Button, the Options Button and the Experiment Selection. +</div> + +<div class=elem><i>Update Button</i></div> + <div class='indent'> + Loads plots from the main window of the PyMca session into the plug-in. Notice: + If the plot window of the main application is zoomed in or out, only the data + within the zoomed in energy range is considered for analysis. After zooming in + or out in the main application, the spectra in the plug-in should be updated. + </div> + +<div class=elem><i>Options Button</i></div> + <div class='indent'> + Allows to specify the plug-in behavior during the analysis. For information in + can be found in <a href=#OptionsWindow>section 2.2</a>. + </div> + +<div class='elem'><i>Experiment Selection:</i></div> + <div class='indent'> + The options for the experiments carried out at beamlines ID08 and ID12 are + embedded in the plug-in. Selecting one of the experiments sets these options + and divides the spectra automatically into groups 'A' and 'B'. + A new experimental configuration can be added using the 'Add new configuration' + option. A window will open and ask the user to name the configuration. + Once accepted, an option window is opened and can be used to define the experimental + configuration. This can be done by either loading an existing configuration + or by specifying it by hand. + The new experimental configuration can now be selected in the drop down menu and + remains there until the end of the PyMca session. It sets all options as specified, + however the spectra assignment into groups has still to be done by hand. + </div> + +<br><a href=#Up>up</a> + +<H4><a NAME=OptionsWindow> +2.2 Options Window +</a></H4> + +<div class='main'> +With the Options Window, the user can control the details of the analysis and +determine the information shown in the table. A configuration made in the Options +Window can be saved and an existing configuration can be loaded. Notice that once +the 'OK' button is clicked, the analysis is immediately recalculated.<br> +<br> +The saved options are stored in a config file. If the result of a XLD/XMCD +analysis is saved a spec file, the current configuration is automatically +saved in a separate file. +</div> + +<br><a href=#Up>up</a> + +<H4><a NAME=OptionsWindowNorm> +2.2.1 Normalization +</a></H4> + +<div class='main'> +One can select if and when a normalization is applied, the normalization method can +be specified. Either no normalization is applied at all or it is applied before +performing the averages over groups 'A' and 'B'. The third option is to perform +the normalization after averaging over both groups.<br> +<br> +The following table explains the various normalization methods in detail. +</div> + +<table border="1"> + <colgroup> + <col span="1" style="width: 45%;"> + <col span="1" style="width: 55%;"> + </colgroup> + <tr> + <th text-align='left'>Option</th> + <th>Explanation</th> + </tr> + <tr> + <td>(y-min(y))<br>/trapz(max(y)-min(y),x)</td> + <td> + Default selection. Subtracts the minimum value as offset from the spectrum + and normalizes it to its integral + </td> + </tr> + <tr> + <td>y/max(y)</td> + <td> + Normalizes the curve to its maximum value + </td> + </tr> + <tr> + <td>(y-min(y))<br>/(max(y)-min(y))</td> + <td> + Subtracts the minimum value as offset from the spectrum and normalizes to the + resulting maximum, effectively putting all spectral values between zero and one + </td> + </tr> + <tr> + <td>(y-min(y))<br>/sum(max(y)-min(y))</td> + <td> + Similar to the default options, but uses the summation over all spectral values + instead of the integral + </td> + </tr> +</table> + +<br><a href=#Up>up</a> + +<H4><a NAME=OptionsWindowInterp> +2.2.2 Interpolation +</a></H4> + +<div class='main'> +The plug-in performs an interpolation of the spectra selected to be used in the analysis +before calculation averages and differences. In the "Interpolation x-range" section the +user can select, which energy range is used for interpolation. To guarantee numerical +stability of the interpolation, the spectra are cleaned up before being copied from +the main application to the plug-in. +The clean up process consists of sorting the data with respect to the energy (i.e. x) +range as well as removing energies that have been measured twice.<br> +<br> +One can chose between selecting one of the energy ranges that actually have been measured or +let the plug-in determine a equidistant energy range, which might be beneficial for further +analysis such as Savitzky-Golay smoothing. Options that conserve at least one measured +energy range are 'First curve in sequence' or 'Active curve' (i.e. taking the active curve in +the plot window of the main application). +</div> + +<br><a href=#Up>up</a> + +<H4><a NAME=OptionsWindowMotors> +2.2.3 Motor Selection +</a></H4> + +<div class='main'> +The drop down menus allow to select the motors positions to be shown in the plug-in +table. Notice that all motors in the drop down menu are not hard coded in the plug-in +but are obtained dynamically from meta data in the spec file. Motor names are treated +case sensitive by the plug-in. +</div> + + +<div class='elem'><i>Motors for ID08 are:</i></div> +<div class='indent'> +phaseD, PhaseD, oxPS, magnet +</div> + +<div class='elem'><i>Motors for ID12 are:</i></div> +<div class='indent'> +Phase, PhaseA, BRUKER, CRYO, OXFORD +</div> + +<div class='main'> +Notice that ID12 also uses different counters to differ between polarizations. +</div> + +<br><a href=#Up>up</a> + +<H4><a NAME=Table> +2.3 Table +</a></H4> + +<div class='main'> +The table, positioned beneath the top row, shows the spectra that are included +in the XLD/XMCD analysis. The table shows the group to which a curve is assigned, +the curves' legend, the scan number and the counter of a spectrum. The +remaining columns display settings of various physical or virtual motors that were +recorded during the course of the measurement and stored in the meta data of the +spec file. +Every column of the table can be used to sort it with respect to the values in this +column by double clicking the right top corner of the respective header section.<br> +<br> +Right click on the table provides the user with a context menu with the following +options: +</div> + +<div class='elem'><i>Perform Analysis</i></div> + <div class='indent'> + Although most calculation is triggered automatically upon selection of a set + of scans, selecting this option forces the plug-in to recalculate the XLD/XMCD spectrum. + </div> + +<div class='elem'><i>Set as A</i> resp. <i>Set as B</i></div> + <div class='indent'> + Assigns a scan selected in the table to the respective group and triggers a + recalculation of the XLD/XMCD Analysis. + </div> + +<div class='elem'><i>Enter sequence</i></div> + <div class='indent'> + Opens a window and allows to enter a sequence of letters ('A', 'B', 'D'). The + spectra in the table are sorted after their scan number and assigned into + groups 'A' and 'B' based on the sequence, 'D' leaves a spectrum unselected. + If no scan number is present, the spectra remain unsorted. + The length of the sequence does not need to match the number of spectra. If the + length of the sequence is smaller than the number of spectra, the plug-in assumes + the entered sequence as a pattern and repeats it. + </div> + +<div class='elem'><i>Remove selection</i></div> + <div class='indent'> + Removes a scan from the selection, effectively setting its group to 'D' + </div> + +<div class='elem'><i>Invert selection</i></div> + <div class='indent'> + Selects scans in the table that are not selected yet and deselects the selected + scans. + </div> + +<div class='elem'><i>Remove curves</i></div> + <div class='indent'> + Removes curves from the table and the plot window in the main application. + </div> + +<br><a href=#Up>up</a> + +<H4><a NAME=AnalysisWindow> +2.4 Analysis Window +</a></H4> + +<div class='main'> +The analysis window beneath the table shows the result of the XLD/XMCD analysis. Four +curves are displayed: the arithmetic averages over groups A and B, the XAS spectrum +(an arithmetic average over the averages of groups A and B) and the difference spectrum +(group B - group A) called the XMCD spectrum.<br> +<br> +Notice that the XMCD spectrum usually is not in the same order of magnitude as the average +spectra and the XAS spectrum. Thus, the XMCD spectrum is plotted to the secondary y axis +on the right. In order to hide individual spectra, one can right-click on the legend and +select 'Hide curve'.<br> +<br> +In the analysis window behaves exactly like the plot window of the main application. The +plot can be zoomed and the spectra can be manipulated using the usual tools of PyMca. Only +the save routine has been modified to the specific demands of XLD/XMCD analysis. +</div> + +<div class='elem'><i>Save routine</i></div> + <div class='indent'> + The save icon in the analysis window allows the users to save all results of the XLD/XMCD + analysis at once in a single spec file. The data is divided into multiple columns. The + first column contains the energy range over which the analysis is carried out, followed + by the averages over groups 'A' and 'B'. The last two columns are occupied by the XLD/XMCD + spectra.<br> + The save dialog also allows to enter a comment that will be written in the spec file. + If multiple datasets are analyzed consecutively, the results can be still saved in a single + spec file by selecting the 'Append to existing file' option. Every individual scan is saved + in a separate file, too. Therefore, the original file name is extended by an underscore and + the number of scans already present in the file to which the analysis is appended to.<br> + Along with the data, the configuration from the options menu is also saved under the same + file name, but with the extension 'cfg'. + </div> + +<div class='elem'>Buttons <i>Add, Add all, Replace </i>and<i> Replace All</i></div> + <div class='indent'> + Allow to push the resulting spectra from the plug-in window to the plot window of the main + application. While 'Add' and 'Replace' only affect the active curve in the plug-in plot + window, 'Add all' and 'Replace all' copy all curves from the analysis to the main application. + Notice: If one plans to compare two or more analyzed spectra by consecutively pushing them + to the main window, the spectra should be renamed beforehand. The name for each analyzed + spectrum remains the same (avg_A, avg_B, XMCD, XAS) and moving spectra of the same name + to the plot window in the main application just replaces them there. +</div> + +<br><a href=#Up>up</a> + +<H4><a NAME=EditAutoAssign> +3. Extend the automatic assignment +</a></H4> + +<div class='main'> +The scope of this paragraph is to explain the additions to the source code necessary to make to +define a new experiment. The paragraph assumes entry level knowledge of the Python programming +language.<br> +<br> +Data measured on beamline ID08 or ID12 of the ESRF can automatically be assigned to one of groups 'A' +or 'B', as long as it is saved in spec files. By selecting one of the experiments from the drop down +menu in the top row, the XLD/XMCD plug-in sets the motors resp. counters controlling the polarization +in the options menu. This displays the respective values in the plug-ins table. To achieve the +automatic assignment, the plug-in reads the displayed values and guesses the affiliation of a +spectrum based on a set of rules. +</div> + +<br><a href=#Up>up</a> + +<H4><a NAME=EditExpDict> +3.1 Edit the experiments dictionary +</a></H4> + +<div class='main'> +The experiments dictionary contains the settings specific to an experiments. The options concern +the normalization settings and method, the interpolation settings and most importantly the motors +on which the assignment depends.<br> +<br> +The following code fragment shows the exemplary entry 'Generic Dichorism' in the experiments +dictionary. +</div> + +<div class="highlight"><pre><span class="bp">self</span><span class="o">.</span><span class="n">experimentsDict</span> <span class="o">=</span> <span class="p">{</span> + <span class="s">'Generic Dichorism'</span><span class="p">:</span> <span class="p">{</span> + <span class="s">'xrange'</span><span class="p">:</span> <span class="mi">0</span><span class="p">,</span> + <span class="s">'normalization'</span><span class="p">:</span> <span class="mi">0</span><span class="p">,</span> + <span class="s">'normalizationMethod'</span><span class="p">:</span> <span class="s">'offsetAndArea'</span><span class="p">,</span> + <span class="s">'motor0'</span><span class="p">:</span> <span class="s">''</span><span class="p">,</span> + <span class="s">'motor1'</span><span class="p">:</span> <span class="s">''</span><span class="p">,</span> + <span class="s">'motor2'</span><span class="p">:</span> <span class="s">''</span><span class="p">,</span> + <span class="s">'motor3'</span><span class="p">:</span> <span class="s">''</span><span class="p">,</span> + <span class="s">'motor4'</span><span class="p">:</span> <span class="s">''</span> + <span class="p">},</span> + <span class="p">...</span> +<span class="p">}</span> +</div> + +<div class='main'> +Notice that every experiment is represented by a dictionary itself, with the different options +as keys and the respective settings as values. Valid values for each option, as well as the +necessary types are shown in the following table. + +<table border="1"> + <colgroup> + <col span="1" style="width: 15%;"> + <col span="1" style="width: 15%;"> + <col span="1"> + </colgroup> + <tr> + <th text-align='left'>Option</th> + <th>Type</th> + <th>Values: Explanation</th> + </tr> + <tr> + <td>xrange</td> + <td>Int</td> + <td> + <b>0</b>: First curve in sequence<br> + <b>1</b>: Active curve<br> + <b>2</b>: Equidistant x-range</td> + </tr> + <tr> + <td>normalization</td> + <td>Int</td> + <td> + <b>0</b>: No normalization<br> + <b>1</b>: Normalize after average<br> + <b>2</b>: Normalize before average</td> + </tr> + <tr> + <td>normalizationMethod</td> + <td>String</td> + <td> + <b>OffsetAndArea</b>: Subtracts minimum and normalizes to the integral, + <b>OffsetAndCounts</b>: Subtracts minimum and normalizes to the sum, + <b>OffsetAndMaximum</b>: Subtracts minimum and normalizes to the maximum + <b>NormToMaximum</b>: Normalizes to the maximum + </td> + </tr> + </tr> + <tr> + <td>motor0,<br>motor1,<br>motor2,<br>motor3,<br>motor4</td> + <td>String</td> + <td> + Assumes knowledge of the motor settings in the experimental apparatus. + If unsure, consult the Motor Info plug-in or a Beamline Scientist. + </td> + </tr> +</table> + +Notice that up to five motors can be specified, however no motor must be specified. If a +motor is not needed, just set the variable to an empty string. +</div> + +<br><a href=#Up>up</a> + +<H4><a NAME=EditComboBox> +3.2 Edit the drop down menu +</a></H4> + +<div class='main'> +Now that a new experiment is present in the experiments dictionary, it can be added into +the selection of the drop down menu. The drop down menu itself is a QComboBox whose items are +added using the addItem member function. The explicit code to do so (at least in the initial +version of this program) looks as follows: + +<div class="highlight"><pre><span class="bp">self</span><span class="o">.</span><span class="n">expCBox</span><span class="o">.</span><span class="n">addItems</span><span class="p">(</span> + <span class="p">[</span><span class="s">'Generic Dichorism'</span><span class="p">,</span> + <span class="s">'ID08: XLD 9 Tesla Magnet'</span><span class="p">,</span> + <span class="s">'ID08: XLD 5 Tesla Magnet'</span><span class="p">,</span> + <span class="s">'ID08: XMCD 9 Tesla Magnet'</span><span class="p">,</span> + <span class="s">'ID08: XMCD 5 Tesla Magnet'</span><span class="p">,</span> + <span class="s">'ID12: XLD (quater wave plate)'</span><span class="p">,</span> + <span class="s">'ID12: XMCD (Flipper)'</span><span class="p">,</span> + <span class="s">'ID12: XMCD'</span><span class="p">,</span> + <span class="s">'Add new configuration'</span><span class="p">])</span> +</pre></div> + +It is important, that the registered string is the exact key of the experiment in the experiments +dictionary. New experiments should be added above the 'Add new configuration' option. + +<br><a href=#Up>up</a> + +<H4><a NAME=EditSelectExp> +3.3 Edit the selectExperiment function +</a></H4> + +<div class='main'> +The selectExperiment function is called every time a item from the drop down menu is selected. In the process, +the selected option is passed on to the function as a string. Based on this string, the function then sets +the options as defined in the experiments dictionary. This triggers the table of the plug-in to display the +information, especially if motors are present in the options.<br> +<br> +In a second step, the function reads all values shown in the tables motor columns (that is columns 4 to 8). If +needed (as in case of two of the ID12 experiments), the counter column (no. 3) might as well be read out. +The code fragment below shows the updating of the table and the readout. +</div> + +<div class="highlight"><pre><span class="bp">self</span><span class="o">.</span><span class="n">updateTree</span><span class="p">()</span> +<span class="n">values0</span> <span class="o">=</span> <span class="n">numpy</span><span class="o">.</span><span class="n">array</span><span class="p">(</span> + <span class="bp">self</span><span class="o">.</span><span class="n">list</span><span class="o">.</span><span class="n">getColumn</span><span class="p">(</span><span class="mi">4</span><span class="p">,</span> <span class="n">convertType</span><span class="o">=</span><span class="nb">float</span><span class="p">))</span> +<span class="n">values1</span> <span class="o">=</span> <span class="n">numpy</span><span class="o">.</span><span class="n">array</span><span class="p">(</span> + <span class="bp">self</span><span class="o">.</span><span class="n">list</span><span class="o">.</span><span class="n">getColumn</span><span class="p">(</span><span class="mi">5</span><span class="p">,</span> <span class="n">convertType</span><span class="o">=</span><span class="nb">float</span><span class="p">))</span> +<span class="n">values2</span> <span class="o">=</span> <span class="n">numpy</span><span class="o">.</span><span class="n">array</span><span class="p">(</span> + <span class="bp">self</span><span class="o">.</span><span class="n">list</span><span class="o">.</span><span class="n">getColumn</span><span class="p">(</span><span class="mi">6</span><span class="p">,</span> <span class="n">convertType</span><span class="o">=</span><span class="nb">float</span><span class="p">))</span> +<span class="n">values3</span> <span class="o">=</span> <span class="n">numpy</span><span class="o">.</span><span class="n">array</span><span class="p">(</span> + <span class="bp">self</span><span class="o">.</span><span class="n">list</span><span class="o">.</span><span class="n">getColumn</span><span class="p">(</span><span class="mi">7</span><span class="p">,</span> <span class="n">convertType</span><span class="o">=</span><span class="nb">float</span><span class="p">))</span> +<span class="n">values4</span> <span class="o">=</span> <span class="n">numpy</span><span class="o">.</span><span class="n">array</span><span class="p">(</span> + <span class="bp">self</span><span class="o">.</span><span class="n">list</span><span class="o">.</span><span class="n">getColumn</span><span class="p">(</span><span class="mi">8</span><span class="p">,</span> <span class="n">convertType</span><span class="o">=</span><span class="nb">float</span><span class="p">))</span> +</pre></div> + +<div class='main'> +The table function getColumn returns the entries of a table column as a list while conserving the current order +of the table rows. The type of the list elements can be specified using the convertType option. The numpy +Arrays values0 to values4 now contain different motor positions, each values array has the length of the +number of scans in question<br> +<br> +The next section consists of a succession of if/else statements to determine the specific experiment. Within +such a statement, the values from the table are reduced to a single vector named 'values' that determines +the affiliation of a spectrum to groups 'A' or 'B'. This array contains numerical values for every spectrum. +The second step here is to set a pivot element (or threshold value), so that if the value for a spectrum is +above this value, the spectrum belongs to group 'A' and below to group 'B'. New assignment routines must be +implemented here as a new elif block.<br> +<br> +In case of the XLD experiment of ID08, the decision process is shown in the code fragment below. +</div> + +<div class="highlight"><pre><span class="k">if</span> <span class="n">exp</span><span class="o">.</span><span class="n">startswith</span><span class="p">(</span><span class="s">'ID08: XLD'</span><span class="p">):</span> + <span class="n">values</span> <span class="o">=</span> <span class="n">values0</span> + <span class="n">mask</span> <span class="o">=</span> <span class="n">numpy</span><span class="o">.</span><span class="n">where</span><span class="p">(</span><span class="n">numpy</span><span class="o">.</span><span class="n">isfinite</span><span class="p">(</span><span class="n">values</span><span class="p">))[</span><span class="mi">0</span><span class="p">]</span> + <span class="n">minmax</span> <span class="o">=</span> <span class="n">values</span><span class="o">.</span><span class="n">take</span><span class="p">(</span><span class="n">mask</span><span class="p">)</span> + <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">minmax</span><span class="p">):</span> + <span class="n">vmin</span> <span class="o">=</span> <span class="n">minmax</span><span class="o">.</span><span class="n">min</span><span class="p">()</span> + <span class="n">vmax</span> <span class="o">=</span> <span class="n">minmax</span><span class="o">.</span><span class="n">max</span><span class="p">()</span> + <span class="n">vpivot</span> <span class="o">=</span> <span class="o">.</span><span class="mi">5</span> <span class="o">*</span> <span class="p">(</span><span class="n">vmax</span> <span class="o">+</span> <span class="n">vmin</span><span class="p">)</span> + <span class="k">else</span><span class="p">:</span> + <span class="n">values</span> <span class="o">=</span> <span class="n">numpy</span><span class="o">.</span><span class="n">array</span><span class="p">(</span> + <span class="p">[</span><span class="nb">float</span><span class="p">(</span><span class="s">'NaN'</span><span class="p">)]</span><span class="o">*</span><span class="n">numOfSpectra</span><span class="p">)</span> +</pre></div> + +<div class='main'> +In this case, the motor 'PhaseD' (or 'phaseD', depending on the magnet) determines the polarization on the sample +and is thus set in the options dictionary. All motor positions are then contained in numpy array 'values0'. Since no +further calculations are needed, we can directly assign 'values0' to 'values'. The pivot element in this case is +calculated as the average between maximal and minimal values in 'values'.<br> +<br> +The last step of the assignment processes is to loop though the 'values' array and check if the element is +above or below threshold, as shown in the next code fragement. +</div> + +<div class="highlight"><pre><span class="n">seq</span> <span class="o">=</span> <span class="s">''</span> +<span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="n">values</span><span class="p">:</span> + <span class="k">if</span> <span class="nb">str</span><span class="p">(</span><span class="n">x</span><span class="p">)</span> <span class="o">==</span> <span class="s">'nan'</span><span class="p">:</span> + <span class="n">seq</span> <span class="o">+=</span> <span class="s">'D'</span> + <span class="k">elif</span> <span class="n">x</span><span class="o">></span><span class="n">vpivot</span><span class="p">:</span> + <span class="n">seq</span> <span class="o">+=</span> <span class="s">'A'</span> + <span class="k">else</span><span class="p">:</span> + <span class="n">seq</span> <span class="o">+=</span> <span class="s">'B'</span> +<span class="bp">self</span><span class="o">.</span><span class="n">list</span><span class="o">.</span><span class="n">setSelectionToSequence</span><span class="p">(</span><span class="n">seq</span><span class="p">)</span> +</pre></div> + +<div class='main'> +Notice that not-a-number float values in the 'values' array are set to the dummy identifier 'D' and thus are ignored in +the selection. The resulting sequence of this procedure is then passed on to the table function setToSequence, which +assigns the selection. Once a selection is made, a recalculation is triggered automatically. +</div> + +<br><a href=#Up>up</a> + +</body> +</html> diff --git a/PyMca/PyMcaIOHelper/PyMcaIOHelper.c b/PyMca/PyMcaIOHelper/PyMcaIOHelper.c index ad1d772..32681d7 100644 --- a/PyMca/PyMcaIOHelper/PyMcaIOHelper.c +++ b/PyMca/PyMcaIOHelper/PyMcaIOHelper.c @@ -1,4 +1,8 @@ #include "Python.h" +/* adding next line may raise errors ... +#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION +*/ + #include <./numpy/arrayobject.h> #include <stdio.h> @@ -35,7 +39,7 @@ PyMcaIOHelper_fillSupaVisio(PyObject *self, PyObject *args) if (!PyArg_ParseTuple(args, "O|d", &input, &nChannels)) return NULL; inputArray = (PyArrayObject *) - PyArray_ContiguousFromObject(input, PyArray_USHORT, 2,2); + PyArray_ContiguousFromObject(input, NPY_USHORT, 2,2); if (inputArray == NULL) { struct module_state *st = GETSTATE(self); @@ -43,17 +47,17 @@ PyMcaIOHelper_fillSupaVisio(PyObject *self, PyObject *args) return NULL; } - dataPointer = (unsigned short *) inputArray->data; + dataPointer = (unsigned short *) PyArray_DATA(inputArray); dataPointer++; dimensions[1] = *dataPointer++; dimensions[0] = *dataPointer++; dimensions[2] = nChannels; - outputArray = (PyArrayObject *) PyArray_SimpleNew(3, dimensions, PyArray_UINT); + outputArray = (PyArrayObject *) PyArray_SimpleNew(3, dimensions, NPY_UINT); PyArray_FILLWBYTE(outputArray, 0); /* Do the job */ maxy=maxch=0; - outputPointer = (unsigned int *) outputArray->data; - for (i=3; i<inputArray->dimensions[0]; i++) + outputPointer = (unsigned int *) PyArray_DATA(outputArray); + for (i = 3; i < PyArray_DIMS(inputArray)[0]; i++) { y = *dataPointer++; x = *dataPointer++; @@ -114,11 +118,11 @@ PyMcaIOHelper_readAifira(PyObject *self, PyObject *args) dimensions[1] = 128; dimensions[2] = nChannels; - outputArray = (PyArrayObject *) PyArray_SimpleNew(3, dimensions, PyArray_UINT); + outputArray = (PyArrayObject *) PyArray_SimpleNew(3, dimensions, NPY_UINT); PyArray_FILLWBYTE(outputArray, 0); /* Do the job */ - outputPointer = (unsigned int *) outputArray->data; + outputPointer = (unsigned int *) PyArray_DATA(outputArray); while(fscanf(fd, "%2c%c%c", (char *)&channel, &x, &y) == 3) { if (channel >= nChannels) diff --git a/PyMca/PyMcaIOHelper/setup.py b/PyMca/PyMcaIOHelper/setup.py deleted file mode 100644 index be0db11..0000000 --- a/PyMca/PyMcaIOHelper/setup.py +++ /dev/null @@ -1,36 +0,0 @@ -#!/usr/bin/env python - -"""Setup script for the PyMcaIOHelper module distribution.""" - -import os, sys, glob -try: - import numpy -except ImportError: - text = "You must have numpy installed.\n" - text += "See http://sourceforge.net/project/showfiles.php?group_id=1369&package_id=175103\n" - raise ImportError(text) - -from distutils.core import setup -from distutils.extension import Extension - -sources = glob.glob('*.c') -define_macros = [] -setup ( - name = "PyMcaIOHelper", - version = "1.0", - description = "PyMca Input Output helper module", - author = "V.A. Sole - BLISS Group", - author_email = "sole@esrf.fr", - url = "http://www.esrf.fr/computing/bliss/", - - # Description of the modules and packages in the distribution - ext_modules = [ - Extension( - name = 'PyMcaIOHelper', - sources = sources, - define_macros = define_macros, - libraries = [], - include_dirs = [numpy.get_include()] - ), - ], -) diff --git a/PyMca/PyMcaMain.py b/PyMca/PyMcaMain.py index 5df2c22..5f119d7 100644 --- a/PyMca/PyMcaMain.py +++ b/PyMca/PyMcaMain.py @@ -93,7 +93,7 @@ from PyMca.PyMca_Icons import IconDict from PyMca.PyMca_help import HelpDict from PyMca import PyMcaDataDir import os -__version__ = "4.7.0" +__version__ = "4.7.1" if (QTVERSION < '4.0.0') and (sys.platform == 'darwin'): class SplashScreen(qt.QWidget): def __init__(self,parent=None,name="SplashScreen", diff --git a/PyMca/PyMcaPlugins/AdvancedAlignmentScanPlugin.py b/PyMca/PyMcaPlugins/AdvancedAlignmentScanPlugin.py new file mode 100644 index 0000000..9c05b2b --- /dev/null +++ b/PyMca/PyMcaPlugins/AdvancedAlignmentScanPlugin.py @@ -0,0 +1,1075 @@ +#/*########################################################################## +# Copyright (C) 2004-2013 European Synchrotron Radiation Facility +# +# This file is part of the PyMca X-ray Fluorescence Toolkit developed at +# the ESRF by the Software group. +# +# This toolkit is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the Free +# Software Foundation; either version 2 of the License, or (at your option) +# any later version. +# +# PyMca is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +# details. +# +# You should have received a copy of the GNU General Public License along with +# PyMca; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +# +# PyMca follows the dual licensing model of Riverbank's PyQt and cannot be +# used as a free plugin for a non-free program. +# +# Please contact the ESRF industrial unit (industry@esrf.fr) if this license +# is a problem for you. +#############################################################################*/ +__author__ = "Tonn Rueter & V.A. Sole - ESRF Data Analysis" +import numpy +import sys +import traceback +from PyMca import PyMcaQt as qt +from PyMca import PyMcaDataDir, PyMcaDirs, PyMcaFileDialogs +from PyMca import ConfigDict +from PyMca import specfilewrapper as SFW +from PyMca import SpecfitFunctions as SF +from PyMca import SNIPModule as snip +from PyMca.Gefit import LeastSquaresFit as LSF +from PyMca.SpecfitFuns import gauss +from PyMca import SpecfitFuns +from os.path import join as pathjoin + +try: + from PyMca import Plugin1DBase +except ImportError: + print("WARNING:AlignmentScanPlugin import from somewhere else") + from . import Plugin1DBase + +DEBUG = 0 +class AlignmentWidget(qt.QDialog): + + _storeCode = 2 + _colLegend = 0 # Column number of current legends from plot window + _colShiftLegend = 1 # Column number of curve from which the shift was calculated + _colShift = 2 # Shift + + def __init__(self, parent, ddict, llist, plugin): + qt.QDialog.__init__(self, parent) + self.setWindowTitle('Alignment Window') + + nCols = 2 + nRows = len(ddict) + self.plugin = plugin + + # Buttons + buttonSave = qt.QPushButton('Save') + buttonSave.setToolTip('Save shifts to file') + buttonLoad = qt.QPushButton('Load') + buttonLoad.setToolTip('Load shifts from file') + buttonStore = qt.QPushButton('Store') + buttonStore.setToolTip('Store shifts in memory.\n') + buttonApply = qt.QPushButton('Apply') + buttonApply.setToolTip('Apply shift to curves present' + +' in the plot window') + buttonCancel = qt.QPushButton('Cancel') + buttonCalc = qt.QPushButton('Calculate') + + # Table + self.shiftTab = qt.QTableWidget(nRows, nCols) + self.shiftTab.verticalHeader().hide() + self.shiftTab.horizontalHeader().setStretchLastSection(True) + self.shiftTab.setHorizontalHeaderLabels(['Legend','Shift']) + + # Shift Method selector + self.shiftMethodComboBox = qt.QComboBox() + self.shiftMethodComboBox.addItems( + ['Shift x-range', + 'Inverse FFT shift']) + shiftMethodToolTip =\ + ('Select the method that shifts the spectra\n\n' + +'Shift x-range:\n' + +' Directly applies the shift to the data\'s\n' + +' x-range\n' + +'Inverse FFT shift:\n' + +' Shifts the spectra by multiplying a\n' + +' phase factor to their Fourier transform. The result is\n' + +' transformed back to real space. Recommended for data with\n' + +' resp. regions with constant background.') + self.shiftMethodComboBox.setToolTip(shiftMethodToolTip) + + # Alignment Method selector + self.alignmentMethodComboBox = qt.QComboBox() + self.alignmentMethodComboBox.addItems( + ['FFT', + 'MAX', + 'FIT', + 'FIT DRV']) + alignmentMethodToolTip =\ + ('Select the method used to calculate the shift is calculated.\n\n' + +'FFT:\n' + +' Calculates the correlation between two curves using its\n' + +' Fourier transform. The shift is proportional to the distance of\n' + +' the correlation function\'s maxima.\n' + +'MAX:\n' + +' Determines the shift as the distance between the maxima of\n' + +' two peaks\n' + +'FIT:\n' + +' Guesses the most prominent feature in a spectrum and tries\n' + +' to fit it with a Gaussian peak. Before the fit is perform, the\n' + +' background is substracted. The shift is given by the difference\n' + +' of the center of mass between two peaks.\n' + +'FIT DRV:\n' + +' Like FIT, but the fit is performed on the derivate of the\n' + +' spectrum. Recommended procedure for XAFS data.') + self.alignmentMethodComboBox.setToolTip(alignmentMethodToolTip) + + # Fill table with data + self.setDict(llist, ddict) + self.shiftTab.resizeColumnToContents(self._colLegend) + self.shiftTab.resizeColumnToContents(self._colShiftLegend) + + #Layouts + topLayout = qt.QHBoxLayout() + topLayout.addWidget(buttonCalc) + topLayout.addWidget(qt.HorizontalSpacer()) + topLayout.addWidget(qt.QLabel('Alignment method:')) + topLayout.addWidget(self.alignmentMethodComboBox) + topLayout.addWidget(qt.QLabel('Shift method:')) + topLayout.addWidget(self.shiftMethodComboBox) + + buttonLayout = qt.QHBoxLayout() + buttonLayout.addWidget(buttonSave) + buttonLayout.addWidget(buttonLoad) + buttonLayout.addWidget(qt.HorizontalSpacer()) + buttonLayout.addWidget(buttonApply) + buttonLayout.addWidget(buttonStore) + buttonLayout.addWidget(buttonCancel) + + mainLayout = qt.QVBoxLayout() + mainLayout.addLayout(topLayout) + mainLayout.addWidget(self.shiftTab) + mainLayout.addLayout(buttonLayout) + mainLayout.setContentsMargins(1,1,1,1) + self.setLayout(mainLayout) + + # Connects + self.shiftTab.cellChanged.connect(self.validateInput) + buttonApply.clicked.connect(self.accept) + buttonCancel.clicked.connect(self.reject) + buttonStore.clicked.connect(self.store) + buttonSave.clicked.connect(self.saveDict) + buttonLoad.clicked.connect(self.loadDict) + + # ..to Plugin instance + buttonCalc.clicked[()].connect(self.triggerCalculateShift) + self.alignmentMethodComboBox.activated['QString'].\ + connect(self.triggerCalculateShift) + + def triggerCalculateShift(self, methodName=None): + # Need to call the plugin instance to perform calculations + try: + if methodName != None: + self.plugin.setAlignmentMethod(methodName) + llist, ddict = self.plugin.calculateShifts() + self.setDict(llist, ddict) + except: + msg = qt.QMessageBox(self) + msg.setIcon(qt.QMessageBox.Critical) + msg.setWindowTitle("Plugin error") + msg.setText("An error has occured while executing the plugin:") + msg.setInformativeText(str(sys.exc_info()[1])) + msg.setDetailedText(traceback.format_exc()) + msg.exec_() + + def store(self): + self.done(self._storeCode) + + def loadDict(self): + openDir = PyMcaDirs.outputDir + filter = 'PyMca (*.shift)' + filename = qt.QFileDialog.\ + getOpenFileName(self, + 'Load Shifts obtained from FFTAlignment', + openDir, + filter) + if len(filename) == 0: + return + inDict = ConfigDict.ConfigDict() + try: + inDict.read(filename) + except IOError: + msg = qt.QMessageBox() + msg.setTitle('FFTAlignment Load Error') + msg.setText('Unable to read shifts form file \'%s\''%filename) + msg.exec_() + return + if 'Shifts' not in inDict.keys(): + # Only if the shift file consists exclusively of ShiftList + orderedLegends = [legend for legend in self.plugin.getOrder()] + try: + shiftList = inDict['ShiftList']['ShiftList'] + except KeyError: + msg = qt.QMessageBox() + msg.setWindowTitle('FFTAlignment Load Error') + msg.setText('No shift information found in file \'%s\''%filename) + msg.exec_() + ddict = dict(zip(orderedLegends, shiftList)) + llist = self.plugin.getOrder() + else: + llist = inDict['Order']['Order'] + ddict = inDict['Shifts'] + self.setDict(llist, ddict) + + def saveDict(self): + saveDir = PyMcaDirs.outputDir + filter = ['PyMca (*.shift)'] + try: + filename = PyMcaFileDialogs.\ + getFileList(parent=self, + filetypelist=filter, + message='Safe FFT Alignment shifts', + mode='SAVE', + single=True)[0] + except IndexError: + # Returned list is empty + return False + if len(filename) == 0: + return False + if not str(filename).endswith('.shift'): + filename += '.shift' + if DEBUG: + print('saveOptions -- Filename: "%s"' % filename) + currentOrder = self.plugin.getOrder() + outDict = ConfigDict.ConfigDict() + llist, ddict = self.getDict() + outDict['Order'] = {'Order': currentOrder} + outDict['Shifts'] = ddict + outDict['ShiftList'] = { + 'ShiftList':[ddict[legend] for legend in currentOrder]} + try: + outDict.write(filename) + except IOError: + msg = qt.QMessageBox() + msg.setWindowTitle('FFTAlignment Save Error') + msg.setText('Unable to write configuration to \'%s\''%filename) + msg.exec_() + return True + + def getAlignmentMethodName(self): + return self.alignmentMethodComboBox.currentText() + + def getShiftMethodName(self): + return self.shiftMethodComboBox.currentText() + + def getDict(self): + llist, ddict = [], {} + for idx in range(self.shiftTab.rowCount()): + # Loop through rows + legend = self.shiftTab.item(idx, self._colLegend) + shiftLegend = self.shiftTab.item(idx, self._colShiftLegend) + value = self.shiftTab.item(idx, self._colShift) + try: + floatValue = float(value.text()) + except: + floatValue = float('NaN') + ddict[str(legend.text())] = floatValue + llist.append(str(shiftLegend.text())) + return llist, ddict + + def setDict(self, llist, ddict): + # Order in which shift are shown is not + # necessarily the order in which they were + # added to plot window + + curr = self.plugin.getOrder() + keys = llist + vals = [ddict[k] for k in keys] + # ..or just leave them in random ddict order + #dkeys = ddict.keys() + #dvals = ddict.values() + + self.shiftTab.clear() + self.shiftTab.setColumnCount(3) + self.shiftTab.setHorizontalHeaderLabels( + ['Legend','Shift calculated from','Shift']) + self.shiftTab.setRowCount(len(keys)) + if len(ddict) == 0: + return + + for j, dlist in enumerate([curr, keys, vals]): + # j denotes the column of the table + # j = 0: Legend, set cells inactive (greyed out) + # j = 1: Legend from which the shift was calculated (greyed out) + # j = 2: Shift values, set cells active + for i in range(len(dlist)): + # i loops through the contents of each list + # setting every row of the table + if (j == 0) or (j == 1): + elem = qt.QTableWidgetItem(dlist[i]) + elem.setFlags(qt.Qt.ItemIsSelectable) + #elem.setFlags(qt.Qt.ItemIsEnabled) + elif j == 2: + elem = qt.QTableWidgetItem(str(dlist[i])) + elem.setTextAlignment(qt.Qt.AlignRight) + elem.setTextAlignment(qt.Qt.AlignRight + qt.Qt.AlignVCenter) + elem.setFlags(qt.Qt.ItemIsEditable | qt.Qt.ItemIsEnabled) + else: + elem = qt.QTableWidgetItem('') + self.shiftTab.setItem(i,j, elem) + self.shiftTab.resizeColumnToContents(self._colLegend) + self.shiftTab.resizeColumnToContents(self._colShiftLegend) + self.shiftTab.resizeRowsToContents() + + def validateInput(self, row, col): + if (col == 0) or (col == 1): + return + elif col == 2: + item = self.shiftTab.item(row, 2) + try: + floatValue = float(item.text()) + item.setText('%.6g'%floatValue) + except: + floatValue = float('NaN') + item.setText(str(floatValue)) + +class AdvancedAlignmentScanPlugin(Plugin1DBase.Plugin1DBase): + def __init__(self, plotWindow, **kw): + Plugin1DBase.Plugin1DBase.__init__(self, plotWindow, **kw) + self.__randomization = True + self.__methodKeys = [] + self.methodDict = {} + + function = self.calculateAndApplyShifts + method = "Perform FFT Alignment" + text = "Performs FFT based alignment and\n" + text += "inverse FFT based shift" + info = text + icon = None + self.methodDict[method] = [function, + info, + icon] + self.__methodKeys.append(method) + + function = self.showShifts + method = "Show Alignment Window" + text = "Displays the calculated shifts and\n" + text += "allows to fine tune the plugin" + info = text + icon = None + self.methodDict[method] = [function, + info, + icon] + self.__methodKeys.append(method) + + function = self.showDocs + method = "Show documentation" + text = "Shows the plug-ins documentation\n" + text += "in a browser window" + info = text + icon = None + self.methodDict[method] = [function, + info, + icon] + self.__methodKeys.append(method) + + self.alignmentMethod = self.calculateShiftsFFT + self.shiftMethod = self.fftShift + self.shiftDict = {} + self.shiftList = [] + + #Methods to be implemented by the plugin + def getMethods(self, plottype=None): + """ + A list with the NAMES associated to the callable methods + that are applicable to the specified plot. + + Plot type can be "SCAN", "MCA", None, ... + """ +# if self.__randomization: +# return self.__methodKeys[0:1] + self.__methodKeys[2:] +# else: +# return self.__methodKeys[1:] + return self.__methodKeys + + def getMethodToolTip(self, name): + """ + Returns the help associated to the particular method name or None. + """ + return self.methodDict[name][1] + + def getMethodPixmap(self, name): + """ + Returns the pixmap associated to the particular method name or None. + """ + return None + + def applyMethod(self, name): + """ + The plugin is asked to apply the method associated to name. + """ + return self.methodDict[name][0]() + + + def calculateAndApplyShifts(self): + # Assure that FFT alignment & shift methods are set + self.alignmentMethod = self.calculateShiftsFFT + self.shiftMethod = self.fftShift + self.calculateShifts() + self.applyShifts() + # Reset shift Dictionary and legend List + self.shiftDict = {} + self.shiftList = [] + + def calculateShifts(self): + ''' + Generic alignment method, executes the method + that is set under self.alignmentMethod. + + Choices are: + - calculateShiftsFit + - calculateShiftsFFT + - calculateShiftsMax + + Sets self.shiftList and self.shiftDict + ''' + self.shiftList, self.shiftDict = self.alignmentMethod() + return self.shiftList, self.shiftDict + + def getOrder(self): + ''' + Returns the legends of the curves in the plot winow + in the order they were added. + ''' + ret = [legend for (x,y,legend,info) in self._plotWindow.getAllCurves()] + return ret + + # BEGIN Alignment Methods + def calculateShiftsFitDerivative(self): + return self.calculateShiftsFit(derivative=True) + + def calculateShiftsFit(self, derivative=False, thr=30): + retDict = {} + retList = [] + + curves = self.getAllCurves() + nCurves = len(curves) + if nCurves < 2: + raise ValueError("At least 2 curves needed") + return + + # Check if scan window is zoomed in + xmin, xmax = self.getGraphXLimits() + # Determine largest overlap between curves + xmin0, xmax0 = self.getXLimits(x for (x,y,leg,info) in curves) + if xmin0 > xmin: + xmin = xmin0 + if xmax0 < xmax: + xmax = xmax0 + if DEBUG: + print('calculateShiftsFit -- xmin = %.3f, xmax = %.3f'%(xmin, xmax)) + + # Get active curve + activeCurve = self.getActiveCurve() + if activeCurve is None: + # If active curve is not set, continue with first curve + activeCurve = curves[0] + else: + activeLegend = activeCurve[2] + idx = list.index([curve[2] for curve in curves], + activeLegend) + activeCurve = curves[idx] + + x0, y0 = activeCurve[0], activeCurve[1] + idx = numpy.nonzero((xmin <= x0) & (x0 <= xmax))[0] + x0 = numpy.take(x0, idx) + y0 = numpy.take(y0, idx) + + if derivative: + # Take first derivative + y0 = numpy.diff(y0)/numpy.diff(x0) + x0 = .5 * (x0[1:] + x0[:-1]) + + peak0 = self.findPeaks(x0, y0, .80, derivative) + if peak0: + xp0, yp0, fwhm0, fitrange0 = peak0 + else: + raise ValueError("No peak identified in '%s'"%activeCurve[2]) + fitp0, chisq0, sigma0 = LSF(gauss, + numpy.asarray([yp0, xp0, fwhm0]), + xdata=x0[fitrange0], + ydata=y0[fitrange0]) + if DEBUG: + if derivative: + print('calculateShiftsFit -- Results (Leg, PeakPos, Shift):') + else: + print('calculateShiftsFitDerivative -- Results (Leg, PeakPos, Shift):') + for x,y,legend,info in curves: + idx = numpy.nonzero((xmin <= x) & (x <= xmax))[0] + x = numpy.take(x, idx) + y = numpy.take(y, idx) + + if derivative: + # Take first derivative + y = numpy.diff(y)/numpy.diff(x) + x = .5 * (x[1:] + x[:-1]) + + peak = self.findPeaks(x, y, .80, derivative) + if peak: + xp, yp, fwhm, fitrange = peak + else: + raise ValueError("No peak identified in '%s'"%activeCurve[2]) + try: + fitp, chisq, sigma = LSF(gauss, + numpy.asarray([yp, xp, fwhm]), + xdata=x[fitrange], + ydata=y[fitrange]) + # Shift is difference in peak's x position + shift = fitp0[1] - fitp[1] + except numpy.linalg.linalg.LinAlgError: + msg = qt.QMessageBox(None) + msg.setWindowTitle('Alignment Error') + msg.setText('Singular matrix encountered during least squares fit.') + msg.setStandardButtons(qt.QMessageBox.Ok) + msg.exec_() + shift = float('NaN') + key = legend + retList.append(key) + retDict[key] = shift + if DEBUG: + print( '\t%s\t%.3f\t%.3f'%(legend, fitp[1], shift)) + return retList, retDict + + def calculateShiftsMax(self): + retDict = {} + retList = [] + + curves = self.getAllCurves() + nCurves = len(curves) + + if nCurves < 2: + raise ValueError("At least 2 curves needed") + return + + # Check if plotwindow is zoomed in + xmin, xmax = self.getGraphXLimits() + # Determine largest overlap between curves + xmin0, xmax0 = self.getXLimits(x for (x,y,leg,info) in curves) + if xmin0 > xmin: + xmin = xmin0 + if xmax0 < xmax: + xmax = xmax0 + + # Get active curve + activeCurve = self.getActiveCurve() + if activeCurve is None: + # If active curve is not set, continue with first curve + activeCurve = curves[0] + else: + activeLegend = activeCurve[2] + idx = list.index([curve[2] for curve in curves], + activeLegend) + activeCurve = curves[idx] + + x0, y0 = activeCurve[0], activeCurve[1] + idx = numpy.nonzero((xmin <= x0) & (x0 <= xmax))[0] + x0 = numpy.take(x0, idx) + y0 = numpy.take(y0, idx) + + # Determine the index of maximum in active curve + shift0 = numpy.argmax(y0) + if DEBUG: + print('calculateShiftsMax -- Results:') + print('\targmax(y) shift') + for x,y,legend,info in curves: + idx = numpy.nonzero((xmin <= x) & (x <= xmax))[0] + x = numpy.take(x, idx) + y = numpy.take(y, idx) + + shifty = numpy.argmax(y) + shift = x0[shift0] - x[shifty] + key = legend + retList.append(key) + retDict[key] = shift + if DEBUG: + print('\t%d %.3f'%(x[shifty],shift)) + return retList, retDict + + def calculateShiftsFFT(self, portion=.95): + retDict = {} + retList = [] + + curves = self.interpolate() + nCurves = len(curves) + if nCurves < 2: + raise ValueError("At least 2 curves needed") + return + + # Check if scan window is zoomed in + xmin, xmax = self.getGraphXLimits() + # Determine largest overlap between curves + xmin0, xmax0 = self.getXLimits(x for (x,y,leg,info) in curves) + if xmin0 > xmin: + xmin = xmin0 + if xmax0 < xmax: + xmax = xmax0 + if DEBUG: + print('calculateShiftsFFT -- xmin = %.3f, xmax = %.3f'%(xmin, xmax)) + + # Get active curve + activeCurve = self.getActiveCurve() + if activeCurve is None: + # If active curve is not set, continue with first curve + activeCurve = curves[0] + else: + activeLegend = activeCurve[2] + idx = list.index([curve[2] for curve in curves], + activeLegend) + activeCurve = curves[idx] + + x0, y0 = activeCurve[0], activeCurve[1] + idx = numpy.nonzero((xmin <= x0) & (x0 <= xmax))[0] + x0 = numpy.take(x0, idx) + y0 = self.normalize(y0) + y0 = numpy.take(y0, idx) + + fft0 = numpy.fft.fft(y0) + if DEBUG: + print('calculateShiftsFFT -- results (Legend len(idx) shift):') + for x,y,legend,info in curves: + idx = numpy.nonzero((x >= xmin) & (x <= xmax))[0] + x = numpy.take(x, idx) + y = numpy.take(y, idx) + ffty = numpy.fft.fft(y) + shiftTmp = numpy.fft.ifft(fft0 * ffty.conjugate()).real + shiftPhase = numpy.zeros(shiftTmp.shape, dtype=shiftTmp.dtype) + m = shiftTmp.size//2 + shiftPhase[m:] = shiftTmp[:-m] + shiftPhase[:m] = shiftTmp[-m:] + # Normalize shiftPhase to standardize thresholding + shiftPhase = self.normalize(shiftPhase) + + # Thresholding + xShiftMax = shiftPhase.argmax() + left, right = xShiftMax, xShiftMax + threshold = portion * shiftPhase.max() + while (shiftPhase[left] > threshold)&\ + (shiftPhase[right] > threshold): + left -= 1 + right += 1 + idx = numpy.arange(left, right+1, 1, dtype=int) + # The shift is determined by center-of-mass around shiftMax + shiftTmp = (shiftPhase[idx] * idx/shiftPhase[idx].sum()).sum() + shift = (shiftTmp - m) * (x[1] - x[0]) + + key = legend + retList.append(key) + retDict[key] = shift + if DEBUG: + print('\t%s\t%d\t%f'%(legend,len(idx),shift)) + return retList, retDict + # END Alignment Methods + + def applyShifts(self): + ''' + Generic shift method. The method shifts curves + according to the shift stored in self.shiftDict + and executes the method stored in self.shiftMethod. + + Curves are sorted with respect to their legend, + the values of self.shiftDict are sorted with + respect to their key. + ''' + if len(self.shiftDict) == 0: + msg = qt.QMessageBox(None) + msg.setWindowTitle('Alignment Error') + msg.setText('No shift data present.') + msg.setStandardButtons(qt.QMessageBox.Ok) + msg.exec_() + return False + + # Check if interpolation is needed + if self.shiftMethod == self.fftShift: + curves = self.interpolate() + else: + curves = self.getAllCurves() + + if len(self.shiftList) != len(curves): + msg = qt.QMessageBox(None) + msg.setWindowTitle('Alignment Error') + msg.setText( + '''Number of shifts does not match the number of curves. + Do you want to continue anyway?''') + msg.setStandardButtons(qt.QMessageBox.Ok) + msg.setStandardButtons(qt.QMessageBox.Ok | qt.QMessageBox.Cancel) + msg.setDefaultButton(qt.QMessageBox.Ok) + + if msg.exec_() != qt.QMessageBox.Ok: + return False + + if DEBUG: + print('applyShifts -- Shifting ...') + for idx, (x,y,legend,info) in enumerate(curves): + shift = self.shiftDict[legend] + + if shift is None: + if DEBUG: + print('\tCurve \'%s\' not found in shiftDict\n%s'\ + %(legend,str(self.shiftDict))) + continue + if shift == float('NaN'): + if DEBUG: + print('\tCurve \'%s\' has NaN shift'%legend) + continue + + # Limit shift to zoomed in area + xmin, xmax = self.getGraphXLimits() + mask = numpy.nonzero((xmin<=x) & (x<=xmax))[0] + # Execute method stored in self.shiftMethod + xShifted, yShifted = self.shiftMethod(shift, x[mask], y[mask]) + + if idx == 0: + replace, replot = True, False + elif idx == (len(curves)-1): + replace, replot = False, True + else: + replace, replot = False, False + # Check if scan number is adopted by new curve + if DEBUG: + print('\'%s\' -- shifts -> \'%s\' by %f'%(self.shiftList[idx], legend, shift)) + selectionlegend = info.get('selectionlegend',legend) + self.addCurve(xShifted, yShifted, + (selectionlegend + ' SHIFT'), + info, + replace, replot) + return True + + + # BEGIN Shift Methods + def fftShift(self, shift, x, y): + yShifted = numpy.fft.ifft( + numpy.exp(-2.0*numpy.pi*numpy.sqrt(numpy.complex(-1))*\ + numpy.fft.fftfreq(len(x), d=x[1]-x[0])*shift)*numpy.fft.fft(y)) + return x, yShifted.real + + def xShift(self, shift, x, y): + return x+shift, y + # END Shift Methods + + def showShifts(self): + ''' + Creates an instance of Alignment Widget that + allows to + + - Calculate, display & save/store shifts + - Load existing shift data + - Select different alignment and shift methods + ''' + # Empty shift table in the beginning + widget = AlignmentWidget(None, self.shiftDict, self.shiftList, self) + ret = widget.exec_() + if ret == 1: + # Result code Apply + self.shiftList, self.shiftDict = widget.getDict() + # self.shiftList = self.getOrder() + self.setShiftMethod(widget.getShiftMethodName()) + self.applyShifts() + self.shiftDict = {} + self.shiftList = [] + elif ret == 2: + # Result code Store + self.shiftList, self.shiftDict = widget.getDict() + self.shiftList = self.getOrder() # Remember order of scans + self.setShiftMethod(widget.getShiftMethodName()) + else: + # Dialog is canceled + self.shiftDict = {} + self.shiftList = [] + widget.destroy() # Widget should be destroyed after finishing method + return + + # BEGIN Helper Methods + def setShiftMethod(self, methodName): + ''' + Method receives methodName from AlignmentWidget + instance and assigns the according shift method. + ''' + if DEBUG: + print('setShiftMethod -- %s'%methodName) + methodName = str(methodName) + if methodName == 'Inverse FFT shift': + self.shiftMethod = self.fftShift + elif methodName == 'Shift x-range': + self.shiftMethod = self.xShift + else: + # Unknown method name, use fftShift as default + self.shiftMethod = self.fftShift + + def setAlignmentMethod(self, methodName): + ''' + Method receives methodName from AlignmentWidget + instance and assigns the according alignment method. + ''' + if DEBUG: + print('setAlignmentMethod -- %s'%methodName) + methodName = str(methodName) + if methodName == 'FFT': + self.alignmentMethod = self.calculateShiftsFFT + elif methodName == 'MAX': + self.alignmentMethod = self.calculateShiftsMax + elif methodName == 'FIT': + self.alignmentMethod = self.calculateShiftsFit + elif methodName == 'FIT DRV': + self.alignmentMethod = self.calculateShiftsFitDerivative + else: + # Unknown method name, use fftShift as default + self.alignmentMethod = self.calculateShiftsFFT + + def getAllCurves(self, just_legend=False): + ''' + Ensures that the x-range of the curves + is strictly monotonically increasing. + Conserves curves legend and info dictionary. + ''' + curves = Plugin1DBase.Plugin1DBase.getAllCurves(self) + if just_legend: + return curves + + processedCurves = [] + for curve in curves: + x, y, legend, info = curve[0:4] + xproc = x[:] + yproc = y[:] + # Sort + idx = numpy.argsort(xproc, kind='mergesort') + xproc = numpy.take(xproc, idx) + yproc = numpy.take(yproc, idx) + # Ravel, Increasing + xproc = xproc.ravel() + idx = numpy.nonzero((xproc[1:] > xproc[:-1]))[0] + xproc = numpy.take(xproc, idx) + yproc = numpy.take(yproc, idx) + processedCurves += [(xproc, yproc, legend, info)] + return processedCurves + + def interpolate(self, factor=1.): + ''' + Input + ----- + factor : float + factor used to oversample existing data, use + with caution. + + Interpolates all existing curves to an equidistant + x-range using the either the active or the first + curve do determine the number of data points. + Use this method instead of self.getAllCurves() when + performin FFT related tasks. + + Returns + ------- + interpCurves : ndarray + Array containing the interpolated curves shown + in the plot window. + Format: [(x0, y0, legend0, info0), ...] + ''' + curves = self.getAllCurves() + if len(curves) < 1: + raise ValueError("At least 1 curve needed") + if DEBUG: + print('interpolate -- no curves present') + return + + activeCurve = self.getActiveCurve() + if not activeCurve: + activeCurve = curves[0] + else: + activeLegend = activeCurve[2] + idx = list.index([curve[2] for curve in curves], + activeLegend) + activeCurve = curves[idx] + activeX, activeY, activeLegend, activeInfo = activeCurve[0:4] + + # Determine average spaceing between Datapoints + step = numpy.average(numpy.diff(activeX)) + xmin, xmax = self.getXLimits([x for (x,y,leg,info) in curves], + overlap=False) + num = factor * numpy.ceil((xmax-xmin)/step) + + # Create equidistant x-range, exclude first and last point + xeq = numpy.linspace(xmin, xmax, num, endpoint=False)[:-1] + + # Interpolate on sections of xeq + interpCurves = [] + for (x,y,legend,info) in curves: + idx = numpy.nonzero((x.min()<xeq) & (xeq<x.max()))[0] + xi = numpy.take(xeq, idx) + yi = SpecfitFuns.interpol([x], y, xi.reshape(-1,1), y.min()) + yi.shape = -1 + interpCurves += [(xi, yi, legend, info)] + return interpCurves + + def getXLimits(self, values, overlap=True): + ''' + Input + ----- + overlap : bool + True -> returns minimal and maximal x-values + that are that are still lie within the + x-ranges of all curves in plot window + False -> returns minimal and maximal x-values of + all curves in plot window + + Returns + ------- + xmin0, xmax0 : float + ''' + if overlap: + xmin0, xmax0 = -numpy.inf, numpy.inf + else: + xmin0, xmax0 = numpy.inf, -numpy.inf + for x in values: + xmin = x.min() + xmax = x.max() + if overlap: + if xmin > xmin0: + xmin0 = xmin + if xmax < xmax0: + xmax0 = xmax + else: + if xmin < xmin0: + xmin0 = xmin + if xmax > xmax0: + xmax0 = xmax + if DEBUG: + print('getXLimits -- overlap = %s, xmin = %.3f, xmax =%.3f'\ + %(overlap,xmin0,xmax0)) + return xmin0, xmax0 + + def normalize(self, y): + ''' + Normalizes spectrum to values between zero and one. + ''' + ymax, ymin = y.max(), y.min() + return (y-ymin)/(ymax-ymin) + + def findPeaks(self, x, y, thr, derivative): + ''' + Input + ----- + x,y : ndarrays + Arrays contain curve intformation + thr : float + Threshold in percent of normalized maximum + derivative : bool + The derivative of a curve is being fitted + + Finds most prominent feature contained in y + and tries to estimate starting parameters for a + Gaussian least squares fit (LSF). Recommends values + used to fit the Gaussian. + + Return + ------ + xpeak, ypeak, fwhm : float + Estimated values for x-position, amplitude + and width of the Gaussian + fwhmIdx : ndarray + Indices determine the range on which the LSF + is performed + ''' + # Use SNIP algorithm for background substraction & + # seek method for peak detection + sffuns = SF.SpecfitFunctions() + if derivative: + # Avoid BG substraction & normalization if + # fitting the derivate of a curve + ybg = y + ynorm = y/(abs(y.max())+abs(y.min())) + else: + ybg = y-snip.getSnip1DBackground(y, len(y)//thr) # USER INPUT!!! + # Normalize background substracted data to + # standardize the yscaling of seek method + #ynorm = (ybg - ybg.min())/(ybg.max()-ybg.min()) + ynorm = self.normalize(ybg) + + # Replace by max()? + try: + # Calculate array woth all peak indices + peakIdx = numpy.asarray(sffuns.seek(ybg, yscaling=1000.), dtype=int) + # Extract highest peak + sortIdx = y[peakIdx].argsort()[-1] + except IndexError: + if DEBUG: + print('No peaks found..') + return None + except SystemError: + if DEBUG: + print('Peak search failed. Continue with y maximum') + peakIdx = [ybg.argmax()] + sortIdx = 0 + xpeak = float(x[peakIdx][sortIdx]) + ypeak = float(y[peakIdx][sortIdx]) + ypeak_norm = float(ynorm[peakIdx][sortIdx]) + ypeak_bg = float(ybg[peakIdx][sortIdx]) + + # Estimate FWHM + fwhmIdx = numpy.nonzero(ynorm >= thr*ypeak_norm)[0] + #fwhmIdx = numpy.nonzero(ybg >= thr*ypeak_bg)[0] + # Underestimates FWHM + x0, x1 = x[fwhmIdx].min(), x[fwhmIdx].max() + fwhm = x1 - x0 + + return xpeak, ypeak, fwhm, fwhmIdx + # END Helper Methods + + def showDocs(self): + ''' + Displays QTextBrowser showing the documentation + ''' + helpFileName = pathjoin(PyMcaDataDir.PYMCA_DOC_DIR, + "HTML", + "AdvancedAlignmentScanPlugin.html") + self.helpFileBrowser = qt.QTextBrowser() + self.helpFileBrowser.setWindowTitle('Alignment Scan Plug-in Documentation') + self.helpFileBrowser.setLineWrapMode(qt.QTextEdit.FixedPixelWidth) + self.helpFileBrowser.setLineWrapColumnOrWidth(500) + self.helpFileBrowser.resize(520,300) + try: + helpFileHandle = open(helpFileName) + helpFileHTML = helpFileHandle.read() + helpFileHandle.close() + self.helpFileBrowser.setHtml(helpFileHTML) + except IOError: + msg = qt.QMessageBox() + msg.setWindowTitle('Alignment Scan Error') + msg.setText('No help file found.') + msg.exec_() + if DEBUG: + print('XMCDWindow -- init: Unable to read help file') + self.helpFileBrowser = None + if self.helpFileBrowser is not None: + self.helpFileBrowser.show() + self.helpFileBrowser.raise_() + +MENU_TEXT = "Advanced Alignment Plugin" +def getPlugin1DInstance(plotWindow, **kw): + ob = AdvancedAlignmentScanPlugin(plotWindow) + return ob + +if __name__ == "__main__": + from PyMca import PyMcaQt as qt + app = qt.QApplication([]) + from PyMca.Plot1DQwt import Plot1DQwt as Plot1D + + x = numpy.arange(250, 750, 2, dtype=float) + y1 = 1.0 + 50.0 * numpy.exp(-0.001*(x-500)**2) + 2.*numpy.random.random(250.) + y2 = 1.0 + 20.5 * numpy.exp(-0.005*(x-600)**2) + 2.*numpy.random.random(250.) + + plot = Plot1D() + plot.addCurve(x, y1, "y1", {'selectionlegend': 'y1'}) + plot.addCurve(x, y2, "y2", {'selectionlegend': 'y2'}) + + plugin = getPlugin1DInstance(plot) + for method in plugin.getMethods(): + print(method, ":", plugin.getMethodToolTip(method)) + plugin.applyMethod(plugin.getMethods()[0]) diff --git a/PyMca/PyMcaPlugins/FastXRFLinearFitStackPlugin.py b/PyMca/PyMcaPlugins/FastXRFLinearFitStackPlugin.py new file mode 100644 index 0000000..81f4e5d --- /dev/null +++ b/PyMca/PyMcaPlugins/FastXRFLinearFitStackPlugin.py @@ -0,0 +1,263 @@ +#/*########################################################################## +# Copyright (C) 2013 European Synchrotron Radiation Facility +# +# This file is part of the PyMca X-ray Fluorescence Toolkit developed at +# the ESRF by the Software group. +# +# This toolkit is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the Free +# Software Foundation; either version 2 of the License, or (at your option) +# any later version. +# +# PyMca is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +# details. +# +# You should have received a copy of the GNU General Public License along with +# PyMca; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +# +# PyMca follows the dual licensing model of Riverbank's PyQt and cannot be +# used as a free plugin for a non-free program. +# +# Please contact the ESRF industrial unit (industry@esrf.fr) if this license +# is a problem for you. +#############################################################################*/ +__author__ = "V.A. Sole - ESRF Data Analysis" +""" + +A Stack plugin is a module that will be automatically added to the PyMca stack windows +in order to perform user defined operations on the data stack. + +These plugins will be compatible with any stack window that provides the functions: + #data related + getStackDataObject + getStackData + getStackInfo + setStack + + #images related + addImage + removeImage + replaceImage + + #mask related + setSelectionMask + getSelectionMask + + #displayed curves + getActiveCurve + getGraphXLimits + getGraphYLimits + + #information method + stackUpdated + selectionMaskUpdated +""" +import os +import numpy +import time +from PyMca import StackPluginBase +from PyMca import FastXRFLinearFit +from PyMca import FastXRFLinearFitWindow +from PyMca import CalculationThread +from PyMca import StackPluginResultsWindow +import PyMca.PyMca_Icons as PyMca_Icons +from PyMca import PyMcaQt as qt +from PyMca import ArraySave + +DEBUG = 0 + +class FastXRFLinearFitStackPlugin(StackPluginBase.StackPluginBase): + def __init__(self, stackWindow, **kw): + StackPluginBase.DEBUG = DEBUG + StackPluginBase.StackPluginBase.__init__(self, stackWindow, **kw) + self.methodDict = {} + function = self.calculate + info = "Fit stack with current fit configuration" + icon = PyMca_Icons.fit + self.methodDict["Fit Stack"] =[function, + info, + icon] + function = self._showWidget + info = "Show last results" + icon = PyMca_Icons.brushselect + self.methodDict["Show"] =[function, + info, + icon] + self.__methodKeys = ["Fit Stack", "Show"] + self.configurationWidget = \ + FastXRFLinearFitWindow.FastXRFLinearFitDialog() + self.fitInstance = None + self._widget = None + self.thread = None + + def stackUpdated(self): + if DEBUG: + print("FastXRFLinearFitStackPlugin.stackUpdated() called") + self._widget = None + + def selectionMaskUpdated(self): + if self._widget is None: + return + if self._widget.isHidden(): + return + mask = self.getStackSelectionMask() + self._widget.setSelectionMask(mask) + + def mySlot(self, ddict): + if DEBUG: + print("mySlot ", ddict['event'], ddict.keys()) + if ddict['event'] == "selectionMaskChanged": + self.setStackSelectionMask(ddict['current']) + elif ddict['event'] == "addImageClicked": + self.addImage(ddict['image'], ddict['title']) + elif ddict['event'] == "removeImageClicked": + self.removeImage(ddict['title']) + elif ddict['event'] == "replaceImageClicked": + self.replaceImage(ddict['image'], ddict['title']) + elif ddict['event'] == "resetSelection": + self.setStackSelectionMask(None) + + #Methods implemented by the plugin + def getMethods(self): + if self._widget is None: + return [self.__methodKeys[0]] + else: + return self.__methodKeys + + def getMethodToolTip(self, name): + return self.methodDict[name][1] + + def getMethodPixmap(self, name): + return self.methodDict[name][2] + + def applyMethod(self, name): + return self.methodDict[name][0]() + + # The specific part + def calculate(self): + ret = self.configurationWidget.exec_() + if ret: + self._executeFunctionAndParameters() + + def _executeFunctionAndParameters(self): + self._parameters = self.configurationWidget.getParameters() + self._widget = None + if self.fitInstance is None: + self.fitInstance = FastXRFLinearFit.FastXRFLinearFit() + #self._fitConfigurationFile="E:\DATA\COTTE\CH1777\G4-4720eV-NOWEIGHT-Constant-batch.cfg" + + if DEBUG: + self.thread = CalculationThread.CalculationThread(\ + calculation_method=self.actualCalculation) + self.thread.result = self.actualCalculation() + self.threadFinished() + else: + self.thread = CalculationThread.CalculationThread(\ + calculation_method=self.actualCalculation) + #qt.QObject.connect(self.thread, + # qt.SIGNAL('finished()'), + # self.threadFinished) + self.thread.start() + message = "Please wait. Calculation going on." + CalculationThread.waitingMessageDialog(self.thread, + parent=self.configurationWidget, + message=message) + while self.thread.isRunning(): + time.sleep(2) + self.threadFinished() + + def actualCalculation(self): + activeCurve = self.getActiveCurve() + if activeCurve is not None: + x, spectrum, legend, info = activeCurve + else: + x = None + spectrum = None + if not self.isStackFinite(): + # one has to check for NaNs in the used region(s) + # for the time being only in the global image + # spatial_mask = numpy.isfinite(image_data) + spatial_mask = numpy.isfinite(self.getStackOriginalImage()) + stack = self.getStackDataObject() + fitConfigurationFile = self._parameters['configuration'] + concentrations = self._parameters['concentrations'] + self.fitInstance.setFitConfigurationFile(fitConfigurationFile) + result = self.fitInstance.fitMultipleSpectra(x=None, + y=stack, + concentrations=concentrations, + ysum=spectrum) + return result + + def threadFinished(self): + result = self.thread.result + self.thread = None + if type(result) == type((1,)): + #if we receive a tuple there was an error + if len(result): + if result[0] == "Exception": + # somehow this exception is not caught + raise Exception(result[1], result[2]) + return + if 'concentrations' in result: + imageNames = result['names'] + images = numpy.concatenate((result['parameters'], + result['concentrations']), axis=0) + else: + images = result['parameters'] + imageNames = result['names'] + nImages = images.shape[0] + self._widget = StackPluginResultsWindow.StackPluginResultsWindow(\ + usetab=False) + self._widget.buildAndConnectImageButtonBox() + qt = StackPluginResultsWindow.qt + qt.QObject.connect(self._widget, + qt.SIGNAL('MaskImageWidgetSignal'), + self.mySlot) + + self._widget.setStackPluginResults(images, + image_names=imageNames) + self._showWidget() + + # save to output directory + parameters = self.configurationWidget.getParameters() + outputDir = parameters["output_dir"] + if outputDir in [None, ""]: + if DEBUG: + print("Nothing to be saved") + return + if parameters["file_root"] is None: + fileRoot = "" + else: + fileRoot = parameters["file_root"].replace(" ","") + if fileRoot in [None, ""]: + fileRoot = "images" + if not os.path.exists(outputDir): + os.mkdir(outputDir) + imagesDir = os.path.join(outputDir, "IMAGES") + if not os.path.exists(imagesDir): + os.mkdir(imagesDir) + imageList = [None] * nImages + for i in range(nImages): + imageList[i] = images[i] + fileName = os.path.join(imagesDir, fileRoot+".edf") + ArraySave.save2DArrayListAsEDF(imageList, fileName, labels=imageNames) + fileName = os.path.join(imagesDir, fileRoot+".csv") + ArraySave.save2DArrayListAsASCII(imageList, fileName, csv=True, labels=imageNames) + + def _showWidget(self): + if self._widget is None: + return + #Show + self._widget.show() + self._widget.raise_() + + #update + self.selectionMaskUpdated() + +MENU_TEXT = "Fast XRF Stack Fitting" +def getStackPluginInstance(stackWindow, **kw): + ob = FastXRFLinearFitStackPlugin(stackWindow) + return ob diff --git a/PyMca/PyMcaPlugins/ImageAlignmentStackPlugin.py b/PyMca/PyMcaPlugins/ImageAlignmentStackPlugin.py index a4290d7..2f311f0 100644 --- a/PyMca/PyMcaPlugins/ImageAlignmentStackPlugin.py +++ b/PyMca/PyMcaPlugins/ImageAlignmentStackPlugin.py @@ -58,24 +58,17 @@ These plugins will be compatible with any stack window that provides the functio import sys import os import numpy -try: - from PyMca import StackPluginBase - from PyMca import PyMcaQt as qt - from PyMca import FFTAlignmentWindow - from PyMca import ImageRegistration - from PyMca import SpecfitFuns - from PyMca import CalculationThread - from PyMca import ArraySave - -except ImportError: - print("ExternalImagesWindow importing from somewhere else") - import StackPluginBase - import PyMcaQt as qt - import ImageRegistration - import FFTAlignmentWindow - import SpecfitFuns - import CalculationThread - import ArraySave +from PyMca import StackPluginBase +from PyMca import PyMcaQt as qt +from PyMca import FFTAlignmentWindow +from PyMca import ImageRegistration +from PyMca import SpecfitFuns +from PyMca import CalculationThread +from PyMca import ArraySave +from PyMca import PyMcaFileDialogs +from PyMca import specfilewrapper +from PyMca import HDF5Widget + try: from PyMca import SIFTAlignmentWindow sift = SIFTAlignmentWindow.sift @@ -104,6 +97,11 @@ class ImageAlignmentStackPlugin(StackPluginBase.StackPluginBase): "Align using SIFT Algorithm", None] self.__methodKeys.append(key) + key = 'From File Alignment' + self.methodDict[key] = [self._shiftFromFile, + "Align using shifts from file", + None] + self.__methodKeys.append(key) self.widget = None def stackUpdated(self): @@ -508,6 +506,149 @@ class ImageAlignmentStackPlugin(StackPluginBase.StackPluginBase): raise IndexError("Only stacks of images or spectra supported. 1D index should be 0 or 2") return shifts + def _shiftFromFile(self): + stack = self.getStackDataObject() + if stack is None: + return + data = stack.data + mcaIndex = stack.info.get('McaIndex') + if not (mcaIndex in [0, -1, 2]): + raise IndexError("1D index must be 0, 2, or -1") + filefilter = ['HDF5 Files (*.h5 *.nxs *.hdf)', 'CSV 2-column (*.csv)', 'ASCII 2-column (*)'] + filename, ffilter = PyMcaFileDialogs.\ + getFileList(parent=None, + filetypelist=filefilter, + message='Load', + mode='OPEN', + single=True, + getfilter=True, + currentfilter=filefilter[0]) + if len(filename): + if DEBUG: + print("file name = %s file filter = %s" % (filename, ffilter)) + else: + if DEBUG: + print("nothing selected") + return + filename = filename[0] + if ffilter.startswith('HDF5'): + # browse + self.__hdf5Dialog = qt.QDialog() + self.__hdf5Dialog.setWindowTitle('Select your data set by a double click') + self.__hdf5Dialog.mainLayout = qt.QVBoxLayout(self.__hdf5Dialog) + self.__hdf5Dialog.mainLayout.setMargin(0) + self.__hdf5Dialog.mainLayout.setSpacing(0) + fileModel = HDF5Widget.FileModel() + fileView = HDF5Widget.HDF5Widget(fileModel) + hdf5File = fileModel.openFile(filename) + shiftsDataset = None + qt.QObject.connect(fileView, qt.SIGNAL("HDF5WidgetSignal"), self._hdf5WidgetSlot) + self.__hdf5Dialog.mainLayout.addWidget(fileView) + self.__hdf5Dialog.resize(400, 200) + ret = self.__hdf5Dialog.exec_() + if not ret: + return + shifts = hdf5File[self.__shitfsDataset].value + else: + sf = specfilewrapper.Specfile(filename) + nScans = len(sf) + targetScan = None + for scan in sf: + if scan.lines() == data.shape[stack.info['McaIndex']]: + targetScan = scan + break + if targetScan is None: + scan = None + sf = None + raise IOError("Number of read lines does not match stack shape") + shifts = targetScan.data() + targetScan = None + scan = None + sf = None + if shifts.shape[0] == 3 and\ + shifts.shape[1] == data.shape[stack.info['McaIndex']]: + # one column was added (point number) + shifts = shifts[1:].T + + filename = None + if not isinstance(data, numpy.ndarray): + filefilter = ['HDF5 Files (*.h5)'] + filename = PyMcaFileDialogs.\ + getFileList(parent=None, + filetypelist=filefilter, + message='Select output file', + mode='SAVE', + single=True, + getfilter=False, + currentfilter=filefilter[0]) + if len(filename): + filename = filename[0] + if DEBUG: + print("file name = %s" % filename) + else: + raise IOError("No output file selected") + if filename is not None: + self.__hdf5 = self.initializeHDF5File(filename) + crop = False + if DEBUG: + result = self.shiftStack(stack, + shifts, + crop=crop, + filename=filename) + else: + result = self.__shiftStack(stack, + shifts, + crop=crop, + filename=filename) + if result is not None: + # exception occurred + raise Exception(result[1], result[2], result[3]) + + if filename is not None: + hdf = self.__hdf5 + alignmentGroup = hdf['/entry_000/Alignment'] + outputShifts = self.getHDF5BufferIntoGroup(alignmentGroup, + shape=(stack.data.shape[mcaIndex], 2), + name="shifts", + dtype=numpy.float32) + outputShifts[:,:] = shifts + attributes={'interpretation':'image'} + # fill the axes information + dataGroup = hdf['/entry_000/Data'] + if mcaIndex == 0: + reference_shape = data[0].shape + else: + reference_shape = data.shape[0], data.shape[1] + try: + activeCurve = self.getActiveCurve() + if activeCurve is None: + activeCurve = self.getAllCurves()[0] + x, y, legend, info = activeCurve + dataGroup[info['xlabel']] = numpy.array(x, dtype=numpy.float32) + dataGroup[info['xlabel']].attrs['axis'] = numpy.int32(1) + axesAttribute = '%s:dim_1:dim_2' % info['xlabel'] + except: + if DEBUG: + raise + dataGroup['dim_0'] = numpy.arange(stack.data.shape[mcaIndex]).astype(numpy.float32) + dataGroup['dim_0'].attrs['axis'] = numpy.int32(1) + axesAttribute = 'dim_0:dim_1:dim_2' + dataGroup['dim_1'] = numpy.arange(reference_shape[0]).astype(numpy.float32) + dataGroup['dim_1'].attrs['axis'] = numpy.int32(2) + dataGroup['dim_2'] = numpy.arange(reference_shape[1]).astype(numpy.float32) + dataGroup['dim_2'].attrs['axis'] = numpy.int32(3) + dim2 = numpy.arange(reference_shape[1]).astype(numpy.float32) + dataGroup['data'].attrs['axes'] = axesAttribute + self.finishHDF5File(hdf) + else: + self.setStack(stack) + + def _hdf5WidgetSlot(self, ddict): + if ddict['event'] == "itemDoubleClicked": + if ddict['type'].lower() in ['dataset']: + self.__shitfsDataset = ddict['name'] + self.__hdf5Dialog.accept() + def shiftStack(self, stack, shifts, crop=False, filename=None): """ """ diff --git a/PyMca/PyMcaPlugins/MotorInfoPlugin.py b/PyMca/PyMcaPlugins/MotorInfoPlugin.py index f7058e9..3e05965 100644 --- a/PyMca/PyMcaPlugins/MotorInfoPlugin.py +++ b/PyMca/PyMcaPlugins/MotorInfoPlugin.py @@ -1,3 +1,29 @@ +#/*########################################################################## +# Copyright (C) 2004-2013 European Synchrotron Radiation Facility +# +# This file is part of the PyMca X-ray Fluorescence Toolkit developed at +# the ESRF by the Software group. +# +# This toolkit is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the Free +# Software Foundation; either version 2 of the License, or (at your option) +# any later version. +# +# PyMca is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +# details. +# +# You should have received a copy of the GNU General Public License along with +# PyMca; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +# +# PyMca follows the dual licensing model of Riverbank's PyQt and cannot be +# used as a free plugin for a non-free program. +# +# Please contact the ESRF industrial unit (industry@esrf.fr) if this license +# is a problem for you. +#############################################################################*/ __author__ = 'Tonn Rueter' try: from PyMca import Plugin1DBase diff --git a/PyMca/PyMcaPlugins/MotorInfoWindow.py b/PyMca/PyMcaPlugins/MotorInfoWindow.py index cf41546..29814a8 100644 --- a/PyMca/PyMcaPlugins/MotorInfoWindow.py +++ b/PyMca/PyMcaPlugins/MotorInfoWindow.py @@ -1,3 +1,29 @@ +#/*########################################################################## +# Copyright (C) 2004-2013 European Synchrotron Radiation Facility +# +# This file is part of the PyMca X-ray Fluorescence Toolkit developed at +# the ESRF by the Software group. +# +# This toolkit is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the Free +# Software Foundation; either version 2 of the License, or (at your option) +# any later version. +# +# PyMca is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +# details. +# +# You should have received a copy of the GNU General Public License along with +# PyMca; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +# +# PyMca follows the dual licensing model of Riverbank's PyQt and cannot be +# used as a free plugin for a non-free program. +# +# Please contact the ESRF industrial unit (industry@esrf.fr) if this license +# is a problem for you. +#############################################################################*/ __author__ = 'Tonn Rueter' from PyMca import PyMcaQt as qt from PyMca.PyMca_Icons import IconDict diff --git a/PyMca/PyMcaPlugins/StackAxesPlugin.py b/PyMca/PyMcaPlugins/StackAxesPlugin.py index 1a2bf11..04fd401 100644 --- a/PyMca/PyMcaPlugins/StackAxesPlugin.py +++ b/PyMca/PyMcaPlugins/StackAxesPlugin.py @@ -57,19 +57,12 @@ functions: selectionMaskUpdated """ import numpy -if 1:#try: - from PyMca import StackPluginBase - from PyMca import PyMcaFileDialogs - import PyMca.PyMca_Icons as PyMca_Icons -else:#except ImportError: - print("Plugin importing from somewhere else") - import StackPluginBase - import PyMcaFileDialogs - import PyMca_Icons +from PyMca import StackPluginBase +from PyMca import PyMcaFileDialogs +import PyMca.PyMca_Icons as PyMca_Icons DEBUG = 0 - class StackAxesPlugin(StackPluginBase.StackPluginBase): def __init__(self, stackWindow, **kw): StackPluginBase.DEBUG = DEBUG @@ -79,8 +72,22 @@ class StackAxesPlugin(StackPluginBase.StackPluginBase): function = self.replace1DAxisWithASCII info = text icon = None - self.methodDict["1D axis from file"] = [function, info, icon] - self.__methodKeys = ["1D axis from file"] + self.methodDict["1D axis from ASCII file"] = [function, info, icon] + self.__methodKeys = ["1D axis from ASCII file"] + + function = self.replace1DAxisWithActiveCurveXValues + text = "Replace current 1D axis by X values in current MCA curve" + info = text + icon = None + self.methodDict["1D axis from MCA curve X values"] = [function, info, icon] + self.__methodKeys.append("1D axis from MCA curve X values") + + function = self.replace1DAxisWithActiveCurveYValues + text = "Replace current 1D axis by Y values in current MCA curve" + info = text + icon = None + self.methodDict["1D axis from MCA curve Y values"] = [function, info, icon] + self.__methodKeys.append("1D axis from MCA curve Y values") #Methods implemented by the plugin def getMethods(self): @@ -107,6 +114,7 @@ class StackAxesPlugin(StackPluginBase.StackPluginBase): single=True) if not len(fileList): return + filename = fileList[0] data = numpy.loadtxt(filename) data.shape = -1 @@ -116,6 +124,32 @@ class StackAxesPlugin(StackPluginBase.StackPluginBase): stack.x = [data] self.setStack(stack, mcaindex=mcaIndex) + def replace1DAxisWithActiveCurveYValues(self): + stack = self.getStackDataObject() + mcaIndex = stack.info.get('McaIndex', -1) + nPoints = stack.data.shape[mcaIndex] + curve = self.getActiveCurve() + data = curve[1] + data.shape = -1 + if data.size != nPoints: + raise ValueError("Number of read values not equal to %d" % nPoints) + else: + stack.x = [data] + self.setStack(stack, mcaindex=mcaIndex) + + def replace1DAxisWithActiveCurveXValues(self): + stack = self.getStackDataObject() + mcaIndex = stack.info.get('McaIndex', -1) + nPoints = stack.data.shape[mcaIndex] + curve = self.getActiveCurve() + data = curve[0] + data.shape = -1 + if data.size != nPoints: + raise ValueError("Number of read values not equal to %d" % nPoints) + else: + stack.x = [data] + self.setStack(stack, mcaindex=mcaIndex) + MENU_TEXT = "Stack Axes Options" def getStackPluginInstance(stackWindow, **kw): ob = StackAxesPlugin(stackWindow) diff --git a/PyMca/PyMcaPlugins/StackScanWindowPlugin.py b/PyMca/PyMcaPlugins/StackScanWindowPlugin.py index 4ea1e97..566fe89 100644 --- a/PyMca/PyMcaPlugins/StackScanWindowPlugin.py +++ b/PyMca/PyMcaPlugins/StackScanWindowPlugin.py @@ -1,3 +1,29 @@ +#/*########################################################################## +# Copyright (C) 2004-2013 European Synchrotron Radiation Facility +# +# This file is part of the PyMca X-ray Fluorescence Toolkit developed at +# the ESRF by the Software group. +# +# This toolkit is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the Free +# Software Foundation; either version 2 of the License, or (at your option) +# any later version. +# +# PyMca is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +# details. +# +# You should have received a copy of the GNU General Public License along with +# PyMca; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +# +# PyMca follows the dual licensing model of Riverbank's PyQt and cannot be +# used as a free plugin for a non-free program. +# +# Please contact the ESRF industrial unit (industry@esrf.fr) if this license +# is a problem for you. +#############################################################################*/ """ A Stack plugin is a module that will be automatically added to the PyMca stack windows diff --git a/PyMca/PyMcaPlugins/XMCDPlugin.py b/PyMca/PyMcaPlugins/XMCDPlugin.py index dc1ae6c..bd426c9 100644 --- a/PyMca/PyMcaPlugins/XMCDPlugin.py +++ b/PyMca/PyMcaPlugins/XMCDPlugin.py @@ -1,3 +1,29 @@ +#/*########################################################################## +# Copyright (C) 2004-2013 European Synchrotron Radiation Facility +# +# This file is part of the PyMca X-ray Fluorescence Toolkit developed at +# the ESRF by the Software group. +# +# This toolkit is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the Free +# Software Foundation; either version 2 of the License, or (at your option) +# any later version. +# +# PyMca is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +# details. +# +# You should have received a copy of the GNU General Public License along with +# PyMca; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +# +# PyMca follows the dual licensing model of Riverbank's PyQt and cannot be +# used as a free plugin for a non-free program. +# +# Please contact the ESRF industrial unit (industry@esrf.fr) if this license +# is a problem for you. +#############################################################################*/ import PyMca.PyMca_Icons as PyMca_Icons from PyMca import Plugin1DBase from PyMca import XMCDWindow @@ -52,7 +78,7 @@ class XMCDAnalysis(Plugin1DBase.Plugin1DBase): self.widget = XMCDWindow.XMCDWidget(parent, self._plotWindow, beamline, - nSelectors = 2) + nSelectors = 5) MENU_TEXT = "XLD/XMCD Analysis" diff --git a/PyMca/PyMcaSciPy/signal/mediantools.c b/PyMca/PyMcaSciPy/signal/mediantools.c index 2396574..a4628da 100644 --- a/PyMca/PyMcaSciPy/signal/mediantools.c +++ b/PyMca/PyMcaSciPy/signal/mediantools.c @@ -6,6 +6,9 @@ is granted under the SciPy License. */ #include "Python.h" +/* adding next line may raise errors ... +#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION +*/ #include "numpy/noprefix.h" #include <setjmp.h> @@ -45,16 +48,6 @@ static struct module_state _state; {struct module_state *st = GETSTATE(self);\ PyErr_SetString(st->error, message);goto fail;} -#define DATA(arr) ((arr)->data) -#define DIMS(arr) ((arr)->dimensions) -#define STRIDES(arr) ((arr)->strides) -#define ELSIZE(arr) ((arr)->descr->elsize) -#define OBJECTTYPE(arr) ((arr)->descr->type_num) -#define BASEOBJ(arr) ((PyArrayObject *)((arr)->base)) -#define RANK(arr) ((arr)->nd) -#define ISCONTIGUOUS(m) ((m)->flags & CONTIGUOUS) - - jmp_buf MALLOC_FAIL; char *check_malloc (int); @@ -103,18 +96,18 @@ static PyObject *mediantools_median2d(PyObject *self, PyObject *args) if (a_image == NULL) goto fail; if (size != NULL) { - a_size = (PyArrayObject *)PyArray_ContiguousFromObject(size, PyArray_LONG, 1, 1); + a_size = (PyArrayObject *)PyArray_ContiguousFromObject(size, NPY_LONG, 1, 1); if (a_size == NULL) goto fail; - if ((RANK(a_size) != 1) || (DIMS(a_size)[0] < 2)) + if ((PyArray_NDIM(a_size) != 1) || (PyArray_DIMS(a_size)[0] < 2)) PYERR("Size must be a length two sequence"); - lhelp = (long *) DATA(a_size); + lhelp = (long *) PyArray_DATA(a_size); Nwin[0] = (int) (*lhelp); Nwin[1] = (int) (*(lhelp++)); - Idims[0] = (int) (a_image->dimensions[0]); - Idims[1] = (int) (a_image->dimensions[1]); + Idims[0] = (int) (PyArray_DIMS(a_image)[0]); + Idims[1] = (int) (PyArray_DIMS(a_image)[1]); } - a_out = (PyArrayObject *)PyArray_SimpleNew(2,DIMS(a_image),typenum); + a_out = (PyArrayObject *)PyArray_SimpleNew(2,PyArray_DIMS(a_image),typenum); if (a_out == NULL) goto fail; if (setjmp(MALLOC_FAIL)) { @@ -122,41 +115,41 @@ static PyObject *mediantools_median2d(PyObject *self, PyObject *args) } else { switch (typenum) { - case PyArray_UBYTE: - b_medfilt2((unsigned char *)DATA(a_image), (unsigned char *)DATA(a_out),\ - Nwin, Idims, conditional_flag); + case NPY_UBYTE: + b_medfilt2((unsigned char *)PyArray_DATA(a_image), (unsigned char *)PyArray_DATA(a_out),\ + Nwin, Idims, conditional_flag); break; - case PyArray_FLOAT: - f_medfilt2((float *)DATA(a_image), (float *)DATA(a_out),\ - Nwin, Idims, conditional_flag); + case NPY_FLOAT: + f_medfilt2((float *)PyArray_DATA(a_image), (float *)PyArray_DATA(a_out),\ + Nwin, Idims, conditional_flag); break; - case PyArray_DOUBLE: - d_medfilt2((double *)DATA(a_image), (double *)DATA(a_out),\ - Nwin, Idims, conditional_flag); + case NPY_DOUBLE: + d_medfilt2((double *)PyArray_DATA(a_image), (double *)PyArray_DATA(a_out),\ + Nwin, Idims, conditional_flag); break; - case PyArray_SHORT: - short_medfilt2((short *)DATA(a_image), (short *)DATA(a_out),\ - Nwin, Idims, conditional_flag); + case NPY_SHORT: + short_medfilt2((short *)PyArray_DATA(a_image), (short *)PyArray_DATA(a_out),\ + Nwin, Idims, conditional_flag); break; - case PyArray_USHORT: - ushort_medfilt2((unsigned short *)DATA(a_image), (unsigned short *)DATA(a_out),\ - Nwin, Idims, conditional_flag); + case NPY_USHORT: + ushort_medfilt2((unsigned short *)PyArray_DATA(a_image), (unsigned short *)PyArray_DATA(a_out),\ + Nwin, Idims, conditional_flag); break; - case PyArray_INT: - int_medfilt2((int *)DATA(a_image), (int *)DATA(a_out),\ - Nwin, Idims, conditional_flag); + case NPY_INT: + int_medfilt2((int *)PyArray_DATA(a_image), (int *)PyArray_DATA(a_out),\ + Nwin, Idims, conditional_flag); break; - case PyArray_UINT: - uint_medfilt2((unsigned int *)DATA(a_image), (unsigned int *)DATA(a_out),\ - Nwin, Idims, conditional_flag); + case NPY_UINT: + uint_medfilt2((unsigned int *)PyArray_DATA(a_image), (unsigned int *)PyArray_DATA(a_out),\ + Nwin, Idims, conditional_flag); break; - case PyArray_LONG: - long_medfilt2((long *)DATA(a_image), (long *)DATA(a_out),\ - Nwin, Idims, conditional_flag); + case NPY_LONG: + long_medfilt2((long *)PyArray_DATA(a_image), (long *)PyArray_DATA(a_out),\ + Nwin, Idims, conditional_flag); break; - case PyArray_ULONG: - ulong_medfilt2((unsigned long *)DATA(a_image), (unsigned long *)DATA(a_out),\ - Nwin, Idims, conditional_flag); + case NPY_ULONG: + ulong_medfilt2((unsigned long *)PyArray_DATA(a_image), (unsigned long *)PyArray_DATA(a_out),\ + Nwin, Idims, conditional_flag); break; default: PYERR("Median filter unsupported data type."); diff --git a/PyMca/PyMcaSciPy/signal/setup.py b/PyMca/PyMcaSciPy/signal/setup.py deleted file mode 100644 index 05aaf80..0000000 --- a/PyMca/PyMcaSciPy/signal/setup.py +++ /dev/null @@ -1,19 +0,0 @@ -try: - import numpy -except ImportError: - text = "You must have numpy installed.\n" - text += "See http://sourceforge.net/project/showfiles.php?group_id=1369&package_id=175103\n" - raise ImportError(text) - -from distutils.core import setup -from distutils.extension import Extension - -data_files = ('signal',['__init__.py', 'median.py']) -setup( name = 'signal', - ext_modules = [Extension( - name = 'signal.mediantools', - sources = ['mediantools.c', 'medianfilter.c'], - define_macros = [], - include_dirs = [numpy.get_include()] - ),], - data_files=data_files) diff --git a/PyMca/QHDF5StackWizard.py b/PyMca/QHDF5StackWizard.py index 18f09a9..e63bfb2 100644 --- a/PyMca/QHDF5StackWizard.py +++ b/PyMca/QHDF5StackWizard.py @@ -257,6 +257,14 @@ class DatasetSelectionPage(qt.QWizardPage): ddict['counters'].append(path) ddict['aliases'].append(posixpath.basename(axis)) + if sys.platform == "darwin" and\ + len(ddict['counters']) > 3 and\ + qt.qVersion().startswith('4.8'): + # workaround a strange bug on Mac: + # when the counter list has to be scrolled + # the selected button also changes!!!! + return + self.nexusWidget.setWidgetConfiguration(ddict) if len(signalList): if len(axesList) == 0: diff --git a/PyMca/QStackWidget.py b/PyMca/QStackWidget.py index d9a37c9..d4032ea 100644 --- a/PyMca/QStackWidget.py +++ b/PyMca/QStackWidget.py @@ -598,7 +598,7 @@ class QStackWidget(StackBase.StackBase, idx = 0 else: actionList = [] - methods.sort() + #methods.sort() menu = qt.QMenu(self) for method in methods: text = QString(method) @@ -621,7 +621,7 @@ class QStackWidget(StackBase.StackBase, if a.text() == action[0]: idx = actionList.index(action) try: - self.pluginInstanceDict[key].applyMethod(methods[idx]) + self.pluginInstanceDict[key].applyMethod(methods[idx]) except: msg = qt.QMessageBox(self) msg.setIcon(qt.QMessageBox.Critical) diff --git a/PyMca/SGModule.py b/PyMca/SGModule.py index 773b60a..364d62d 100644 --- a/PyMca/SGModule.py +++ b/PyMca/SGModule.py @@ -7,8 +7,30 @@ # and are very grateful to Uwe for making his code available to the # community. # +# Copyright (C) 2008 Uwe Schmitt # - +# Permission is hereby granted, free of charge, to any person +# obtaining a copy of this software and associated documentation +# files (the "Software"), to deal in the Software without +# restriction, including without limitation the rights to use, +# copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following +# conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +# OTHER DEALINGS IN THE SOFTWARE. +# +__license__ = "MIT" import numpy from numpy.linalg import solve diff --git a/PyMca/ScanWindow.py b/PyMca/ScanWindow.py index e829cda..676b85f 100644 --- a/PyMca/ScanWindow.py +++ b/PyMca/ScanWindow.py @@ -1,5 +1,5 @@ #/*########################################################################## -# Copyright (C) 2004-2012 European Synchrotron Radiation Facility +# Copyright (C) 2004-2013 European Synchrotron Radiation Facility # # This file is part of the PyMca X-ray Fluorescence Toolkit developed at # the ESRF by the Software group. @@ -1721,6 +1721,12 @@ class ScanWindow(qt.QWidget, Plot1DBase.Plot1DBase): else: return self.graph.getY2AxisLimits() + def setGraphXLimits(self, xmin, xmax, replot=False): + return self.graph.setX1AxisLimits(xmin, xmax, replot=replot) + + def setGraphYLimits(self, ymin, ymax, replot=False): + return self.graph.setY1AxisLimits(ymin, ymax, replot=replot) + def setActiveCurve(self, legend): self.graph.setActiveCurve(legend) ddict = {} diff --git a/PyMca/SixCircle.py b/PyMca/SixCircle.py index ac7a4d2..10d8554 100644 --- a/PyMca/SixCircle.py +++ b/PyMca/SixCircle.py @@ -1,172 +1,250 @@ #/*########################################################################## -# Copyright (C) 2004-2012 European Synchrotron Radiation Facility +# Copyright (C) 2004-2013 European Synchrotron Radiation Facility # # This file is part of the PyMca X-ray Fluorescence Toolkit developed at # the ESRF by the Software group. # -# This toolkit is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License as published by the Free +# This file is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by the Free # Software Foundation; either version 2 of the License, or (at your option) # any later version. # -# PyMca is distributed in the hope that it will be useful, but WITHOUT ANY +# This file is distributed in the hope that it will be useful, but WITHOUT ANY # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more # details. # -# You should have received a copy of the GNU General Public License along with -# PyMca; if not, write to the Free Software Foundation, Inc., -# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -# -# PyMca follows the dual licensing model of Riverbank's PyQt and cannot be -# used as a free plugin for a non-free program. -# # Please contact the ESRF industrial unit (industry@esrf.fr) if this license # is a problem for you. #############################################################################*/ __author__ = "V.A. Sole - ESRF Data Analysis" +__license__ = "LGPL" +__doc__ = """ +Methods to convert single point or complete images to reciprocal space. +It is fully vectorized and therefore very fast for converting complete +images. +""" import numpy + cos = numpy.cos sin = numpy.sin + class SixCircle(object): def __init__(self): self._energy = None self._lambda = None - self._K = 1.0 + self._K = 1.0 + self._ub = None self.setLambda(1.0) self.setUB([1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0]) def setUB(self, ublist): + """ + :param ublist: the ub matrix element values + :type ublist: list(float) + """ self._ub = numpy.array(ublist).astype(numpy.float) self._ub.shape = 3, 3 def getUB(self): + """ + :return: the ub matrix element values + :rtype: list(float) + """ a = self._ub * 1 a.shape = -1 return a.tolist() def setEnergy(self, energy): """ - setEnergy(self, energy) - The energy has to be given in keV + :param energy: the energy to set in KeV + :type energy: float """ self._lambda = 12.39842 / energy self._energy = energy self.update() def getEnergy(self): + """ + :return: the energy in KeV + :rtype: float + """ return self._energy def setLambda(self, value): """ - setLamabda(self, lambda) - The wavelength has to be given in Angstroms + :param value: the wavelength to set in Angstroms + :type value: float """ self._lambda = value self._energy = 12.39842 / value self.update() def getLambda(self): + """ + :return: the wavelength in Angstroms + :rtype: float + """ return self._lambda def update(self): - self._K = (2*numpy.pi)/self._lambda + """ + compute K from the wavelength value + """ + self._K = (2 * numpy.pi) / self._lambda def getPhiMatrix(self, phi): - angle = phi * numpy.pi/180. + """ + :param phi: the phi angle in degree + :type phi: float + :return: the rotation matrix of the phi axis for a given angle + :rtype: numpy.ndarray + """ + angle = numpy.radians(phi) cphi = cos(angle) sphi = sin(angle) - return numpy.array([[ cphi, sphi, 0.0], + return numpy.array([[cphi, sphi, 0.0], [-sphi, cphi, 0.0], - [ 0.0, 0.0, 1.0]],numpy.float) + [0.0, 0.0, 1.0]], numpy.float) def getChiMatrix(self, chi): - angle = chi * numpy.pi/180. + """ + :param chi: the chi angle in degree + :type chi: float + :return: the rotation matrix of the chi + :rtype: numpy.ndarray + """ + angle = numpy.radians(chi) cchi = cos(angle) schi = sin(angle) - return numpy.array([[ cchi, 0.0, schi], - [ 0.0, 1.0, 0.0], + return numpy.array([[cchi, 0.0, schi], + [0.0, 1.0, 0.0], [-schi, 0.0, cchi]], numpy.float) def getThetaMatrix(self, th): - angle = th * numpy.pi/180. + """ + :param th: the theta angle in Degree + :type th: float + :return: the rotation matrix of the theta axis + :rtype: numpy.ndarray + """ + angle = numpy.radians(th) cth = cos(angle) sth = sin(angle) - return numpy.array([[ cth, sth, 0], - [-sth, cth, 0], - [ 0, 0, 1]], numpy.float) + return numpy.array([[cth, sth, 0], + [-sth, cth, 0], + [0, 0, 1]], numpy.float) def getDeltaMatrix(self, delta): - angle = delta * numpy.pi/180. + """ + :param delta: the delta angle in Degree + :type delta: float + :return: the rotation matrix of the delta axis + :rtype: numpy.ndarray + """ + angle = numpy.radians(delta) cdel = cos(angle) sdel = sin(angle) - return numpy.array([[ cdel, sdel, 0], - [-sdel, cdel, 0], - [ 0, 0, 1]], numpy.float) + return numpy.array([[cdel, sdel, 0], + [-sdel, cdel, 0], + [0, 0, 1]], numpy.float) def getGammaMatrix(self, gamma): - angle = gamma * numpy.pi/180. + """ + :param gamma: the gamma angle in Degree + :type gamma: float + :return: the rotation matrix of the gamma axis + :rtype: numpy.ndarray + """ + angle = numpy.radians(gamma) cgam = cos(angle) sgam = sin(angle) - return numpy.array([[1.0, 0.0, 0.0], - [0.0, cgam, -sgam], - [0.0, sgam, cgam]], numpy.float) + return numpy.array([[1.0, 0.0, 0.0], + [0.0, cgam, -sgam], + [0.0, sgam, cgam]], numpy.float) def getMuMatrix(self, mu): - angle = mu * numpy.pi/180. + """ + :param mu: the mu angle in degree + :type mu: float + :return: the rotation matrix of the mu axis + :rtype: numpy.ndarray + """ + angle = numpy.radians(mu) cmu = cos(angle) smu = sin(angle) - return numpy.array([[1.0, 0.0, 0.0], - [0.0, cmu, -smu], - [0.0, smu, cmu]], numpy.float) - + return numpy.array([[1.0, 0.0, 0.0], + [0.0, cmu, -smu], + [0.0, smu, cmu]], numpy.float) - def _getDeltaDotGammaMatrix(self, delta, gamma): + def _getDeltaDotGammaMatrix(self, delta, gamma, gamma_first=False): """ - Given a 1D array of delta values and a 1D array of gamma values - returns an array of dimension (3, 3, ndelta_values * n_gamma_values) + :param delta: the delta angles in Degrees + :type delta: numpy.ndarray (1D) + :param gamma: the gamma values in Degrees + :type gamma: numpy.ndarray (1D) + :param gamma_first: if delta and gamma are arrays, which one variates first. + :type gamma_first: boolean + :return: all the rotation matrix of all the delta, gamma combinations + :rtype: numpy.ndarray (3x3, len(delta) * len(gamma)) """ - delr = delta * numpy.pi/180. - gamr = gamma * numpy.pi/180. - if 0: + delr = numpy.radians(delta) + gamr = numpy.radians(gamma) + if gamma_first: cgam, cdel = numpy.meshgrid(numpy.cos(gamr), numpy.cos(delr)) sgam, sdel = numpy.meshgrid(numpy.sin(gamr), numpy.sin(delr)) else: #this is to give the same result as Didier and not the transpose cdel, cgam = numpy.meshgrid(numpy.cos(delr), numpy.cos(gamr)) sdel, sgam = numpy.meshgrid(numpy.sin(delr), numpy.sin(gamr)) - deltaDotGamma = numpy.zeros((3, 3, len(delta), len(gamma)), numpy.float) - #1st row of dot(deltamatrix, gammaMatrix) - deltaDotGamma[0, 0, :] = cdel - deltaDotGamma[0, 1, :] = (sdel * cgam)[:] + deltaDotGamma = numpy.zeros((3, 3, len(delta), len(gamma)), + numpy.float) + # 1st row of dot(deltamatrix, gammaMatrix) + deltaDotGamma[0, 0, :] = cdel + deltaDotGamma[0, 1, :] = (sdel * cgam)[:] deltaDotGamma[0, 2, :] = -sdel * sgam - #2nd row of dot(deltaMatrix, gammaMatrix) + # 2nd row of dot(deltaMatrix, gammaMatrix) deltaDotGamma[1, 0, :] = -sdel - deltaDotGamma[1, 1, :] = cdel * cgam + deltaDotGamma[1, 1, :] = cdel * cgam deltaDotGamma[1, 2, :] = -cdel * sgam - #3rd row of dot(deltaMatrix, gammaMatrix) - deltaDotGamma[2, 0, :] = 0.0 - deltaDotGamma[2, 1, :] = sgam - deltaDotGamma[2, 2, :] = cgam - deltaDotGamma.shape = 3, 3, len(delta)*len(gamma) + # 3rd row of dot(deltaMatrix, gammaMatrix) + deltaDotGamma[2, 0, :] = 0.0 + deltaDotGamma[2, 1, :] = sgam + deltaDotGamma[2, 2, :] = cgam + deltaDotGamma.shape = 3, 3, len(delta) * len(gamma) + return deltaDotGamma - def getQMu(self, phi=0., chi=0., theta=0., mu=0., delta=0., gamma=0.): + def getQMu(self, phi=0., chi=0., theta=0., mu=0., + delta=0., gamma=0., gamma_first=False): """ - getQMu(self, phi=0., chi=0., theta=0., mu=0., delta=0., gamma=0.) - - Angles given in degrees - + :param phi: angle in Degrees + :type phi: float + :param chi: angle in Degrees + :type chi: float + :param theta: angle in Degrees + :type theta: float + :param mu: angle in Degrees + :type mu: float + :param delta: angle in Degrees + :type delta: float or numpy.ndarray + :param gamma: angle in Degrees + :type gamma: float or numpy.ndarray + :param gamma_first: if delta and gamma are arrays, which one variates first. + :type gamma_first: boolean + + :return: Q coordinates for all the given delta, gamma values + :rtype: numpy.ndarray (len(delta), len(gamma), 3) """ PHIi = self.getPhiMatrix(phi).T CHIi = self.getChiMatrix(chi).T - THi = self.getThetaMatrix(theta).T - MUi = self.getMuMatrix(mu).T - tmpArray = numpy.dot(PHIi,numpy.dot(CHIi,numpy.dot(THi, MUi))) - Q = self.getQLab(mu=mu, delta=delta, gamma=gamma) + THi = self.getThetaMatrix(theta).T + MUi = self.getMuMatrix(mu).T + tmpArray = numpy.dot(PHIi, numpy.dot(CHIi, numpy.dot(THi, MUi))) + Q = self.getQLab(mu=mu, delta=delta, gamma=gamma, gamma_first=gamma_first) Q.shape = 3, -1 Q = numpy.transpose(numpy.dot(tmpArray, Q)) if type(delta) in [type(1.0), type(1)]: @@ -180,38 +258,55 @@ class SixCircle(object): Q.shape = lengamma, lendelta, 3 return Q - - def getQSurface(self, phi=0., chi=0., theta=0., mu=0., delta=0., gamma=0.): + def getQSurface(self, phi=0., chi=0., theta=0., mu=0., + delta=0., gamma=0., gamma_first=False): """ - getQSurface(self, phi=0., chi=0., theta=0., mu=0., delta=0., gamma=0.) - - Angles given in degrees + :param phi: angle in Degrees + :type phi: float + :param chi: angle in Degrees + :type chi: float + :param theta: angle in Degrees + :type theta: float + :param mu: angle in Degrees + :type mu: float + :param delta: angle in Degrees + :type delta: float or numpy.ndarray + :param gamma: angle in Degrees + :type gamma: float or numpy.ndarray + :param gamma_first: if delta and gamma are arrays, which one variates first. + :type gamma_first: boolean + + :return: Q values for all the given delta, gamma values This is only true if the diffractometer has been properly aligned. - """ PHIi = self.getPhiMatrix(phi).T CHIi = self.getChiMatrix(chi).T THi = self.getThetaMatrix(theta).T MUi = self.getMuMatrix(mu).T - tmpArray = numpy.dot(PHIi,numpy.dot(CHIi,numpy.dot(THi, MUi))) - Q = self.getQLab(mu=mu, delta=delta, gamma=gamma) + tmpArray = numpy.dot(PHIi, numpy.dot(CHIi, numpy.dot(THi, MUi))) + Q = self.getQLab(mu=mu, delta=delta, gamma=gamma, gamma_first=gamma_first) Q.shape = 3, -1 return (numpy.dot(tmpArray, Q)) - def getQLab(self, mu=0.0, delta=0.0, gamma=0.0): + def getQLab(self, mu=0.0, delta=0.0, gamma=0.0, gamma_first=False): """ - getQLab(self, mu=0.0, delta=0.0, gamma=0.0) - - Angles are given in degrees. - - The momentum transfer in the Lab system is + :param mu: angle in Degrees + :type mu: float + :param delta: angle in Degrees + :type delta: float or numpy.ndarray + :param gamma: angle in Degrees + :type gamma: float or numpy.ndarray + :param gamma_first: if delta and gamma are arrays, which one variates first. + :type gamma_first: boolean + + :return: the Q coordinates in the Lab system + :rtype: numpy.ndarray () Q = Kf - Ki = (2 * pi / lambda) * (MU DELTA GAMMA - I) * (0, 1, 0) This gives (transforming angles to radians): - (2*pi/lambda) * ( sin(delta) cos(gamma), cos(mu) cos(delta) cos(gamma) - sin(mu) sin(gamma) - 1, sin(mu) cos(delta) cos(gamma) + cos(mu) sin(gamma)) @@ -224,21 +319,23 @@ class SixCircle(object): """ - alpha = mu * (numpy.pi/180.) + alpha = numpy.radians(mu) cmu = cos(alpha) smu = sin(alpha) - alpha = delta * (numpy.pi/180.) + alpha = numpy.radians(delta) cdel = cos(alpha) sdel = sin(alpha) - alpha = gamma * (numpy.pi/180.) + alpha = numpy.radians(gamma) cgam = cos(alpha) sgam = sin(alpha) - if isinstance(delta, numpy.ndarray) and isinstance(gamma, numpy.ndarray): - if 0: - cgam, cdel = numpy.meshgrid(cgam, cdelr) - sgam, sdel = numpy.meshgrid(sgamr, sdel) + + if isinstance(delta, numpy.ndarray) or \ + isinstance(gamma, numpy.ndarray): + if gamma_first: + cgam, cdel = numpy.meshgrid(cgam, cdel) + sgam, sdel = numpy.meshgrid(sgam, sdel) else: - #this is to give the same result as Didier and not the transpose + # this is to give the same result as Didier and not the transpose cdel, cgam = numpy.meshgrid(cdel, cgam) sdel, sgam = numpy.meshgrid(sdel, sgam) Q = numpy.zeros((3, sdel.shape[0], sdel.shape[1]), numpy.float) @@ -246,76 +343,116 @@ class SixCircle(object): Q[1, :, :] = cmu * cdel * cgam - smu * sgam - 1 Q[2, :, :] = smu * cdel * cgam + cmu * sgam else: - Q = numpy.zeros((3,1), numpy.float) - Q[0,0] = sdel * cgam - Q[1,0] = cmu * cdel * cgam - smu * sgam - 1 - Q[2,0] = smu * cdel * cgam + cmu * sgam + Q = numpy.zeros((3, 1), numpy.float) + Q[0, 0] = sdel * cgam + Q[1, 0] = cmu * cdel * cgam - smu * sgam - 1 + Q[2, 0] = smu * cdel * cgam + cmu * sgam return Q * self._K - def getHKL(self, phi=0., chi=0., theta=0., mu=0., delta=0., gamma=0.): + def getHKL(self, phi=0., chi=0., theta=0., mu=0., + delta=0., gamma=0., gamma_first=False): + """ + :param phi: angle in Degrees + :type phi: float + :param chi: angle in Degrees + :type chi: float + :param theta: angle in Degrees + :type theta: float + :param mu: angle in Degrees + :type mu: float + :param delta: angle in Degrees + :type delta: float or numpy.ndarray + :param gamma: angle in Degrees + :type gamma: float or numpy.ndarray + :param gamma_first: if delta and gamma are arrays, which one variates first. + :type gamma_first: boolean + + :return: HKL values for all the given delta, gamma values + """ PHIi = self.getPhiMatrix(phi).T CHIi = self.getChiMatrix(chi).T - THi = self.getThetaMatrix(theta).T - MUi = self.getMuMatrix(mu).T + THi = self.getThetaMatrix(theta).T + MUi = self.getMuMatrix(mu).T UBi = numpy.linalg.inv(self._ub) - tmpArray = numpy.dot(UBi,numpy.dot(PHIi,numpy.dot(CHIi,numpy.dot(THi, MUi)))) - Q = self.getQLab(mu=mu, delta=delta, gamma=gamma) + tmpArray = numpy.dot(UBi, + numpy.dot(PHIi, + numpy.dot(CHIi, + numpy.dot(THi, MUi)))) + Q = self.getQLab(mu=mu, delta=delta, gamma=gamma, gamma_first=gamma_first) Q.shape = 3, -1 return (numpy.dot(tmpArray, Q)) -def getHKL(wavelength, ub, phi=0., chi=0., theta=0., mu=0., delta=0., gamma=0.): + +def getHKL(wavelength, ub, phi=0., chi=0., theta=0., mu=0., + delta=0., gamma=0., gamma_first=False): """ - getHKL(wavelength, ub, phi=0., chi=0., theta=0., mu=0., delta=0., gamma=0.): + :param wavelength: the wavelength in Angstroms + :type wavelength: float + :param ub: the ub matrix element values + :type ub: list(float) + :param phi: angle in Degrees + :type phi: float + :param chi: angle in Degrees + :type chi: float + :param theta: angle in Degrees + :type theta: float + :param mu: angle in Degrees + :type mu: float + :param delta: angle in Degrees + :type delta: float or numpy.ndarray + :param gamma: angle in Degrees + :type gamma: float or numpy.ndarray + :param gamma_first: if delta and gamma are arrays, which one variates first. + :type gamma_first: boolean + + :return: HKL values for all the given delta, gamma values + A convenience function that takes the whole input in one go """ a = SixCircle() a.setLambda(wavelength) a.setUB(ub) - return a.getHKL(delta=delta, theta=theta, chi=chi, phi=phi, mu=mu, gamma=gamma) + return a.getHKL(delta=delta, theta=theta, chi=chi, phi=phi, + mu=mu, gamma=gamma, gamma_first=gamma_first) -if __name__ == "__main__": + +def main(): wavelength = 0.363504 - UB = [1.0, 0.0, 0.0, + UB = [1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0] UB[0] = -4.080 - UB[1] = 0.000 - UB[2] = 0.000 - UB[3] = 0.000 - UB[4] = 4.080 - UB[5] = 0.000 - UB[6] = 0.000 - UB[7] = 0.000 - UB[8] = -4.080 + UB[1] = 0.000 + UB[2] = 0.000 + UB[3] = 0.000 + UB[4] = 4.080 + UB[5] = 0.000 + UB[6] = 0.000 + UB[7] = 0.000 + UB[8] = -4.080 d = SixCircle() d.setLambda(wavelength) d.setUB(UB) print("H = 0 K = 0 L = 1") delta, theta, chi, phi, mu, gamma = 13.5558, 6.77779, -90, 0.0, 0.0, 0.0 - print(d.getHKL(delta=delta, theta=theta, chi=chi, phi=phi, mu=mu, gamma=gamma)) + print(d.getHKL(delta=delta, theta=theta, chi=chi, phi=phi, + mu=mu, gamma=gamma)) print("H = 0 K = 1 L = 0") delta, theta, chi, phi, mu, gamma = 13.5558, 96.77779, -90, 0.0, 0.0, 0.0 - print(d.getHKL(delta=delta, theta=theta, chi=chi, phi=phi, mu=mu, gamma=gamma)) + print(d.getHKL(delta=delta, theta=theta, chi=chi, phi=phi, + mu=mu, gamma=gamma)) print("H = 1 K = 1 L = 1") delta, theta, chi, phi, mu, gamma = 23.5910, 47.0595, -135., 0.0, 0.0, 0.0 - print(d.getHKL(delta=delta, theta=theta, chi=chi, phi=phi, mu=mu, gamma=gamma)) + print(d.getHKL(delta=delta, theta=theta, chi=chi, phi=phi, + mu=mu, gamma=gamma)) print("H = 2 K = -1 L = 0") delta, theta, chi, phi, mu, gamma = 30.6035, -11.2635, 180.0, 0.0, 0.0, 0.0 - print(d.getHKL(delta=delta, theta=theta, chi=chi, phi=phi, mu=mu, gamma=gamma)) + print(d.getHKL(delta=delta, theta=theta, chi=chi, phi=phi, + mu=mu, gamma=gamma)) print("H = 2 K = -1 L = 0") - print(getHKL(wavelength, UB, delta=delta, theta=theta, chi=chi, phi=phi, mu=mu, gamma=gamma)) - - if 0: - print("DIDIER Image") - wavelength = 1.12711884437 - UB = [1.99593e-16, 2.73682e-16, -1.54, -1.08894, 1.08894, 1.6083e-16, 1.08894, 1.08894, 9.28619e-17] - chi = 90. - phi = -13.3 - theta = -5.53 - mu = 0.0 - gamma = 12.3 - delta = 23.23 - print(getHKL(wavelength, UB, delta=delta, theta=theta, chi=chi, phi=phi, mu=mu, gamma=gamma)) - + print(getHKL(wavelength, UB, delta=delta, theta=theta, chi=chi, phi=phi, + mu=mu, gamma=gamma)) +if __name__ == "__main__": + main() diff --git a/PyMca/StackSelector.py b/PyMca/StackSelector.py index 7fcb0f6..33f713d 100644 --- a/PyMca/StackSelector.py +++ b/PyMca/StackSelector.py @@ -31,6 +31,7 @@ import copy from PyMca import PyMcaQt as qt from PyMca import PyMcaDirs from PyMca import DataObject +from PyMca import MRCMap from PyMca import OmnicMap from PyMca import OpusDPTMap from PyMca import LuciaMap @@ -64,7 +65,7 @@ class StackSelector(object): if not len(filelist): return None - if filefilter == "": + if filefilter in ["", "All Files (*)"]: if HDF5: if h5py.is_hdf5(filelist[0]): filefilter = "HDF5" @@ -82,7 +83,11 @@ class StackSelector(object): if sys.version < '3.0': line = f.read(10) else: - line = str(f.read(10).decode()) + try: + line = str(f.read(10).decode()) + except UnicodeDecodeError: + #give a dummy value + line = " " f.close() omnicfile = False if filefilter.upper().startswith('HDF5'): @@ -150,6 +155,10 @@ class StackSelector(object): #Roper Scientific format #handle it as MarCCD stack stack = QStack(imagestack=True) + elif MRCMap.isMRCFile(filelist[0]): + stack = MRCMap.MRCMap(filelist[0]) + omnicfile = True + imagestack = True else: stack = QSpecFileStack() @@ -385,6 +394,7 @@ class StackSelector(object): "OPUS-DPT Files (*.DPT *.dpt)", "AIFIRA Files (*DAT)", "SupaVisio Files (*pige *pixe *rbs)", + "MRC files (*.mrc *.st)", "All Files (*)"] if not HDF5: idx = fileTypeList.index("HDF5 Files (*.nxs *.hdf *.h5)") diff --git a/PyMca/XMCDWindow.py b/PyMca/XMCDWindow.py index d554699..3330259 100644 --- a/PyMca/XMCDWindow.py +++ b/PyMca/XMCDWindow.py @@ -1,19 +1,56 @@ +#/*########################################################################## +# Copyright (C) 2004-2013 European Synchrotron Radiation Facility +# +# This file is part of the PyMca X-ray Fluorescence Toolkit developed at +# the ESRF by the Software group. +# +# This toolkit is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the Free +# Software Foundation; either version 2 of the License, or (at your option) +# any later version. +# +# PyMca is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +# details. +# +# You should have received a copy of the GNU General Public License along with +# PyMca; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +# +# PyMca follows the dual licensing model of Riverbank's PyQt and cannot be +# used as a free plugin for a non-free program. +# +# Please contact the ESRF industrial unit (industry@esrf.fr) if this license +# is a problem for you. +#############################################################################*/ +__author__ = "T. Rueter - ESRF Data Analysis" import numpy, copy +from os.path import splitext, basename, dirname, exists, join as pathjoin from PyMca.PyMca_Icons import IconDict from PyMca import PyMcaDirs, PyMcaFileDialogs from PyMca import ConfigDict -from os.path import splitext, basename, dirname, exists, join as pathjoin from PyMca import PyMcaQt as qt from PyMca import specfilewrapper as specfile - +from PyMca import PyMcaDataDir from PyMca import ScanWindow as sw +if hasattr(qt, "QString"): + QString = qt.QString + QStringList = qt.QStringList +else: + QString = str + QStringList = list + DEBUG = 0 if DEBUG: numpy.set_printoptions(threshold=50) NEWLINE = '\n' class TreeWidgetItem(qt.QTreeWidgetItem): + + __legendColumn = 1 + def __init__(self, parent, itemList): qt.QTreeWidgetItem.__init__(self, parent, itemList) @@ -23,7 +60,7 @@ class TreeWidgetItem(qt.QTreeWidgetItem): valOther = other.text(col) if val == '---': ret = True - elif col > 0: + elif col > self.__legendColumn: try: ret = (float(val) < float(valOther)) except ValueError: @@ -43,10 +80,14 @@ class XMCDOptions(qt.QDialog): # Buttons buttonOK = qt.QPushButton('OK') + buttonOK.setToolTip('Accept the configuration') buttonCancel = qt.QPushButton('Cancel') + buttonCancel.setToolTip('Return to XMCD Analysis\nwithout changes') if full: buttonSave = qt.QPushButton('Save') + buttonSave.setToolTip('Save configuration to *.cfg-File') buttonLoad = qt.QPushButton('Load') + buttonLoad.setToolTip('Load existing configuration from *.cfg-File') # OptionLists and ButtonGroups # GroupBox can be generated from self.getGroupBox @@ -60,20 +101,23 @@ class XMCDOptions(qt.QDialog): normBG = qt.QButtonGroup(self) xrangeBG = qt.QButtonGroup(self) # ComboBoxes - normMeth = self.getComboBox(['(y-min(y))/trapz(max(y)-min(y),x)', - 'y/max(y)', - '(y-min(y))/(max(y)-min(y))', - '(y-min(y))/sum(max(y)-min(y))']) + normMeth = qt.QComboBox() + normMeth.addItems(['(y-min(y))/trapz(max(y)-min(y),x)', + 'y/max(y)', + '(y-min(y))/(max(y)-min(y))', + '(y-min(y))/sum(max(y)-min(y))']) normMeth.setEnabled(False) - motor0 = self.getComboBox(mList) - motor1 = self.getComboBox(mList) self.optsDict = { 'normalization' : normBG, 'normalizationMethod' : normMeth, - 'xrange' : xrangeBG, - 'motor0': motor0, - 'motor1': motor1 + 'xrange' : xrangeBG } + for idx in range(5): + # key: motor0, motor1, ... + key = 'motor%d'%idx + tmp = qt.QComboBox() + tmp.addItems(mList) + self.optsDict[key] = tmp # Subdivide into GroupBoxes normGroupBox = self.getGroupBox('Normalization', normOpts, @@ -95,10 +139,11 @@ class XMCDOptions(qt.QDialog): buttonLayout.addWidget(buttonCancel) normLayout.addWidget(qt.QLabel('Method:')) normLayout.addWidget(normMeth) - motorLayout.addWidget(qt.QLabel('Motor 1:'),0,0) - motorLayout.addWidget(motor0,0,1) - motorLayout.addWidget(qt.QLabel('Motor 2:'),1,0) - motorLayout.addWidget(motor1,1,1) + for idx in range(5): + label = qt.QLabel('Motor %d:'%(idx+1)) + cbox = self.optsDict['motor%d'%idx] + motorLayout.addWidget(label,idx,0) + motorLayout.addWidget(cbox,idx,1) motorGroupBox.setLayout(motorLayout) normGroupBox.layout().addLayout(normLayout) mainLayout.addWidget(normGroupBox) @@ -121,6 +166,8 @@ class XMCDOptions(qt.QDialog): normBG.button(0).toggled.connect(normMeth.setDisabled) def showEvent(self, event): + # Plugin does not destroy Options Window when accepted + # Reset self.saved manually self.saved = False qt.QDialog.showEvent(self, event) @@ -137,11 +184,6 @@ class XMCDOptions(qt.QDialog): # Motor not found in Motorlist, set to default obj.setCurrentIndex(idx) - def getComboBox(self, itemList): - tmp = qt.QComboBox() - tmp.addItems(itemList) - return tmp - def getGroupBox(self, title, optionList, buttongroup=None): ''' title : string @@ -178,7 +220,7 @@ class XMCDOptions(qt.QDialog): 'offsetAndCounts' : r'(y-min(y))/sum(max(y)-min(y))', 'offsetAndArea' : r'(y-min(y))/trapz(max(y)-min(y),x)' } - for (name, eq) in normDict.iteritems(): + for (name, eq) in normDict.items(): if ident == name: return eq if ident == eq: @@ -299,9 +341,9 @@ class XMCDOptions(qt.QDialog): name = ddict[option] if option == 'normalizationMethod': name = self.normalizationMethod(name) - if option.startswith('Motor') and name=='None': + if option.startswith('Motor') and name == 'None': name = '' - idx = obj.findText(qt.QString(name)) + idx = obj.findText(QString(name)) obj.setCurrentIndex(idx) elif isinstance(obj, qt.QButtonGroup): try: @@ -315,11 +357,20 @@ class XMCDOptions(qt.QDialog): class XMCDScanWindow(sw.ScanWindow): plotModifiedSignal = qt.pyqtSignal() - saveOptionsSignal = qt.pyqtSignal('QString') + saveOptionsSignal = qt.pyqtSignal('QString') def __init__(self, origin, parent=None): + ''' + Input + ----- + + origin : ScanWindow instance + Plot window containing the data on which + the analysis is performed + parent : QWidgit instance + ''' sw.ScanWindow.__init__(self, parent, name='XLD/XMCD Analysis', @@ -330,25 +381,24 @@ class XMCDScanWindow(sw.ScanWindow): # Buttons to push spectra to main Window buttonWidget = qt.QWidget() buttonAdd = qt.QPushButton('Add', self) - buttonAdd.setToolTip('Add active curve to scan window') + buttonAdd.setToolTip('Add active curve to main window') buttonReplace = qt.QPushButton('Replace', self) - buttonReplace.setToolTip('Replace all curves in scan window with active curve') + buttonReplace.setToolTip( + 'Replace all curves in main window ' + +'with active curve in analysis window') buttonAddAll = qt.QPushButton('Add all', self) - buttonAddAll.setToolTip('Add all curves to scan window') + buttonAddAll.setToolTip( + 'Add all curves in analysis window ' + +'to main window') buttonReplaceAll = qt.QPushButton('Replace all', self) - buttonReplaceAll.setToolTip('Replace all curves in scan window with all curves') - buttonLayout = qt.QHBoxLayout(None) - buttonLayout.setContentsMargins(0, 0, 0, 0) - buttonLayout.setSpacing(5) - # Show XAS & XMCD Buttons - buttonLayout.addWidget(qt.HorizontalSpacer(self)) - buttonLayout.addWidget(buttonAdd) - buttonLayout.addWidget(buttonAddAll) - buttonLayout.addWidget(buttonReplace) - buttonLayout.addWidget(buttonReplaceAll) - buttonWidget.setLayout(buttonLayout) -# self.mainLayout.addLayout(buttonLayout) - self.mainLayout.addWidget(buttonWidget) + buttonReplaceAll.setToolTip( + 'Replace all curves in main window ' + +'with all curves from analysis window') + self.graphBottomLayout.addWidget(qt.HorizontalSpacer()) + self.graphBottomLayout.addWidget(buttonAdd) + self.graphBottomLayout.addWidget(buttonAddAll) + self.graphBottomLayout.addWidget(buttonReplace) + self.graphBottomLayout.addWidget(buttonReplaceAll) buttonAdd.clicked.connect(self.add) buttonReplace.clicked.connect(self.replace) @@ -366,7 +416,8 @@ class XMCDScanWindow(sw.ScanWindow): 'normalizationMethod' : self.NormOffsetAndArea } self.xRange = None - # Keep track of Averages, XMCD and XAS curves + + # Keep track of Averages, XMCD and XAS curves by label self.avgA = None self.avgB = None self.xmcd = None @@ -396,9 +447,9 @@ class XMCDScanWindow(sw.ScanWindow): tmp['normalizationMethod'] = self.setNormalizationMethod(normMethod) # Trigger reclaculation self.optsDict = tmp - msel = self.selectionDict['A'] - psel = self.selectionDict['B'] - self.processSelection(msel, psel) + groupA = self.selectionDict['A'] + groupB = self.selectionDict['B'] + self.processSelection(groupA, groupB) def setNormalizationMethod(self, fname): if fname == 'toMaximum': @@ -423,14 +474,12 @@ class XMCDScanWindow(sw.ScanWindow): return ynorm def NormOffsetAndCounts(self, x, y): - # Check for non-zero values? ynorm = y - numpy.min(y) ymax = numpy.sum(ynorm) ynorm /= ymax return ynorm def NormOffsetAndArea(self, x, y): - # Check for non-zero values? ynorm = y - numpy.min(y) ymax = numpy.trapz(ynorm, x) ynorm /= ymax @@ -443,38 +492,27 @@ class XMCDScanWindow(sw.ScanWindow): ''' Input ----- - fromCurves : Bool - Uses curves present in self.curvesDict - if set to true. If set to false, an - ndarray with equistant interpolation - points is returned + xRange : ndarray + x-range on which all curves are interpolated + If set to none, the first curve in xRangeList + is used + equidistant : Bool + Determines equidistant xrange on which + all curves are interpolated xRangeList : List - List of ndarray from whose the overlap - is determined - - Checks dataObjectsDictionary for curves - present in the ScanWindow and tries to - find the overlap in the x-range of these - curves. - - If equidistant is True: - The x-ranges of the curves containing - the minmal resp. the maximal x-value are - used to determine the minimal number of - points (n) in their overlap in order to - avoid oversampling. + List of ndarray from which the overlap + is determined. If set to none, self.curvesDict + is used. - If equidistant is False: - If an active curve in the plotWindow is - set, its xRange is used as interpolation - points. If not active curve is set, the - first curve in the scan sequence is taken + Determines the interpolation x-range used for XMCD + Analysis specified by the provided parameters. The + interpolation x-range is limited by the maximal + overlap between the curves present in the plot window. Returns ------- out : numpy array - (Evenly spaced) x-range between xmin and - xmax containing n points + x-range between xmin and xmax containing n points ''' if not xRangeList: # Default xRangeList: curvesDict sorted for legends @@ -508,13 +546,14 @@ class XMCDScanWindow(sw.ScanWindow): x = xRange else: x = xRangeList[0] + # Ensure monotonically increasing x-range + if not numpy.all(numpy.diff(x)>0.): + mask = numpy.nonzero(numpy.diff(x)>0.)[0] + x = numpy.take(x, mask) + # Exclude the endpoints mask = numpy.nonzero((x > xmin) & (x < xmax))[0] out = numpy.sort(numpy.take(x, mask)) - # Remove remaining duplicates - if not numpy.all(numpy.diff(out) > 0.): - mask = numpy.nonzero(numpy.diff(out)>0.)[0] - out = numpy.take(out, mask) if DEBUG: print('interpXRange -- Resulting xrange:') print('\tmin = %f' % out.min()) @@ -522,14 +561,23 @@ class XMCDScanWindow(sw.ScanWindow): print('\tnum = %f' % len(out)) return out - def processSelection(self, msel, psel): + def processSelection(self, groupA, groupB): + ''' + Input + ----- + groupA, groupB : Lists of strings + Contain the legends of curves selected + to Group A resp. B + ''' + # Clear analysis window all = self.getAllCurves(just_legend=True) self.removeCurves(all) self.avgB, self.avgA = None, None + self.xas, self.xmcd = None, None - self.selectionDict['A'] = msel[:] - self.selectionDict['B'] = psel[:] - self.curvesDict = self.copyCurves(msel + psel) + self.selectionDict['A'] = groupA[:] + self.selectionDict['B'] = groupB[:] + self.curvesDict = self.copyCurves(groupA + groupB) if (len(self.curvesDict) == 0) or\ ((len(self.selectionDict['A']) == 0) and\ @@ -602,9 +650,16 @@ class XMCDScanWindow(sw.ScanWindow): def copyCurves(self, selection): ''' + Input + ----- selection : List - Contains names of curves to be processed - + Contains legends of curves to be processed + + Creates a deep copy of the curves present in the + plot window. In order to avoid interpolation + errors later on, it is ensured that the xranges + of the data is strictly monotonically increasing. + Returns ------- out : Dictionary @@ -617,7 +672,25 @@ class XMCDScanWindow(sw.ScanWindow): for legend in selection: tmp = self.plotWindow.dataObjectsDict.get(legend, None) if tmp: - out[legend] = copy.deepcopy(tmp) + tmp = copy.deepcopy(tmp) + xarr, yarr = tmp.x, tmp.y + #if len(tmp.x) == len(tmp.y): + xprocArr, yprocArr = [], [] + for (x,y) in zip(xarr,yarr): + # Sort + idx = numpy.argsort(x, kind='mergesort') + xproc = numpy.take(x, idx) + yproc = numpy.take(y, idx) + # Ravel, Increase + xproc = xproc.ravel() + idx = numpy.nonzero((xproc[1:] > xproc[:-1]))[0] + xproc = numpy.take(xproc, idx) + yproc = numpy.take(yproc, idx) + xprocArr += [xproc] + yprocArr += [yproc] + tmp.x = xprocArr + tmp.y = yprocArr + out[legend] = tmp else: # TODO: Errorhandling, curve not found if DEBUG: @@ -732,8 +805,6 @@ class XMCDScanWindow(sw.ScanWindow): pass elif len(labelNames) == 2: [xlabel, ylabel] = labelNames -# print 'extractLabels -- using labelNames' -# print '\t',labelNames elif sel: xsel = sel.get('x',[]) ysel = sel.get('y',[]) @@ -743,9 +814,6 @@ class XMCDScanWindow(sw.ScanWindow): if len(ysel) > 0: y = ysel[0] ylabel = labelNames[y] -# print 'extractLabels -- xsel, ysel:' -# print '\txsel: ', xsel -# print '\tysel: ', ysel return xlabel, ylabel def performXAS(self): @@ -819,18 +887,11 @@ class XMCDScanWindow(sw.ScanWindow): def _saveIconSignal(self): saveDir = PyMcaDirs.outputDir -# filter = ['spec File (*.spec)','Any File (*.*)'] - ffilter = 'spec File (*.spec);;Any File (*.*)' + filter = 'spec File (*.spec);;Any File (*.*)' try: - # filename = PyMcaFileDialogs.\ - # getFileList(parent=self, - # filetypelist=filter, - # message='Save XMCD Analysis', - # mode='SAVE', - # single=True)[0] (filelist, append, comment) = getSaveFileName(parent=self, caption='Save XMCD Analysis', - filter=ffilter, + filter=filter, directory=saveDir) filename = filelist[0] except IndexError: @@ -841,7 +902,7 @@ class XMCDScanWindow(sw.ScanWindow): return if append: - specf = specfile.Specfile(filename) + specf = specfile.Specfile(filename) scanno = specf.scanno() + 1 else: scanno = 1 @@ -852,17 +913,41 @@ class XMCDScanWindow(sw.ScanWindow): filename += ext try: if append: - filehandle = open(filename, 'ab') # sepFile = splitext(basename(filename)) - sepFilename = sepFile[0] + '_%.2d'%scanno + sepFile[1] - sepFileName = pathjoin(dirname(filename),sepFilename) - # TODO: Check if sepFilename exists + sepFileName = sepFile[0] + '_%.2d'%scanno + sepFile[1] + sepFileName = pathjoin(dirname(filename),sepFileName) + if scanno == 2: + # Case: Scan appended to file containing + # a single scan. Make sure, that the first + # scan is also written to seperate file and + # the corresponding cfg-file is copied + # 1. Create filename of first scan + sepFirstFileName = sepFile[0] + '_01' + sepFile[1] + sepFirstFileName = pathjoin(dirname(filename),sepFirstFileName) + # 2. Guess filename of first config + confname = sepFile[0] + '.cfg' + confname = pathjoin(dirname(filename),confname) + # 3. Create new filename of first config + sepFirstConfName = sepFile[0] + '_01' + '.cfg' + sepFirstConfName = pathjoin(dirname(filename),sepFirstConfName) + # Copy contents + firstSeperateFile = open(sepFirstFileName, 'wb') + firstSeperateConf = open(sepFirstConfName, 'wb') + filehandle = open(filename, 'rb') + confhandle = open(confname, 'rb') + firstFile = filehandle.read() + firstConf = confhandle.read() + firstSeperateFile.write(firstFile) + firstSeperateConf.write(firstConf) + firstSeperateFile.close() + firstSeperateConf.close() + filehandle = open(filename, 'ab') seperateFile = open(sepFileName, 'wb') else: filehandle = open(filename, 'wb') seperateFile = None except IOError: - msg = qt.QMessageBox(text="Unable to write to '%s'"%filename) + msg = qt.QMessageBox(text="Unable to open '%s'"%filename) msg.exec_() return @@ -920,29 +1005,18 @@ class XMCDScanWindow(sw.ScanWindow): if seperateFile is not None: self.saveOptionsSignal.emit(splitext(sepFileName)[0]) - #def noiseFilter(self, y): - # size = asarray([3] * len(y.shape)) - # mean = numpy.correlate(y, ones(size), 'same') / product(size, axis=0) - # var = (numpy.correlate(y**2, ones(size), 'same') / product(size, axis=0)\ - # - mean**2) - # noise = numpy.mean(numpy.ravel(var), axis=0) - # filt = y - mean - # filt *= (1 - noise/var) - # filt += mean - # out = numpy.where(var < noise, mean, res) - # return out - def add(self): activeCurve = self.getActiveCurve() if activeCurve is None: return (xVal, yVal, legend, info) = activeCurve - if 'selectionlegend' in info: - newLegend = info['selectionlegend'] - elif 'operation' in info: - newLegend = (str(operation) + ' ' + self.title) - else: - newLegend = (legend + ' ' + self.title) + #if 'selectionlegend' in info: + # newLegend = info['selectionlegend'] + #elif 'operation' in info: + # newLegend = (str(operation) + ' ' + self.title) + #else: + # newLegend = (legend + ' ' + self.title) + newLegend = legend self.plotWindow.addCurve(xVal, yVal, newLegend, @@ -951,12 +1025,13 @@ class XMCDScanWindow(sw.ScanWindow): def addAll(self): for (xVal, yVal, legend, info) in self.getAllCurves(): - if 'selectionlegend' in info: - newLegend = info['selectionlegend'] - elif 'operation' in info: - newLegend = (str(operation) + ' ' + self.title) - else: - newLegend = (legend + ' ' + self.title) + #if 'selectionlegend' in info: + # newLegend = info['selectionlegend'] + #elif 'operation' in info: + # newLegend = (str(operation) + ' ' + self.title) + #else: + # newLegend = (legend + ' ' + self.title) + newLegend = legend self.plotWindow.addCurve(xVal, yVal, newLegend, @@ -983,14 +1058,14 @@ class XMCDScanWindow(sw.ScanWindow): def replaceAll(self): allCurves = self.getAllCurves() - for (i, (xVal, yVal, legend, info)) in enumerate(allCurves): + for (idx, (xVal, yVal, legend, info)) in enumerate(allCurves): if 'selectionlegend' in info: newLegend = info['selectionlegend'] elif 'operation' in info: newLegend = (str(operation) + ' ' + self.title) else: newLegend = (legend + ' ' + self.title) - if i == 0: + if idx == 0: self.plotWindow.addCurve(xVal, yVal, newLegend, @@ -1003,20 +1078,6 @@ class XMCDScanWindow(sw.ScanWindow): info) self.plotModifiedSignal.emit() - def detrend(self): - for (k,v) in self.dataObjectsDict.items(): - if k.startswith('XMCD'): - xmcd = v - xmcdLegend = k - break - xmcd = self.dataObjectsDict[xmcdLegend] - x = xmcd.x[0] - y = xmcd.y[0] - a, b = numpy.polyfit(x,y,1) - ynew = y - a*x - b - y = ynew - self.graph.checky2scale() - class XMCDMenu(qt.QMenu): def __init__(self, parent, title=None): qt.QMenu.__init__(self, parent) @@ -1047,6 +1108,10 @@ class XMCDMenu(qt.QMenu): class XMCDTreeWidget(qt.QTreeWidget): + __colGroup = 0 + __colLegend = 1 + __colScanNo = 2 + __colCounter = 3 selectionModifiedSignal = qt.pyqtSignal() def __init__(self, parent, groups = ['B','A','D'], color=True): @@ -1067,7 +1132,7 @@ class XMCDTreeWidget(qt.QTreeWidget): width = vscrollbar.width() for i in range(self.columnCount()): width += (2 + self.columnWidth(i)) - return qt.QSize( width, 200 ) + return qt.QSize( width, 20*22) def setContextMenu(self, menu): self.contextMenu = menu @@ -1147,32 +1212,32 @@ class XMCDTreeWidget(qt.QTreeWidget): items must be of type [QStringList] (List of Lists) ''' # Remember selection, then clear list - sel = self.getColumn(1, True) + sel = self.getColumn(self.__colLegend, True) self.clear() self.setHeaderLabels(headerLabels) for item in items: treeItem = TreeWidgetItem(self, item) if self.color: - idx = str(treeItem.text(0)) + idx = str(treeItem.text(self.__colGroup)) for i in range(self.columnCount()): treeItem.setBackground(i, self.colorDict[idx]) - if treeItem.text(1) in sel: + if treeItem.text(self.__colLegend) in sel: treeItem.setSelected(True) - self.resizeColumnToContents(0) - self.resizeColumnToContents(1) def setSelectionAs(self, idx): ''' Sets the items currently selected to - the identifier given in id. + the identifier given in idx. ''' if idx not in self.groupList: raise ValueError('XMCDTreeWidget: invalid identifer \'%s\'' % idx) sel = self.selectedItems() if idx == self.groupList[-1]: + # Last identifier in self.groupList + # is the dummy identifier idx = '' for item in sel: - item.setText(0, idx) + item.setText(self.__colGroup, idx) if self.color: for i in range(self.columnCount()): item.setBackground(i, self.colorDict[idx]) @@ -1180,8 +1245,8 @@ class XMCDTreeWidget(qt.QTreeWidget): def setSelectionToSequence(self, seq=None, selectedOnly=False): ''' - Sets the id column (col 0) to seq. If - sequence is None, a dialog window is + Sets the group column (col 0) to seq. + If sequence is None, a dialog window is shown. ''' chk = True @@ -1190,14 +1255,15 @@ class XMCDTreeWidget(qt.QTreeWidget): else: root = self.invisibleRootItem() sel = [root.child(i) for i in range(root.childCount())] - # Ensure alphabetically ordered list - self.sortItems(1, qt.Qt.AscendingOrder) + # Try to sort for scanNo + #self.sortItems(self.__colLegend, qt.Qt.AscendingOrder) + self.sortItems(self.__colScanNo, qt.Qt.AscendingOrder) if not seq: seq, chk = qt.QInputDialog.\ getText(None, 'Sequence Dialog', 'Valid identifiers are: ' + ', '.join(self.groupList), - qt.QLineEdit.Normal, + qt.QLineEdit.Normal, 'Enter sequence') seq = str(seq).upper() if not chk: @@ -1212,14 +1278,14 @@ class XMCDTreeWidget(qt.QTreeWidget): if len(sel) != len(seq): # Assume pattern and repeat seq = seq * (len(sel)//len(seq) + 1) - # invalidMsg = qt.QMessageBox(None) - # invalidMsg.setText('Sequence length does not match item count.') - # invalidMsg.setStandardButtons(qt.QMessageBox.Ok) - # invalidMsg.exec_() + #invalidMsg = qt.QMessageBox(None) + #invalidMsg.setText('Sequence length does not match item count.') + #invalidMsg.setStandardButtons(qt.QMessageBox.Ok) + #invalidMsg.exec_() for (idx, item) in zip(seq, sel): if idx == self.groupList[-1]: idx = '' - item.setText(0, idx) + item.setText(self.__colGroup, idx) if self.color: for i in range(self.columnCount()): item.setBackground(i, self.colorDict[idx]) @@ -1227,7 +1293,7 @@ class XMCDTreeWidget(qt.QTreeWidget): def clearSelection(self, selectedOnly=True): ''' - Empties the id column for the selected rows. + Empties the groups column for the selected rows. ''' if selectedOnly: sel = self.selectedItems() @@ -1235,7 +1301,7 @@ class XMCDTreeWidget(qt.QTreeWidget): root = self.invisibleRootItem() sel = [root.child(i) for i in range(root.childCount())] for item in sel: - item.setText(0,'') + item.setText(self.__colGroup,'') if self.color: for i in range(self.columnCount()): item.setBackground(i, self.colorDict['']) @@ -1244,9 +1310,9 @@ class XMCDTreeWidget(qt.QTreeWidget): def getSelection(self): ''' Returns dictionary with where the keys - are the identifiers and the values are - (sorted) lists containing legends to - which the respective identifier is + are the identifiers ('D', 'A', 'B') and + the values are (sorted) lists containing + legends to which the respective identifier is assigned to. ''' out = dict((group, []) for group in self.groupList) @@ -1255,6 +1321,8 @@ class XMCDTreeWidget(qt.QTreeWidget): item = root.child(i) group = str(item.text(0)) legend = str(item.text(1)) + #nCols = item.columnCount() + #legend = str(item.text(nCols-1)) if len(group) == 0: group = self.groupList[-1] out[group] += [legend] @@ -1269,7 +1337,7 @@ class XMCDWidget(qt.QWidget): def __init__(self, parent, plotWindow, beamline, - nSelectors = 2): + nSelectors = 5): """ Input ----- @@ -1277,17 +1345,9 @@ class XMCDWidget(qt.QWidget): ScanWindow from which curves are passed for XLD/XMCD Analysis nSelectors : Int - Number of Comboboxes shown in the widget. - Every Combobox allows to select a different motor - - legendList : List - Contains curve legends. Format - ['Legend0', ... , 'LegendX'] - motorsList : List - Contains dictionaries. Format: - [{'MotorName0':MotorValue0, ... , 'MotorNameN':MotorValueN}, - ..., - {'MotorName2':MotorValue2, ... , 'MotorNameM':MotorValueM}] + Number of columns show in the widget. Per default + these are + <Group> <Legend> <ScanNo> <Counter> <Motor 1> ... <Motor5> """ qt.QWidget.__init__(self, parent) self.setWindowIcon(qt.QIcon(IconDict['peak'])) @@ -1304,35 +1364,54 @@ class XMCDWidget(qt.QWidget): self.analysisWindow = XMCDScanWindow(origin=plotWindow, parent=None) self.optsWindow = XMCDOptions(self, self.motorNamesList) + + helpFileName = pathjoin(PyMcaDataDir.PYMCA_DOC_DIR, + "HTML", + "XMCDInfotext.html") + self.helpFileBrowser = qt.QTextBrowser() + self.helpFileBrowser.setWindowTitle("XMCD Help") + self.helpFileBrowser.setLineWrapMode(qt.QTextEdit.FixedPixelWidth) + self.helpFileBrowser.setLineWrapColumnOrWidth(500) + self.helpFileBrowser.resize(520,300) + try: + helpFileHandle = open(helpFileName) + helpFileHTML = helpFileHandle.read() + helpFileHandle.close() + self.helpFileBrowser.setHtml(helpFileHTML) + except IOError: + if DEBUG: + print('XMCDWindow -- init: Unable to read help file') + self.helpFileBrowser = None self.selectionDict = {'D': [], 'B': [], 'A': []} - self.beamline = beamline self.setSizePolicy(qt.QSizePolicy.MinimumExpanding, qt.QSizePolicy.Expanding) self.setWindowTitle("XLD/XMCD Analysis") - updatePixmap = qt.QPixmap(IconDict["reload"]) - buttonUpdate = qt.QPushButton(qt.QIcon(updatePixmap), '', self) + buttonOptions = qt.QPushButton('Options', self) - #for i in range(nSelectors): - # cBox = qt.QComboBox(self) - # cBox.addItems(self.motorNamesList) - # cBox.currentIndexChanged['QString'].connect(self.updateTree) - # self.cBoxList += [cBox] - - self.ident = 'Key' - for ddict in self.infoList: - if self.ident not in ddict.keys(): - self.ident = 'selectionlegend' - break - elif not len(ddict[self.ident]): - self.ident = 'selectionlegend' - break + buttonOptions.setToolTip( + 'Set normalization and interpolation\n' + +'method and motors shown') + + buttonInfo = qt.QPushButton('Info') + buttonInfo.setToolTip( + 'Shows a describtion of the plugins features\n' + +'and gives instructions on how to use it') + + updatePixmap = qt.QPixmap(IconDict["reload"]) + buttonUpdate = qt.QPushButton( + qt.QIcon(updatePixmap), '', self) + buttonUpdate.setIconSize(qt.QSize(21,21)) + buttonUpdate.setToolTip( + 'Update curves in XMCD Analysis\n' + +'by checking the plot window') self.list = XMCDTreeWidget(self) - labels = ['Legend'] + nSelectors*[''] + labels = ['Group', 'Legend', 'S#','Counter']+\ + (['']*nSelectors) ncols = len(labels) self.list.setColumnCount(ncols) self.list.setHeaderLabels(labels) @@ -1352,14 +1431,8 @@ class XMCDWidget(qt.QWidget): ('Remove curve(s)', self.removeCurve_)]) self.list.setContextMenu(listContextMenu) self.expCBox = qt.QComboBox(self) - self.expCBox.addItems( - ['Generic Dichorism', - 'ID08: XLD', - 'ID08: XLD (old)', - 'ID08: XMCD', - 'ID08: XMCD (old)', - 'Add new configuration']) - self.expCBox.insertSeparator(5) + self.expCBox.setToolTip('Select configuration of predefined\n' + +'experiment or configure new experiment') self.experimentsDict = { 'Generic Dichorism': { @@ -1367,65 +1440,112 @@ class XMCDWidget(qt.QWidget): 'normalization': 0, 'normalizationMethod': 'offsetAndArea', 'motor0': '', - 'motor1': '' + 'motor1': '', + 'motor2': '', + 'motor3': '', + 'motor4': '' }, - 'ID08: XMCD': { + 'ID08: XMCD 9 Tesla Magnet': { 'xrange': 0, 'normalization': 0, 'normalizationMethod': 'offsetAndArea', 'motor0': 'phaseD', - 'motor1': 'magnet' + 'motor1': 'magnet', + 'motor2': '', + 'motor3': '', + 'motor4': '' }, - 'ID08: XMCD (old)': { + 'ID08: XMCD 5 Tesla Magnet': { 'xrange': 0, 'normalization': 0, 'normalizationMethod': 'offsetAndArea', 'motor0': 'PhaseD', - 'motor1': 'oxPS' + 'motor1': 'oxPS', + 'motor2': '', + 'motor3': '', + 'motor4': '' }, - 'ID08: XLD (old)': { + 'ID08: XLD 5 Tesla Magnet': { 'xrange': 0, 'normalization': 0, 'normalizationMethod': 'offsetAndArea', 'motor0': 'PhaseD', - 'motor1': '' + 'motor1': '', + 'motor2': '', + 'motor3': '', + 'motor4': '' }, - 'ID08: XLD': { + 'ID08: XLD 9 Tesla Magnet': { 'xrange': 0, 'normalization': 0, 'normalizationMethod': 'offsetAndArea', 'motor0': 'phaseD', - 'motor1': '' + 'motor1': '', + 'motor2': '', + 'motor3': '', + 'motor4': '' + }, + 'ID12: XMCD (Flipper)': { + 'xrange': 0, + 'normalization': 0, + 'normalizationMethod': 'offsetAndArea', + 'motor0': 'BRUKER', + 'motor1': 'OXFORD', + 'motor2': 'CRYO', + 'motor3': '', + 'motor4': '' + }, + 'ID12: XMCD': { + 'xrange': 0, + 'normalization': 0, + 'normalizationMethod': 'offsetAndArea', + 'motor0': 'Phase', + 'motor1': 'PhaseA', + 'motor2': 'BRUKER', + 'motor3': 'OXFORD', + 'motor4': 'CRYO' + }, + 'ID12: XLD (quater wave plate)': { + 'xrange': 0, + 'normalization': 0, + 'normalizationMethod': 'offsetAndArea', + 'motor0': '', + 'motor1': '', + 'motor2': '', + 'motor3': '', + 'motor4': '' } } - - #cBoxLayout = qt.QHBoxLayout(None) - #self.cBoxWidget = qt.QWidget() - #cBoxLayout.addWidget(qt.HorizontalSpacer(self)) - #cBoxLayout.addWidget( - # qt.QLabel('Selected motor(s):', self)) - #for cBox in self.cBoxList: - # cBoxLayout.addWidget(cBox) - #self.cBoxWidget.setLayout(cBoxLayout) - #cBoxLayout.setContentsMargins(0,0,0,0) + self.expCBox.addItems( + ['Generic Dichorism', + 'ID08: XLD 9 Tesla Magnet', + 'ID08: XLD 5 Tesla Magnet', + 'ID08: XMCD 9 Tesla Magnet', + 'ID08: XMCD 5 Tesla Magnet', + 'ID12: XLD (quater wave plate)', + 'ID12: XMCD (Flipper)', + 'ID12: XMCD', + 'Add new configuration']) + self.expCBox.insertSeparator(len(self.experimentsDict)) topLayout = qt.QHBoxLayout() topLayout.addWidget(buttonUpdate) topLayout.addWidget(buttonOptions) + topLayout.addWidget(buttonInfo) topLayout.addWidget(qt.HorizontalSpacer(self)) topLayout.addWidget(self.expCBox) leftLayout = qt.QGridLayout() leftLayout.setContentsMargins(1, 1, 1, 1) leftLayout.setSpacing(2) - #leftLayout.addWidget(self.cBoxWidget, 2, 0) - leftLayout.addWidget(self.list, 1, 0) leftLayout.addLayout(topLayout, 0, 0) + leftLayout.addWidget(self.list, 1, 0) leftWidget = qt.QWidget(self) leftWidget.setLayout(leftLayout) self.analysisWindow.setSizePolicy(qt.QSizePolicy.Minimum, qt.QSizePolicy.Minimum) - self.splitter = qt.QSplitter(qt.Qt.Horizontal, self) + #self.splitter = qt.QSplitter(qt.Qt.Horizontal, self) + self.splitter = qt.QSplitter(qt.Qt.Vertical, self) self.splitter.addWidget(leftWidget) self.splitter.addWidget(self.analysisWindow) stretch = int(leftWidget.width()) @@ -1447,10 +1567,13 @@ class XMCDWidget(qt.QWidget): self.optsWindow.accepted[()].connect(self.updateTree) buttonUpdate.clicked.connect(self.updatePlots) buttonOptions.clicked.connect(self.showOptionsWindow) + buttonInfo.clicked.connect(self.showInfoWindow) self.updateTree() self.list.sortByColumn(1, qt.Qt.AscendingOrder) - self._setBeamlineSpecific(self.beamline) + + def sizeHint(self): + return self.list.sizeHint() + self.analysisWindow.sizeHint() def addExperiment(self): exp, chk = qt.QInputDialog.\ @@ -1487,6 +1610,18 @@ class XMCDWidget(qt.QWidget): options = self.optsWindow.getOptions() self.analysisWindow.processOptions(options) + def showInfoWindow(self): + if self.helpFileBrowser is None: + msg = qt.QMessageBox() + msg.setWindowTitle('XLD/XMCD Error') + msg.setText('No help file found.') + msg.exec_() + return + else: + self.helpFileBrowser.show() + self.helpFileBrowser.raise_() + + # Implement new assignment routines here BEGIN def selectExperiment(self, exp): exp = str(exp) @@ -1495,18 +1630,25 @@ class XMCDWidget(qt.QWidget): self.updateTree() elif exp in self.experimentsDict: try: + # Sets motors 0 to 4 in optsWindow self.optsWindow.setOptions(self.experimentsDict[exp]) except ValueError: self.optsWindow.setOptions( self.experimentsDict['Generic Dichorism']) return - self.updateTree() # Get motor values from tree + self.updateTree() values0 = numpy.array( - self.list.getColumn(2, convertType=float)) + self.list.getColumn(4, convertType=float)) values1 = numpy.array( - self.list.getColumn(3, convertType=float)) - # Calculate p/m selection + self.list.getColumn(5, convertType=float)) + values2 = numpy.array( + self.list.getColumn(6, convertType=float)) + values3 = numpy.array( + self.list.getColumn(7, convertType=float)) + values4 = numpy.array( + self.list.getColumn(8, convertType=float)) + # Determine p/m selection if exp.startswith('ID08: XLD'): values = values0 mask = numpy.where(numpy.isfinite(values))[0] @@ -1516,50 +1658,99 @@ class XMCDWidget(qt.QWidget): vmax = minmax.max() vpivot = .5 * (vmax + vmin) else: + vpivot = 0. values = numpy.array( [float('NaN')]*len(self.legendList)) elif exp.startswith('ID08: XMCD'): - values = values0 * values1 + mask = numpy.where(numpy.isfinite(values0))[0] + polarization = values0.take(mask) + values1 = values1.take(mask) + signMagnets = numpy.sign(values1) + if len(polarization)==0: + vpivot = 0. + values = numpy.array( + [float('NaN')]*len(self.legendList)) + elif numpy.all(signMagnets>=0.) or\ + numpy.all(signMagnets<=0.) or\ + numpy.all(signMagnets==0.): + vmin = polarization.min() + vmax = polarization.max() + vpivot = .5 * (vmax + vmin) + values = polarization + else: + vpivot = 0. + values = polarization * signMagnets + elif exp.startswith('ID12: XLD (quater wave plate)'): + # Extract counters from third column + counters = self.list.getColumn(3, convertType=str) + polarization = [] + for counter in counters: + # Relevant counters Ihor, Iver resp. Ihor0, Iver0, etc. + if 'hor' in counter: + pol = -1. + elif 'ver' in counter: + pol = 1. + else: + pol = float('nan') + polarization += [pol] + values = numpy.asarray(polarization, dtype=float) + vpivot = 0. + elif exp.startswith('ID12: XMCD (Flipper)'): + # Extract counters from third column + counters = self.list.getColumn(1, convertType=str) + polarization = [] + for counter in counters: + # Relevant counters: Fminus/Fplus resp. Rminus/Rplus + if 'minus' in counter: + pol = 1. + elif 'plus' in counter: + pol = -1. + else: + pol = float('nan') + polarization += [pol] + magnets = values0 + values1 + values2 + values = numpy.asarray(polarization, dtype=float)*\ + magnets + vpivot = 0. + elif exp.startswith('ID12: XMCD'): + # Sum over phases.. + polarization = values0 + values1 + # ..and magnets + magnets = values2 + values3 + values4 + signMagnets = numpy.sign(magnets) + if numpy.all(signMagnets==0.): + values = polarization + else: + values = numpy.sign(polarization)*\ + numpy.sign(magnets) vpivot = 0. else: values = numpy.array([float('NaN')]*len(self.legendList)) vpivot = 0. + # Sequence is generate according to values and vpivot seq = '' for x in values: if str(x) == 'nan': seq += 'D' - elif x>vpivot: - seq += 'B' - else: + elif x<vpivot: + # Minus group seq += 'A' + else: + # Plus group + seq += 'B' self.list.setSelectionToSequence(seq) # Implement new assignment routines here END def triggerXMCD(self): - msel = self.selectionDict['A'] - psel = self.selectionDict['B'] - self.analysisWindow.processSelection(msel, psel) + groupA = self.selectionDict['A'] + groupB = self.selectionDict['B'] + self.analysisWindow.processSelection(groupA, groupB) def removeCurve_(self): - sel = self.list.getColumn(1, + sel = self.list.getColumn(1, selectedOnly=True, convertType=str) - # Convert from scan number to legend if needed - if self.ident == 'Key': - legends = [] - for item in sel: - for (idx, info) in enumerate(self.infoList): - if item == info['Key']: - legends += [self.legendList[idx]] - else: - legends = sel - - if DEBUG: - print('removeCurve_ -- sel(ection):') - print('\t', sel) - print('removeCurve_ -- legends:') - print('\t', legends) - for legend in legends: + for legend in sel: self.plotWindow.removeCurve(legend) for selection in self.selectionDict.values(): if legend in selection: @@ -1574,26 +1765,18 @@ class XMCDWidget(qt.QWidget): self.updatePlots() def updateSelectionDict(self): - # selDict has format {IDENTIFIER0: LIST_OF_IDENTS0, ... } + # Get selDict from self.list. It consists of tree items: + # {GROUP0: LIST_OF_LEGENDS_IN_GROUP0, + # GROUP1: LIST_OF_LEGENDS_IN_GROUP1, + # GROUP2: LIST_OF_LEGENDS_IN_GROUP2} selDict = self.list.getSelection() # self.selectionDict -> Uses ScanNumbers instead of legends... newDict = {} - if self.ident == 'Key': - # List contains scannumber in the order they were added - scanNumberList = [info['Key'] for info in self.infoList] for (idx, selList) in selDict.items(): if idx not in newDict.keys(): newDict[idx] = [] - if self.ident == 'selectionlegend': - # Uses selectionlegend as identification for scans - for legend in selList: - newDict[idx] += [legend] - else: - # Uses Key (scan number) as identification for scans: - for scanNumber in selList: - scanIdx = scanNumberList.index(scanNumber) - legend = self.legendList[scanIdx] - newDict[idx] += [legend] + for legend in selList: + newDict[idx] += [legend] self.selectionDict = newDict self.setSelectionSignal.emit(self.selectionDict['A'], self.selectionDict['B']) @@ -1608,6 +1791,7 @@ class XMCDWidget(qt.QWidget): self.triggerXMCD() return self._setLists() + self.motorNamesList = [''] + self._getAllMotorNames() self.motorNamesList.sort() self.optsWindow.updateMotorList(self.motorNamesList) @@ -1619,24 +1803,43 @@ class XMCDWidget(qt.QWidget): def updateTree(self): mList = self.optsWindow.getMotors() - if self.ident == 'Key': - labels = ["Group",'S#'] + mList - else: - labels = ["Group",'Legend'] + mList + labels = ["Group",'Legend','S#','Counter'] + mList items = [] for i in range(len(self.legendList)): + # Loop through rows + # Each row is represented by QStringList legend = self.legendList[i] values = self.motorsList[i] info = self.infoList[i] selection = '' + # Determine Group from selectionDict for (idx, v) in self.selectionDict.items(): if (legend in v) and (idx != 'D'): selection = idx break - if self.ident == 'Key': - tmp = qt.QStringList([selection, info['Key']]) - else: - tmp = qt.QStringList([selection, legend]) + # Add filename, scanNo, counter + #sourceName = info.get('SourceName','') + #if isinstance(sourceName,list): + # filename = basename(sourceName[0]) + #else: + # filename = basename(sourceName) + filename = legend + scanNo = info.get('Key','') + counter = info.get('ylabel',None) + if counter is None: + selDict = info.get('selection',{}) + if len(selDict) == 0: + counter = '' + else: + # When do multiple selections occur? + try: + yIdx = selDict['y'][0] + cntList = selDict['cnt_list'] + counter = cntList[yIdx] + except Exception: + counter = '' + tmp = QStringList([selection, filename, scanNo, counter]) + # Determine value for each motor for m in mList: if len(m) == 0: tmp.append('') @@ -1644,6 +1847,8 @@ class XMCDWidget(qt.QWidget): tmp.append(str(values.get(m, '---'))) items.append(tmp) self.list.build(items, labels) + for idx in range(self.list.columnCount()): + self.list.resizeColumnToContents(idx) def setAsA(self): self.list.setSelectionAs('A') @@ -1690,25 +1895,40 @@ class XMCDWidget(qt.QWidget): return ret def _setLists(self): - curves = self.plotWindow.getAllCurves() - nCurves = len(curves) - self.legendList = [leg for (xvals, yvals, leg, info) in curves] - self.infoList = [info for (xvals, yvals, leg, info) in curves] - self.motorsList = self._convertInfoDictionary(self.infoList) - - def _setBeamlineSpecific(self, beamline): ''' - beamline : python str - Beamline identifier, all upper case - (e.g. ID08, ID12, ..) + Curves retrieved from the main plot window using the + Plugin1DBase getActiveCurve() resp. getAllCurves() + member functions are tuple resp. a list of tuples + containing x-data, y-data, legend and the info dictionary. + + _setLists splits these tuples into lists, thus setting + the attributes + + self.legendList + self.infoList + self.motorsList ''' - options = [str(self.expCBox.itemText(i))\ - for i in range(self.expCBox.count())] - for (i, option) in enumerate(options): - if option.startswith(beamline): - self.expCBox.setCurrentIndex(i) - self.expCBox.activated[qt.QString].emit(option) - break + if self.plotWindow is not None: + curves = self.plotWindow.getAllCurves() + else: + if DEBUG: + print('_setLists -- Set self.plotWindow before calling self._setLists') + return + # nCurves = len(curves) + self.legendList = [leg for (xvals, yvals, leg, info) in curves] + self.infoList = [info for (xvals, yvals, leg, info) in curves] + # Try to recover the scan number from the legend, if not set + # Requires additional import: + #from re import search as regexpSearch + #for ddict in self.infoList: + # key = ddict.get('Key','') + # if len(key)== 0: + # selectionlegend = ddict['selectionlegend'] + # match = regexpSearch(r'(?<= )\d{1,5}\.\d{1}',selectionlegend) + # if match: + # scanNo = match.group(0) + # ddict['Key'] = scanNo + self.motorsList = self._convertInfoDictionary(self.infoList) class XMCDFileDialog(qt.QFileDialog): def __init__(self, parent, caption, directory, filter): @@ -1756,28 +1976,39 @@ def main(): swin = sw.ScanWindow() info0 = {'xlabel': 'foo', 'ylabel': 'arb', - 'MotorNames': 'oxPS Motor11 Motor10', - 'MotorValues': '1 8.69271399699 21.9836418539'} - info1 = {'MotorNames': 'PhaseD oxPS Motor16 Motor15', - 'MotorValues': '0.470746882688 -0.695816070299 0.825780811755 0.25876374531'} - info2 = {'MotorNames': 'PhaseD oxPS Motor10 Motor8', - 'MotorValues': '2 0.44400576644 0.613870067852 0.901968648111'} + 'MotorNames': 'oxPS PhaseA Phase BRUKER CRYO OXFORD', + 'MotorValues': '1 -6.27247094 -3.11222732 6.34150808 -34.75892563 21.99607165'} + info1 = {'MotorNames': 'PhaseD oxPS PhaseA Phase BRUKER CRYO OXFORD', + 'MotorValues': '0.470746882688 0.25876374531 -0.18515967 -28.31216591 18.54513221 -28.09735532 -26.78833172'} + info2 = {'MotorNames': 'PhaseD oxPS PhaseA Phase BRUKER CRYO OXFORD', + 'MotorValues': '-9.45353059 -25.37448851 24.37665651 18.88048044 -0.26018745 2 0.901968648111 '} x = numpy.arange(100.,1100.) y0 = 10*x + 10000.*numpy.exp(-0.5*(x-500)**2/400) + 1500*numpy.random.random(1000.) y1 = 10*x + 10000.*numpy.exp(-0.5*(x-600)**2/400) + 1500*numpy.random.random(1000.) y2 = 10*x + 10000.*numpy.exp(-0.5*(x-400)**2/400) + 1500*numpy.random.random(1000.) - swin.newCurve(x, y2, legend="Curve2", xlabel='ene_st2', ylabel='zratio2', info=info2, replot=False, replace=False) - swin.newCurve(x, y0, legend="Curve0", xlabel='ene_st0', ylabel='zratio0', info=info0, replot=False, replace=False) - swin.newCurve(x, y1, legend="Curve1", xlabel='ene_st1', ylabel='zratio1', info=info1, replot=False, replace=False) + swin.newCurve(x, y2, legend="Curve2", xlabel='ene_st2', ylabel='Ihor', info=info2, replot=False, replace=False) + swin.newCurve(x, y0, legend="Curve0", xlabel='ene_st0', ylabel='Iver', info=info0, replot=False, replace=False) + swin.newCurve(x, y1, legend="Curve1", xlabel='ene_st1', ylabel='Ihor', info=info1, replot=False, replace=False) # info['Key'] is overwritten when using newCurve - swin.dataObjectsDict['Curve2 zratio2'].info['Key'] = '1.1' - swin.dataObjectsDict['Curve0 zratio0'].info['Key'] = '34.1' - swin.dataObjectsDict['Curve1 zratio1'].info['Key'] = '123.1' + swin.dataObjectsDict['Curve2 Ihor'].info['Key'] = '1.1' + swin.dataObjectsDict['Curve0 Iver'].info['Key'] = '34.1' + swin.dataObjectsDict['Curve1 Ihor'].info['Key'] = '123.1' - w = XMCDWidget(None, swin, 'ID08', nSelectors = 2) + w = XMCDWidget(None, swin, 'ID08', nSelectors = 5) w.show() + +# helpFileBrowser = qt.QTextBrowser() +# helpFileBrowser.setLineWrapMode(qt.QTextEdit.FixedPixelWidth) +# helpFileBrowser.setLineWrapColumnOrWidth(500) +# helpFileBrowser.resize(520,400) +# helpFileHandle = open('/home/truter/lab/XMCD_infotext.html') +# helpFileHTML = helpFileHandle.read() +# helpFileHandle.close() +# helpFileBrowser.setHtml(helpFileHTML) +# helpFileBrowser.show() + app.exec_() if __name__ == '__main__': diff --git a/PyMca/XRFMC/XMSOParser.py b/PyMca/XRFMC/XMSOParser.py index bad30aa..3bdfd10 100644 --- a/PyMca/XRFMC/XMSOParser.py +++ b/PyMca/XRFMC/XMSOParser.py @@ -1,3 +1,29 @@ +# +# Copyright (C) 2013 V. Armando Sole - ESRF +# +# Permission is hereby granted, free of charge, to any person +# obtaining a copy of this software and associated documentation +# files (the "Software"), to deal in the Software without +# restriction, including without limitation the rights to use, +# copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following +# conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +# OTHER DEALINGS IN THE SOFTWARE. +# +__license__ = "MIT" +__author__ = "V.A. Sole - ESRF Data Analysis" import sys import os import xml.etree.ElementTree as ElementTree diff --git a/PyMca/XRFMC/XRFMCHelper.py b/PyMca/XRFMC/XRFMCHelper.py index 5ff57cf..b3f29a1 100644 --- a/PyMca/XRFMC/XRFMCHelper.py +++ b/PyMca/XRFMC/XRFMCHelper.py @@ -1,3 +1,29 @@ +# +# Copyright (C) 2013 V. Armando Sole - ESRF +# +# Permission is hereby granted, free of charge, to any person +# obtaining a copy of this software and associated documentation +# files (the "Software"), to deal in the Software without +# restriction, including without limitation the rights to use, +# copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following +# conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +# OTHER DEALINGS IN THE SOFTWARE. +# +__license__ = "MIT" +__author__ = "V.A. Sole - ESRF Data Analysis" import sys import os import tempfile diff --git a/PyMca/XRFMC/XRFMCPyMca.py b/PyMca/XRFMC/XRFMCPyMca.py index f16123c..880a8fa 100644 --- a/PyMca/XRFMC/XRFMCPyMca.py +++ b/PyMca/XRFMC/XRFMCPyMca.py @@ -1,3 +1,30 @@ +#/*########################################################################## +# Copyright (C) 2013 V.A. Sole - European Synchrotron Radiation Facility +# +# This file is part of the PyMca X-ray Fluorescence Toolkit developed at +# the ESRF by the Software group. +# +# This toolkit is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the Free +# Software Foundation; either version 2 of the License, or (at your option) +# any later version. +# +# PyMca is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +# details. +# +# You should have received a copy of the GNU General Public License along with +# PyMca; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +# +# PyMca follows the dual licensing model of Riverbank's PyQt and cannot be +# used as a free plugin for a non-free program. +# +# Please contact the ESRF industrial unit (industry@esrf.fr) if this license +# is a problem for you. +#############################################################################*/ +__author__ = "V.A. Sole - ESRF Data Analysis" import sys import os import time diff --git a/PyMca/linalg.py b/PyMca/linalg.py new file mode 100644 index 0000000..9ec72ce --- /dev/null +++ b/PyMca/linalg.py @@ -0,0 +1,326 @@ +import numpy + +# Linear Least Squares + +def lstsq(a, b, rcond=None, sigma_b=None, weight=False, + uncertainties=True, covariances=False, digested_output=False): + """ + Return the least-squares solution to a linear matrix equation. + + Solves the equation `a x = b` by computing a vector `x` that + minimizes the Euclidean 2-norm `|| b - a x ||^2`. The equation may + be under-, well-, or over- determined (i.e., the number of + linearly independent rows of `a` can be less than, equal to, or + greater than its number of linearly independent columns). If `a` + is square and of full rank, then `x` (but for round-off error) is + the "exact" solution of the equation. + + Parameters + ---------- + a : array_like, shape (M, N) + "Model" matrix. + b : array_like, shape (M,) or (M, K) + Ordinate or "dependent variable" values. If `b` is two-dimensional, + the least-squares solution is calculated for each of the `K` columns + of `b`. + sigma_b : uncertainties on the b values + + weight: 0 - No data weighting. + If required, uncertainties will be calculated using either the + supplied experimental uncertainties or an experimental + uncertainty of 1 for each data point. + 1 - Statistical weight. + Weighted fit using the supplied experimental uncertainties or the + square root of the b values. + + uncertainties: If False, no uncertainties will be calculated unless the covariance + matrix is requested. + + covariances: If True, an array of covariance matrix/matrices will be returned. + + digested_output: If True, returns a dictionnary with explicit keys + + Returns + ------- + x : ndarray, shape (N,) or (N, K) + Least-squares solution. The shape of `x` depends on the shape of + `b`. + + uncertainties: ndarray, shape (N,) or (N, K) + + covariances: ndarray, shape (N, N) or (K, N, N) + + Examples + -------- + Fit a line, ``y = mx + c``, through some noisy data-points: + + >>> x = np.array([0, 1, 2, 3]) + >>> y = np.array([-1, 0.2, 0.9, 2.1]) + + By examining the coefficients, we see that the line should have a + gradient of roughly 1 and cut the y-axis at, more or less, -1. + + We can rewrite the line equation as ``y = Ap``, where ``A = [[x 1]]`` + and ``p = [[m], [c]]``. Now use `lstsq` to solve for `p`: + + >>> A = np.vstack([x, np.ones(len(x))]).T + >>> A + array([[ 0., 1.], + [ 1., 1.], + [ 2., 1.], + [ 3., 1.]]) + + >>> m, c = np.linalg.lstsq(A, y)[0] + >>> print m, c + 1.0 -0.95 + + Plot the data along with the fitted line: + + >>> import matplotlib.pyplot as plt + >>> plt.plot(x, y, 'o', label='Original data', markersize=10) + >>> plt.plot(x, m*x + c, 'r', label='Fitted line') + >>> plt.legend() + >>> plt.show() + + """ + + a = numpy.array(a, dtype=numpy.float, copy=False) + b = numpy.array(b, dtype=numpy.float, copy=False) + a_shape = a.shape + b_shape = b.shape + original = b_shape + if len(a_shape) != 2: + raise ValueError("Model matrix must be two dimensional") + if len(b_shape) == 1: + b.shape = b_shape[0], 1 + b_shape = b.shape + + m = a.shape[0] + n = a.shape[1] + + if m != b.shape[0]: + raise ValueError('Incompatible dimensions between A and b matrices') + + fastest = False + if sigma_b is not None: + # experimental uncertainties provided these are the ones to use (if any) + w = numpy.abs(numpy.array(sigma_b, dtype=numpy.float, copy=False)) + w = w + numpy.equal(w, 0) + w.shape = b_shape + elif weight == 0: + # we have an unweighted fit with no uncertainties + # assume all the uncertainties equal to 1 + fastest = True + w = numpy.ones(b.shape, numpy.float) + else: + # "statistical" weight + # we are asked to somehow weight the data but no uncertainties provided + # assume the uncertainties are the square root of the b values ... + w = numpy.sqrt(numpy.abs(b)) + w = w + numpy.equal(w, 0) + + if covariances: + covarianceMatrix = numpy.zeros((b_shape[1], n, n), numpy.float) + + if not weight: + # no weight is applied + # get the SVD decomposition of the A matrix + U, s, V = numpy.linalg.svd(a, full_matrices=False) + + if rcond is None: + s_cutoff = n * numpy.finfo(numpy.float).eps + else: + s_cutoff = rcond * s[0] + s[s < s_cutoff] = numpy.inf + + # and get the parameters + s.shape = -1 + dummy = numpy.dot(V.T, numpy.eye(n)*(1./s)) + parameters = numpy.dot(dummy, numpy.dot(U.T, b)) + parameters.shape = n, b.shape[1] + if uncertainties or covariances: + # get the uncertainties + #(in the no-weight case without experimental uncertainties, + # the uncertainties on the data points are ignored and the + # uncertainty on the fitted parameters are independent of the input data!!!!) + if fastest: + # This is correct for all weights equal to 1 + _covariance = numpy.dot(dummy, dummy.T) + sigmapar = numpy.sqrt(numpy.diag(_covariance)) + sigmapar = numpy.outer(sigmapar, numpy.ones(b_shape[1])) + sigmapar.shape = n, b_shape[1] + if covariances: + covarianceMatrix[:] = _covariance + elif covariances: + # loop in order not to use potentially big matrices + # but calculates the covariance matrices + # It only makes sense if the covariance matrix is requested + sigmapar = numpy.zeros((n, b_shape[1]), numpy.float) + for k in range(b_shape[1]): + pseudoData = numpy.eye(b_shape[0]) * w[:, k] + tmpTerm = numpy.dot(dummy, numpy.dot(U.T, pseudoData)) + _covariance[:, :] = numpy.dot(tmpTerm, tmpTerm.T) + sigmapar[:, k] = numpy.sqrt(numpy.diag(_covariance)) + covarianceMatrix[k] = _covariance + else: + # loop in order not to use potentially big matrices + # but not calculating the covariance matrix + d = numpy.zeros(b.shape, numpy.float) + sigmapar = numpy.zeros((n, b_shape[1])) + for k in range(b_shape[0]): + d[k] = w[k] + sigmapar += (numpy.dot(dummy, numpy.dot(U.T, d))) ** 2 + d[k] = 0.0 + sigmapar[:, :] = numpy.sqrt(sigmapar) + else: + parameters = numpy.zeros((n, b_shape[1]), numpy.float) + sigmapar = numpy.zeros((n, b_shape[1]), numpy.float) + for i in range(b_shape[1]): + tmpWeight = w[:, i:i+1] + tmpData = b[:, i:i+1] / tmpWeight + A = a / tmpWeight + U, s, V = numpy.linalg.svd(A, full_matrices=False) + if rcond is None: + s_cutoff = n * numpy.finfo(numpy.float).eps + else: + s_cutoff = rcond * s[0] + s[s < s_cutoff] = numpy.inf + s.shape = -1 + dummy = numpy.dot(V.T, numpy.eye(n)*(1./s)) + parameters[:, i:i+1] = numpy.dot(dummy, numpy.dot(U.T, tmpData)) + if uncertainties or covariances: + # get the uncertainties + _covariance = numpy.dot(dummy, dummy.T) + sigmapar[:, i] = numpy.sqrt(numpy.diag(_covariance)) + if covariances: + covarianceMatrix[i] = _covariance + + if len(original) == 1: + parameters.shape = -1 + if covariances: + sigmapar.shape = parameters.shape + if len(original) == 1: + covarianceMatrix.shape = parameters.shape[0], parameters.shape[0] + result = [parameters, sigmapar, covarianceMatrix] + elif uncertainties: + sigmapar.shape = parameters.shape + result = [parameters, sigmapar] + else: + result = [parameters] + + if digested_output: + ddict = {} + ddict['parameters'] = result[0] + if len(result) > 1: + ddict['uncertainties'] = result[1] + elif covariances: + ddict['covariances'] = result[2] + return ddict + else: + return result + + +def getModelMatrixFromFunction(model_function, dummy_parameters, xdata, derivative=None): + nPoints = xdata.size + nParameters = len(dummy_parameters) + modelMatrix = numpy.zeros((nPoints, nParameters) , numpy.float) + pwork = dummy_parameters * 1 + for i in range(len(dummy_parameters)): + fitparam = dummy_parameters[i] + if derivative is None: + delta = (pwork[i] + numpy.equal(fitparam, 0.0)) * 0.00001 + pwork[i] = fitparam + delta + f1 = model_function(pwork, xdata) + pwork[i] = fitparam - delta + f2 = model_function(pwork, xdata) + help0 = (f1-f2) / (2.0 * delta) + pwork[i] = fitparam + else: + help0 = derivative(pwork, i, xdata) + help0.shape = -1 + modelMatrix[:, i] = help0 + return modelMatrix + +def modelFunction(p, x): + return p[0] + (p[1] + p[2] * x) * x + +def test1(): + x = numpy.arange(10000.) + x.shape = -1, 1 + y = modelFunction([100., 50., 4.], x) + A = getModelMatrixFromFunction(modelFunction, [0.0, 0.0, 0.0], x) + parameters, uncertainties = lstsq(A, y, uncertainties=True, weight=False) + print("Expected = 100., 50., 4.") + print("Obtained = %f, %f, %f" % (parameters[0], parameters[1], parameters[2])) + +def test2(): + import time + try: + from PyMca import Gefit + GEFIT = True + def f(p, x): + return p[1] * x + p[0] + except: + GEFIT = False + data = "0 0.8214 0.1 1 2.8471 0.3 2 4.852 0.5 3 7.5347 0.7 4 10.2464 0.9 5 10.2707 1.1 6 12.8011 1.3 7 13.7108 1.5 8 17.8501 1.7 9 15.3667 1.9 10 19.3933 2.1" + data = numpy.array([float(x) for x in data.split()]) + data.shape = -1, 3 + + # the model matrix for a straight line + A = numpy.ones((data.shape[0],2), numpy.float) + A[:, 1] = data[:, 0] + print("Unweighted results:") + t0 = time.time() + y = numpy.ones((data.shape[0], 1000), numpy.float) * data[:, 1:2] + sigmay = numpy.ones((data.shape[0], 1000), numpy.float) * data[:, 2:3] + parameters, uncertainties = lstsq(A, y, #sigma_b=sigmay, #sigma_b=numpy.ones(sigmay.shape), + uncertainties=True, weight=False) + print("Elapsed = %f" % (time.time() - t0)) + print("Parameters = %f, %f" % (parameters[0,100], parameters[1, 100])) + print("Uncertainties = %f, %f" % (uncertainties[0,100], uncertainties[1, 100])) + if GEFIT: + t0 = time.time() + for i in range(y.shape[1]): + parameters, chisq, uncertainties = Gefit.LeastSquaresFit(f, [0.0, 0.0], + xdata=data[:,0], + ydata=data[:,1], + sigmadata=data[:,2], + weightflag=0, + linear=1) + print("Elapsed = %f" % (time.time() - t0)) + print("Gefit results:") + print("Parameters = %f, %f" % (parameters[0], parameters[1])) + print("Uncertainties = %f, %f" % (uncertainties[0], uncertainties[1])) + + print("Mathematica results:") + print("Parameters = %f, %f" % (1.57043, 1.78945)) + print("Uncertainties = %f, %f" % (0.68363, 0.11555)) + + print("Weighted results") + t0 = time.time() + #parameters, uncertainties = lstsq(A, data[:, 1], sigma_b=data[:,2], + parameters, uncertainties = lstsq(A, y, sigma_b=numpy.outer(data[:,2], numpy.ones((1000, 1))), + uncertainties=True, weight=True) + print("Elapsed = %f" % (time.time() - t0)) + print("Parameters = %f, %f" % (parameters[0, 100], parameters[1, 100])) + print("Uncertainties = %f, %f" % (uncertainties[0, 100], uncertainties[1, 100])) + if GEFIT: + parameters, chisq, uncertainties = Gefit.LeastSquaresFit(f, [0.0, 0.0], + xdata=data[:,0], + ydata=data[:,1], + sigmadata=data[:,2], + weightflag=1, + linear=1) + print("Gefit results:") + print("Parameters = %f, %f" % (parameters[0], parameters[1])) + print("Uncertainties = %f, %f" % (uncertainties[0], uncertainties[1])) + + print("Mathematica results:") + print("Parameters = %f, %f" % (0.843827, 1.97982)) + print("Uncertainties = %f, %f" % (0.092449, 0.07262)) + + return data + +if __name__ == "__main__": + test1() + test2() diff --git a/PyMca/specfile/src/specfile_py.c b/PyMca/specfile/src/specfile_py.c index 67dc0c1..bbdd9c7 100644 --- a/PyMca/specfile/src/specfile_py.c +++ b/PyMca/specfile/src/specfile_py.c @@ -118,6 +118,9 @@ PERFORMANCE OF THIS SOFTWARE. #ifndef WIN32 #include <Python.h> #endif +/* adding next line may raise errors ... +#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION +*/ #include <numpy/arrayobject.h> #include <SpecFile.h> @@ -678,7 +681,7 @@ scandata_data(PyObject *self,PyObject *args) { dimensions[0] = data_info[1]; dimensions[1] = data_info[0]; - r_array = (PyArrayObject *)PyArray_SimpleNew(2,dimensions,PyArray_DOUBLE); + r_array = (PyArrayObject *)PyArray_SimpleNew(2,dimensions,NPY_DOUBLE); /* * Copy @@ -688,7 +691,7 @@ scandata_data(PyObject *self,PyObject *args) { for (i=0;i<dimensions[0];i++) { for (j=0;j<dimensions[1];j++) { didx = j + i * dimensions[1]; - ((double *)r_array->data)[didx] = data[j][i]; + ((double *)PyArray_DATA(r_array))[didx] = data[j][i]; } } /* memcpy(array->data,data,PyArray_NBYTES(array)); */ @@ -727,9 +730,9 @@ scandata_dataline(PyObject *self,PyObject *args) { if (ret == -1 ) onError("cannot get data for line"); - r_array = (PyArrayObject *)PyArray_SimpleNew(1,&ret,PyArray_DOUBLE); + r_array = (PyArrayObject *)PyArray_SimpleNew(1,&ret,NPY_DOUBLE); - memcpy(r_array->data,data,PyArray_NBYTES(r_array)); + memcpy(PyArray_DATA(r_array),data,PyArray_NBYTES(r_array)); return (PyObject *)r_array; } @@ -765,10 +768,10 @@ scandata_datacol(PyObject *self,PyObject *args) { if (ret == -1 ) onError("cannot get data for column"); - r_array = (PyArrayObject *)PyArray_SimpleNew(1,&ret,PyArray_DOUBLE); + r_array = (PyArrayObject *)PyArray_SimpleNew(1,&ret,NPY_DOUBLE); if (data != (double *) NULL){ - memcpy(r_array->data,data,PyArray_NBYTES(r_array)); + memcpy(PyArray_DATA(r_array),data,PyArray_NBYTES(r_array)); free(data); }else{ /* return an empty array? */ @@ -1149,11 +1152,11 @@ scandata_mca (PyObject *self,PyObject *args) if (ret == -1) onError("cannot get mca for scan"); - r_array = (PyArrayObject *)PyArray_SimpleNew(1,&ret,PyArray_DOUBLE); + r_array = (PyArrayObject *)PyArray_SimpleNew(1,&ret,NPY_DOUBLE); if (mcadata != (double *) NULL){ - memcpy(r_array->data,mcadata,PyArray_NBYTES(r_array)); + memcpy(PyArray_DATA(r_array),mcadata,PyArray_NBYTES(r_array)); free(mcadata); }else{ printf("I should give back an empty array\n"); @@ -1256,13 +1259,13 @@ scandata_col(PyObject *self, Py_ssize_t index) { if (ret == -1 ) onError("cannot get data for column"); - r_array = (PyArrayObject *)PyArray_SimpleNew(1,&ret,PyArray_DOUBLE); + r_array = (PyArrayObject *)PyArray_SimpleNew(1,&ret,NPY_DOUBLE); if ( r_array == NULL ) onError("cannot get memory for array data"); if (data != (double *) NULL){ - memcpy(r_array->data,data,PyArray_NBYTES(r_array)); + memcpy(PyArray_DATA(r_array),data,PyArray_NBYTES(r_array)); free(data); }else{ /* return an empty array? */ diff --git a/PyMca/specfile/src/specfile_py3.c b/PyMca/specfile/src/specfile_py3.c index ad263a1..268b0e4 100644 --- a/PyMca/specfile/src/specfile_py3.c +++ b/PyMca/specfile/src/specfile_py3.c @@ -16,6 +16,9 @@ # #############################################################################*/ #include <Python.h> +/* adding next line may raise errors ... +#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION +*/ #include <numpy/arrayobject.h> #include <SpecFile.h> @@ -342,13 +345,13 @@ specfile_open(PyObject *self, PyObject *args) /* on x = specfile.Specfile(name) return NULL; } { - bytesObject = PyUnicode_AsMBCSString(input);
- if (!bytesObject){
- onError("Cannot generate String from object name attribute")
- }
- filename = PyBytes_AsString(bytesObject);
- }
-#else
+ bytesObject = PyUnicode_AsMBCSString(input); + if (!bytesObject){ + onError("Cannot generate String from object name attribute") + } + filename = PyBytes_AsString(bytesObject); + } +#else if (!PyArg_ParseTuple(args, "s", &filename)) { return NULL; @@ -522,13 +525,13 @@ scandata_col(PyObject *self, Py_ssize_t index) { if (ret == -1 ) onError("cannot get data for column"); - r_array = (PyArrayObject *)PyArray_SimpleNew(1,&ret,PyArray_DOUBLE); + r_array = (PyArrayObject *)PyArray_SimpleNew(1,&ret,NPY_DOUBLE); if ( r_array == NULL ) onError("cannot get memory for array data"); if (data != (double *) NULL){ - memcpy(r_array->data,data,PyArray_NBYTES(r_array)); + memcpy(PyArray_DATA(r_array), data, PyArray_NBYTES(r_array)); free(data); }else{ /* return an empty array? */ @@ -582,7 +585,7 @@ scandata_data(PyObject *self,PyObject *args) { dimensions[0] = data_info[1]; dimensions[1] = data_info[0]; - r_array = (PyArrayObject *)PyArray_SimpleNew(2,dimensions,PyArray_DOUBLE); + r_array = (PyArrayObject *)PyArray_SimpleNew(2,dimensions,NPY_DOUBLE); /* * Copy @@ -592,7 +595,7 @@ scandata_data(PyObject *self,PyObject *args) { for (i=0;i<dimensions[0];i++) { for (j=0;j<dimensions[1];j++) { didx = j + i * dimensions[1]; - ((double *)r_array->data)[didx] = data[j][i]; + ((double *)PyArray_DATA(r_array))[didx] = data[j][i]; } } /* memcpy(array->data,data,PyArray_NBYTES(array)); */ @@ -631,9 +634,9 @@ scandata_dataline(PyObject *self,PyObject *args) { if (ret == -1 ) onError("cannot get data for line"); - r_array = (PyArrayObject *)PyArray_SimpleNew(1,&ret,PyArray_DOUBLE); + r_array = (PyArrayObject *)PyArray_SimpleNew(1,&ret,NPY_DOUBLE); - memcpy(r_array->data,data,PyArray_NBYTES(r_array)); + memcpy(PyArray_DATA(r_array),data,PyArray_NBYTES(r_array)); return (PyObject *)r_array; } @@ -669,10 +672,10 @@ scandata_datacol(PyObject *self,PyObject *args) { if (ret == -1 ) onError("cannot get data for column"); - r_array = (PyArrayObject *)PyArray_SimpleNew(1,&ret,PyArray_DOUBLE); + r_array = (PyArrayObject *)PyArray_SimpleNew(1,&ret,NPY_DOUBLE); if (data != (double *) NULL){ - memcpy(r_array->data,data,PyArray_NBYTES(r_array)); + memcpy(PyArray_DATA(r_array),data,PyArray_NBYTES(r_array)); free(data); }else{ /* return an empty array? */ @@ -1053,11 +1056,11 @@ scandata_mca (PyObject *self,PyObject *args) if (ret == -1) onError("cannot get mca for scan"); - r_array = (PyArrayObject *)PyArray_SimpleNew(1,&ret,PyArray_DOUBLE); + r_array = (PyArrayObject *)PyArray_SimpleNew(1,&ret,NPY_DOUBLE); if (mcadata != (double *) NULL){ - memcpy(r_array->data,mcadata,PyArray_NBYTES(r_array)); + memcpy(PyArray_DATA(r_array),mcadata,PyArray_NBYTES(r_array)); free(mcadata); }else{ printf("I should give back an empty array\n"); diff --git a/PyMca/specfit/SpecfitFuns.c b/PyMca/specfit/SpecfitFuns.c index 12cfe4d..e688b7b 100644 --- a/PyMca/specfit/SpecfitFuns.c +++ b/PyMca/specfit/SpecfitFuns.c @@ -25,9 +25,16 @@ # is a problem for you. #############################################################################*/ #include <Python.h> +/* adding next line may raise errors +#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION +*/ #include <./numpy/arrayobject.h> #include <math.h> +#ifndef NPY_ARRAY_ENSURECOPY +#define NPY_ARRAY_ENSURECOPY NPY_ENSURECOPY +#endif + struct module_state { PyObject *error; }; @@ -58,6 +65,7 @@ static struct module_state _state; void lls(double *data, int size); void lls_inv(double *data, int size); void snip1d(double *data, int size, int width); +void snip1d_multiple(double *data, int n_channels, int snip_width, int n_spectra); void snip2d(double *data, int nrows, int ncolumns, int width); void snip3d(double *data, int nx, int ny, int nz, int width); void lsdf(double *data, int size, int fwhm, double f, double A, double M, double ratio); @@ -76,42 +84,57 @@ SpecfitFuns_snip1d(PyObject *self, PyObject *args) int smooth_iterations = 0; int llsflag = 0; PyArrayObject *ret; - int i, size, width; + double *doublePointer; + int i, n, n_channels, n_spectra, width; if (!PyArg_ParseTuple(args, "Od|ii", &input, &width0, &smooth_iterations, &llsflag)) return NULL; ret = (PyArrayObject *) - PyArray_FROMANY(input, PyArray_DOUBLE, 1, 1, NPY_ENSURECOPY); + PyArray_FROMANY(input, NPY_DOUBLE, 1, 2, NPY_ARRAY_ENSURECOPY); if (ret == NULL){ printf("Cannot create 1D array from input\n"); return NULL; } - size = 1; - for (i=0; i<ret->nd; i++) + if(PyArray_NDIM(ret) == 1) + { + n_spectra = 1; + n_channels = (int) (PyArray_DIMS(ret)[0]); + } + else { - size = (int) (size * ret->dimensions[i]); + n_spectra = (int) (PyArray_DIMS(ret)[0]); + n_channels = (int) (PyArray_DIMS(ret)[1]); } width = (int )width0; - for (i=0; i<smooth_iterations; i++) + for (n = 0; n < n_spectra; n++) { - smooth1d((double *) ret->data, size); + for (i=0; i<smooth_iterations; i++) + { + doublePointer = (double *) PyArray_DATA(ret); + smooth1d(&(doublePointer[n*n_channels]), n_channels); + } + if (llsflag) + { + doublePointer = (double *) PyArray_DATA(ret); + lls(&(doublePointer[n*n_channels]), n_channels); + } } - if (llsflag) - { - lls((double *) ret->data, size); - } - snip1d((double *) ret->data, size, width); + snip1d_multiple((double *) PyArray_DATA(ret), n_channels, width, n_spectra); - if (llsflag) + for (n = 0; n < n_spectra; n++) { - lls_inv((double *) ret->data, size); + if (llsflag) + { + doublePointer = (double *) PyArray_DATA(ret); + lls_inv(&(doublePointer[n*n_channels]), n_channels); + } } return PyArray_Return(ret); @@ -131,7 +154,7 @@ SpecfitFuns_snip2d(PyObject *self, PyObject *args) return NULL; ret = (PyArrayObject *) - PyArray_FROMANY(input, PyArray_DOUBLE, 2, 2, NPY_ENSURECOPY); + PyArray_FROMANY(input, NPY_DOUBLE, 2, 2, NPY_ARRAY_ENSURECOPY); if (ret == NULL){ printf("Cannot create 2D array from input\n"); @@ -139,30 +162,30 @@ SpecfitFuns_snip2d(PyObject *self, PyObject *args) } size = 1; - for (i=0; i<ret->nd; i++) + for (i=0; i<PyArray_NDIM(ret); i++) { - size = (int) (size * ret->dimensions[i]); + size = (int) (size * PyArray_DIMS(ret)[i]); } - nrows = (int) ret->dimensions[0]; - ncolumns = (int) ret->dimensions[1]; + nrows = (int) PyArray_DIMS(ret)[0]; + ncolumns = (int) PyArray_DIMS(ret)[1]; width = (int )width0; for (i=0; i<smooth_iterations; i++) { - smooth2d((double *) ret->data, nrows, ncolumns); + smooth2d((double *) PyArray_DATA(ret), nrows, ncolumns); } if (llsflag) { - lls((double *) ret->data, size); + lls((double *) PyArray_DATA(ret), size); } - snip2d((double *) ret->data, nrows, ncolumns, width); + snip2d((double *) PyArray_DATA(ret), nrows, ncolumns, width); if (llsflag) { - lls_inv((double *) ret->data, size); + lls_inv((double *) PyArray_DATA(ret), size); } return PyArray_Return(ret); @@ -182,7 +205,7 @@ SpecfitFuns_snip3d(PyObject *self, PyObject *args) return NULL; ret = (PyArrayObject *) - PyArray_FROMANY(input, PyArray_DOUBLE, 3, 3, NPY_ENSURECOPY); + PyArray_FROMANY(input, NPY_DOUBLE, 3, 3, NPY_ARRAY_ENSURECOPY); if (ret == NULL){ printf("Cannot create 3D array from input\n"); @@ -190,31 +213,31 @@ SpecfitFuns_snip3d(PyObject *self, PyObject *args) } size = 1; - for (i=0; i<ret->nd; i++) + for (i=0; i<PyArray_NDIM(ret); i++) { - size = (int) (size * ret->dimensions[i]); + size = (int) (size * PyArray_DIMS(ret)[i]); } - nx = (int) ret->dimensions[0]; - ny = (int) ret->dimensions[1]; - nz = (int) ret->dimensions[2]; + nx = (int) PyArray_DIMS(ret)[0]; + ny = (int) PyArray_DIMS(ret)[1]; + nz = (int) PyArray_DIMS(ret)[2]; width = (int )width0; for (i=0; i<smooth_iterations; i++) { - smooth3d((double *) ret->data, nx, ny, nz); + smooth3d((double *) PyArray_DATA(ret), nx, ny, nz); } if (llsflag) { - lls((double *) ret->data, size); + lls((double *) PyArray_DATA(ret), size); } - snip3d((double *) ret->data, nx, ny, nz, width); + snip3d((double *) PyArray_DATA(ret), nx, ny, nz, width); if (llsflag) { - lls_inv((double *) ret->data, size); + lls_inv((double *) PyArray_DATA(ret), size); } return PyArray_Return(ret); @@ -238,20 +261,20 @@ SpecfitFuns_subacold(PyObject *self, PyObject *args) if (!PyArg_ParseTuple(args, "O|dd", &input, &c, &niter0)) return NULL; iarray = (PyArrayObject *) - PyArray_CopyFromObject(input, PyArray_DOUBLE,1,1); + PyArray_CopyFromObject(input, NPY_DOUBLE,1,1); if (iarray == NULL) return NULL; niter = (int ) niter0; - n = iarray->dimensions[0]; - dimensions[0] = iarray->dimensions[0]; - ret = (PyArrayObject *) PyArray_SimpleNew(1, dimensions, PyArray_DOUBLE); + n = PyArray_DIMS(iarray)[0]; + dimensions[0] = PyArray_DIMS(iarray)[0]; + ret = (PyArrayObject *) PyArray_SimpleNew(1, dimensions, NPY_DOUBLE); if (ret == NULL){ Py_DECREF(iarray); return NULL; } /* Do the job */ - data = (double *) iarray->data; + data = (double *) PyArray_DATA(iarray); for (i=0;i<niter;i++){ t_old = *(data); for (j=1;j<n-1;j++) { @@ -293,21 +316,21 @@ SpecfitFuns_subac(PyObject *self, PyObject *args) if (!PyArg_ParseTuple(args, "O|dddO", &input, &c, &niter0,&deltai0, &anchors0)) return NULL; iarray = (PyArrayObject *) - PyArray_CopyFromObject(input, PyArray_DOUBLE,1,1); + PyArray_CopyFromObject(input, NPY_DOUBLE,1,1); if (iarray == NULL) return NULL; deltai= (int ) deltai0; if (deltai <=0) deltai = 1; niter = (int ) niter0; - n = (int) iarray->dimensions[0]; - dimensions[0] = iarray->dimensions[0]; - ret = (PyArrayObject *) PyArray_SimpleNew(1, dimensions, PyArray_DOUBLE); + n = (int) PyArray_DIMS(iarray)[0]; + dimensions[0] = PyArray_DIMS(iarray)[0]; + ret = (PyArrayObject *) PyArray_SimpleNew(1, dimensions, NPY_DOUBLE); if (ret == NULL){ Py_DECREF(iarray); return NULL; } PyArray_FILLWBYTE(ret, 0); - memcpy(ret->data, iarray->data, iarray->dimensions[0] * sizeof(double)); + memcpy(PyArray_DATA(ret), PyArray_DATA(iarray), PyArray_DIMS(iarray)[0] * sizeof(double)); if (n < (2*deltai+1)){ /*ret = (PyArrayObject *) PyArray_Copy(array);*/ @@ -315,21 +338,21 @@ SpecfitFuns_subac(PyObject *self, PyObject *args) return PyArray_Return(ret); } /* do the job */ - data = (double *) iarray->data; - retdata = (double *) ret->data; + data = (double *) PyArray_DATA(iarray); + retdata = (double *) PyArray_DATA(ret); if (anchors0 != NULL) { if (PySequence_Check(anchors0)){ anchors = (PyArrayObject *) - PyArray_ContiguousFromObject(anchors0, PyArray_INT, 1, 1); + PyArray_ContiguousFromObject(anchors0, NPY_INT, 1, 1); if (anchors == NULL) { Py_DECREF(iarray); Py_DECREF(ret); return NULL; } - anchordata = (int *) anchors->data; + anchordata = (int *) PyArray_DATA(anchors); nanchors = (int) PySequence_Size(anchors0); for (i=0;i<niter;i++){ for (j=deltai;j<n-deltai;j++) { @@ -352,7 +375,7 @@ SpecfitFuns_subac(PyObject *self, PyObject *args) if (*(retdata+j) > (t_mean * c)) *(retdata+j) = t_mean; } - memcpy(iarray->data, ret->data, iarray->dimensions[0] * sizeof(double)); + memcpy(PyArray_DATA(iarray), PyArray_DATA(ret), PyArray_DIMS(iarray)[0] * sizeof(double)); } Py_DECREF(anchors); notdone = 0; @@ -366,7 +389,7 @@ SpecfitFuns_subac(PyObject *self, PyObject *args) if (*(retdata+j) > (t_mean * c)) *(retdata+j) = t_mean; } - memcpy(iarray->data, ret->data, iarray->dimensions[0] * sizeof(double)); + memcpy(PyArray_DATA(iarray), PyArray_DATA(ret), PyArray_DIMS(iarray)[0] * sizeof(double)); } } Py_DECREF(iarray); @@ -394,20 +417,20 @@ SpecfitFuns_subacfast(PyObject *self, PyObject *args) if (!PyArg_ParseTuple(args, "O|dddO", &input, &c, &niter0,&deltai0, &anchors0)) return NULL; iarray = (PyArrayObject *) - PyArray_CopyFromObject(input, PyArray_DOUBLE,1,1); + PyArray_CopyFromObject(input, NPY_DOUBLE,1,1); if (iarray == NULL) return NULL; deltai= (int ) deltai0; if (deltai <=0) deltai = 1; niter = (int ) niter0; - n = iarray->dimensions[0]; - dimensions[0] = iarray->dimensions[0]; - ret = (PyArrayObject *) PyArray_SimpleNew(1, dimensions, PyArray_DOUBLE); + n = PyArray_DIMS(iarray)[0]; + dimensions[0] = PyArray_DIMS(iarray)[0]; + ret = (PyArrayObject *) PyArray_SimpleNew(1, dimensions, NPY_DOUBLE); if (ret == NULL){ Py_DECREF(iarray); return NULL; } - memcpy(ret->data, iarray->data, iarray->dimensions[0] * sizeof(double)); + memcpy(PyArray_DATA(ret), PyArray_DATA(iarray), PyArray_DIMS(iarray)[0] * sizeof(double)); if (n < (2*deltai+1)){ /*ret = (PyArrayObject *) PyArray_Copy(array);*/ @@ -415,19 +438,19 @@ SpecfitFuns_subacfast(PyObject *self, PyObject *args) return PyArray_Return(ret); } /* do the job */ - retdata = (double *) ret->data; + retdata = (double *) PyArray_DATA(ret); if (PySequence_Check(anchors0)){ anchors = (PyArrayObject *) - PyArray_ContiguousFromObject(anchors0, PyArray_INT, 1, 1); + PyArray_ContiguousFromObject(anchors0, NPY_INT, 1, 1); if (anchors == NULL) { Py_DECREF(iarray); Py_DECREF(ret); return NULL; } - anchordata = (int *) anchors->data; + anchordata = (int *) PyArray_DATA(anchors); nanchors = (int) PySequence_Size(anchors0); - memcpy(iarray->data, ret->data, iarray->dimensions[0] * sizeof(double)); + memcpy(PyArray_DATA(iarray), PyArray_DATA(ret), PyArray_DIMS(iarray)[0] * sizeof(double)); for (i=0;i<niter;i++){ for (j=deltai;j<n-deltai;j++) { notdoit = 0; @@ -454,7 +477,7 @@ SpecfitFuns_subacfast(PyObject *self, PyObject *args) } else { - memcpy(iarray->data, ret->data, iarray->dimensions[0] * sizeof(double)); + memcpy(PyArray_DATA(iarray), PyArray_DATA(ret), PyArray_DIMS(iarray)[0] * sizeof(double)); for (i=0;i<niter;i++){ for (j=deltai;j<n-deltai;j++) { t_mean = 0.5 * (*(retdata+j-deltai) + *(retdata+j+deltai)); @@ -510,40 +533,40 @@ SpecfitFuns_gauss(PyObject *self, PyObject *args) } param = (PyArrayObject *) - PyArray_ContiguousFromObject(input1, PyArray_DOUBLE,0,0); + PyArray_ContiguousFromObject(input1, NPY_DOUBLE,0,0); if (param == NULL) return NULL; x = (PyArrayObject *) - PyArray_CopyFromObject(input2, PyArray_DOUBLE,0,0); + PyArray_CopyFromObject(input2, NPY_DOUBLE,0,0); if (x == NULL){ Py_DECREF(param); return NULL; } - nd_param = param->nd; - nd_x = x->nd; + nd_param = PyArray_NDIM(param); + nd_x = PyArray_NDIM(x); if(debug !=0) { printf("nd_param = %d nd_x = %d\n",nd_param,nd_x); } if (nd_param == 1) { - dim_param [0] = param->dimensions[0]; + dim_param [0] = PyArray_DIMS(param)[0]; dim_param [1] = 0; }else{ - dim_param [0] = param->dimensions[0]; - dim_param [1] = param->dimensions[1]; + dim_param [0] = PyArray_DIMS(param)[0]; + dim_param [1] = PyArray_DIMS(param)[1]; } if (nd_x == 1) { - dim_x [0] = x->dimensions[0]; + dim_x [0] = PyArray_DIMS(x)[0]; dim_x [1] = 0; }else{ if (nd_x == 0) { dim_x [0] = 0; dim_x [1] = 0; }else{ - dim_x [0] = x->dimensions[0]; - dim_x [1] = x->dimensions[1]; + dim_x [0] = PyArray_DIMS(x)[0]; + dim_x [1] = PyArray_DIMS(x)[1]; } } @@ -566,7 +589,7 @@ SpecfitFuns_gauss(PyObject *self, PyObject *args) } /* Create the output array */ - ret = (PyArrayObject *) PyArray_SimpleNew(nd_x, dim_x, PyArray_DOUBLE); + ret = (PyArrayObject *) PyArray_SimpleNew(nd_x, dim_x, NPY_DOUBLE); if (ret == NULL){ Py_DECREF(param); Py_DECREF(x); @@ -576,12 +599,12 @@ SpecfitFuns_gauss(PyObject *self, PyObject *args) log2 = 0.69314718055994529; /* the pointer to the starting position of par data */ - px = (double *) x->data; - pret = (double *) ret->data; + px = (double *) PyArray_DATA(x); + pret = (double *) PyArray_DATA(ret); if (nd_x == 0){ *pret = 0; - pgauss = (gaussian *) param->data; + pgauss = (gaussian *) PyArray_DATA(param); for (i=0;i<(npars/3);i++){ dhelp = pgauss[i].fwhm/(2.0*sqrt(2.0*log2)); dhelp = (*px - pgauss[i].centroid)/dhelp; @@ -596,7 +619,7 @@ SpecfitFuns_gauss(PyObject *self, PyObject *args) } for (j=0;j<k;j++){ *pret = 0; - pgauss = (gaussian *) param->data; + pgauss = (gaussian *) PyArray_DATA(param); for (i=0;i<(npars/3);i++){ dhelp = pgauss[i].fwhm/(2.0*sqrt(2.0*log2)); dhelp = (*px - pgauss[i].centroid)/dhelp; @@ -639,40 +662,40 @@ SpecfitFuns_agauss(PyObject *self, PyObject *args) return NULL; param = (PyArrayObject *) - PyArray_CopyFromObject(input1, PyArray_DOUBLE,0,0); + PyArray_CopyFromObject(input1, NPY_DOUBLE,0,0); if (param == NULL) return NULL; x = (PyArrayObject *) - PyArray_CopyFromObject(input2, PyArray_DOUBLE,0,0); + PyArray_CopyFromObject(input2, NPY_DOUBLE,0,0); if (x == NULL){ Py_DECREF(param); return NULL; } - nd_param = param->nd; - nd_x = x->nd; + nd_param = PyArray_NDIM(param); + nd_x = PyArray_NDIM(x); if(debug !=0) { printf("nd_param = %d nd_x = %d\n",nd_param,nd_x); } if (nd_param == 1) { - dim_param [0] = param->dimensions[0]; + dim_param [0] = PyArray_DIMS(param)[0]; dim_param [1] = 0; }else{ - dim_param [0] = param->dimensions[0]; - dim_param [1] = param->dimensions[1]; + dim_param [0] = PyArray_DIMS(param)[0]; + dim_param [1] = PyArray_DIMS(param)[1]; } if (nd_x == 1) { - dim_x [0] = x->dimensions[0]; + dim_x [0] = PyArray_DIMS(x)[0]; dim_x [1] = 0; }else{ if (nd_x == 0) { dim_x [0] = 0; dim_x [1] = 0; }else{ - dim_x [0] = x->dimensions[0]; - dim_x [1] = x->dimensions[1]; + dim_x [0] = PyArray_DIMS(x)[0]; + dim_x [1] = PyArray_DIMS(x)[1]; } } @@ -695,7 +718,7 @@ SpecfitFuns_agauss(PyObject *self, PyObject *args) } /* Create the output array */ - ret = (PyArrayObject *) PyArray_SimpleNew(nd_x, dim_x, PyArray_DOUBLE); + ret = (PyArrayObject *) PyArray_SimpleNew(nd_x, dim_x, NPY_DOUBLE); if (ret == NULL){ Py_DECREF(param); Py_DECREF(x); @@ -708,12 +731,12 @@ SpecfitFuns_agauss(PyObject *self, PyObject *args) tosigma=1.0/(2.0*sqrt(2.0*log2)); /* the pointer to the starting position of par data */ - px = (double *) x->data; - pret = (double *) ret->data; + px = (double *) PyArray_DATA(x); + pret = (double *) PyArray_DATA(ret); if (nd_x == 0){ *pret = 0; - pgauss = (gaussian *) param->data; + pgauss = (gaussian *) PyArray_DATA(param); for (i=0;i<(npars/3);i++){ sigma = pgauss[i].fwhm*tosigma; dhelp = (*px - pgauss[i].centroid)/sigma; @@ -726,12 +749,12 @@ SpecfitFuns_agauss(PyObject *self, PyObject *args) for (j=0;j<nd_x;j++){ k = (int) (dim_x [j] * k); } - pgauss = (gaussian *) param->data; + pgauss = (gaussian *) PyArray_DATA(param); for (i=0;i<(npars/3);i++){ sigma = pgauss[i].fwhm*tosigma; dhelp0 = pgauss[i].area/(sigma*sqrt2PI); - px = (double *) x->data; - pret = (double *) ret->data; + px = (double *) PyArray_DATA(x); + pret = (double *) PyArray_DATA(ret); for (j=0;j<k;j++){ if (i==0) *pret = 0.0; @@ -782,40 +805,40 @@ SpecfitFuns_fastagauss(PyObject *self, PyObject *args) return NULL; param = (PyArrayObject *) - PyArray_CopyFromObject(input1, PyArray_DOUBLE,0,0); + PyArray_CopyFromObject(input1, NPY_DOUBLE,0,0); if (param == NULL) return NULL; x = (PyArrayObject *) - PyArray_CopyFromObject(input2, PyArray_DOUBLE,0,0); + PyArray_CopyFromObject(input2, NPY_DOUBLE,0,0); if (x == NULL){ Py_DECREF(param); return NULL; } - nd_param = param->nd; - nd_x = x->nd; + nd_param = PyArray_NDIM(param); + nd_x = PyArray_NDIM(x); if(debug !=0) { printf("nd_param = %d nd_x = %d\n",nd_param,nd_x); } if (nd_param == 1) { - dim_param [0] = param->dimensions[0]; + dim_param [0] = PyArray_DIMS(param)[0]; dim_param [1] = 0; }else{ - dim_param [0] = param->dimensions[0]; - dim_param [1] = param->dimensions[1]; + dim_param [0] = PyArray_DIMS(param)[0]; + dim_param [1] = PyArray_DIMS(param)[1]; } if (nd_x == 1) { - dim_x [0] = x->dimensions[0]; + dim_x [0] = PyArray_DIMS(x)[0]; dim_x [1] = 0; }else{ if (nd_x == 0) { dim_x [0] = 0; dim_x [1] = 0; }else{ - dim_x [0] = x->dimensions[0]; - dim_x [1] = x->dimensions[1]; + dim_x [0] = PyArray_DIMS(x)[0]; + dim_x [1] = PyArray_DIMS(x)[1]; } } @@ -838,7 +861,7 @@ SpecfitFuns_fastagauss(PyObject *self, PyObject *args) } /* Create the output array */ - ret = (PyArrayObject *) PyArray_SimpleNew(nd_x, dim_x, PyArray_DOUBLE); + ret = (PyArrayObject *) PyArray_SimpleNew(nd_x, dim_x, NPY_DOUBLE); if (ret == NULL){ Py_DECREF(param); Py_DECREF(x); @@ -851,12 +874,12 @@ SpecfitFuns_fastagauss(PyObject *self, PyObject *args) tosigma=1.0/(2.0*sqrt(2.0*log2)); /* the pointer to the starting position of par data */ - px = (double *) x->data; - pret = (double *) ret->data; + px = (double *) PyArray_DATA(x); + pret = (double *) PyArray_DATA(ret); if (nd_x == 0){ *pret = 0; - pgauss = (gaussian *) param->data; + pgauss = (gaussian *) PyArray_DATA(param); for (i=0;i<(npars/3);i++){ sigma = pgauss[i].fwhm*tosigma; dhelp = (*px - pgauss[i].centroid)/sigma; @@ -869,12 +892,12 @@ SpecfitFuns_fastagauss(PyObject *self, PyObject *args) for (j=0;j<nd_x;j++){ k = (int) (dim_x [j] * k); } - pgauss = (gaussian *) param->data; + pgauss = (gaussian *) PyArray_DATA(param); for (i=0;i<(npars/3);i++){ sigma = pgauss[i].fwhm*tosigma; dhelp0 = pgauss[i].area/(sigma*sqrt2PI); - px = (double *) x->data; - pret = (double *) ret->data; + px = (double *) PyArray_DATA(x); + pret = (double *) PyArray_DATA(ret); for (j=0;j<k;j++){ if (i==0) *pret = 0.0; @@ -935,40 +958,40 @@ SpecfitFuns_splitgauss(PyObject *self, PyObject *args) } param = (PyArrayObject *) - PyArray_ContiguousFromObject(input1, PyArray_DOUBLE,0,0); + PyArray_ContiguousFromObject(input1, NPY_DOUBLE,0,0); if (param == NULL) return NULL; x = (PyArrayObject *) - PyArray_CopyFromObject(input2, PyArray_DOUBLE,0,0); + PyArray_CopyFromObject(input2, NPY_DOUBLE,0,0); if (x == NULL){ Py_DECREF(param); return NULL; } - nd_param = param->nd; - nd_x = x->nd; + nd_param = PyArray_NDIM(param); + nd_x = PyArray_NDIM(x); if(debug !=0) { printf("nd_param = %d nd_x = %d\n",nd_param,nd_x); } if (nd_param == 1) { - dim_param [0] = param->dimensions[0]; + dim_param [0] = PyArray_DIMS(param)[0]; dim_param [1] = 0; }else{ - dim_param [0] = param->dimensions[0]; - dim_param [1] = param->dimensions[1]; + dim_param [0] = PyArray_DIMS(param)[0]; + dim_param [1] = PyArray_DIMS(param)[1]; } if (nd_x == 1) { - dim_x [0] = x->dimensions[0]; + dim_x [0] = PyArray_DIMS(x)[0]; dim_x [1] = 0; }else{ if (nd_x == 0) { dim_x [0] = 0; dim_x [1] = 0; }else{ - dim_x [0] = x->dimensions[0]; - dim_x [1] = x->dimensions[1]; + dim_x [0] = PyArray_DIMS(x)[0]; + dim_x [1] = PyArray_DIMS(x)[1]; } } @@ -991,7 +1014,7 @@ SpecfitFuns_splitgauss(PyObject *self, PyObject *args) } /* Create the output array */ - ret = (PyArrayObject *) PyArray_SimpleNew(nd_x, dim_x, PyArray_DOUBLE); + ret = (PyArrayObject *) PyArray_SimpleNew(nd_x, dim_x, NPY_DOUBLE); if (ret == NULL){ Py_DECREF(param); Py_DECREF(x); @@ -1001,24 +1024,24 @@ SpecfitFuns_splitgauss(PyObject *self, PyObject *args) log2 = 0.69314718055994529; /* the pointer to the starting position of par data */ - px = (double *) x->data; - pret = (double *) ret->data; + px = (double *) PyArray_DATA(x); + pret = (double *) PyArray_DATA(ret); if (nd_x == 0){ *pret = 0; - pgauss = (gaussian *) param->data; + pgauss = (gaussian *) PyArray_DATA(param); for (i=0;i<(npars/4);i++){ - dhelp = (*px - pgauss[i].centroid) * (2.0*sqrt(2.0*log2)); - if (dhelp > 0) - { - dhelp = dhelp/pgauss[i].fwhm2; - }else{ - dhelp = dhelp/pgauss[i].fwhm1; - } + dhelp = (*px - pgauss[i].centroid) * (2.0*sqrt(2.0*log2)); + if (dhelp > 0) + { + dhelp = dhelp/pgauss[i].fwhm2; + }else{ + dhelp = dhelp/pgauss[i].fwhm1; + } if (dhelp <= 20) { *pret += pgauss[i].height * exp (-0.5 * dhelp * dhelp); } - } + } }else{ k = 1; for (j=0;j<nd_x;j++){ @@ -1026,17 +1049,17 @@ SpecfitFuns_splitgauss(PyObject *self, PyObject *args) } for (j=0;j<k;j++){ *pret = 0; - pgauss = (gaussian *) param->data; + pgauss = (gaussian *) PyArray_DATA(param); for (i=0;i<(npars/4);i++){ - dhelp = (*px - pgauss[i].centroid) * (2.0*sqrt(2.0*log2)); - if (dhelp > 0) - { - dhelp = dhelp /pgauss[i].fwhm2; - }else{ - dhelp = dhelp /pgauss[i].fwhm1; - } + dhelp = (*px - pgauss[i].centroid) * (2.0*sqrt(2.0*log2)); + if (dhelp > 0) + { + dhelp = dhelp /pgauss[i].fwhm2; + }else{ + dhelp = dhelp /pgauss[i].fwhm1; + } if (dhelp <= 20) { - *pret += pgauss[i].height * exp (-0.5 * dhelp * dhelp); + *pret += pgauss[i].height * exp (-0.5 * dhelp * dhelp); } } pret++; @@ -1075,40 +1098,40 @@ SpecfitFuns_apvoigt(PyObject *self, PyObject *args) return NULL; param = (PyArrayObject *) - PyArray_CopyFromObject(input1, PyArray_DOUBLE,0,0); + PyArray_CopyFromObject(input1, NPY_DOUBLE,0,0); if (param == NULL) return NULL; x = (PyArrayObject *) - PyArray_CopyFromObject(input2, PyArray_DOUBLE,0,0); + PyArray_CopyFromObject(input2, NPY_DOUBLE,0,0); if (x == NULL){ Py_DECREF(param); return NULL; } - nd_param = param->nd; - nd_x = x->nd; + nd_param = PyArray_NDIM(param); + nd_x = PyArray_NDIM(x); if(debug !=0) { printf("nd_param = %d nd_x = %d\n",nd_param,nd_x); } if (nd_param == 1) { - dim_param [0] = param->dimensions[0]; + dim_param [0] = PyArray_DIMS(param)[0]; dim_param [1] = 0; }else{ - dim_param [0] = param->dimensions[0]; - dim_param [1] = param->dimensions[1]; + dim_param [0] = PyArray_DIMS(param)[0]; + dim_param [1] = PyArray_DIMS(param)[1]; } if (nd_x == 1) { - dim_x [0] = x->dimensions[0]; + dim_x [0] = PyArray_DIMS(x)[0]; dim_x [1] = 0; }else{ if (nd_x == 0) { dim_x [0] = 0; dim_x [1] = 0; }else{ - dim_x [0] = x->dimensions[0]; - dim_x [1] = x->dimensions[1]; + dim_x [0] = PyArray_DIMS(x)[0]; + dim_x [1] = PyArray_DIMS(x)[1]; } } @@ -1131,7 +1154,7 @@ SpecfitFuns_apvoigt(PyObject *self, PyObject *args) } /* Create the output array */ - ret = (PyArrayObject *) PyArray_SimpleNew(nd_x, dim_x, PyArray_DOUBLE); + ret = (PyArrayObject *) PyArray_SimpleNew(nd_x, dim_x, NPY_DOUBLE); if (ret == NULL){ Py_DECREF(param); Py_DECREF(x); @@ -1140,12 +1163,12 @@ SpecfitFuns_apvoigt(PyObject *self, PyObject *args) PyArray_FILLWBYTE(ret, 0); /* the pointer to the starting position of par data */ - px = (double *) x->data; - pret = (double *) ret->data; + px = (double *) PyArray_DATA(x); + pret = (double *) PyArray_DATA(ret); if (nd_x == 0){ *pret = 0; - ppvoigt = (pvoigtian *) param->data; + ppvoigt = (pvoigtian *) PyArray_DATA(param); for (i=0;i<(npars/4);i++){ dhelp = (*px - ppvoigt[i].centroid) / (0.5 * ppvoigt[i].fwhm); dhelp = 1.0 + (dhelp * dhelp); @@ -1159,7 +1182,7 @@ SpecfitFuns_apvoigt(PyObject *self, PyObject *args) } for (j=0;j<k;j++){ *pret = 0; - ppvoigt = (pvoigtian *) param->data; + ppvoigt = (pvoigtian *) PyArray_DATA(param); for (i=0;i<(npars/4);i++){ dhelp = (*px - ppvoigt[i].centroid) / (0.5 * ppvoigt[i].fwhm); dhelp = 1.0 + (dhelp * dhelp); @@ -1178,11 +1201,11 @@ SpecfitFuns_apvoigt(PyObject *self, PyObject *args) tosigma=1.0/(2.0*sqrt(2.0*log2)); /* the pointer to the starting position of par data */ - px = (double *) x->data; - pret = (double *) ret->data; + px = (double *) PyArray_DATA(x); + pret = (double *) PyArray_DATA(ret); if (nd_x == 0){ - ppvoigt = (pvoigtian *) param->data; + ppvoigt = (pvoigtian *) PyArray_DATA(param); for (i=0;i<(npars/4);i++){ sigma = ppvoigt[i].fwhm * tosigma; dhelp = (*px - ppvoigt[i].centroid)/sigma; @@ -1198,7 +1221,7 @@ SpecfitFuns_apvoigt(PyObject *self, PyObject *args) k = (int) (dim_x [j] * k); } for (j=0;j<k;j++){ - ppvoigt = (pvoigtian *) param->data; + ppvoigt = (pvoigtian *) PyArray_DATA(param); for (i=0;i<(npars/4);i++){ sigma = ppvoigt[i].fwhm * tosigma; dhelp = (*px - ppvoigt[i].centroid)/sigma; @@ -1249,40 +1272,40 @@ SpecfitFuns_pvoigt(PyObject *self, PyObject *args) return NULL; param = (PyArrayObject *) - PyArray_CopyFromObject(input1, PyArray_DOUBLE,0,0); + PyArray_CopyFromObject(input1, NPY_DOUBLE,0,0); if (param == NULL) return NULL; x = (PyArrayObject *) - PyArray_CopyFromObject(input2, PyArray_DOUBLE,0,0); + PyArray_CopyFromObject(input2, NPY_DOUBLE,0,0); if (x == NULL){ Py_DECREF(param); return NULL; } - nd_param = param->nd; - nd_x = x->nd; + nd_param = PyArray_NDIM(param); + nd_x = PyArray_NDIM(x); if(debug !=0) { printf("nd_param = %d nd_x = %d\n",nd_param,nd_x); } if (nd_param == 1) { - dim_param [0] = param->dimensions[0]; + dim_param [0] = PyArray_DIMS(param)[0]; dim_param [1] = 0; }else{ - dim_param [0] = param->dimensions[0]; - dim_param [1] = param->dimensions[1]; + dim_param [0] = PyArray_DIMS(param)[0]; + dim_param [1] = PyArray_DIMS(param)[1]; } if (nd_x == 1) { - dim_x [0] = x->dimensions[0]; + dim_x [0] = PyArray_DIMS(x)[0]; dim_x [1] = 0; }else{ if (nd_x == 0) { dim_x [0] = 0; dim_x [1] = 0; }else{ - dim_x [0] = x->dimensions[0]; - dim_x [1] = x->dimensions[1]; + dim_x [0] = PyArray_DIMS(x)[0]; + dim_x [1] = PyArray_DIMS(x)[1]; } } @@ -1305,7 +1328,7 @@ SpecfitFuns_pvoigt(PyObject *self, PyObject *args) } /* Create the output array */ - ret = (PyArrayObject *) PyArray_SimpleNew(nd_x, dim_x, PyArray_DOUBLE); + ret = (PyArrayObject *) PyArray_SimpleNew(nd_x, dim_x, NPY_DOUBLE); if (ret == NULL){ Py_DECREF(param); Py_DECREF(x); @@ -1314,12 +1337,12 @@ SpecfitFuns_pvoigt(PyObject *self, PyObject *args) PyArray_FILLWBYTE(ret, 0); /* the pointer to the starting position of par data */ - px = (double *) x->data; - pret = (double *) ret->data; + px = (double *) PyArray_DATA(x); + pret = (double *) PyArray_DATA(ret); if (nd_x == 0){ *pret = 0; - ppvoigt = (pvoigtian *) param->data; + ppvoigt = (pvoigtian *) PyArray_DATA(param); for (i=0;i<(npars/4);i++){ dhelp = (*px - ppvoigt[i].centroid) / (0.5 * ppvoigt[i].fwhm); dhelp = 1.0 + (dhelp * dhelp); @@ -1332,7 +1355,7 @@ SpecfitFuns_pvoigt(PyObject *self, PyObject *args) } for (j=0;j<k;j++){ *pret = 0; - ppvoigt = (pvoigtian *) param->data; + ppvoigt = (pvoigtian *) PyArray_DATA(param); for (i=0;i<(npars/4);i++){ dhelp = (*px - ppvoigt[i].centroid) / (0.5 * ppvoigt[i].fwhm); dhelp = 1.0 + (dhelp * dhelp); @@ -1348,11 +1371,11 @@ SpecfitFuns_pvoigt(PyObject *self, PyObject *args) log2 = 0.69314718055994529; /* the pointer to the starting position of par data */ - px = (double *) x->data; - pret = (double *) ret->data; + px = (double *) PyArray_DATA(x); + pret = (double *) PyArray_DATA(ret); if (nd_x == 0){ - ppvoigt = (pvoigtian *) param->data; + ppvoigt = (pvoigtian *) PyArray_DATA(param); for (i=0;i<(npars/4);i++){ dhelp = ppvoigt[i].fwhm/(2.0*sqrt(2.0*log2)); dhelp = (*px - ppvoigt[i].centroid)/dhelp; @@ -1367,7 +1390,7 @@ SpecfitFuns_pvoigt(PyObject *self, PyObject *args) k = (int) (dim_x [j] * k); } for (j=0;j<k;j++){ - ppvoigt = (pvoigtian *) param->data; + ppvoigt = (pvoigtian *) PyArray_DATA(param); for (i=0;i<(npars/4);i++){ dhelp = ppvoigt[i].fwhm/(2.0*sqrt(2.0*log2)); dhelp = (*px - ppvoigt[i].centroid)/dhelp; @@ -1416,40 +1439,40 @@ SpecfitFuns_splitpvoigt(PyObject *self, PyObject *args) return NULL; param = (PyArrayObject *) - PyArray_CopyFromObject(input1, PyArray_DOUBLE,0,0); + PyArray_CopyFromObject(input1, NPY_DOUBLE,0,0); if (param == NULL) return NULL; x = (PyArrayObject *) - PyArray_CopyFromObject(input2, PyArray_DOUBLE,0,0); + PyArray_CopyFromObject(input2, NPY_DOUBLE,0,0); if (x == NULL){ Py_DECREF(param); return NULL; } - nd_param = param->nd; - nd_x = x->nd; + nd_param = PyArray_NDIM(param); + nd_x = PyArray_NDIM(x); if(debug !=0) { printf("nd_param = %d nd_x = %d\n",nd_param,nd_x); } if (nd_param == 1) { - dim_param [0] = param->dimensions[0]; + dim_param [0] = PyArray_DIMS(param)[0]; dim_param [1] = 0; }else{ - dim_param [0] = param->dimensions[0]; - dim_param [1] = param->dimensions[1]; + dim_param [0] = PyArray_DIMS(param)[0]; + dim_param [1] = PyArray_DIMS(param)[1]; } if (nd_x == 1) { - dim_x [0] = x->dimensions[0]; + dim_x [0] = PyArray_DIMS(x)[0]; dim_x [1] = 0; }else{ if (nd_x == 0) { dim_x [0] = 0; dim_x [1] = 0; }else{ - dim_x [0] = x->dimensions[0]; - dim_x [1] = x->dimensions[1]; + dim_x [0] = PyArray_DIMS(x)[0]; + dim_x [1] = PyArray_DIMS(x)[1]; } } @@ -1472,7 +1495,7 @@ SpecfitFuns_splitpvoigt(PyObject *self, PyObject *args) } /* Create the output array */ - ret = (PyArrayObject *) PyArray_SimpleNew(nd_x, dim_x, PyArray_DOUBLE); + ret = (PyArrayObject *) PyArray_SimpleNew(nd_x, dim_x, NPY_DOUBLE); if (ret == NULL){ Py_DECREF(param); Py_DECREF(x); @@ -1481,19 +1504,19 @@ SpecfitFuns_splitpvoigt(PyObject *self, PyObject *args) PyArray_FILLWBYTE(ret, 0); /* the pointer to the starting position of par data */ - px = (double *) x->data; - pret = (double *) ret->data; + px = (double *) PyArray_DATA(x); + pret = (double *) PyArray_DATA(ret); if (nd_x == 0){ *pret = 0; - ppvoigt = (pvoigtian *) param->data; + ppvoigt = (pvoigtian *) PyArray_DATA(param); for (i=0;i<(npars/5);i++){ dhelp = (*px - ppvoigt[i].centroid); - if (dhelp > 0){ - dhelp = dhelp /(0.5 * ppvoigt[i].fwhm2); - }else{ - dhelp = dhelp /(0.5 * ppvoigt[i].fwhm1); - } + if (dhelp > 0){ + dhelp = dhelp /(0.5 * ppvoigt[i].fwhm2); + }else{ + dhelp = dhelp /(0.5 * ppvoigt[i].fwhm1); + } dhelp = 1.0 + (dhelp * dhelp); *pret += ppvoigt[i].eta * (ppvoigt[i].height / dhelp); } @@ -1504,14 +1527,14 @@ SpecfitFuns_splitpvoigt(PyObject *self, PyObject *args) } for (j=0;j<k;j++){ *pret = 0; - ppvoigt = (pvoigtian *) param->data; + ppvoigt = (pvoigtian *) PyArray_DATA(param); for (i=0;i<(npars/5);i++){ dhelp = (*px - ppvoigt[i].centroid); - if (dhelp > 0){ - dhelp = dhelp /(0.5 * ppvoigt[i].fwhm2); - }else{ - dhelp = dhelp /(0.5 * ppvoigt[i].fwhm1); - } + if (dhelp > 0){ + dhelp = dhelp /(0.5 * ppvoigt[i].fwhm2); + }else{ + dhelp = dhelp /(0.5 * ppvoigt[i].fwhm1); + } dhelp = 1.0 + (dhelp * dhelp); *pret += ppvoigt[i].eta * (ppvoigt[i].height / dhelp); } @@ -1525,18 +1548,18 @@ SpecfitFuns_splitpvoigt(PyObject *self, PyObject *args) log2 = 0.69314718055994529; /* the pointer to the starting position of par data */ - px = (double *) x->data; - pret = (double *) ret->data; + px = (double *) PyArray_DATA(x); + pret = (double *) PyArray_DATA(ret); if (nd_x == 0){ - ppvoigt = (pvoigtian *) param->data; + ppvoigt = (pvoigtian *) PyArray_DATA(param); for (i=0;i<(npars/5);i++){ - dhelp = (*px - ppvoigt[i].centroid); - if (dhelp >0){ - dhelp = dhelp /(ppvoigt[i].fwhm2/(2.0*sqrt(2.0*log2))); - }else{ - dhelp = dhelp /(ppvoigt[i].fwhm1/(2.0*sqrt(2.0*log2))); - } + dhelp = (*px - ppvoigt[i].centroid); + if (dhelp >0){ + dhelp = dhelp /(ppvoigt[i].fwhm2/(2.0*sqrt(2.0*log2))); + }else{ + dhelp = dhelp /(ppvoigt[i].fwhm1/(2.0*sqrt(2.0*log2))); + } if (dhelp <= 35) { *pret += (1.0 - ppvoigt[i].eta) * ppvoigt[i].height \ * exp (-0.5 * dhelp * dhelp); @@ -1548,14 +1571,14 @@ SpecfitFuns_splitpvoigt(PyObject *self, PyObject *args) k = (int) (dim_x [j] * k); } for (j=0;j<k;j++){ - ppvoigt = (pvoigtian *) param->data; + ppvoigt = (pvoigtian *) PyArray_DATA(param); for (i=0;i<(npars/5);i++){ - dhelp = (*px - ppvoigt[i].centroid); - if (dhelp > 0){ - dhelp = dhelp /(ppvoigt[i].fwhm2/(2.0*sqrt(2.0*log2))); - }else{ - dhelp = dhelp /(ppvoigt[i].fwhm1/(2.0*sqrt(2.0*log2))); - } + dhelp = (*px - ppvoigt[i].centroid); + if (dhelp > 0){ + dhelp = dhelp /(ppvoigt[i].fwhm2/(2.0*sqrt(2.0*log2))); + }else{ + dhelp = dhelp /(ppvoigt[i].fwhm1/(2.0*sqrt(2.0*log2))); + } if (dhelp <= 35) { *pret += (1.0 - ppvoigt[i].eta) * ppvoigt[i].height \ * exp (-0.5 * dhelp * dhelp); @@ -1599,40 +1622,40 @@ SpecfitFuns_lorentz(PyObject *self, PyObject *args) return NULL; param = (PyArrayObject *) - PyArray_CopyFromObject(input1, PyArray_DOUBLE,0,0); + PyArray_CopyFromObject(input1, NPY_DOUBLE,0,0); if (param == NULL) return NULL; x = (PyArrayObject *) - PyArray_CopyFromObject(input2, PyArray_DOUBLE,0,0); + PyArray_CopyFromObject(input2, NPY_DOUBLE,0,0); if (x == NULL){ Py_DECREF(param); return NULL; } - nd_param = param->nd; - nd_x = x->nd; + nd_param = PyArray_NDIM(param); + nd_x = PyArray_NDIM(x); if(debug !=0) { printf("nd_param = %d nd_x = %d\n",nd_param,nd_x); } if (nd_param == 1) { - dim_param [0] = param->dimensions[0]; + dim_param [0] = PyArray_DIMS(param)[0]; dim_param [1] = 0; }else{ - dim_param [0] = param->dimensions[0]; - dim_param [1] = param->dimensions[1]; + dim_param [0] = PyArray_DIMS(param)[0]; + dim_param [1] = PyArray_DIMS(param)[1]; } if (nd_x == 1) { - dim_x [0] = x->dimensions[0]; + dim_x [0] = PyArray_DIMS(x)[0]; dim_x [1] = 0; }else{ if (nd_x == 0) { dim_x [0] = 0; dim_x [1] = 0; }else{ - dim_x [0] = x->dimensions[0]; - dim_x [1] = x->dimensions[1]; + dim_x [0] = PyArray_DIMS(x)[0]; + dim_x [1] = PyArray_DIMS(x)[1]; } } @@ -1655,7 +1678,7 @@ SpecfitFuns_lorentz(PyObject *self, PyObject *args) } /* Create the output array */ - ret = (PyArrayObject *) PyArray_SimpleNew(nd_x, dim_x, PyArray_DOUBLE); + ret = (PyArrayObject *) PyArray_SimpleNew(nd_x, dim_x, NPY_DOUBLE); if (ret == NULL){ Py_DECREF(param); Py_DECREF(x); @@ -1664,12 +1687,12 @@ SpecfitFuns_lorentz(PyObject *self, PyObject *args) PyArray_FILLWBYTE(ret, 0); /* the pointer to the starting position of par data */ - px = (double *) x->data; - pret = (double *) ret->data; + px = (double *) PyArray_DATA(x); + pret = (double *) PyArray_DATA(ret); if (nd_x == 0){ *pret = 0; - plorentz = (lorentzian *) param->data; + plorentz = (lorentzian *) PyArray_DATA(param); for (i=0;i<(npars/3);i++){ dhelp = (*px - plorentz[i].centroid) / (0.5 * plorentz[i].fwhm); dhelp = 1.0 + (dhelp * dhelp); @@ -1682,7 +1705,7 @@ SpecfitFuns_lorentz(PyObject *self, PyObject *args) } for (j=0;j<k;j++){ *pret = 0; - plorentz = (lorentzian *) param->data; + plorentz = (lorentzian *) PyArray_DATA(param); for (i=0;i<(npars/3);i++){ dhelp = (*px - plorentz[i].centroid) / (0.5 * plorentz[i].fwhm); dhelp = 1.0 + (dhelp * dhelp); @@ -1724,40 +1747,40 @@ SpecfitFuns_alorentz(PyObject *self, PyObject *args) return NULL; param = (PyArrayObject *) - PyArray_CopyFromObject(input1, PyArray_DOUBLE,0,0); + PyArray_CopyFromObject(input1, NPY_DOUBLE,0,0); if (param == NULL) return NULL; x = (PyArrayObject *) - PyArray_CopyFromObject(input2, PyArray_DOUBLE,0,0); + PyArray_CopyFromObject(input2, NPY_DOUBLE,0,0); if (x == NULL){ Py_DECREF(param); return NULL; } - nd_param = param->nd; - nd_x = x->nd; + nd_param = PyArray_NDIM(param); + nd_x = PyArray_NDIM(x); if(debug !=0) { printf("nd_param = %d nd_x = %d\n",nd_param,nd_x); } if (nd_param == 1) { - dim_param [0] = param->dimensions[0]; + dim_param [0] = PyArray_DIMS(param)[0]; dim_param [1] = 0; }else{ - dim_param [0] = param->dimensions[0]; - dim_param [1] = param->dimensions[1]; + dim_param [0] = PyArray_DIMS(param)[0]; + dim_param [1] = PyArray_DIMS(param)[1]; } if (nd_x == 1) { - dim_x [0] = x->dimensions[0]; + dim_x [0] = PyArray_DIMS(x)[0]; dim_x [1] = 0; }else{ if (nd_x == 0) { dim_x [0] = 0; dim_x [1] = 0; }else{ - dim_x [0] = x->dimensions[0]; - dim_x [1] = x->dimensions[1]; + dim_x [0] = PyArray_DIMS(x)[0]; + dim_x [1] = PyArray_DIMS(x)[1]; } } @@ -1780,7 +1803,7 @@ SpecfitFuns_alorentz(PyObject *self, PyObject *args) } /* Create the output array */ - ret = (PyArrayObject *) PyArray_SimpleNew(nd_x, dim_x, PyArray_DOUBLE); + ret = (PyArrayObject *) PyArray_SimpleNew(nd_x, dim_x, NPY_DOUBLE); if (ret == NULL){ Py_DECREF(param); Py_DECREF(x); @@ -1789,12 +1812,12 @@ SpecfitFuns_alorentz(PyObject *self, PyObject *args) PyArray_FILLWBYTE(ret, 0); /* the pointer to the starting position of par data */ - px = (double *) x->data; - pret = (double *) ret->data; + px = (double *) PyArray_DATA(x); + pret = (double *) PyArray_DATA(ret); if (nd_x == 0){ *pret = 0; - plorentz = (lorentzian *) param->data; + plorentz = (lorentzian *) PyArray_DATA(param); for (i=0;i<(npars/3);i++){ dhelp = (*px - plorentz[i].centroid) / (0.5 * plorentz[i].fwhm); dhelp = 1.0 + (dhelp * dhelp); @@ -1807,7 +1830,7 @@ SpecfitFuns_alorentz(PyObject *self, PyObject *args) } for (j=0;j<k;j++){ *pret = 0; - plorentz = (lorentzian *) param->data; + plorentz = (lorentzian *) PyArray_DATA(param); for (i=0;i<(npars/3);i++){ dhelp = (*px - plorentz[i].centroid) / (0.5 * plorentz[i].fwhm); dhelp = 1.0 + (dhelp * dhelp); @@ -1849,40 +1872,40 @@ SpecfitFuns_splitlorentz(PyObject *self, PyObject *args) return NULL; param = (PyArrayObject *) - PyArray_CopyFromObject(input1, PyArray_DOUBLE,0,0); + PyArray_CopyFromObject(input1, NPY_DOUBLE,0,0); if (param == NULL) return NULL; x = (PyArrayObject *) - PyArray_CopyFromObject(input2, PyArray_DOUBLE,0,0); + PyArray_CopyFromObject(input2, NPY_DOUBLE,0,0); if (x == NULL){ Py_DECREF(param); return NULL; } - nd_param = param->nd; - nd_x = x->nd; + nd_param = PyArray_NDIM(param); + nd_x = PyArray_NDIM(x); if(debug !=0) { printf("nd_param = %d nd_x = %d\n",nd_param,nd_x); } if (nd_param == 1) { - dim_param [0] = param->dimensions[0]; + dim_param [0] = PyArray_DIMS(param)[0]; dim_param [1] = 0; }else{ - dim_param [0] = param->dimensions[0]; - dim_param [1] = param->dimensions[1]; + dim_param [0] = PyArray_DIMS(param)[0]; + dim_param [1] = PyArray_DIMS(param)[1]; } if (nd_x == 1) { - dim_x [0] = x->dimensions[0]; + dim_x [0] = PyArray_DIMS(x)[0]; dim_x [1] = 0; }else{ if (nd_x == 0) { dim_x [0] = 0; dim_x [1] = 0; }else{ - dim_x [0] = x->dimensions[0]; - dim_x [1] = x->dimensions[1]; + dim_x [0] = PyArray_DIMS(x)[0]; + dim_x [1] = PyArray_DIMS(x)[1]; } } @@ -1905,7 +1928,7 @@ SpecfitFuns_splitlorentz(PyObject *self, PyObject *args) } /* Create the output array */ - ret = (PyArrayObject *) PyArray_SimpleNew(nd_x, dim_x, PyArray_DOUBLE); + ret = (PyArrayObject *) PyArray_SimpleNew(nd_x, dim_x, NPY_DOUBLE); if (ret == NULL){ Py_DECREF(param); Py_DECREF(x); @@ -1914,19 +1937,19 @@ SpecfitFuns_splitlorentz(PyObject *self, PyObject *args) PyArray_FILLWBYTE(ret, 0); /* the pointer to the starting position of par data */ - px = (double *) x->data; - pret = (double *) ret->data; + px = (double *) PyArray_DATA(x); + pret = (double *) PyArray_DATA(ret); if (nd_x == 0){ *pret = 0; - plorentz = (lorentzian *) param->data; + plorentz = (lorentzian *) PyArray_DATA(param); for (i=0;i<(npars/4);i++){ dhelp = *px - plorentz[i].centroid; - if (dhelp > 0){ - dhelp = dhelp /(0.5 * plorentz[i].fwhm2); - }else{ - dhelp = dhelp /(0.5 * plorentz[i].fwhm1); - } + if (dhelp > 0){ + dhelp = dhelp /(0.5 * plorentz[i].fwhm2); + }else{ + dhelp = dhelp /(0.5 * plorentz[i].fwhm1); + } dhelp = 1.0 + (dhelp * dhelp); *pret += (plorentz[i].height / dhelp); } @@ -1937,16 +1960,16 @@ SpecfitFuns_splitlorentz(PyObject *self, PyObject *args) } for (j=0;j<k;j++){ *pret = 0; - plorentz = (lorentzian *) param->data; + plorentz = (lorentzian *) PyArray_DATA(param); for (i=0;i<(npars/4);i++){ dhelp = *px - plorentz[i].centroid; - if (dhelp > 0){ - dhelp = dhelp /(0.5 * plorentz[i].fwhm2); - }else{ - dhelp = dhelp /(0.5 * plorentz[i].fwhm1); - } - dhelp = 1.0 + (dhelp * dhelp); - *pret += (plorentz[i].height / dhelp); + if (dhelp > 0){ + dhelp = dhelp /(0.5 * plorentz[i].fwhm2); + }else{ + dhelp = dhelp /(0.5 * plorentz[i].fwhm1); + } + dhelp = 1.0 + (dhelp * dhelp); + *pret += (plorentz[i].height / dhelp); } pret++; px++; @@ -1985,40 +2008,40 @@ SpecfitFuns_downstep(PyObject *self, PyObject *args) return NULL; param = (PyArrayObject *) - PyArray_CopyFromObject(input1, PyArray_DOUBLE,0,0); + PyArray_CopyFromObject(input1, NPY_DOUBLE,0,0); if (param == NULL) return NULL; x = (PyArrayObject *) - PyArray_CopyFromObject(input2, PyArray_DOUBLE,0,0); + PyArray_CopyFromObject(input2, NPY_DOUBLE,0,0); if (x == NULL){ Py_DECREF(param); return NULL; } - nd_param = param->nd; - nd_x = x->nd; + nd_param = PyArray_NDIM(param); + nd_x = PyArray_NDIM(x); if(debug !=0) { printf("nd_param = %d nd_x = %d\n",nd_param,nd_x); } if (nd_param == 1) { - dim_param [0] = param->dimensions[0]; + dim_param [0] = PyArray_DIMS(param)[0]; dim_param [1] = 0; }else{ - dim_param [0] = param->dimensions[0]; - dim_param [1] = param->dimensions[1]; + dim_param [0] = PyArray_DIMS(param)[0]; + dim_param [1] = PyArray_DIMS(param)[1]; } if (nd_x == 1) { - dim_x [0] = x->dimensions[0]; + dim_x [0] = PyArray_DIMS(x)[0]; dim_x [1] = 0; }else{ if (nd_x == 0) { dim_x [0] = 0; dim_x [1] = 0; }else{ - dim_x [0] = x->dimensions[0]; - dim_x [1] = x->dimensions[1]; + dim_x [0] = PyArray_DIMS(x)[0]; + dim_x [1] = PyArray_DIMS(x)[1]; } } @@ -2041,7 +2064,7 @@ SpecfitFuns_downstep(PyObject *self, PyObject *args) } /* Create the output array */ - ret = (PyArrayObject *) PyArray_SimpleNew(nd_x, dim_x, PyArray_DOUBLE); + ret = (PyArrayObject *) PyArray_SimpleNew(nd_x, dim_x, NPY_DOUBLE); if (ret == NULL){ Py_DECREF(param); Py_DECREF(x); @@ -2050,15 +2073,15 @@ SpecfitFuns_downstep(PyObject *self, PyObject *args) PyArray_FILLWBYTE(ret, 0); /* the pointer to the starting position of par data */ - px = (double *) x->data; - pret = (double *) ret->data; + px = (double *) PyArray_DATA(x); + pret = (double *) PyArray_DATA(ret); tosigma=1.0/(2.0*sqrt(2.0*log(2.0))); if (nd_x == 0){ *pret = 0; - perrorfc = (errorfc *) param->data; + perrorfc = (errorfc *) PyArray_DATA(param); for (i=0;i<(npars/3);i++){ dhelp = perrorfc[i].fwhm * tosigma; dhelp = (*px - perrorfc[i].centroid) / (sqrt(2)*dhelp); @@ -2071,7 +2094,7 @@ SpecfitFuns_downstep(PyObject *self, PyObject *args) } for (j=0;j<k;j++){ *pret = 0; - perrorfc = (errorfc *) param->data; + perrorfc = (errorfc *) PyArray_DATA(param); for (i=0;i<(npars/3);i++){ dhelp = perrorfc[i].fwhm * tosigma; dhelp = (*px - perrorfc[i].centroid) / (sqrt(2)*dhelp); @@ -2114,40 +2137,40 @@ SpecfitFuns_upstep(PyObject *self, PyObject *args) return NULL; param = (PyArrayObject *) - PyArray_CopyFromObject(input1, PyArray_DOUBLE,0,0); + PyArray_CopyFromObject(input1, NPY_DOUBLE,0,0); if (param == NULL) return NULL; x = (PyArrayObject *) - PyArray_CopyFromObject(input2, PyArray_DOUBLE,0,0); + PyArray_CopyFromObject(input2, NPY_DOUBLE,0,0); if (x == NULL){ Py_DECREF(param); return NULL; } - nd_param = param->nd; - nd_x = x->nd; + nd_param = PyArray_NDIM(param); + nd_x = PyArray_NDIM(x); if(debug !=0) { printf("nd_param = %d nd_x = %d\n",nd_param,nd_x); } if (nd_param == 1) { - dim_param [0] = param->dimensions[0]; + dim_param [0] = PyArray_DIMS(param)[0]; dim_param [1] = 0; }else{ - dim_param [0] = param->dimensions[0]; - dim_param [1] = param->dimensions[1]; + dim_param [0] = PyArray_DIMS(param)[0]; + dim_param [1] = PyArray_DIMS(param)[1]; } if (nd_x == 1) { - dim_x [0] = x->dimensions[0]; + dim_x [0] = PyArray_DIMS(x)[0]; dim_x [1] = 0; }else{ if (nd_x == 0) { dim_x [0] = 0; dim_x [1] = 0; }else{ - dim_x [0] = x->dimensions[0]; - dim_x [1] = x->dimensions[1]; + dim_x [0] = PyArray_DIMS(x)[0]; + dim_x [1] = PyArray_DIMS(x)[1]; } } @@ -2170,7 +2193,7 @@ SpecfitFuns_upstep(PyObject *self, PyObject *args) } /* Create the output array */ - ret = (PyArrayObject *) PyArray_SimpleNew(nd_x, dim_x, PyArray_DOUBLE); + ret = (PyArrayObject *) PyArray_SimpleNew(nd_x, dim_x, NPY_DOUBLE); if (ret == NULL){ Py_DECREF(param); Py_DECREF(x); @@ -2179,14 +2202,14 @@ SpecfitFuns_upstep(PyObject *self, PyObject *args) PyArray_FILLWBYTE(ret, 0); /* the pointer to the starting position of par data */ - px = (double *) x->data; - pret = (double *) ret->data; + px = (double *) PyArray_DATA(x); + pret = (double *) PyArray_DATA(ret); tosigma=1.0/(2.0*sqrt(2.0*log(2.0))); if (nd_x == 0){ *pret = 0; - perrorf = (errorf *) param->data; + perrorf = (errorf *) PyArray_DATA(param); for (i=0;i<(npars/3);i++){ dhelp = perrorf[i].fwhm * tosigma; dhelp = (*px - perrorf[i].centroid) / (sqrt(2)*dhelp); @@ -2199,7 +2222,7 @@ SpecfitFuns_upstep(PyObject *self, PyObject *args) } for (j=0;j<k;j++){ *pret = 0; - perrorf = (errorf *) param->data; + perrorf = (errorf *) PyArray_DATA(param); for (i=0;i<(npars/3);i++){ dhelp = perrorf[i].fwhm * tosigma; dhelp = (*px - perrorf[i].centroid) / (sqrt(2)*dhelp); @@ -2243,40 +2266,40 @@ SpecfitFuns_slit(PyObject *self, PyObject *args) return NULL; param = (PyArrayObject *) - PyArray_CopyFromObject(input1, PyArray_DOUBLE,0,0); + PyArray_CopyFromObject(input1, NPY_DOUBLE,0,0); if (param == NULL) return NULL; x = (PyArrayObject *) - PyArray_CopyFromObject(input2, PyArray_DOUBLE,0,0); + PyArray_CopyFromObject(input2, NPY_DOUBLE,0,0); if (x == NULL){ Py_DECREF(param); return NULL; } - nd_param = param->nd; - nd_x = x->nd; + nd_param = PyArray_NDIM(param); + nd_x = PyArray_NDIM(x); if(debug !=0) { printf("nd_param = %d nd_x = %d\n",nd_param,nd_x); } if (nd_param == 1) { - dim_param [0] = param->dimensions[0]; + dim_param [0] = PyArray_DIMS(param)[0]; dim_param [1] = 0; }else{ - dim_param [0] = param->dimensions[0]; - dim_param [1] = param->dimensions[1]; + dim_param [0] = PyArray_DIMS(param)[0]; + dim_param [1] = PyArray_DIMS(param)[1]; } if (nd_x == 1) { - dim_x [0] = x->dimensions[0]; + dim_x [0] = PyArray_DIMS(x)[0]; dim_x [1] = 0; }else{ if (nd_x == 0) { dim_x [0] = 0; dim_x [1] = 0; }else{ - dim_x [0] = x->dimensions[0]; - dim_x [1] = x->dimensions[1]; + dim_x [0] = PyArray_DIMS(x)[0]; + dim_x [1] = PyArray_DIMS(x)[1]; } } @@ -2299,7 +2322,7 @@ SpecfitFuns_slit(PyObject *self, PyObject *args) } /* Create the output array */ - ret = (PyArrayObject *) PyArray_SimpleNew(nd_x, dim_x, PyArray_DOUBLE); + ret = (PyArrayObject *) PyArray_SimpleNew(nd_x, dim_x, NPY_DOUBLE); if (ret == NULL){ Py_DECREF(param); Py_DECREF(x); @@ -2308,14 +2331,14 @@ SpecfitFuns_slit(PyObject *self, PyObject *args) PyArray_FILLWBYTE(ret, 0); /* the pointer to the starting position of par data */ - px = (double *) x->data; - pret = (double *) ret->data; + px = (double *) PyArray_DATA(x); + pret = (double *) PyArray_DATA(ret); tosigma=1.0/(2.0*sqrt(2.0*log(2.0))); if (nd_x == 0){ *pret = 0; - perrorf = (errorf *) param->data; + perrorf = (errorf *) PyArray_DATA(param); for (i=0;i<(npars/4);i++){ dhelp = perrorf[i].beamfwhm * tosigma; centroid1=perrorf[i].position - 0.5 * perrorf[i].fwhm; @@ -2331,7 +2354,7 @@ SpecfitFuns_slit(PyObject *self, PyObject *args) } for (j=0;j<k;j++){ *pret = 0; - perrorf = (errorf *) param->data; + perrorf = (errorf *) PyArray_DATA(param); for (i=0;i<(npars/4);i++){ dhelp = perrorf[i].beamfwhm * tosigma; centroid1=perrorf[i].position - 0.5 * perrorf[i].fwhm; @@ -2370,26 +2393,26 @@ SpecfitFuns_erfc(PyObject *self, PyObject *args) return NULL; x = (PyArrayObject *) - PyArray_CopyFromObject(input1, PyArray_DOUBLE,0,0); + PyArray_CopyFromObject(input1, NPY_DOUBLE,0,0); if (x == NULL){ return NULL; } - nd_x = x->nd; + nd_x = PyArray_NDIM(x); if(debug !=0) { printf("nd_x = %d\n",nd_x); } if (nd_x == 1) { - dim_x [0] = x->dimensions[0]; + dim_x [0] = PyArray_DIMS(x)[0]; dim_x [1] = 0; }else{ if (nd_x == 0) { dim_x [0] = 0; dim_x [1] = 0; }else{ - dim_x [0] = x->dimensions[0]; - dim_x [1] = x->dimensions[1]; + dim_x [0] = PyArray_DIMS(x)[0]; + dim_x [1] = PyArray_DIMS(x)[1]; } } @@ -2398,7 +2421,7 @@ SpecfitFuns_erfc(PyObject *self, PyObject *args) } /* Create the output array */ - ret = (PyArrayObject *) PyArray_SimpleNew(nd_x, dim_x, PyArray_DOUBLE); + ret = (PyArrayObject *) PyArray_SimpleNew(nd_x, dim_x, NPY_DOUBLE); if (ret == NULL){ Py_DECREF(x); return NULL; @@ -2406,8 +2429,8 @@ SpecfitFuns_erfc(PyObject *self, PyObject *args) PyArray_FILLWBYTE(ret, 0); /* the pointer to the starting position of par data */ - px = (double *) x->data; - pret = (double *) ret->data; + px = (double *) PyArray_DATA(x); + pret = (double *) PyArray_DATA(ret); if (nd_x == 0){ dhelp = *px; @@ -2450,26 +2473,26 @@ SpecfitFuns_erf(PyObject *self, PyObject *args) return NULL; x = (PyArrayObject *) - PyArray_CopyFromObject(input1, PyArray_DOUBLE,0,0); + PyArray_CopyFromObject(input1, NPY_DOUBLE,0,0); if (x == NULL){ return NULL; } - nd_x = x->nd; + nd_x = PyArray_NDIM(x); if(debug !=0) { printf("nd_x = %d\n",nd_x); } if (nd_x == 1) { - dim_x [0] = x->dimensions[0]; + dim_x [0] = PyArray_DIMS(x)[0]; dim_x [1] = 0; }else{ if (nd_x == 0) { dim_x [0] = 0; dim_x [1] = 0; }else{ - dim_x [0] = x->dimensions[0]; - dim_x [1] = x->dimensions[1]; + dim_x [0] = PyArray_DIMS(x)[0]; + dim_x [1] = PyArray_DIMS(x)[1]; } } @@ -2478,7 +2501,7 @@ SpecfitFuns_erf(PyObject *self, PyObject *args) } /* Create the output array */ - ret = (PyArrayObject *) PyArray_SimpleNew(nd_x, dim_x, PyArray_DOUBLE); + ret = (PyArrayObject *) PyArray_SimpleNew(nd_x, dim_x, NPY_DOUBLE); if (ret == NULL){ Py_DECREF(x); return NULL; @@ -2486,8 +2509,8 @@ SpecfitFuns_erf(PyObject *self, PyObject *args) PyArray_FILLWBYTE(ret, 0); /* the pointer to the starting position of par data */ - px = (double *) x->data; - pret = (double *) ret->data; + px = (double *) PyArray_DATA(x); + pret = (double *) PyArray_DATA(ret); if (nd_x == 0){ dhelp = *px; @@ -2546,46 +2569,46 @@ SpecfitFuns_ahypermet(PyObject *self, PyObject *args) return NULL; param = (PyArrayObject *) - PyArray_CopyFromObject(input1, PyArray_DOUBLE,0,0); + PyArray_CopyFromObject(input1, NPY_DOUBLE,0,0); if (param == NULL) return NULL; x = (PyArrayObject *) - PyArray_CopyFromObject(input2, PyArray_DOUBLE,0,0); + PyArray_CopyFromObject(input2, NPY_DOUBLE,0,0); if (x == NULL){ Py_DECREF(param); return NULL; } - nd_param = param->nd; - nd_x = x->nd; + nd_param = PyArray_NDIM(param); + nd_x = PyArray_NDIM(x); if(debug !=0) { printf("nd_param = %d nd_x = %d\n",nd_param,nd_x); } if (nd_param == 1) { - dim_param [0] = param->dimensions[0]; + dim_param [0] = PyArray_DIMS(param)[0]; dim_param [1] = 0; }else{ - dim_param [0] = param->dimensions[0]; - dim_param [1] = param->dimensions[1]; + dim_param [0] = PyArray_DIMS(param)[0]; + dim_param [1] = PyArray_DIMS(param)[1]; } if (nd_x == 1) { - dim_x [0] = x->dimensions[0]; + dim_x [0] = PyArray_DIMS(x)[0]; dim_x [1] = 0; }else{ if (nd_x == 0) { dim_x [0] = 0; dim_x [1] = 0; }else{ - dim_x [0] = x->dimensions[0]; - dim_x [1] = x->dimensions[1]; + dim_x [0] = PyArray_DIMS(x)[0]; + dim_x [1] = PyArray_DIMS(x)[1]; } } /* The gaussian terms must always be there */ if(tails <= 0){ /* I give back a matrix filled with zeros */ - ret = (PyArrayObject *) PyArray_SimpleNew(nd_x, dim_x, PyArray_DOUBLE); + ret = (PyArrayObject *) PyArray_SimpleNew(nd_x, dim_x, NPY_DOUBLE); if (ret == NULL){ Py_DECREF(param); Py_DECREF(x); @@ -2627,7 +2650,7 @@ SpecfitFuns_ahypermet(PyObject *self, PyObject *args) } /* Create the output array */ - ret = (PyArrayObject *) PyArray_SimpleNew(nd_x, dim_x, PyArray_DOUBLE); + ret = (PyArrayObject *) PyArray_SimpleNew(nd_x, dim_x, NPY_DOUBLE); if (ret == NULL){ Py_DECREF(param); Py_DECREF(x); @@ -2640,9 +2663,9 @@ SpecfitFuns_ahypermet(PyObject *self, PyObject *args) tosigma=1.0/(2.0*sqrt(2.0*log2)); /* the pointer to the starting position of par data */ - px = (double *) x->data; - pret = (double *) ret->data; - phyper = (hypermet *) param->data; + px = (double *) PyArray_DATA(x); + pret = (double *) PyArray_DATA(ret); + phyper = (hypermet *) PyArray_DATA(param); if(0){ if(debug !=0){ for (i=0;i<(npars/expected_pars);i++){ @@ -2652,7 +2675,7 @@ printf("Area%d=%f,Pos%d=%f,FWHM%d=%f\n",i,phyper[i].area,i,phyper[i].position,i, } if (nd_x == 0){ *pret = 0; - phyper = (hypermet *) param->data; + phyper = (hypermet *) PyArray_DATA(param); for (i=0;i<(npars/expected_pars);i++){ /* g_term = st_term = lt_term = step_term = 0; */ x1 = phyper[i].area; @@ -2716,7 +2739,7 @@ printf("LT_Area=%f,LT_Slope=%f\n",phyper[i].lt_area_r,phyper[i].lt_slope_r); } for (j=0;j<k;j++){ *pret = 0; - phyper = (hypermet *) param->data; + phyper = (hypermet *) PyArray_DATA(param); for (i=0;i<(npars/expected_pars);i++){ /* g_term = st_term = lt_term = step_term = 0; */ x1 = phyper[i].area; @@ -2867,46 +2890,46 @@ SpecfitFuns_fastahypermet(PyObject *self, PyObject *args) return NULL; param = (PyArrayObject *) - PyArray_ContiguousFromObject(input1, PyArray_DOUBLE,0,0); + PyArray_ContiguousFromObject(input1, NPY_DOUBLE,0,0); if (param == NULL) return NULL; x = (PyArrayObject *) - PyArray_ContiguousFromObject(input2, PyArray_DOUBLE,0,0); + PyArray_ContiguousFromObject(input2, NPY_DOUBLE,0,0); if (x == NULL){ Py_DECREF(param); return NULL; } - nd_param = param->nd; - nd_x = x->nd; + nd_param = PyArray_NDIM(param); + nd_x = PyArray_NDIM(x); if(debug !=0) { printf("nd_param = %d nd_x = %d\n",nd_param,nd_x); } if (nd_param == 1) { - dim_param [0] = param->dimensions[0]; + dim_param [0] = PyArray_DIMS(param)[0]; dim_param [1] = 0; }else{ - dim_param [0] = param->dimensions[0]; - dim_param [1] = param->dimensions[1]; + dim_param [0] = PyArray_DIMS(param)[0]; + dim_param [1] = PyArray_DIMS(param)[1]; } if (nd_x == 1) { - dim_x [0] = x->dimensions[0]; + dim_x [0] = PyArray_DIMS(x)[0]; dim_x [1] = 0; }else{ if (nd_x == 0) { dim_x [0] = 0; dim_x [1] = 0; }else{ - dim_x [0] = x->dimensions[0]; - dim_x [1] = x->dimensions[1]; + dim_x [0] = PyArray_DIMS(x)[0]; + dim_x [1] = PyArray_DIMS(x)[1]; } } /* The gaussian terms must always be there */ if(tails <= 0){ /* I give back a matrix filled with zeros */ - ret = (PyArrayObject *) PyArray_SimpleNew(nd_x, dim_x, PyArray_DOUBLE); + ret = (PyArrayObject *) PyArray_SimpleNew(nd_x, dim_x, NPY_DOUBLE); if (ret == NULL){ Py_DECREF(param); Py_DECREF(x); @@ -2948,7 +2971,7 @@ SpecfitFuns_fastahypermet(PyObject *self, PyObject *args) } /* Create the output array */ - ret = (PyArrayObject *) PyArray_SimpleNew(nd_x, dim_x, PyArray_DOUBLE); + ret = (PyArrayObject *) PyArray_SimpleNew(nd_x, dim_x, NPY_DOUBLE); if (ret == NULL){ Py_DECREF(param); Py_DECREF(x); @@ -2961,9 +2984,9 @@ SpecfitFuns_fastahypermet(PyObject *self, PyObject *args) tosigma=1.0/(2.0*sqrt(2.0*log2)); /* the pointer to the starting position of par data */ - px = (double *) x->data; - pret = (double *) ret->data; - phyper = (hypermet *) param->data; + px = (double *) PyArray_DATA(x); + pret = (double *) PyArray_DATA(ret); + phyper = (hypermet *) PyArray_DATA(param); if(0){ if(debug !=0){ for (i=0;i<(npars/expected_pars);i++){ @@ -2973,7 +2996,7 @@ printf("Area%d=%f,Pos%d=%f,FWHM%d=%f\n",i,phyper[i].area,i,phyper[i].position,i, } if (nd_x == 0){ *pret = 0; - phyper = (hypermet *) param->data; + phyper = (hypermet *) PyArray_DATA(param); for (i=0;i<(npars/expected_pars);i++){ /* g_term = st_term = lt_term = step_term = 0; */ x1 = phyper[i].area; @@ -3040,13 +3063,13 @@ printf("LT_Area=%f,LT_Slope=%f\n",phyper[i].lt_area_r,phyper[i].lt_slope_r); for (j=0;j<nd_x;j++){ k = (int) (dim_x [j] * k); } - phyper = (hypermet *) param->data; + phyper = (hypermet *) PyArray_DATA(param); for (i=0;i<(npars/expected_pars);i++){ if (i == 0){ *pret = 0; }else{ - px = (double *) x->data; - pret = (double *) ret->data; + px = (double *) PyArray_DATA(x); + pret = (double *) PyArray_DATA(ret); } x1 = phyper[i].area; x2 = phyper[i].position; @@ -3174,29 +3197,29 @@ SpecfitFuns_seek(PyObject *self, PyObject *args) &debug_info, &relevance_info )) return NULL; yspec = (PyArrayObject *) - PyArray_CopyFromObject(input, PyArray_DOUBLE,0,0); + PyArray_CopyFromObject(input, NPY_DOUBLE,0,0); if (yspec == NULL) return NULL; if (Sensitivity < 0.1) { Sensitivity = 3.25; } - nd = yspec->nd; + nd = PyArray_NDIM(yspec); if (nd == 0) { printf("I need at least a vector!\n"); Py_DECREF(yspec); return NULL; } - nchannels = (long) yspec->dimensions[0]; + nchannels = (long) PyArray_DIMS(yspec)[0]; if (nd > 1) { if (nchannels == 1){ - nchannels = (long) yspec->dimensions[0]; + nchannels = (long) PyArray_DIMS(yspec)[0]; } } - pvalues = (double *) yspec->data; + pvalues = (double *) PyArray_DATA(yspec); seek_result=SpecfitFuns_seek2(BeginChannel, EndChannel, nchannels, FWHM, Sensitivity, debug_info, @@ -3215,19 +3238,18 @@ SpecfitFuns_seek(PyObject *self, PyObject *args) if (relevance_info) { dimensions [0] = npeaks; dimensions [1] = 2; - result = (PyArrayObject *) PyArray_SimpleNew(2,dimensions,PyArray_DOUBLE); + result = (PyArrayObject *) PyArray_SimpleNew(2,dimensions,NPY_DOUBLE); + pvalues = (double *) PyArray_DATA(result); for (i=0;i<npeaks;i++){ - /*printf("Peak %ld found at %g rel %g\n",i+1,peaks[i],relevances[i]);*/ - *((double *) (result->data + i*result->strides[0])) = peaks[i]; - *((double *) (result->data +(i*result->strides[0] + result->strides[1]))) = relevances[i]; + pvalues[2*i] = peaks[i]; + pvalues[2*i + 1] = relevances[i]; } - }else{ dimensions [0] = npeaks; - result = (PyArrayObject *) PyArray_SimpleNew(1,dimensions,PyArray_DOUBLE); + result = (PyArrayObject *) PyArray_SimpleNew(1,dimensions,NPY_DOUBLE); + pvalues = (double *) PyArray_DATA(result); for (i=0;i<npeaks;i++){ - /*printf("Peak %ld found at %g\n",i+1,peaks[i]);*/ - *((double *) (result->data +i*result->strides[0])) = peaks[i]; + pvalues[i] = peaks[i]; } } return PyArray_Return(result); @@ -3507,8 +3529,8 @@ SpecfitFuns_interpol(PyObject *self, PyObject *args) npy_intp nd_y, nd_x, index1, *points, *indices, max_points; /*int dimensions[1];*/ npy_intp npoints; - npy_intp dimensions[1]; - npy_intp dim_xinter[1]; + npy_intp dimensions[2]; + npy_intp dim_xinter[2]; double *helppointer; /* statements */ @@ -3517,12 +3539,12 @@ SpecfitFuns_interpol(PyObject *self, PyObject *args) return NULL; } ydata = (PyArrayObject *) - PyArray_CopyFromObject(yinput, PyArray_DOUBLE,0,0); + PyArray_CopyFromObject(yinput, NPY_DOUBLE,0,0); if (ydata == NULL){ printf("Copy from Object error!\n"); return NULL; } - nd_y = ydata->nd; + nd_y = PyArray_NDIM(ydata); if (nd_y == 0) { printf("I need at least a vector!\n"); Py_DECREF(ydata); @@ -3530,7 +3552,7 @@ SpecfitFuns_interpol(PyObject *self, PyObject *args) } /* for (i=0;i<nd_y;i++){ - printf("Dimension %d = %d\n",i,ydata->dimensions[i]); + printf("Dimension %d = %d\n",i,PyArray_DIMS(ydata)[i]); } */ /* xdata parsing */ @@ -3548,11 +3570,11 @@ SpecfitFuns_interpol(PyObject *self, PyObject *args) for (i=0;i<nd_y;i++){ /* printf("i = %d\n",i);*/ /*xdata[i] = (PyArrayObject *) - PyArray_CopyFromObject(yinput,PyArray_DOUBLE,0,0); + PyArray_CopyFromObject(yinput,NPY_DOUBLE,0,0); */ xdata[i] = (PyArrayObject *) PyArray_CopyFromObject((PyObject *) - (PySequence_Fast_GET_ITEM(xinput,i)), PyArray_DOUBLE,0,0); + (PySequence_Fast_GET_ITEM(xinput,i)), NPY_DOUBLE,0,0); if (xdata[i] == NULL){ printf("x Copy from Object error!\n"); for (j=0;j<i;j++){ @@ -3567,13 +3589,13 @@ SpecfitFuns_interpol(PyObject *self, PyObject *args) /* check x dimensions are appropriate */ j=0; for (i=0;i<nd_y;i++){ - nd_x = xdata[i]->nd; + nd_x = PyArray_NDIM(xdata[i]); if (nd_x != 1) { printf("I need a vector!\n"); j++; break; } - if (xdata[i]->dimensions[0] != ydata->dimensions[i]){ + if (PyArray_DIMS(xdata[i])[0] != PyArray_DIMS(ydata)[i]){ printf("xdata[%d] does not have appropriate dimension\n", (int) i); j++; break; @@ -3588,10 +3610,10 @@ SpecfitFuns_interpol(PyObject *self, PyObject *args) return NULL; } - xinter = (PyArrayObject *) PyArray_ContiguousFromObject(xinter0, PyArray_DOUBLE,0,0); + xinter = (PyArrayObject *) PyArray_ContiguousFromObject(xinter0, NPY_DOUBLE,0,0); - if (xinter->nd == 1){ - dim_xinter[0] = xinter->dimensions[0]; + if (PyArray_NDIM(xinter) == 1){ + dim_xinter[0] = PyArray_DIMS(xinter)[0]; dim_xinter[1] = 0; if (dim_xinter[0] != nd_y){ printf("Wrong size\n"); @@ -3604,8 +3626,8 @@ SpecfitFuns_interpol(PyObject *self, PyObject *args) return NULL; } }else{ - dim_xinter[0] = xinter->dimensions[0]; - dim_xinter[1] = xinter->dimensions[1]; + dim_xinter[0] = PyArray_DIMS(xinter)[0]; + dim_xinter[1] = PyArray_DIMS(xinter)[1]; if (dim_xinter[1] != nd_y){ printf("Wrong size\n"); for (j=0;j<nd_y;j++){ @@ -3618,8 +3640,8 @@ SpecfitFuns_interpol(PyObject *self, PyObject *args) } } - npoints = xinter->dimensions[0]; - helppointer = (double *) xinter->data; + npoints = PyArray_DIMS(xinter)[0]; + helppointer = (double *) PyArray_DATA(xinter); /* printf("npoints = %d\n",npoints); printf("ndimensions y = %d\n",nd_y); */ @@ -3637,7 +3659,7 @@ SpecfitFuns_interpol(PyObject *self, PyObject *args) factors = malloc(nd_y * sizeof(double)); dimensions [0] = npoints; - result = (PyArrayObject *) PyArray_SimpleNew(1,dimensions,PyArray_DOUBLE); + result = (PyArrayObject *) PyArray_SimpleNew(1,dimensions,NPY_DOUBLE); for (i=0;i<npoints;i++){ badpoint = 0; @@ -3645,8 +3667,8 @@ SpecfitFuns_interpol(PyObject *self, PyObject *args) index1 = -1; if (badpoint == 0){ value = *helppointer++; - k=xdata[j]->dimensions[0] - 1; - nvalue = (double *) (xdata[j]->data + k * xdata[j]->strides[0]); + k=PyArray_DIMS(xdata[j])[0] - 1; + nvalue = (double *) (PyArray_BYTES(xdata[j]) + k * (PyArray_STRIDES(xdata[j])[0])); /* test against other version valueold = PyFloat_AsDouble( PySequence_Fast_GET_ITEM(PySequence_Fast_GET_ITEM(xinter0,i),j)); @@ -3657,20 +3679,20 @@ SpecfitFuns_interpol(PyObject *self, PyObject *args) if (value > *nvalue){ badpoint = 1; }else{ - nvalue = (double *) (xdata[j]->data); + nvalue = (double *) (PyArray_DATA(xdata[j])); if (value < *nvalue){ badpoint = 1; } } if (badpoint == 0){ if (1){ - k = xdata[j]->dimensions[0]; + k = PyArray_DIMS(xdata[j])[0]; jl = -1; ju = k-1; if (badpoint == 0){ while((ju-jl) > 1){ k = (ju+jl)/2; - nvalue = (double *) (xdata[j]->data + k * xdata[j]->strides[0]); + nvalue = (double *) (PyArray_BYTES(xdata[j]) + k * (PyArray_STRIDES(xdata[j])[0])); if (value >= *nvalue){ jl=k; }else{ @@ -3684,8 +3706,8 @@ SpecfitFuns_interpol(PyObject *self, PyObject *args) if (0){ k=0; ju = -1; - while(k < (xdata[j]->dimensions[0] - 1)){ - nvalue = (double *) (xdata[j]->data + k * xdata[j]->strides[0]); + while(k < (PyArray_DIMS(xdata[j])[0] - 1)){ + nvalue = (double *) (PyArray_BYTES(xdata[j]) + k * (PyArray_STRIDES(xdata[j])[0])); /*printf("nvalue = %g\n",*nvalue);*/ if (value >= *nvalue){ ju = k; @@ -3694,14 +3716,14 @@ SpecfitFuns_interpol(PyObject *self, PyObject *args) } if (ju != index1){ printf("i = %d, j= %d, value = %.5f indexvalue = %d, newvalue = %d\n",\ - (int) i, (int) j,value, (int) ju, (int) index1); + (int) i, (int) j,value, (int) ju, (int) index1); } } if (index1 < 0){ badpoint = 1; }else{ - x1 = (double *) (xdata[j]->data + index1 * xdata[j]->strides[0]); - x2 = (double *) (xdata[j]->data + (index1+1) * xdata[j]->strides[0]); + x1 = (double *) (PyArray_BYTES(xdata[j])+ index1 * (PyArray_STRIDES(xdata[j])[0])); + x2 = (double *) (PyArray_BYTES(xdata[j])+(index1+1) * (PyArray_STRIDES(xdata[j])[0])); factors[j] = (value - *x1) / (*x2 - *x1); indices[j] = index1; } @@ -3738,7 +3760,7 @@ SpecfitFuns_interpol(PyObject *self, PyObject *args) }else{ l = ((nd_y * k) + j); } - offset += points[(nd_y * k) + j] * (ydata -> strides[j]); + offset += points[(nd_y * k) + j] * (PyArray_STRIDES(ydata)[j]); /*printf("factors[%d] = %g\n",j,factors[j]);*/ if ((l % 2) == 0){ dhelp = (1.0 - factors[j]) * dhelp; @@ -3746,10 +3768,10 @@ SpecfitFuns_interpol(PyObject *self, PyObject *args) dhelp = factors[j] * dhelp; } } - yresult += *((double *) (ydata -> data + offset)) * dhelp; + yresult += *((double *) (PyArray_BYTES(ydata) + offset)) * dhelp; } } - *((double *) (result->data +i*result->strides[0])) = yresult; + *((double *) (PyArray_BYTES(result) + i*PyArray_STRIDES(result)[0])) = yresult; } free(points); free(indices); @@ -3800,8 +3822,8 @@ SpecfitFuns_voxelize(PyObject *self, PyObject *args) } grid = (PyArrayObject *) - PyArray_ContiguousFromObject(grid_input, PyArray_NOTYPE,0,0); - switch (grid->descr->type_num){ + PyArray_ContiguousFromObject(grid_input, NPY_NOTYPE,0,0); + switch (PyArray_DESCR(grid)->type_num){ case NPY_DOUBLE: double_flag = 1; break; @@ -3811,12 +3833,12 @@ SpecfitFuns_voxelize(PyObject *self, PyObject *args) Py_DECREF(grid); if (double_flag){ grid = (PyArrayObject *) - PyArray_ContiguousFromObject(grid_input, PyArray_DOUBLE,0,0); + PyArray_ContiguousFromObject(grid_input, NPY_DOUBLE,0,0); } else { grid = (PyArrayObject *) - PyArray_ContiguousFromObject(grid_input, PyArray_FLOAT,0,0); + PyArray_ContiguousFromObject(grid_input, NPY_FLOAT,0,0); } - nd_grid = grid->nd; + nd_grid = PyArray_NDIM(grid); if (nd_grid == 0) { printf("Grid should be at least a vector!\n"); Py_DECREF(grid); @@ -3824,7 +3846,7 @@ SpecfitFuns_voxelize(PyObject *self, PyObject *args) } hits = (PyArrayObject *) - PyArray_ContiguousFromObject(hits_input, PyArray_INT,0,0); + PyArray_ContiguousFromObject(hits_input, NPY_INT,0,0); if (hits == NULL) { Py_DECREF(grid); return NULL; @@ -3846,7 +3868,7 @@ SpecfitFuns_voxelize(PyObject *self, PyObject *args) } ydata = (PyArrayObject *) - PyArray_ContiguousFromObject(yinput, PyArray_DOUBLE,0,0); + PyArray_ContiguousFromObject(yinput, NPY_DOUBLE,0,0); if (ydata == NULL){ printf("Contiguous from object error!\n"); Py_DECREF(grid); @@ -3855,7 +3877,7 @@ SpecfitFuns_voxelize(PyObject *self, PyObject *args) } limits = (PyArrayObject *) - PyArray_ContiguousFromObject(limits_input, PyArray_DOUBLE,0,0); + PyArray_ContiguousFromObject(limits_input, NPY_DOUBLE,0,0); if (limits == NULL){ printf("Limits. Contiguous from object error!\n"); Py_DECREF(grid); @@ -3878,7 +3900,7 @@ SpecfitFuns_voxelize(PyObject *self, PyObject *args) for (i=0;i<nd_grid;i++){ xdata[i] = (PyArrayObject *) PyArray_ContiguousFromObject((PyObject *) - (PySequence_Fast_GET_ITEM(xinput,i)), PyArray_DOUBLE,0,0); + (PySequence_Fast_GET_ITEM(xinput,i)), NPY_DOUBLE,0,0); if (xdata[i] == NULL){ printf("x Copy from Object error!\n"); for (j=0;j<i;j++){ @@ -3911,24 +3933,24 @@ SpecfitFuns_voxelize(PyObject *self, PyObject *args) if (i==0){ delta_index[nd_grid-1] = 1; }else{ - delta_index[nd_grid-1-i] = delta_index[nd_grid-i] * grid->dimensions[nd_grid-i]; + delta_index[nd_grid-1-i] = delta_index[nd_grid-i] * PyArray_DIMS(grid)[nd_grid-i]; } } /* get the number of points in each of the arrays */ npoints = 0; - for (i=0; i<ydata->nd;i++){ + for (i=0; i<PyArray_NDIM(ydata);i++){ if (i==0) - npoints = ydata->dimensions[0]; + npoints = PyArray_DIMS(ydata)[0]; else - npoints *= ydata->dimensions[i]; + npoints *= PyArray_DIMS(ydata)[i]; } /* do the work */ - data_pointer = (double *) ydata->data; - grid_pointerf = (float *) grid->data; - grid_pointerd = (double *) grid->data; - hits_pointer = (int *) hits->data; + data_pointer = (double *) PyArray_DATA(ydata); + grid_pointerf = (float *) PyArray_DATA(grid); + grid_pointerd = (double *) PyArray_DATA(grid); + hits_pointer = (int *) PyArray_DATA(hits); for (i=0;i<npoints;i++){ if (use_datathreshold){ @@ -3938,13 +3960,13 @@ SpecfitFuns_voxelize(PyObject *self, PyObject *args) goodpoint = 1; grid_position = 0; for (j=0; j< nd_grid; j++){ - double_pointer = (double *) xdata[j]->data; + double_pointer = (double *) PyArray_DATA(xdata[j]); value = *(double_pointer+i); - double_pointer = (double *) limits->data; + double_pointer = (double *) PyArray_DATA(limits); limit0 = *(double_pointer+j); limit1 = *(double_pointer+j+nd_grid); - index = (int)(grid->dimensions[j]*(value - limit0)/(limit1-limit0)); - if ((index < 0) || (index >= grid->dimensions[j])) + index = (int)(PyArray_DIMS(grid)[j]*(value - limit0)/(limit1-limit0)); + if ((index < 0) || (index >= PyArray_DIMS(grid)[j])) { /* this point is not going to contribute */ goodpoint = 0; @@ -3993,25 +4015,25 @@ SpecfitFuns_pileup(PyObject *self, PyObject *args) return NULL; x = (PyArrayObject *) - PyArray_CopyFromObject(input1, PyArray_DOUBLE,0,0); + PyArray_CopyFromObject(input1, NPY_DOUBLE,0,0); if (x == NULL) return NULL; - nd_x = x->nd; + nd_x = PyArray_NDIM(x); if(debug !=0) { printf("nd_x = %d\n",nd_x); } if (nd_x == 1) { - dim_x [0] = x->dimensions[0]; + dim_x [0] = PyArray_DIMS(x)[0]; dim_x [1] = 0; }else{ if (nd_x == 0) { dim_x [0] = 0; dim_x [1] = 0; }else{ - dim_x [0] = x->dimensions[0]; - dim_x [1] = x->dimensions[1]; + dim_x [0] = PyArray_DIMS(x)[0]; + dim_x [1] = PyArray_DIMS(x)[1]; } } if(debug !=0) { @@ -4019,7 +4041,7 @@ SpecfitFuns_pileup(PyObject *self, PyObject *args) } /* Create the output array */ - ret = (PyArrayObject *) PyArray_SimpleNew(nd_x, dim_x, PyArray_DOUBLE); + ret = (PyArrayObject *) PyArray_SimpleNew(nd_x, dim_x, NPY_DOUBLE); if (ret == NULL){ Py_DECREF(x); return NULL; @@ -4027,17 +4049,17 @@ SpecfitFuns_pileup(PyObject *self, PyObject *args) PyArray_FILLWBYTE(ret, 0); /* the pointer to the starting position of par data */ - px = (double *) x->data; - pret = (double *) ret->data; + px = (double *) PyArray_DATA(x); + pret = (double *) PyArray_DATA(ret); if(1){ *pret = 0; k = (int )(zero/gain); for (i=input2;i<dim_x[0];i++){ - pall=(double *) x->data; + pall=(double *) PyArray_DATA(x); if ((i+k) >= 0) { - pret = (double *) ret->data+(i+k); + pret = (double *) PyArray_DATA(ret)+(i+k); for (j=0;j<dim_x[0]-i-k;j++){ *pret += *px * (*pall); pall++; @@ -4070,7 +4092,7 @@ SpecfitFuns_SavitskyGolay(PyObject *self, PyObject *args) return NULL; ret = (PyArrayObject *) - PyArray_FROMANY(input, PyArray_DOUBLE, 1, 1, NPY_ENSURECOPY); + PyArray_FROMANY(input, NPY_DOUBLE, 1, 1, NPY_ARRAY_ENSURECOPY); if (ret == NULL){ printf("Cannot create 1D array from input\n"); @@ -4079,7 +4101,7 @@ SpecfitFuns_SavitskyGolay(PyObject *self, PyObject *args) npoints = (int ) dpoints; if (!(npoints % 2)) npoints +=1; - n = (int) ret->dimensions[0]; + n = (int) PyArray_DIMS(ret)[0]; if((npoints < MIN_SAVITSKY_GOLAY_WIDTH) || (n < npoints)) { @@ -4096,7 +4118,7 @@ SpecfitFuns_SavitskyGolay(PyObject *self, PyObject *args) } /* do the job */ - output = (double *) ret->data; + output = (double *) PyArray_DATA(ret); /* simple smoothing at the beginning */ for (j=0; j<=(int)(npoints/3); j++) diff --git a/PyMca/specfit/setup.py b/PyMca/specfit/setup.py index 150bebb..6c4b945 100644 --- a/PyMca/specfit/setup.py +++ b/PyMca/specfit/setup.py @@ -22,7 +22,7 @@ setup ( name = "SpecfitFuns", version = "2.1", description = "fit functions module", - author = "V.A. Sole - BLISS Group", + author = "V.A. Sole - Software Group", author_email = "sole@esrf.fr", url = "http://www.esrf.fr/computing/bliss/", diff --git a/PyMca/specfit/snip1d.c b/PyMca/specfit/snip1d.c index a40633e..73c760b 100644 --- a/PyMca/specfit/snip1d.c +++ b/PyMca/specfit/snip1d.c @@ -1,140 +1,152 @@ -#/*##########################################################################
-# Copyright (C) 2004-2009 European Synchrotron Radiation Facility
-#
-# This file is part of the PyMCA X-ray Fluorescence Toolkit developed at
-# the ESRF by the Beamline Instrumentation Software Support (BLISS) group.
-#
-# This toolkit is free software; you can redistribute it and/or modify it
-# under the terms of the GNU General Public License as published by the Free
-# Software Foundation; either version 2 of the License, or (at your option)
-# any later version.
-#
-# PyMCA is distributed in the hope that it will be useful, but WITHOUT ANY
-# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
-# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
-# details.
-#
-# You should have received a copy of the GNU General Public License along with
-# PyMCA; if not, write to the Free Software Foundation, Inc., 59 Temple Place,
-# Suite 330, Boston, MA 02111-1307, USA.
-#
-# PyMCA follows the dual licensing model of Trolltech's Qt and Riverbank's PyQt
-# and cannot be used as a free plugin for a non-free program.
-#
-# Please contact the ESRF industrial unit (industry@esrf.fr) if this license
-# is a problem for you.
-#############################################################################*/
-/*
- Implementation of the algorithm SNIP in 1D described in
- Miroslav Morhac et al. Nucl. Instruments and Methods in Physics Research A401 (1997) 113-132.
-
- The original idea for 1D and the low-statistics-digital-filter (lsdf) come from
- C.G. Ryan et al. Nucl. Instruments and Methods in Physics Research B34 (1988) 396-402.
-*/
-#include <stdlib.h>
-#include <string.h>
-#include <math.h>
-#define MIN(x, y) (((x) < (y)) ? (x) : (y))
-#define MAX(x, y) (((x) > (y)) ? (x) : (y))
-
-void lls(double *data, int size);
-void lls_inv(double *data, int size);
-void snip1d(double *data, int size, int width);
-void lsdf(double *data, int size, int fwhm, double f, double A, double M, double ratio);
-
-void lls(double *data, int size)
-{
- int i;
- for (i=0; i< size; i++)
- {
- data[i] = log(log(sqrt(data[i]+1.0)+1.0)+1.0);
- }
-}
-
-void lls_inv(double *data, int size)
-{
- int i;
- double tmp;
- for (i=0; i< size; i++)
- {
- /* slightly different than the published formula because
- with the original formula:
-
- tmp = exp(exp(data[i]-1.0)-1.0);
- data[i] = tmp * tmp - 1.0;
-
- one does not recover the original data */
-
- tmp = exp(exp(data[i])-1.0)-1.0;
- data[i] = tmp * tmp - 1.0;
- }
-}
-
-void lsdf(double *data, int size, int fwhm, double f, double A, double M, double ratio)
-{
- int channel, i, j;
- double L, R, S;
- int width;
- double dhelp;
-
- width = (int) (f * fwhm);
- for (channel=width; channel<(size-width); channel++)
- {
- i = width;
- while(i>0)
- {
- L=0;
- R=0;
- for(j=channel-i; j<channel; j++)
- {
- L += data[j];
- }
- for(j=channel+1; j<channel+i; j++)
- {
- R += data[j];
- }
- S = data[channel] + L + R;
- if (S<M)
- {
- data[channel] = S /(2*i+1);
- break;
- }
- dhelp = (R+1)/(L+1);
- if ((dhelp < ratio) && (dhelp > (1/ratio)))
- {
- if (S<(A*sqrt(data[channel])))
- {
- data[channel] = S /(2*i+1);
- break;
- }
- }
- i=i-1;
- }
- }
-}
-
-
-void snip1d(double *data, int size, int width)
-{
- int i;
- int p;
- double *w;
-
- i = (int) (0.5*width);
- /* lsdf(data, size, i, 1.5, 75., 10., 1.3); */
-
- w = (double *) malloc(size * sizeof(double));
-
- for (p=width; p > 0; p--)
- {
- for (i=p; i<(size-p); i++)
- {
- w[i] = MIN(data[i], 0.5*(data[i-p]+data[i+p]));
- }
- for (i=p; i<(size-p); i++)
- {
- data[i] = w[i];
- }
- }
- free(w);
-}
+#/*########################################################################## +# Copyright (C) 2004-2013 European Synchrotron Radiation Facility +# +# This file is part of the PyMCA X-ray Fluorescence Toolkit developed at +# the ESRF by the Beamline Instrumentation Software Support (BLISS) group. +# +# This toolkit is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the Free +# Software Foundation; either version 2 of the License, or (at your option) +# any later version. +# +# PyMCA is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +# details. +# +# You should have received a copy of the GNU General Public License along with +# PyMCA; if not, write to the Free Software Foundation, Inc., 59 Temple Place, +# Suite 330, Boston, MA 02111-1307, USA. +# +# PyMCA follows the dual licensing model of Trolltech's Qt and Riverbank's PyQt +# and cannot be used as a free plugin for a non-free program. +# +# Please contact the ESRF industrial unit (industry@esrf.fr) if this license +# is a problem for you. +#############################################################################*/ +/* + Implementation of the algorithm SNIP in 1D described in + Miroslav Morhac et al. Nucl. Instruments and Methods in Physics Research A401 (1997) 113-132. + + The original idea for 1D and the low-statistics-digital-filter (lsdf) come from + C.G. Ryan et al. Nucl. Instruments and Methods in Physics Research B34 (1988) 396-402. +*/ +#include <stdlib.h> +#include <string.h> +#include <math.h> +#define MIN(x, y) (((x) < (y)) ? (x) : (y)) +#define MAX(x, y) (((x) > (y)) ? (x) : (y)) + +void lls(double *data, int size); +void lls_inv(double *data, int size); +void snip1d(double *data, int n_channels, int snip_width); +void snip1d_multiple(double *data, int n_channels, int snip_width, int n_spectra); +void lsdf(double *data, int size, int fwhm, double f, double A, double M, double ratio); + +void lls(double *data, int size) +{ + int i; + for (i=0; i< size; i++) + { + data[i] = log(log(sqrt(data[i]+1.0)+1.0)+1.0); + } +} + +void lls_inv(double *data, int size) +{ + int i; + double tmp; + for (i=0; i< size; i++) + { + /* slightly different than the published formula because + with the original formula: + + tmp = exp(exp(data[i]-1.0)-1.0); + data[i] = tmp * tmp - 1.0; + + one does not recover the original data */ + + tmp = exp(exp(data[i])-1.0)-1.0; + data[i] = tmp * tmp - 1.0; + } +} + +void lsdf(double *data, int size, int fwhm, double f, double A, double M, double ratio) +{ + int channel, i, j; + double L, R, S; + int width; + double dhelp; + + width = (int) (f * fwhm); + for (channel=width; channel<(size-width); channel++) + { + i = width; + while(i>0) + { + L=0; + R=0; + for(j=channel-i; j<channel; j++) + { + L += data[j]; + } + for(j=channel+1; j<channel+i; j++) + { + R += data[j]; + } + S = data[channel] + L + R; + if (S<M) + { + data[channel] = S /(2*i+1); + break; + } + dhelp = (R+1)/(L+1); + if ((dhelp < ratio) && (dhelp > (1/ratio))) + { + if (S<(A*sqrt(data[channel]))) + { + data[channel] = S /(2*i+1); + break; + } + } + i=i-1; + } + } +} + + +void snip1d(double *data, int n_channels, int snip_width) +{ + snip1d_multiple(data, n_channels, snip_width, 1); +} + +void snip1d_multiple(double *data, int n_channels, int snip_width, int n_spectra) +{ + int i; + int j; + int p; + int offset; + double *w; + + i = (int) (0.5 * snip_width); + /* lsdf(data, size, i, 1.5, 75., 10., 1.3); */ + + w = (double *) malloc(n_channels * sizeof(double)); + + for (j=0; j < n_spectra; j++) + { + offset = j * n_channels; + for (p = snip_width; p > 0; p--) + { + for (i=p; i<(n_channels - p); i++) + { + w[i] = MIN(data[i + offset], 0.5*(data[i + offset - p] + data[ i + offset + p])); + } + for (i=p; i<(n_channels - p); i++) + { + data[i+offset] = w[i]; + } + } + } + free(w); +} diff --git a/PyMca/sps/Src/sps_py.c b/PyMca/sps/Src/sps_py.c index be3cfdc..5114863 100644 --- a/PyMca/sps/Src/sps_py.c +++ b/PyMca/sps/Src/sps_py.c @@ -30,6 +30,9 @@ #include <sps.h> /* #include <stdio.h> */ #include <Python.h> +/* adding next line may raise errors ... +#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION +*/ #include <numpy/arrayobject.h> static PyObject *SPSError; diff --git a/PyMca/sps/Src/spslut_py.c b/PyMca/sps/Src/spslut_py.c index 39eae5b..78c5588 100644 --- a/PyMca/sps/Src/spslut_py.c +++ b/PyMca/sps/Src/spslut_py.c @@ -1,5 +1,5 @@ #/*########################################################################## -# Copyright (C) 2004-2011 European Synchrotron Radiation Facility +# Copyright (C) 2004-2013 European Synchrotron Radiation Facility # # This file is part of the PyMCA X-ray Fluorescence Toolkit developed at # the ESRF by the Beamline Instrumentation Software Support (BLISS) group. @@ -50,6 +50,9 @@ */ #include <stdio.h> #include <Python.h> +/* +#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION +*/ #include <numpy/arrayobject.h> #include <sps_lut.h> @@ -172,11 +175,11 @@ static PyObject *spslut_transform(PyObject *self, PyObject *args) } if (!(src = (PyArrayObject*) PyArray_ContiguousFromObject(in_src, - PyArray_NOTYPE, 2, 2))) { + NPY_NOTYPE, 2, 2))) { onError("Input Array is not a 2x2 array"); } - switch (src->descr->type_num) { + switch (PyArray_DESCR(src)->type_num) { case NPY_UINT: type = SPS_UINT; break; case NPY_ULONG: @@ -201,9 +204,9 @@ static PyObject *spslut_transform(PyObject *self, PyObject *args) onError("Input Array type not supported"); } - data = src->data; - cols = (int) src->dimensions[1]; /*FIX THIS cols and rows are turned around */ - rows = (int) src->dimensions[0]; /*###CHANGED - ALEXANDRE 24/07/2001*/ + data = PyArray_DATA(src); + cols = (int) PyArray_DIMS(src)[1]; /*FIX THIS cols and rows are turned around */ + rows = (int) PyArray_DIMS(src)[0]; /*###CHANGED - ALEXANDRE 24/07/2001*/ @@ -234,7 +237,7 @@ static PyObject *spslut_transform(PyObject *self, PyObject *args) Py_DECREF(src); return NULL; } - as_pointer = (char *) as_aux -> data; + as_pointer = (char *) PyArray_DATA(as_aux); as_r = (char *) r; memcpy(as_pointer, as_r, as_dim[0] * as_dim[1]); @@ -307,11 +310,11 @@ static PyObject *spslut_transformarray(PyObject *self, PyObject *args) } if (!(src = (PyArrayObject*) PyArray_ContiguousFromObject(in_src, - PyArray_NOTYPE, 2, 2))) { + NPY_NOTYPE, 2, 2))) { onError("spslut.transformarray: Input Array is not a 2x2 array"); } - switch (src->descr->type_num) { + switch (PyArray_DESCR(src)->type_num) { case NPY_ULONG: type = SPS_ULONG; break; case NPY_UINT: @@ -336,9 +339,9 @@ static PyObject *spslut_transformarray(PyObject *self, PyObject *args) onError("Input Array type not supported"); } - data = src->data; - cols = (int) src->dimensions[1]; /*FIX THIS cols and rows are turned around */ - rows = (int) src->dimensions[0]; /*###CHANGED - ALEXANDRE 24/07/2001*/ + data = PyArray_DATA(src); + cols = (int) PyArray_DIMS(src); /*FIX THIS cols and rows are turned around */ + rows = (int) PyArray_DIMS(src); /*###CHANGED - ALEXANDRE 24/07/2001*/ r = SPS_PaletteArray (data, type, cols, rows, reduc, fastreduc, meth, gamma, autoscale, mapmin, mapmax, Xservinfo, palette_code, @@ -350,13 +353,13 @@ static PyObject *spslut_transformarray(PyObject *self, PyObject *args) as_dim[0] = strlen(mode); as_dim[1] = prows * pcols; /* printf("dim[0] = %d dim[1] = %d \"%s\" \n",as_dim[0],as_dim[1],mode); */ - aux = (PyArrayObject*) PyArray_SimpleNew(2, as_dim, PyArray_CHAR); + aux = (PyArrayObject*) PyArray_SimpleNew(2, as_dim, NPY_CHAR); if (aux == NULL){ free(r); Py_DECREF(src); return NULL; } - as_pointer = (char *) aux -> data; + as_pointer = (char *) PyArray_DATA(aux); as_r = (char *) r; memcpy(as_pointer, as_r, as_dim[0] * as_dim[1]); free(r); diff --git a/changelog.txt b/changelog.txt index a324727..0ab07cb 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,3 +1,17 @@ +VERSION 4.7.1 + +Support SOLEIL multiple-file different-scan-number maps. + +Support batch fitting of multiple HDF5 files. + +Fast XRF linear fit stack plugin. + +Possibility to load image shifts in the image alignment stack plugin. + +Basic support of MRC file format. + +Add ID08 advanced alignment scan plugin. + VERSION 4.7.0 Add basic support for calculating multiple excitation corrections via the diff --git a/cx_setup.py b/cx_setup.py index 377ba3a..76b0192 100644 --- a/cx_setup.py +++ b/cx_setup.py @@ -1,3 +1,23 @@ +# +# These Python module have been developed by V.A. Sole, from the European +# Synchrotron Radiation Facility (ESRF) to build a frozen version of PyMca. +# Given the nature of this work, these module can be considered public domain. +# Therefore redistribution and use in source and binary forms, with or without +# modification, are permitted provided the following disclaimer is accepted: +# +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) AND THE ESRF ``AS IS'' AND ANY +# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) AND/OR THE ESRF BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# + # A cx_freeze setup script to create PyMca executables # # Use "python cx_setup.py install" diff --git a/py2app_setup.py b/py2app_setup.py index 6b31ed6..63fd69e 100755 --- a/py2app_setup.py +++ b/py2app_setup.py @@ -1,3 +1,22 @@ +# +# These Python module have been developed by V.A. Sole, from the European +# Synchrotron Radiation Facility (ESRF) to build a frozen version of PyMca. +# Given the nature of this work, these module can be considered public domain. +# Therefore redistribution and use in source and binary forms, with or without +# modification, are permitted provided the following disclaimer is accepted: +# +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) AND THE ESRF ``AS IS'' AND ANY +# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) AND/OR THE ESRF BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# """ Script for building the PyMca bundle. For a distributable application Platypus is needed diff --git a/scripts/pymca_win_post_install.py b/scripts/pymca_win_post_install.py index 363282a..39c7ed2 100644 --- a/scripts/pymca_win_post_install.py +++ b/scripts/pymca_win_post_install.py @@ -1,4 +1,29 @@ #!python +# +# Copyright (C) 2004-2013 V. Armando Sole - ESRF +# +# Permission is hereby granted, free of charge, to any person +# obtaining a copy of this software and associated documentation +# files (the "Software"), to deal in the Software without +# restriction, including without limitation the rights to use, +# copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following +# conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +# OTHER DEALINGS IN THE SOFTWARE. +# +__license__ = "MIT" """Windows-specific part of the installation""" import os, sys, shutil @@ -106,5 +131,5 @@ if len(sys.argv) > 1: elif sys.argv[1] in ['-remove', 'remove']: remove() else: - print "Script was called with option %s" % sys.argv[1] - print "It has to be called with option -install or -remove" + print("Script was called with option %s" % sys.argv[1]) + print("It has to be called with option -install or -remove") @@ -1,3 +1,22 @@ +# +# This Python module has been developed by V.A. Sole, from the European +# Synchrotron Radiation Facility (ESRF) to build PyMca. +# Given the nature of this work, these module can be considered public domain. +# Therefore redistribution and use in source and binary forms, with or without +# modification, are permitted provided the following disclaimer is accepted: +# +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) AND THE ESRF ``AS IS'' AND ANY +# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) AND/OR THE ESRF BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# import sys,os import glob import platform @@ -214,17 +233,26 @@ def build_Object3DCTools(ext_modules): include_dirs = includes) ext_modules.append(module) -def build_Object3DQhull(ext_modules): + +def build_Object3DQhull(extensions): if sys.platform == "win32": libraries = ['opengl32', 'glu32'] + elif sys.platform == "darwin": + libraries = [] else: - libraries = ['GL', 'GLU'] - module = Extension(name = 'PyMca.Object3D.Object3DQhull', - sources = glob.glob('PyMca/Object3D/Object3DQhull/src/*.c'), - define_macros = define_macros, - include_dirs = [numpy.get_include()]) + libraries = ['GL', 'GLU'] + sources = ["PyMca/Object3D/Object3DQhull/Object3DQhull.c"] + sources += glob.glob("third-party/qhull/src/*.c") + + module = Extension(name='PyMca.Object3D.Object3DQhull', + sources=sources, + define_macros=define_macros, + libraries=libraries, + include_dirs=[numpy.get_include(), + "third-party/qhull/src"]) + + extensions.append(module) - ext_modules.append(module) def build_PyMcaSciPy(ext_modules): packages.append('PyMca.PyMcaSciPy') @@ -550,6 +578,40 @@ description = "Mapping and X-Ray Fluorescence Analysis" long_description = """Stand-alone application and Python tools for interactive and/or batch processing analysis of X-Ray Fluorescence Spectra. Graphical user interface (GUI) and batch processing capabilities provided """ +####################### +# build_doc commands # +####################### + +try: + import sphinx + import sphinx.util.console + sphinx.util.console.color_terminal = lambda: False + from sphinx.setup_command import BuildDoc +except: + sphinx = None + +if sphinx: + class build_doc(BuildDoc): + + def run(self): + + # make sure the python path is pointing to the newly built + # code so that the documentation is built on this and not a + # previously installed version + + build = self.get_finalized_command('build') + sys.path.insert(0, os.path.abspath(build.build_lib)) + + # Build the Users Guide in HTML and TeX format + for builder in ('html', 'latex'): + self.builder = builder + self.builder_target_dir = os.path.join(self.build_dir, builder) + self.mkpath(self.builder_target_dir) + builder_index = 'index_{0}.txt'.format(builder) + BuildDoc.run(self) + sys.path.pop(0) + cmdclass['build_doc'] = build_doc + distrib = setup(name="PyMca", version= __version__, description = description, |