7 #include "PlusConfigure.h" 12 #include "vtkMatrix4x4.h" 13 #include "vtkModifiedBSPTree.h" 14 #include "vtkObjectFactory.h" 15 #include "vtkSTLReader.h" 16 #include "vtkXMLPolyDataReader.h" 17 #include "vtkPolyDataNormals.h" 18 #include "vtkProbeFilter.h" 19 #include "vtkPointData.h" 20 #include "vtkIdList.h" 21 #include "vtkTriangle.h" 33 , ModelFileNeedsUpdate(false)
34 , ModelToObjectTransform(vtkMatrix4x4::New())
35 , ReferenceToObjectTransform(vtkMatrix4x4::New())
36 , ObjectCoordinateFrame(
"")
37 , ImagingFrequencyMhz(5.0)
39 , SoundVelocityMPerSec(1540)
40 , AttenuationCoefficientDbPerCmMhz(0.65)
41 , SurfaceReflectionIntensityDecayDbPerMm(20)
42 , BackscatterDiffuseReflectionCoefficient(0.1)
43 , TransducerSpatialModelMaxOverlapMm(10.0)
44 , SurfaceSpecularReflectionCoefficient(0.0)
45 , SurfaceDiffuseReflectionCoefficient(0.1)
46 , ModelLocalizer(vtkModifiedBSPTree::New())
185 XML_VERIFY_ELEMENT(spatialModelElement,
"SpatialModel");
187 XML_READ_STRING_ATTRIBUTE_OPTIONAL(
Name, spatialModelElement);
189 XML_READ_STRING_ATTRIBUTE_OPTIONAL(
ModelFile, spatialModelElement);
191 XML_READ_SCALAR_ATTRIBUTE_OPTIONAL(
double,
DensityKgPerM3, spatialModelElement);
207 return acousticImpedanceRayls * 1e-6;
211 void PlusSpatialModel::CalculateIntensity(std::vector<double>& reflectedIntensity,
unsigned int numberOfFilledPixels,
double distanceBetweenScanlineSamplePointsMm,
double previousModelAcousticImpedanceMegarayls,
double incidentIntensity,
double& transmittedIntensity,
double incidenceAngleRad)
215 if (numberOfFilledPixels <= 0)
217 transmittedIntensity = incidentIntensity;
222 if (reflectedIntensity.size() < numberOfFilledPixels)
224 reflectedIntensity.resize(numberOfFilledPixels);
230 double intensityReflectionCoefficient =
231 (previousModelAcousticImpedanceMegarayls - acousticImpedanceMegarayls) * (previousModelAcousticImpedanceMegarayls - acousticImpedanceMegarayls)
232 / (previousModelAcousticImpedanceMegarayls + acousticImpedanceMegarayls) / (previousModelAcousticImpedanceMegarayls + acousticImpedanceMegarayls);
233 double surfaceReflectedBeamIntensity = incidentIntensity * intensityReflectionCoefficient;
234 double surfaceTransmittedBeamIntensity = incidentIntensity - surfaceReflectedBeamIntensity;
242 if (incidenceAngleRad > vtkMath::Pi() / 2)
244 incidenceAngleRad -= vtkMath::Pi();
246 else if (incidenceAngleRad < -vtkMath::Pi() / 2)
248 incidenceAngleRad += vtkMath::Pi();
251 float reflectionDirectionFactor = exp(-(incidenceAngleRad * incidenceAngleRad) / (stdev * stdev));
258 double intensityAttenuationCoefficientPerPixel = pow(10.0, -intensityAttenuationCoefficientdBPerPixel / 10.0);
260 double intensityAttenuatedFractionPerPixel = (1 - intensityAttenuationCoefficientPerPixel);
262 double intensityTransmittedFractionPerPixelTwoWay = intensityAttenuationCoefficientPerPixel * intensityAttenuationCoefficientPerPixel;
264 transmittedIntensity = surfaceTransmittedBeamIntensity * intensityTransmittedFractionPerPixelTwoWay;
273 unsigned int numberOfIterationsToReachMinimumBeamIntensity = 0;
276 numberOfIterationsToReachMinimumBeamIntensity =
277 std::min<unsigned int>(numberOfFilledPixels,
278 static_cast<unsigned int>(std::max<int>(0,
279 floor(log(
MINIMUM_BEAM_INTENSITY / transmittedIntensity) / log(intensityTransmittedFractionPerPixelTwoWay)) + 1)));
281 for (
unsigned int currentPixelInFilledPixels = 0; currentPixelInFilledPixels < numberOfIterationsToReachMinimumBeamIntensity; currentPixelInFilledPixels++)
285 reflectedIntensity[currentPixelInFilledPixels] = this->
PrecomputedAttenuations[currentPixelInFilledPixels] * backScatterFactor;
287 transmittedIntensity *= pow(intensityTransmittedFractionPerPixelTwoWay, static_cast<double>(numberOfIterationsToReachMinimumBeamIntensity));
291 transmittedIntensity = 0;
294 for (
unsigned int currentPixelInFilledPixels = numberOfIterationsToReachMinimumBeamIntensity; currentPixelInFilledPixels < numberOfFilledPixels; currentPixelInFilledPixels++)
296 reflectedIntensity[currentPixelInFilledPixels] = 0.0;
305 int numberOfIterationsToReachMinimumBackscatteredIntensity = std::min<int>(numberOfFilledPixels, floor(log(
MINIMUM_BEAM_INTENSITY / backscatteredReflectedIntensity) / log(surfaceReflectionIntensityDecayPerPixel)) + 1);
306 for (
int currentPixelInFilledPixels = 0; currentPixelInFilledPixels < numberOfIterationsToReachMinimumBackscatteredIntensity; currentPixelInFilledPixels++)
309 reflectedIntensity[currentPixelInFilledPixels] += backscatteredReflectedIntensity;
310 backscatteredReflectedIntensity *= surfaceReflectionIntensityDecayPerPixel;
326 intersectionInfo.
Model =
this;
329 lineIntersections.push_back(intersectionInfo);
334 double scanLineDirectionVector_Reference[4] =
336 scanLineEndPoint_Reference[0] - scanLineStartPoint_Reference[0],
337 scanLineEndPoint_Reference[1] - scanLineStartPoint_Reference[1],
338 scanLineEndPoint_Reference[2] - scanLineStartPoint_Reference[2],
341 double scanLineDirectionVectorNorm_Reference = vtkMath::Norm(scanLineDirectionVector_Reference);
342 double searchLineStartPoint_Reference[4] = {0, 0, 0, 1};
343 for (
int i = 0;
i < 3;
i++)
345 searchLineStartPoint_Reference[
i] = scanLineStartPoint_Reference[
i] - this->
TransducerSpatialModelMaxOverlapMm * scanLineDirectionVector_Reference[
i] / scanLineDirectionVectorNorm_Reference;
348 vtkSmartPointer<vtkMatrix4x4> objectToModelMatrix = vtkSmartPointer<vtkMatrix4x4>::New();
350 vtkSmartPointer<vtkMatrix4x4> referenceToModelMatrix = vtkSmartPointer<vtkMatrix4x4>::New();
353 double searchLineStartPoint_Model[4] = {0, 0, 0, 1};
354 double scanLineEndPoint_Model[4] = {0, 0, 0, 1};
355 referenceToModelMatrix->MultiplyPoint(searchLineStartPoint_Reference, searchLineStartPoint_Model);
356 referenceToModelMatrix->MultiplyPoint(scanLineEndPoint_Reference, scanLineEndPoint_Model);
358 vtkSmartPointer<vtkPoints> intersectionPoints_Model = vtkSmartPointer<vtkPoints>::New();
359 vtkSmartPointer<vtkIdList> intersectionCellIds = vtkSmartPointer<vtkIdList>::New();
360 this->
ModelLocalizer->IntersectWithLine(searchLineStartPoint_Model, scanLineEndPoint_Model, 0.0, intersectionPoints_Model, intersectionCellIds);
362 if (intersectionPoints_Model->GetNumberOfPoints() < 1)
368 vtkSmartPointer<vtkMatrix4x4> modelToReferenceMatrix = vtkSmartPointer<vtkMatrix4x4>::New();
369 vtkMatrix4x4::Invert(referenceToModelMatrix, modelToReferenceMatrix);
372 double intersectionPoint_Model[4] = {0, 0, 0, 1};
373 double intersectionPoint_Reference[4] = {0, 0, 0, 1};
374 int intersectionPointIndex = 0;
375 bool scanLineStartPointInsideModel =
false;
378 for (; intersectionPointIndex < intersectionPoints_Model->GetNumberOfPoints(); intersectionPointIndex++)
380 intersectionPoints_Model->GetPoint(intersectionPointIndex, intersectionPoint_Model);
381 modelToReferenceMatrix->MultiplyPoint(intersectionPoint_Model, intersectionPoint_Reference);
382 double intersectionDistanceFromSearchLineStartPointMm = sqrt(vtkMath::Distance2BetweenPoints(searchLineStartPoint_Reference, intersectionPoint_Reference));
386 scanLineStartPointInsideModel = (!scanLineStartPointInsideModel);
395 intersectionInfo.
Model =
this;
396 if (scanLineStartPointInsideModel)
400 lineIntersections.push_back(intersectionInfo);
404 vtkDataArray* normals_Model = NULL;
407 normals_Model = this->
PolyData->GetPointData()->GetNormals();
410 double scanLineDirectionVector_Model[4] = {0, 0, 0, 0};
411 referenceToModelMatrix->MultiplyPoint(scanLineDirectionVector_Reference, scanLineDirectionVector_Model);
412 vtkMath::Normalize(scanLineDirectionVector_Model);
414 for (; intersectionPointIndex < intersectionPoints_Model->GetNumberOfPoints(); intersectionPointIndex++)
416 intersectionPoints_Model->GetPoint(intersectionPointIndex, intersectionPoint_Model);
417 modelToReferenceMatrix->MultiplyPoint(intersectionPoint_Model, intersectionPoint_Reference);
419 vtkTriangle* cell = vtkTriangle::SafeDownCast(this->
PolyData->GetCell(intersectionCellIds->GetId(intersectionPointIndex)));
420 if (cell != NULL && normals_Model != NULL)
422 const int NUMBER_OF_POINTS_PER_CELL = 3;
423 double pcoords[NUMBER_OF_POINTS_PER_CELL] = {0, 0, 0};
425 double weights[NUMBER_OF_POINTS_PER_CELL] = {0, 0, 0};
426 double closestPoint[3] = {0, 0, 0};
428 cell->EvaluatePosition(intersectionPoint_Model, closestPoint, subId, pcoords, dist2, weights);
429 double interpolatedNormal_Model[3] = {0, 0, 0};
430 for (
int pointIndex = 0; pointIndex < NUMBER_OF_POINTS_PER_CELL; pointIndex++)
432 double* normalAtCellCorner = normals_Model->GetTuple3(cell->GetPointId(pointIndex));
433 if (normalAtCellCorner == NULL)
435 LOG_ERROR(
"SpatialModel::GetLineIntersections error: invalid normal");
438 interpolatedNormal_Model[0] += normalAtCellCorner[0] * weights[pointIndex];
439 interpolatedNormal_Model[1] += normalAtCellCorner[1] * weights[pointIndex];
440 interpolatedNormal_Model[2] += normalAtCellCorner[2] * weights[pointIndex];
442 vtkMath::Normalize(interpolatedNormal_Model);
447 LOG_ERROR(
"SpatialModel::GetLineIntersections error: surface normal is not available");
450 lineIntersections.push_back(intersectionInfo);
472 LOG_DEBUG(
"ModelFileName is not specified for SpatialModel " << (this->
Name.empty() ?
"(undefined)" : this->
Name) <<
" it will be used as background media");
476 std::string foundAbsoluteImagePath;
481 LOG_ERROR(
"Cannot find input model file " << this->
ModelFile);
485 vtkSmartPointer<vtkPolyData> polyData;
487 std::string fileExt = vtksys::SystemTools::GetFilenameLastExtension(foundAbsoluteImagePath);
488 if (igsioCommon::IsEqualInsensitive(fileExt,
".stl"))
490 vtkSmartPointer<vtkSTLReader> modelReader = vtkSmartPointer<vtkSTLReader>::New();
491 modelReader->SetFileName(foundAbsoluteImagePath.c_str());
492 modelReader->Update();
493 polyData = modelReader->GetOutput();
497 vtkSmartPointer<vtkXMLPolyDataReader> modelReader = vtkSmartPointer<vtkXMLPolyDataReader>::New();
498 modelReader->SetFileName(foundAbsoluteImagePath.c_str());
499 modelReader->Update();
500 polyData = modelReader->GetOutput();
503 if (polyData.GetPointer() == NULL || polyData->GetNumberOfPoints() == 0)
505 LOG_ERROR(
"Model specified cannot be found: " << foundAbsoluteImagePath);
509 vtkSmartPointer<vtkPolyDataNormals> polyDataNormalsComputer = vtkSmartPointer<vtkPolyDataNormals>::New();
510 polyDataNormalsComputer->SetInputData(polyData);
511 polyDataNormalsComputer->Update();
512 this->
PolyData = polyDataNormalsComputer->GetOutput();
526 if (this->
ModelFile.compare(modelFile) != 0)
537 double attenuation = intensityTransmittedFractionPerPixelTwoWay;
538 for (
int i = 0;
i < numberOfElements;
i++)
541 attenuation *= intensityTransmittedFractionPerPixelTwoWay;
vtkMatrix4x4 * ReferenceToObjectTransform
void SetModelLocalizer(vtkModifiedBSPTree *modelLocalizer)
double IntersectionDistanceFromStartPointMm
virtual PlusStatus ReadConfiguration(vtkXMLDataElement *spatialModelElement)
void SetReferenceToObjectTransform(vtkMatrix4x4 *referenceToObjectTransform)
vtkMatrix4x4 * ModelToObjectTransform
double SurfaceReflectionIntensityDecayDbPerMm
double ImagingFrequencyMhz
double SoundVelocityMPerSec
const double MINIMUM_BEAM_INTENSITY
static vtkPlusConfig * GetInstance()
double BackscatterDiffuseReflectionCoefficient
double AttenuationCoefficientDbPerCmMhz
void SetModelFile(const std::string &modelFile)
double SurfaceSpecularReflectionCoefficient
void CalculateIntensity(std::vector< double > &reflectedIntensity, unsigned int numberOfFilledPixels, double distanceBetweenScanlineSamplePointsMm, double previousModelAcousticImpedanceMegarayls, double incidentIntensity, double &transmittedIntensity, double incidenceAngleRad)
std::string ObjectCoordinateFrame
double SPECULAR_REFLECTION_BRDF_STDEV
void UpdatePrecomputedAttenuations(double intensityTransmittedFractionPerPixelTwoWay, int numberOfElements)
void SetPolyData(vtkPolyData *polyData)
double SurfaceDiffuseReflectionCoefficient
double IntersectionIncidenceAngleRad
void operator=(const PlusSpatialModel &model)
double TransducerSpatialModelMaxOverlapMm
PlusStatus UpdateModelFile()
vtkModifiedBSPTree * ModelLocalizer
virtual ~PlusSpatialModel()
std::vector< double > PrecomputedAttenuations
void GetLineIntersections(std::deque< LineIntersectionInfo > &lineIntersections, double *scanLineStartPoint_Reference, double *scanLineEndPoint_Reference)
void SetModelToObjectTransform(vtkMatrix4x4 *modelToObjectTransform)
bool ModelFileNeedsUpdate
double GetAcousticImpedanceMegarayls()