diff --git a/.appveyor.yml b/.appveyor.yml new file mode 100644 index 0000000000..376070813d --- /dev/null +++ b/.appveyor.yml @@ -0,0 +1,20 @@ +version: 1.0.{build} +branches: + only: + - dev +image: Visual Studio 2017 +clone_depth: 1 +environment: + QT5: C:\Qt\5.10.1\msvc2017_64 +configuration: Release +build_script: +- cmd: >- + mkdir cmakebuild + + cd cmakebuild + + if exist "%QT5%" set Path=%QT5%\bin;%Path% + + cmake -G "Visual Studio 15 2017 Win64" -DCMAKE_BUILD_TYPE=Release -DRESINSIGHT_BUILD_WITH_QT5=true -DRESINSIGHT_ENABLE_COTIRE=on "-DCMAKE_PREFIX_PATH=%QT5%" .. + + cmake --build . --target ResInsight_unity --config Release \ No newline at end of file diff --git a/.clang-tidy b/.clang-tidy index 390f03e959..8348d93169 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -1,5 +1,5 @@ --- -Checks: '-*,modernize-use-nullptr,modernize-use-override' +Checks: '-*,modernize-use-nullptr,modernize-use-override,modernize-deprecated-headers' HeaderFilterRegex: '' AnalyzeTemporaryDtors: false ... diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 0000000000..b1fd9845b5 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,27 @@ +--- +name: Bug report +about: Create a report to help us improve +title: '' +labels: Bug +assignees: '' + +--- + +**Describe the bug** +A clear and concise description of what the bug is. + +**To Reproduce** +Steps to reproduce the behavior: +1. Go to '...' +2. Click on '....' +3. Scroll down to '....' +4. See error + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Screenshots** +If applicable, add screenshots to help explain your problem. + +**Additional context** +Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/enhancement.md b/.github/ISSUE_TEMPLATE/enhancement.md new file mode 100644 index 0000000000..c121801e24 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/enhancement.md @@ -0,0 +1,10 @@ +--- +name: Enhancement +about: Describe enhancement. +title: 'Context : EnhancementName' +labels: Enhancement +assignees: '' + +--- + + diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 0000000000..b80a526ea0 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,20 @@ +--- +name: Feature request +about: Suggest an idea for this project +title: '' +labels: FeatureRequest +assignees: '' + +--- + +**Is your feature request related to a problem? Please describe.** +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +**Describe the solution you'd like** +A clear and concise description of what you want to happen. + +**Describe alternatives you've considered** +A clear and concise description of any alternative solutions or features you've considered. + +**Additional context** +Add any other context or screenshots about the feature request here. diff --git a/ApplicationCode/Adm/RiaVersionInfo.h.cmake b/ApplicationCode/Adm/RiaVersionInfo.h.cmake index f140fde60c..c638ee4fd7 100644 --- a/ApplicationCode/Adm/RiaVersionInfo.h.cmake +++ b/ApplicationCode/Adm/RiaVersionInfo.h.cmake @@ -26,3 +26,5 @@ // Externally shipped versions should have even build numbers #define PRODUCTVER "@PRODUCTVER@" #define STRPRODUCTVER "@STRPRODUCTVER@" + +#define RESINSIGHT_OCTAVE_VERSION "@OCTAVE_VERSION_STRING@" diff --git a/ApplicationCode/Adm/projectfilekeywords/2018.11/ri-fieldKeywords.txt b/ApplicationCode/Adm/projectfilekeywords/2018.11/ri-fieldKeywords.txt new file mode 100644 index 0000000000..b30a5f18e9 --- /dev/null +++ b/ApplicationCode/Adm/projectfilekeywords/2018.11/ri-fieldKeywords.txt @@ -0,0 +1,2315 @@ +// ResInsight version string : 2018.11.0-dev +// Report generated : Wed 28. Nov 12:29:03 2018 +// +// + +AsciiDataCurve - class RimAsciiDataCurve + Show + CurveName + CurveDescription + AutoName + Color + Thickness + CurveInterpolation + LineStyle + PointSymbol + SymbolSkipPxDist + ShowLegend + SymbolSize + ShowErrorBars + PlotAxis + TimeSteps + Values + Title + +CalcScript - class RimCalcScript + AbsolutePath + Content + +CalculatedSummaryCase - class RimCalculatedSummaryCase + ShortName + AutoShortyName + SummaryHeaderFilename + +CellEdgeResultSlot - class RimCellEdgeColors + EnableCellEdgeColors + propertyType + CellEdgeVariable + UseXVariable + UseYVariable + UseZVariable + LegendDefinition + SingleVarEdgeResult + +CellFilter - class RimCellFilter + UserDescription + Active + FilterType + +CellPropertyFilter - class RimEclipsePropertyFilter + UserDescription + Active + FilterType + SelectedValues + EvaluationRegion + ResultDefinition + Dummy_keyword + LowerBound + UpperBound + CategorySelection + +CellPropertyFilters - class RimEclipsePropertyFilterCollection + Active + PropertyFilters + +CellRangeFilter - class RimCellRangeFilter + UserDescription + Active + FilterType + GridIndex + PropagateToSubGrids + StartIndexI + CellCountI + StartIndexJ + CellCountJ + StartIndexK + CellCountK + UseIndividualCellIndices + IndividualCellIndices + +CellRangeFilterCollection - class RimCellRangeFilterCollection + RangeFilters + Active + +ChangeDataSourceFeatureUi - class RimWellLogCurveCommonDataSource + CurveCase + TrajectoryType + CurveWellPath + SimulationWellName + BranchDetection + Branch + CurveTimeStep + +CmdAddItemExecData - class caf::CmdAddItemExecData + PathToField + indexAfter + createdItemIndex + +CmdDeleteItemExecData - class caf::CmdDeleteItemExecData + PathToField + indexToObject + deletedObjectAsXml + +CmdFieldChangeExecData - class caf::CmdFieldChangeExecData + PathToField + +CrossSection - class RimIntersection + UserDescription + Active + Type + Direction + WellPath + SimulationWell + Points + AzimuthAngle + DipAngle + CustomExtrusionPoints + TwoAzimuthPoints + Branch + ExtentLength + lengthUp + lengthDown + ShowInactiveCells + m_activateUiAppendPointsCommand + inputExtrusionPointsFromViewerEnabled + inputTwoAzimuthPointsFromViewerEnabled + +CrossSectionCollection - class RimIntersectionCollection + CrossSections + IntersectionBoxes + Active + +Eclipse2dViewCollection - class RimContourMapViewCollection + EclipseViews + +EclipseCase - class RimEclipseResultCase + CaseUserDescription + CaseId + DefaultFormationNames + TimeStepFilter + IntersectionViewCollection + ReservoirViews + MatrixModelResults + FractureModelResults + FlipXAxis + FlipYAxis + CachedFileNamesContainingFaults + ContourMaps + FilesContainingFaults + CaseName + CaseFileName + UnitSystem + FlowDiagSolutions + CaseFolder + SourSimFileName + +EclipseGeometrySelectionItem - class RimEclipseGeometrySelectionItem + EclipseCase + GridIndex + CellIndex + LocalIntersectionPoint + +Fault - class RimFaultInView + FaultName + ShowFault + Color + +Faults - class RimFaultInViewCollection + Active + ShowFaultFaces + ShowOppositeFaultFaces + ShowFaultsOutsideFilters + FaultFaceCulling + ShowFaultLabel + FaultLabelColor + ShowNNCs + HideNncsWhenNoResultIsAvailable + NoCommonAreaNnncCollection + Faults + +FileSummaryCase - class RimFileSummaryCase + ShortName + AutoShortyName + SummaryHeaderFilename + IncludeRestartFiles + +FishbonesCollection - class RimFishbonesCollection + Name + IsChecked + FishbonesSubs + WellPathCollection + StartMD + MainBoreDiameter + MainBoreSkinFactor + MswParameters + LinerDiameter + RoughnessFactor + PressureDrop + LengthAndDepth + +FishbonesMultipleSubs - class RimFishbonesMultipleSubs + Active + Name + Color + LateralCountPerSub + LateralLength + LateralExitAngle + LateralBuildAngle + LateralTubingDiameter + LateralOpenHoleRoghnessFactor + LateralTubingRoghnessFactor + LateralInstallSuccessFraction + IcdCount + IcdOrificeDiameter + IcdFlowCoefficient + SubsLocationMode + RangeStart + RangeEnd + RangeSubSpacing + RangeSubCount + LocationOfSubs + ValveLocations + SubsOrientationMode + InstallationRotationAngles + FixedInstallationRotationAngle + PipeProperties + +FishbonesPipeProperties - class RimFishbonesPipeProperties + LateralHoleDiameter + SkinFactor + +FlowCharacteristicsPlot - class RimFlowCharacteristicsPlot + WindowController + ShowWindow + WindowGeometry + FlowCase + FlowDiagSolution + TimeSelectionType + SelectedTimeSteps + SelectedTimeStepsUi + ApplyTimeSteps + CellPVThreshold + ShowLegend + CellFilter + CellFilterView + TracerFilter + SelectedTracerNames + ShowRegion + MinCommunication + MaxTof + +FlowDiagSolution - class RimFlowDiagSolution + UserDescription + +FlowPlotCollection - class RimFlowPlotCollection + FlowCharacteristicsPlot + DefaultWellAllocationPlot + StoredWellAllocationPlots + StoredFlowCharacteristicsPlots + +FormationNames - class RimFormationNames + FormationNamesFileName + +FormationNamesCollectionObject - class RimFormationNamesCollection + FormationNamesList + +FractureContainment - class RimFractureContainment + IsUsingFractureContainment + TopKLayer + BaseKLayer + TruncateAtFaults + FaultThrowValue + +FractureDefinitionCollection - class RimFractureTemplateCollection + DefaultUnitForTemplates + FractureDefinitions + NextValidFractureTemplateId + +GeoMechGeometrySelectionItem - class RimGeoMechGeometrySelectionItem + GeoMechCase + m_gridIndex + m_cellIndex + m_elementFace + m_hasIntersectionTriangle + m_intersectionTriangle_0 + m_intersectionTriangle_1 + m_intersectionTriangle_2 + m_localIntersectionPoint + +GeoMechPropertyFilter - class RimGeoMechPropertyFilter + UserDescription + Active + FilterType + SelectedValues + ResultDefinition + LowerBound + UpperBound + +GeoMechPropertyFilters - class RimGeoMechPropertyFilterCollection + Active + PropertyFilters + +GeoMechResultDefinition - class RimGeoMechResultDefinition + ResultPositionType + ResultFieldName + ResultComponentName + IsTimeLapseResult + TimeLapseBaseTimeStep + CompactionRefLayer + ResultPositionTypeUi + ResultVariableUI + IsTimeLapseResultUI + TimeLapseBaseTimeStepUI + CompactionRefLayerUi + +GeoMechResultSlot - class RimGeoMechCellColors + ResultPositionType + ResultFieldName + ResultComponentName + IsTimeLapseResult + TimeLapseBaseTimeStep + CompactionRefLayer + ResultPositionTypeUi + ResultVariableUI + IsTimeLapseResultUI + TimeLapseBaseTimeStepUI + CompactionRefLayerUi + LegendDefinition + +GeoMechView - class RimGeoMechView + WindowController + ShowWindow + WindowGeometry + UserDescription + CameraPosition + CameraPointOfInterest + PerspectiveProjection + GridZScale + ViewBackgroundColor + MaximumFrameRate + AnimationMode + CurrentTimeStep + MeshMode + SurfaceMode + ShowGridBox + DisableLighting + RangeFilters + RangeFiltersControlled + CrossSections + GridCollection + OverlayInfoConfig + GridCellResult + TensorResults + PropertyFilters + +GridCollection - class RimGridCollection + IsActive + MainGrid + PersistentLgrs + TemporaryLgrs + +GridInfo - class RimGridInfo + IsActive + GridName + GridIndex + +GridInfoCollection - class RimGridInfoCollection + IsActive + GridInfos + +GridSummaryCase - class RimGridSummaryCase + ShortName + AutoShortyName + SummaryHeaderFilename + Associated3DCase + CachedCasename + Associated3DCaseGridFileName + IncludeRestartFiles + +GridTimeHistoryCurve - class RimGridTimeHistoryCurve + Show + CurveName + CurveDescription + AutoName + Color + Thickness + CurveInterpolation + LineStyle + PointSymbol + SymbolSkipPxDist + ShowLegend + SymbolSize + ShowErrorBars + GeometrySelectionText + EclipseResultDefinition + GeoMechResultDefinition + GeometrySelectionItem + PlotAxis + +Intersection2dView - class Rim2dIntersectionView + WindowController + ShowWindow + WindowGeometry + UserDescription + CameraPosition + CameraPointOfInterest + PerspectiveProjection + GridZScale + ViewBackgroundColor + MaximumFrameRate + AnimationMode + CurrentTimeStep + MeshMode + SurfaceMode + ShowGridBox + DisableLighting + Intersection + LegendDefinition + TernaryLegendDefinition + ShowDefiningPoints + ShowAxisLines + +Intersection2dViewCollection - class Rim2dIntersectionViewCollection + IntersectionViews + +IntersectionBox - class RimIntersectionBox + UserDescription + Active + singlePlaneState + MinXCoord + MaxXCoord + MinYCoord + MaxYCoord + MinDepth + MaxDepth + ShowInactiveCells + xySliderStepSize + DepthSliderStepSize + show3DManipulator + +Legend - class RimRegularLegendConfig + ShowLegend + NumberOfLevels + Precision + TickNumberFormat + ColorRangeMode + MappingMode + RangeType + UserDefinedMax + UserDefinedMin + ResultVariableUsage + +MainPlotCollection - class RimMainPlotCollection + Show + WellLogPlotCollection + RftPlotCollection + PltPlotCollection + SummaryPlotCollection + SummaryCrossPlotCollection + FlowPlotCollection + +MdiWindowController - class RimMdiWindowController + MainWindowID + xPos + yPos + Width + Height + IsMaximized + +MockModelSettings - class RimMockModelSettings + CellCountX + CellCountY + CellCountZ + TotalCellCount + ResultCount + TimeStepCount + +ModeledWellPath - class RimModeledWellPath + WellPathName + DatumElevation + UnitSystem + SimWellName + SimBranchIndex + ShowWellPathLabel + ShowWellPath + WellPathRadiusScale + WellPathColor + Completions + WellLogFiles + CollectionOf3dWellLogCurves + WellPathFormationKeyInFile + WellPathFormationFilePath + WellLogFile + WellPathAttributes + WellPathGeometryDef + +MultiSnapshotDefinition - class RimMultiSnapshotDefinition + IsActive + View + EclipseResultType + SelectedEclipseResults + TimeStepStart + TimeStepEnd + SnapShotDirection + RangeFilterStart + RangeFilterEnd + AdditionalCases + +NoCommonAreaNNC - class RimNoCommonAreaNNC + Name + +ObservedDataCollection - class RimObservedDataCollection + ObservedDataArray + +PdmDocument - class caf::PdmDocument + DocumentFileName + +PdmObjectCollection - class caf::PdmObjectCollection + PdmObjects + +PdmObjectGroup - class caf::PdmObjectGroup + +Perforation - class RimPerforationInterval + Name + IsChecked + StartMeasuredDepth + EndMeasuredDepth + Diameter + SkinFactor + StartOfHistory + UseCustomStartDate + StartDate + UseCustomEndDate + EndDate + Valves + +PerforationCollection - class RimPerforationCollection + Name + IsChecked + Perforations + MswParameters + NonDarcyParameters + +PropertyFilter - class RimPropertyFilter + UserDescription + Active + FilterType + SelectedValues + +ResInsightAnalysisModels - class RimEclipseCaseCollection + Reservoirs + CaseGroups + +ResInsightGeoMechCase - class RimGeoMechCase + CaseUserDescription + CaseId + DefaultFormationNames + TimeStepFilter + IntersectionViewCollection + CaseFileName + GeoMechViews + CaseCohesion + FrctionAngleDeg + ElementPropertyFileNames + ElementPropertyFileNameIndexUiSelection + closeElementPropertyFileCommad + reloadElementPropertyFileCommand + +ResInsightGeoMechModels - class RimGeoMechModels + Cases + +ResInsightOilField - class RimOilField + AnalysisModels + GeoMechModels + WellPathCollection + FractureDefinitionCollection + SummaryCaseCollection + FormationNamesCollection + ObservedDataCollection + +ResInsightProject - class RimProject + DocumentFileName + ProjectFileVersionString + NextValidCaseId + NextValidCaseGroupId + OilFields + ScriptCollection + WellPathImport + MainPlotCollection + LinkedViews + CalculationCollection + CommandObjects + MultiSnapshotDefinitions + TreeViewState + TreeViewCurrentModelIndexPath + PlotWindowTreeViewState + PlotWindowTreeViewCurrentModelIndexPath + show3DWindow + showPlotWindow + DialogData + Reservoirs + CaseGroups + +ReservoirCellResultStorage - class RimReservoirCellResultsStorage + ResultCacheFileName + ResultCacheEntries + +ReservoirView - class RimEclipseView + WindowController + ShowWindow + WindowGeometry + UserDescription + CameraPosition + CameraPointOfInterest + PerspectiveProjection + GridZScale + ViewBackgroundColor + MaximumFrameRate + AnimationMode + CurrentTimeStep + MeshMode + SurfaceMode + ShowGridBox + DisableLighting + RangeFilters + RangeFiltersControlled + CrossSections + GridCollection + OverlayInfoConfig + GridCellResult + GridCellEdgeResult + FaultResultSettings + StimPlanColors + VirtualPerforationResult + WellCollection + FaultCollection + PropertyFilters + ShowMainGrid + ShowInactiveCells + ShowInvalidCells + +ResultDefinition - class RimEclipseResultDefinition + ResultType + PorosityModelType + ResultVariable + FlowDiagSolution + SelectedTracers + SelectedInjectorTracers + SelectedProducerTracers + SelectedSouringTracers + FlowTracerSelectionMode + PhaseSelection + MResultType + MPorosityModelType + MResultVariable + MFlowDiagSolution + MSyncSelectedInjProd + MSyncSelectedProdInj + MSelectedInjectorTracers + MSelectedProducerTracers + MSelectedSouringTracers + +ResultSlot - class RimEclipseCellColors + ResultType + PorosityModelType + ResultVariable + FlowDiagSolution + SelectedTracers + SelectedInjectorTracers + SelectedProducerTracers + SelectedSouringTracers + FlowTracerSelectionMode + PhaseSelection + MResultType + MPorosityModelType + MResultVariable + MFlowDiagSolution + MSyncSelectedInjProd + MSyncSelectedProdInj + MSelectedInjectorTracers + MSelectedProducerTracers + MSelectedSouringTracers + LegendDefinition + ResultVarLegendDefinitionList + TernaryLegendDefinition + LegendDefinitionPtrField + +ResultStorageEntryInfo - class RimReservoirCellResultsStorageEntryInfo + ResultType + ResultName + TimeSteps + DaysSinceSimulationStart + FilePositionDataStart + +RftAddress - class RimDataSourceForRftPlt + SourceType + EclipseCase + WellLogFile + +RiaMemoryCleanup - class RiaMemoryCleanup + DataCase + ResultsToDelete + ClearSelectedData + +RiaPreferences - class RiaPreferences + navigationPolicy + scriptDirectory + scriptEditorExecutable + octaveExecutable + octaveShowHeaderInfoWhenExecutingScripts + ssihubAddress + defaultGridLines + defaultGridLineColors + defaultFaultGridLineColors + defaultWellLableColor + defaultViewerBackgroundColor + defaultScaleFactorZ + fontSizeInScene + showLasCurveWithoutTvdWarning + useShaders + showHud + appendClassNameToUiText + appendFieldKeywordToToolTipText + showTestToolbar + includeFractureDebugInfoFile + showLegendBackground + lastUsedProjectFileName + autocomputeDepth + loadAndShowSoil + summaryRestartFilesShowImportDialog + summaryImportMode + gridImportMode + holoLensExportFolder + readerSettings + +RiaRegressionTest - class RiaRegressionTest + workingFolder + folderContainingDiffTool + folderContainingGitTool + regressionTestFolder + showInteractiveDiffImages + useOpenMPForGeometryCreation + testFilter + +RicCaseAndFileExportSettingsUi - class RicCaseAndFileExportSettingsUi + Folder + CaseToApply + +RicCellRangeUi - class RicCellRangeUi + Case + GridIndex + StartIndexI + StartIndexJ + StartIndexK + CellCountI + CellCountJ + CellCountK + +RicDeleteItemExecData - class RicDeleteItemExecData + PathToField + indexToObject + deletedObjectAsXml + +RicExportCarfinUi - class RicExportCarfinUi + CellRange + ExportFileName + CaseToApply + CellCountI + CellCountJ + CellCountK + MaxWellCount + +RicExportCompletionDataSettingsUi - class RicExportCompletionDataSettingsUi + Folder + CaseToApply + FileSplit + compdatExport + TimeStepIndex + IncludeMSW + UseLateralNTG + IncludePerforations + IncludeFishbones + IncludeFractures + TransScalingType + TransScalingTimeStep + TransScalingWBHPSource + TransScalingWBHP + ExcludeMainBoreForFishbones + ReportCompletionTypesSeparately + +RicExportLgrUi - class RicExportLgrUi + ExportFolder + CaseToApply + TimeStepIndex + IncludePerforations + IncludeFractures + IncludeFishbones + CellCountI + CellCountJ + CellCountK + SplitType + +RicExportToLasFileObj - class RicExportToLasFileObj + tvdrkbOffset + +RicExportToLasFileResampleUi - class RicExportToLasFileResampleUi + ExportFolder + ActivateResample + ResampleInterval + ExportTvdrkb + tvdrkbOffsets + +RicExportWellPathsUi - class RicExportWellPathsUi + ExportFolder + MdStepSize + +RicHoloLensCreateSessionUi - class RicHoloLensCreateSessionUi + SessionName + SessionPinCode + ServerSettings + +RicHoloLensExportToFolderUi - class RicHoloLensExportToFolderUi + ViewForExport + ExportFolder + +RicHoloLensServerSettings - class RicHoloLensServerSettings + ServerAddress + +RicLinkVisibleViewsFeatureUi - class RicLinkVisibleViewsFeatureUi + MasterView + +RicPasteAsciiDataToSummaryPlotFeatureUi - class RicPasteAsciiDataToSummaryPlotFeatureUi + PlotTitle + CurvePrefix + DecimalSeparator + DateFormat + TimeFormat + UseCustomDateFormat + CustomDateTimeFormat + LineStyle + Symbol + SymbolSkipDinstance + CellSeparator + TimeColumnName + PreviewText + +RicSaveEclipseInputVisibleCellsUi - class RicSaveEclipseInputVisibleCellsUi + ExportFilename + ExportKeyword + VisibleActiveCellsValue + HiddenActiveCellsValue + InactiveCellsValue + +RicSelectSummaryPlotUI - class RicSelectSummaryPlotUI + SelectedSummaryPlot + CreateNewPlot + NewViewName + +RicSelectViewUI - class RicSelectViewUI + MasterView + CreateNewView + NewViewName + +RicSummaryAddressSelection - class RiuSummaryCurveDefSelection + SummaryCases + CurrentSummaryCategory + SelectedSummaryCategories + FieldVectors + Aquifers + AquiferVectors + NetworkVectors + MiscVectors + Regions + RegionsVectors + Region2RegionRegions + Region2RegionVectors + WellGroupWellGroupNames + WellGroupVectors + WellWellName + WellVectors + WellCompletionWellName + WellCompletionIjk + WellCompletionVectors + WellCompletionLgrLgrName + WellCompletionLgrWellName + WellCompletionLgrIjk + WellCompletionLgrVectors + WellLgrLgrName + WellLgrWellName + WellLgrVectors + WellSegmentWellName + WellSegmentNumber + WellSegmentVectors + BlockIjk + BlockVectors + BlockLgrLgrName + BlockLgrIjk + BlockLgrVectors + CalculatedVectors + ImportedVectors + +RicSummaryCurveCalculator - class RicSummaryCurveCalculator + CurrentCalculation + NewCalculation + DeleteCalculation + +RicSummaryCurveCreator - class RicSummaryCurveCreator + TargetPlot + UseAutoAppearanceAssignment + AppearanceApplyButton + CaseAppearanceType + VariableAppearanceType + WellAppearanceType + GroupAppearanceType + RegionAppearanceType + UseAutoPlotTitle + ApplySelection + Close + OK + SummaryCurveNameConfig + +RicWellPathsUnitSystemSettingsUi - class RicWellPathsUnitSystemSettingsUi + UnitSystem + +RifReaderSettings - class RifReaderSettings + importFaults + importSimulationNNCs + importAdvancedMswData + useResultIndexFile + skipWellData + faultIncludeFileAbsolutePathPrefix + +Rim3dWellLogCurveCollection - class Rim3dWellLogCurveCollection + Show3dWellLogCurves + PlaneWidthScaling + Show3dWellLogGrid + Show3dWellLogBackground + ArrayOf3dWellLogCurves + +Rim3dWellLogExtractionCurve - class Rim3dWellLogExtractionCurve + Show3dWellLogCurve + MinCurveValue + MaxCurveValue + DrawPlane + CurveColor + CurveCase + CurveTimeStep + CurveEclipseResult + CurveGeomechResult + NameConfig + +Rim3dWellLogFileCurve - class Rim3dWellLogFileCurve + Show3dWellLogCurve + MinCurveValue + MaxCurveValue + DrawPlane + CurveColor + CurveWellLogChannel + WellLogFile + NameConfig + +Rim3dWellLogRftCurve - class Rim3dWellLogRftCurve + Show3dWellLogCurve + MinCurveValue + MaxCurveValue + DrawPlane + CurveColor + eclipseResultCase + timeStep + wellLogChannelName + my2dWellLogRftCurve + NameConfig + +RimBinaryExportSettings - class RimBinaryExportSettings + Filename + EclipseKeyword + UndefinedValue + +RimCaseCollection - class RimCaseCollection + Reservoirs + +RimCommandExecuteScript - class RimCommandExecuteScript + Name + ScriptText + IsEnabled + Execute + +RimCommandIssueFieldChanged - class RimCommandIssueFieldChanged + CommandName + ObjectName + FieldName + FieldValueToApply + +RimCommandObject - class RimCommandObject + +RimContourMapNameConfig - class RimContourMapNameConfig + IsUsingAutoName + CustomCurveName + AutoCurveName + AddCaseName + AddAggregationType + AddProperty + AddSampleSpacing + +RimContourMapProjection - class RimContourMapProjection + Name + IsChecked + SampleSpacing + ResultAggregation + ContourLines + WeightByParameter + WeightingResult + +RimContourMapView - class RimContourMapView + WindowController + ShowWindow + WindowGeometry + UserDescription + CameraPosition + CameraPointOfInterest + PerspectiveProjection + GridZScale + ViewBackgroundColor + MaximumFrameRate + AnimationMode + CurrentTimeStep + MeshMode + SurfaceMode + ShowGridBox + DisableLighting + RangeFilters + RangeFiltersControlled + CrossSections + GridCollection + OverlayInfoConfig + GridCellResult + GridCellEdgeResult + FaultResultSettings + StimPlanColors + VirtualPerforationResult + WellCollection + FaultCollection + PropertyFilters + ShowMainGrid + ShowInactiveCells + ShowInvalidCells + ContourMapProjection + ShowAxisLines + NameConfig + +RimCsvUserData - class RimCsvUserData + ShortName + AutoShortyName + SummaryHeaderFilename + ImportedSummaryData + UseCustomIdentifier + SummaryType + IdentifierName + ParseOptions + +RimCurveNameConfig - class RimNameConfig + IsUsingAutoName + CustomCurveName + AutoCurveName + +RimDerivedEnsembleCaseCollection - class RimDerivedEnsembleCaseCollection + SummaryCases + SummaryCollectionName + NameCount + IsEnsemble + Ensemble1 + Ensemble2 + Operator + SwapEnsembles + CaseCount + +RimDialogData - class RimDialogData + ExportCarfin + ExportCompletionData + MultipleFractionsData + HoloLenseExportToFolderData + ExportwellPathsData + ExportLgr + MockModelSettings + +RimEllipseFractureTemplate - class RimEllipseFractureTemplate + Id + UserDescription + NameAndUnit + UnitSystem + Orientation + AzimuthAngle + SkinFactor + PerforationLength + PerforationEfficiency + WellDiameter + ConductivityType + FractureContainmentField + NonDarcyFlowType + UserDefinedDFactor + FractureWidthType + FractureWidth + BetaFactorType + InertialCoefficient + PermeabilityType + RelativePermeability + EffectivePermeability + RelativeGasDensity + GasViscosity + dFactorDisplayField + dFactorSummaryText + HeightScaleFactor + WidthScaleFactor + DFactorScaleFactor + ConductivityFactor + ScaleApplyButton + HalfLength + Height + Width + Permeability + +RimEnsembleCurveFilter - class RimEnsembleCurveFilter + Active + EnsembleParameter + MinValue + MaxValue + Categories + DeleteEnsembleFilter + +RimEnsembleCurveFilterCollection - class RimEnsembleCurveFilterCollection + Active + CurveFilters + NewEnsembleFilter + +RimEnsembleCurveSet - class RimEnsembleCurveSet + EnsembleCurveSet + IsActive + SummaryGroup + SelectedVariableDisplayVar + VarListFilter + FilterResultSelection + SummaryAddress + SelectAddress + ColorMode + Color + EnsembleParameter + PlotAxis + LegendConfig + CurveFilters + Statistics + UserDefinedName + AutoGeneratedName + AutoName + SummaryAddressNameTools + +RimEnsembleCurveSetCollection - class RimEnsembleCurveSetCollection + EnsembleCurveSets + IsActive + +RimEnsembleStatistics - class RimEnsembleStatistics + Active + HideEnsembleCurves + BasedOnFilteredCases + ShowP10Curve + ShowP50Curve + ShowP90Curve + ShowMeanCurve + ShowCurveLabels + WarningLabel + Color + +RimExportInputSettings - class RimExportInputSettings + Filename + Keyword + +RimFaultResultSlot - class RimEclipseFaultColors + ShowCustomFaultResult + CustomResultSlot + +RimFractureExportSettings - class RimFractureExportSettings + Filename + CaseToApply + +RimIdenticalGridCaseGroup - class RimIdenticalGridCaseGroup + UserDescription + GroupId + StatisticsCaseCollection + CaseCollection + +RimInputProperty - class RimEclipseInputProperty + ResultName + EclipseKeyword + FileName + ResolvedState + +RimInputPropertyCollection - class RimEclipseInputPropertyCollection + InputProperties + +RimInputReservoir - class RimEclipseInputCase + CaseUserDescription + CaseId + DefaultFormationNames + TimeStepFilter + IntersectionViewCollection + ReservoirViews + MatrixModelResults + FractureModelResults + FlipXAxis + FlipYAxis + CachedFileNamesContainingFaults + ContourMaps + FilesContainingFaults + CaseName + GridFileName + InputPropertyCollection + AdditionalFileNamesProxy + AdditionalFileNames + +RimMswCompletionParameters - class RimMswCompletionParameters + LinerDiameter + RoughnessFactor + PressureDrop + LengthAndDepth + EnforceMaxSegmentLength + MaxSegmentLength + +RimMultipleValveLocations - class RimMultipleValveLocations + LocationMode + RangeStart + RangeEnd + ValveSpacing + RangeValveCount + LocationOfValves + +RimNoCommonAreaNncCollection - class RimNoCommonAreaNncCollection + UserDescription + NoCommonAreaNncs + +RimNonDarcyPerforationParameters - class RimNonDarcyPerforationParameters + NonDarcyFlowType + UserDefinedDFactor + GridPermeabilityScalingFactor + WellRadius + RelativeGasDensity + GasViscosity + InertialCoefficientBeta0 + PermeabilityScalingFactor + PorosityScalingFactor + +RimObservedEclipseUserData - class RimObservedEclipseUserData + ShortName + AutoShortyName + SummaryHeaderFilename + ImportedSummaryData + UseCustomIdentifier + SummaryType + IdentifierName + +RimOilFieldEntry - class RimOilFieldEntry + OilFieldName + EdmId + Selected + wellsFilePath + Wells + +RimOilRegionEntry - class RimOilRegionEntry + OilRegionEntry + Fields + Selected + +RimStatisticalCalculation - class RimEclipseStatisticsCase + CaseUserDescription + CaseId + DefaultFormationNames + TimeStepFilter + IntersectionViewCollection + ReservoirViews + MatrixModelResults + FractureModelResults + FlipXAxis + FlipYAxis + CachedFileNamesContainingFaults + ContourMaps + FilesContainingFaults + CaseName + m_editingAllowed + SelectionSummary + ResultType + PorosityModel + DynamicPropertiesToCalculate + StaticPropertiesToCalculate + GeneratedPropertiesToCalculate + InputPropertiesToCalculate + FractureDynamicPropertiesToCalculate + FractureStaticPropertiesToCalculate + FractureGeneratedPropertiesToCalculate + FractureInputPropertiesToCalculate + CalculatePercentiles + PercentileCalculationType + LowPercentile + MidPercentile + HighPercentile + WellDataSourceCase + UseZeroAsInactiveCellValue + +RimStatisticalCollection - class RimEclipseStatisticsCaseCollection + Reservoirs + +RimStimPlanColors - class RimStimPlanColors + IsChecked + ResultName + DefaultColor + LegendConfigurations + ShowStimPlanMesh + StimPlanCellVizMode + +RimStimPlanFractureTemplate - class RimStimPlanFractureTemplate + Id + UserDescription + NameAndUnit + UnitSystem + Orientation + AzimuthAngle + SkinFactor + PerforationLength + PerforationEfficiency + WellDiameter + ConductivityType + FractureContainmentField + NonDarcyFlowType + UserDefinedDFactor + FractureWidthType + FractureWidth + BetaFactorType + InertialCoefficient + PermeabilityType + RelativePermeability + EffectivePermeability + RelativeGasDensity + GasViscosity + dFactorDisplayField + dFactorSummaryText + HeightScaleFactor + WidthScaleFactor + DFactorScaleFactor + ConductivityFactor + ScaleApplyButton + StimPlanFileName + WellPathDepthAtFracture + BorderPolygonResultName + ActiveTimeStepIndex + ConductivityResultName + ShowStimPlanMesh + +RimStimPlanLegendConfig - class RimStimPlanLegendConfig + Name + Legend + +RimSummaryCalculation - class RimSummaryCalculation + Description + Expression + Unit + Variables + CalculatedValues + TimeSteps + +RimSummaryCalculationCollection - class RimSummaryCalculationCollection + Calculations + CalculationsSummaryCase + +RimSummaryCalculationVariable - class RimSummaryCalculationVariable + VariableName + PushButton + SummaryAddressUi + SummaryCase + SummaryAddress + +RimSummaryCurveCollection - class RimSummaryCurveCollection + CollectionCurves + IsActive + YSourceStepping + XSourceStepping + UnionSourceStepping + +RimSummaryCurveCollectionModifier - class RimSummaryPlotSourceStepping + CurveCase + WellName + GroupName + Region + Quantities + Placeholder + +RimTensorResults - class RimTensorResults + LegendDefinition + ResultVariable + ResultVariableUI + ShowTensors + Principal1 + Principal2 + Principal3 + Threshold + VectorColor + ScaleMethod + SizeScale + RangeType + +RimTernaryLegendConfig - class RimTernaryLegendConfig + ShowTernaryLegend + Precision + RangeType + m_applyLocalMinMax + m_applyGlobalMinMax + m_applyFullRangeMinMax + ternaryRangeSummary + UserDefinedMaxSoil + UserDefinedMinSoil + UserDefinedMaxSgas + UserDefinedMinSgas + UserDefinedMaxSwat + UserDefinedMinSwat + +RimTimeStepFilter - class RimTimeStepFilter + FilterType + FirstTimeStep + LastTimeStep + Interval + TimeStepsFromFile + DateFormat + TimeStepIndicesToImport + TimeStepIndicesUi + ApplyReloadOfCase + +RimViewLinkerCollection - class RimViewLinkerCollection + Active + ViewLinkers + +RimVirtualPerforationResults - class RimVirtualPerforationResults + ShowConnectionFactors + ShowClosedConnections + GeometryScaleFactor + LegendDefinition + +RimWellLogExtractionCurve - class RimWellLogExtractionCurve + Show + CurveName + CurveDescription + AutoName + Color + Thickness + CurveInterpolation + LineStyle + PointSymbol + SymbolSkipPxDist + ShowLegend + SymbolSize + ShowErrorBars + TrajectoryType + CurveWellPath + SimulationWellName + BranchDetection + Branch + CurveCase + CurveEclipseResult + CurveGeomechResult + CurveTimeStep + AddCaseNameToCurveName + AddPropertyToCurveName + AddWellNameToCurveName + AddTimestepToCurveName + AddDateToCurveName + +RimWellLogExtractionCurveNameConfig - class RimWellLogExtractionCurveNameConfig + IsUsingAutoName + CustomCurveName + AutoCurveName + AddCaseName + AddProperty + AddWellName + AddTimeStep + AddDate + +RimWellLogFileCurveNameConfig - class RimWellLogFileCurveNameConfig + IsUsingAutoName + CustomCurveName + AutoCurveName + +RimWellLogPlotNameConfig - class RimWellLogPlotNameConfig + IsUsingAutoName + CustomCurveName + AutoCurveName + AddCaseName + AddWellName + AddTimeStep + AddAirGap + AddWaterDepth + +RimWellLogRftCurveNameConfig - class RimWellLogRftCurveNameConfig + IsUsingAutoName + CustomCurveName + AutoCurveName + +RimWellPathEntry - class RimWellPathEntry + Name + Selected + WellPathType + surveyType + requestUrl + wellPathFilePath + +RimWellPathImport - class RimWellPathImport + WellTypeSurvey + WellTypePlans + UtmMode + UtmNorth + UtmSouth + UtmEast + UtmWest + Regions + +RiuCreateMultipleFractionsUi - class RiuCreateMultipleFractionsUi + SourceCase + MinDistanceFromWellTd + MaxFracturesPerWell + Options + FractureCreationSummary + +RiuMultipleFractionsOptions - class RicCreateMultipleFracturesOptionItemUi + TopKLayer + BaseKLayer + Template + MinSpacing + +ScriptLocation - class RimScriptCollection + ScriptDirectory + CalcScripts + SubDirectories + +SimWellFracture - class RimSimWellFracture + Name + IsChecked + FractureDef + AnchorPosition + ui_positionAtWellpath + Azimuth + PerforationLength + PerforationEfficiency + WellDiameter + Dip + Tilt + FractureUnit + TimeIndexToPlot + WellPathAzimuth + WellFractureAzimuthDiff + WellFractureAzimithAngleWarning + MeasuredDepth + Cell_IJK + Branch + +SimWellFractureCollection - class RimSimWellFractureCollection + Fractures + +SummaryAddress - class RimSummaryAddress + SummaryVarType + SummaryQuantityName + SummaryRegion + SummaryRegion2 + SummaryWellGroup + SummaryWell + SummaryWellSegment + SummaryLgr + SummaryCellI + SummaryCellJ + SummaryCellK + SummaryAquifer + IsErrorResult + +SummaryCaseCollection - class RimSummaryCaseMainCollection + SummaryCases + SummaryCaseCollections + +SummaryCaseSubCollection - class RimSummaryCaseCollection + SummaryCases + SummaryCollectionName + NameCount + IsEnsemble + +SummaryCrossPlot - class RimSummaryCrossPlot + WindowController + ShowWindow + WindowGeometry + PlotDescription + ShowPlotTitle + ShowLegend + LegendFontSize + IsUsingAutoName + SummaryCurveFilters + SummaryCurveCollection + EnsembleCurveSetCollection + SummaryCurves + GridTimeHistoryCurves + AsciiDataCurves + LeftYAxisProperties + RightYAxisProperties + BottomAxisProperties + TimeAxisProperties + AutoZoom + +SummaryCrossPlotCollection - class RimSummaryCrossPlotCollection + SummaryCrossPlots + +SummaryCurve - class RimSummaryCurve + Show + CurveName + CurveDescription + AutoName + Color + Thickness + CurveInterpolation + LineStyle + PointSymbol + SymbolSkipPxDist + ShowLegend + SymbolSize + ShowErrorBars + SummaryCase + SelectedVariableDisplayVar + VarListFilter + FilterResultSelection + SummaryAddress + SelectAddress + SummaryCaseX + SelectedVariableDisplayVarX + VarListFilterX + FilterResultSelectionX + SummaryAddressX + SelectAddressX + PlotAxis + SummaryCurveNameConfig + +SummaryCurveAutoName - class RimSummaryCurveAutoName + VectorName + Unit + RegionNumber + WellGroupName + WellName + WellSegmentNumber + LgrName + Completion + Aquifer + CaseName + +SummaryCurveFilter - class RimSummaryCurveFilter_OBSOLETE + SummaryCases + VarListFilter + FilterResultSelection + FilteredCurves + ApplySelection + AutoApplyFilterChanges + IsActive + UseAutoAppearanceAssignment + CaseAppearanceType + VariableAppearanceType + WellAppearanceType + GroupAppearanceType + RegionAppearanceType + PlotAxis + ShowLegend + SummaryCurveNameConfig + +SummaryFilterSettings - class RimSummaryFilter + SummaryFilterType + SummaryCompleteVarStringFilter + SummaryVarQuantityFilter + SummaryRegionNumberFilter + SummaryRegionNumber2Filter + SummaryWellGroupNameFilter + SummaryWellNameFilter + SummaryWellSegmentNumberFilter + SummaryLgrNameFilter + SummaryCellIJKFilter + +SummaryObservedDataFile - class RimSummaryObservedDataFile + ShortName + AutoShortyName + SummaryHeaderFilename + ImportedSummaryData + UseCustomIdentifier + SummaryType + IdentifierName + +SummaryPageDownloadEntity - class SummaryPageDownloadEntity + Name + RequestUrl + ResponseFilename + +SummaryPlot - class RimSummaryPlot + WindowController + ShowWindow + WindowGeometry + PlotDescription + ShowPlotTitle + ShowLegend + LegendFontSize + IsUsingAutoName + SummaryCurveFilters + SummaryCurveCollection + EnsembleCurveSetCollection + SummaryCurves + GridTimeHistoryCurves + AsciiDataCurves + LeftYAxisProperties + RightYAxisProperties + BottomAxisProperties + TimeAxisProperties + AutoZoom + +SummaryPlotCollection - class RimSummaryPlotCollection + SummaryPlots + +SummaryTimeAxisProperties - class RimSummaryTimeAxisProperties + Active + ShowTitle + Title + TitlePosition + FontSize + ValuesFontSize + AutoZoom + TimeMode + TimeUnit + VisibleRangeMax + VisibleRangeMin + VisibleTimeModeRangeMax + VisibleTimeModeRangeMin + +SummaryYAxisProperties - class RimSummaryAxisProperties + Active + Name + AutoTitle + DisplayLongName + DisplayShortName + DisplayUnitText + CustomTitle + TitlePosition + FontSize + VisibleRangeMax + VisibleRangeMin + NumberFormat + Decimals + ScaleFactor + ValuesFontSize + AutoZoom + LogarithmicScale + +TC2 - class TC2 + ta + da + ia + ba + +TestCommand1 - class TestCommand1 + TextArgument + DoubleArgument + IntArgument + BoolArgument + +TofAccumulatedPhaseFractionsPlot - class RimTofAccumulatedPhaseFractionsPlot + WindowController + ShowWindow + WindowGeometry + PlotDescription + ShowPlotTitle + MaxTof + +TotalWellAllocationPlot - class RimTotalWellAllocationPlot + WindowController + ShowWindow + WindowGeometry + PlotDescription + ShowPlotTitle + +View3dOverlayInfoConfig - class Rim3dOverlayInfoConfig + Active + ShowAnimProgress + ShowInfoText + ShowResultInfo + ShowHistogram + ShowVolumeWeightedMean + StatisticsTimeRange + StatisticsCellRange + +ViewController - class RimViewController + Active + Name + ManagedView + SyncCamera + ShowCursor + SyncTimeStep + SyncCellResult + SyncLegendDefinitions + SyncVisibleCells + SyncRangeFilters + SyncPropertyFilters + +ViewLinker - class RimViewLinker + Name + MainView + ManagedViews + +Well - class RimSimWellInView + WellName + ShowWell + ShowWellLabel + ShowWellHead + ShowWellPipe + ShowWellSpheres + WellHeadScaleFactor + WellPipeRadiusScale + WellPipeColor + ShowWellCells + ShowWellCellFence + FractureCollection + +WellAllocationPlot - class RimWellAllocationPlot + WindowController + ShowWindow + WindowGeometry + PlotDescription + ShowPlotTitle + BranchDetection + CurveCase + PlotTimeStep + WellName + FlowDiagSolution + FlowType + GroupSmallContributions + SmallContributionsThreshold + AccumulatedWellFlowPlot + TotalWellFlowPlot + WellAllocLegend + TofAccumulatedPhaseFractionsPlot + +WellAllocationPlotLegend - class RimWellAllocationPlotLegend + ShowPlotLegend + +WellFlowRateCurve - class RimWellFlowRateCurve + Show + CurveName + CurveDescription + AutoName + Color + Thickness + CurveInterpolation + LineStyle + PointSymbol + SymbolSkipPxDist + ShowLegend + SymbolSize + ShowErrorBars + +WellLogFile - class RimWellLogFile + WellName + Date + FileName + Name + WellLogFileChannels + WellFlowCondition + InvalidDateMessage + +WellLogFileChannel - class RimWellLogFileChannel + Name + +WellLogFileCurve - class RimWellLogFileCurve + Show + CurveName + CurveDescription + AutoName + Color + Thickness + CurveInterpolation + LineStyle + PointSymbol + SymbolSkipPxDist + ShowLegend + SymbolSize + ShowErrorBars + CurveWellPath + CurveWellLogChannel + WellLogFile + +WellLogPlot - class RimWellLogPlot + WindowController + ShowWindow + WindowGeometry + PlotDescription + CommonDataSource + DepthType + DepthUnit + MinimumDepth + MaximumDepth + ShowDepthGridLines + AutoScaleDepthEnabled + ShowTitleInPlot + ShowTrackLegends + TrackLegendsHorizontal + Tracks + NameConfig + +WellLogPlotCollection - class RimWellLogPlotCollection + WellLogPlots + +WellLogPlotTrack - class RimWellLogTrack + TrackDescription + Show + Curves + VisibleXRangeMin + VisibleXRangeMax + AutoScaleX + LogarithmicScaleX + ShowXGridLines + ExplicitTickIntervals + MajorTickIntervals + MinorTickIntervals + ShowFormations + ShowFormationLabels + FormationSource + FormationTrajectoryType + FormationWellPath + FormationWellPathForSourceWellPath + FormationSimulationWellName + FormationBranchIndex + FormationBranchDetection + FormationCase + FormationLevel + ShowFormationFluids + ShowWellPathAttributes + WellPathAttributesInLegend + ShowWellPathCompletions + WellPathCompletionsInLegend + ShowWellPathAttrBothSides + ShowWellPathAttrLabels + AttributesWellPathSource + AttributesCollection + Width + +WellLogRftCurve - class RimWellLogRftCurve + Show + CurveName + CurveDescription + AutoName + Color + Thickness + CurveInterpolation + LineStyle + PointSymbol + SymbolSkipPxDist + ShowLegend + SymbolSize + ShowErrorBars + CurveEclipseResultCase + TimeStep + WellName + BranchIndex + BranchDetection + WellLogChannelName + +WellPath - class RimFileWellPath + WellPathName + DatumElevation + UnitSystem + SimWellName + SimBranchIndex + ShowWellPathLabel + ShowWellPath + WellPathRadiusScale + WellPathColor + Completions + WellLogFiles + CollectionOf3dWellLogCurves + WellPathFormationKeyInFile + WellPathFormationFilePath + WellLogFile + WellPathAttributes + WellPathId + SourceSystem + UTMZone + WellPathUpdateDate + WellPathUpdateUser + WellPathSurveyType + WellPathFilepath + WellPathNumberInFile + +WellPathAttribute - class RimWellPathAttribute + CompletionType + DepthStart + DepthEnd + DiameterInInches + +WellPathAttributes - class RimWellPathAttributeCollection + Name + IsChecked + Attributes + +WellPathBase - class RimWellPath + WellPathName + DatumElevation + UnitSystem + SimWellName + SimBranchIndex + ShowWellPathLabel + ShowWellPath + WellPathRadiusScale + WellPathColor + Completions + WellLogFiles + CollectionOf3dWellLogCurves + WellPathFormationKeyInFile + WellPathFormationFilePath + WellLogFile + WellPathAttributes + +WellPathCompletion - class RimFishboneWellPath + Name + IsChecked + Coordinates + MeasuredDepth + DisplayCoordinates + +WellPathCompletionCollection - class RimFishboneWellPathCollection + Name + IsChecked + WellPaths + PipeProperties + +WellPathCompletions - class RimWellPathCompletions + Perforations + Fishbones + Fractures + WellNameForExport + WellGroupNameForExport + ReferenceDepthForExport + WellTypeForExport + +WellPathFracture - class RimWellPathFracture + Name + IsChecked + FractureDef + AnchorPosition + ui_positionAtWellpath + Azimuth + PerforationLength + PerforationEfficiency + WellDiameter + Dip + Tilt + FractureUnit + TimeIndexToPlot + WellPathAzimuth + WellFractureAzimuthDiff + WellFractureAzimithAngleWarning + MeasuredDepth + +WellPathFractureCollection - class RimWellPathFractureCollection + Name + IsChecked + Fractures + RefMDType + RefMD + MswParameters + +WellPathGeometryDef - class RimWellPathGeometryDef + ReferencePosUtmXyd + MdrkbAtFirstTarget + WellPathTargets + m_pickPointsEnabled + ReferencePos + WellStartType + ParentWell + KickoffDepthOrMD + +WellPathTarget - class RimWellPathTarget + IsEnabled + TargetPoint + Dogleg1 + Dogleg2 + TargetType + HasTangentConstraint + Azimuth + Inclination + +WellPathValve - class RimWellPathValve + Name + IsChecked + CompletionType + StartMeasuredDepth + ValveLocations + +WellPaths - class RimWellPathCollection + Active + ShowWellPathLabel + WellPathLabelColor + GlobalWellPathVisibility + WellPathRadiusScale + WellPathVertexCount + WellPathClip + WellPathClipZDistance + WellPaths + +WellPltPlot - class RimWellPltPlot + WindowController + ShowWindow + WindowGeometry + PlotDescription + ShowPlotTitle + WellLog + WellName + SourcesInternal + Sources + TimeSteps + UseStandardConditionCurves + UseReservoirConditionCurves + Phases + +WellPltPlotCollection - class RimPltPlotCollection + PltPlots + +WellRftPlot - class RimWellRftPlot + WindowController + ShowWindow + WindowGeometry + PlotDescription + ShowPlotTitle + WellLog + WellName + BranchIndex + BranchDetection + Sources + TimeSteps + +WellRftPlotCollection - class RimRftPlotCollection + RftPlots + +Wells - class RimSimWellInViewCollection + Active + ShowWellsIntersectingVisibleCells + ShowWellHeadTristate + ShowWellLabelTristate + ShowWellPipe + ShowWellSpheres + WellHeadScale + WellPipeRadiusScale + CellCenterSphereScale + WellLabelColor + ShowConnectionStatusColors + WellColorForApply + ApplySingleColorToWells + ApplyIndividualColorsToWells + WellPipeVertexCount + WellPipeCoordType + ShowWellCellsTristate + DefaultWellFenceDirection + WellCellTransparency + IsAutoDetectingBranches + WellHeadPosition + Wells + ShowWellCellFenceTristate + GlobalWellPipeVisibility + GlobalWellCellVisibility + ShowWellHead + ShowWellLabel + ShowWellFences + ShowWellCommunicationLines + +closeProject - class RicfCloseProject + +computeCaseGroupStatistics - class RicfComputeCaseGroupStatistics + caseIds + +createLgrForCompletions - class RicfCreateLgrForCompletions + caseId + timeStep + wellPathNames + refinementI + refinementJ + refinementK + splitType + +createMultipleFractures - class RicfCreateMultipleFractures + caseId + wellPathNames + minDistFromWellTd + maxFracturesPerWell + templateId + topLayer + baseLayer + spacing + action + +exportLgrForCompletions - class RicfExportLgrForCompletions + caseId + timeStep + wellPathNames + refinementI + refinementJ + refinementK + splitType + +exportMsw - class RicfExportMsw + caseId + wellPath + +exportMultiCaseSnapshots - class RicfExportMultiCaseSnapshots + gridListFile + +exportProperty - class RicfExportProperty + caseId + timeStep + property + eclipseKeyword + undefinedValue + exportFile + +exportPropertyInViews - class RicfExportPropertyInViews + caseId + viewNames + undefinedValue + +exportSimWellFractureCompletions - class RicfExportSimWellFractureCompletions + caseId + viewName + timeStep + simulationWellNames + fileSplit + compdatExport + +exportSnapshots - class RicfExportSnapshots + type + prefix + +exportVisibleCells - class RicfExportVisibleCells + caseId + viewName + exportKeyword + visibleActiveCellsValue + hiddenActiveCellsValue + inactiveCellsValue + +exportWellPathCompletions - class RicfExportWellPathCompletions + caseId + timeStep + wellPathNames + fileSplit + compdatExport + combinationMode + useNtgHorizontally + includePerforations + includeFishbones + includeFractures + excludeMainBoreForFishbones + performTransScaling + transScalingTimeStep + transScalingWBHPFromSummary + transScalingWBHP + +exportWellPaths - class RicfExportWellPaths + wellPathNames + mdStepSize + +loadCase - class RicfLoadCase + path + +openProject - class RicfOpenProject + path + +replaceCase - class RicfSingleCaseReplace + caseId + newGridFile + +replaceCaseImpl_no_support_for_command_file_text_parsing - class RicfMultiCaseReplace + +replaceSourceCases - class RicfReplaceSourceCases + caseGroupId + gridListFile + +runOctaveScript - class RicfRunOctaveScript + path + caseIds + +scaleFractureTemplate - class RicfScaleFractureTemplate + id + halfLength + height + dFactor + conductivity + width + +setExportFolder - class RicfSetExportFolder + type + path + createFolder + +setFractureContainment - class RicfSetFractureContainment + id + topLayer + baseLayer + +setMainWindowSize - class RicfSetMainWindowSize + height + width + +setStartDir - class RicfSetStartDir + path + +setTimeStep - class RicfSetTimeStep + caseId + timeStep + diff --git a/ApplicationCode/Adm/projectfilekeywords/2018.11/ri-objectKeywords.txt b/ApplicationCode/Adm/projectfilekeywords/2018.11/ri-objectKeywords.txt new file mode 100644 index 0000000000..1aa52c9e5b --- /dev/null +++ b/ApplicationCode/Adm/projectfilekeywords/2018.11/ri-objectKeywords.txt @@ -0,0 +1,240 @@ +// ResInsight version string : 2018.11.0-dev +// Report generated : Wed 28. Nov 12:29:03 2018 +// +// + +AsciiDataCurve +CalcScript +CalculatedSummaryCase +CellEdgeResultSlot +CellFilter +CellPropertyFilter +CellPropertyFilters +CellRangeFilter +CellRangeFilterCollection +ChangeDataSourceFeatureUi +CmdAddItemExecData +CmdDeleteItemExecData +CmdFieldChangeExecData +CrossSection +CrossSectionCollection +Eclipse2dViewCollection +EclipseCase +EclipseGeometrySelectionItem +Fault +Faults +FileSummaryCase +FishbonesCollection +FishbonesMultipleSubs +FishbonesPipeProperties +FlowCharacteristicsPlot +FlowDiagSolution +FlowPlotCollection +FormationNames +FormationNamesCollectionObject +FractureContainment +FractureDefinitionCollection +GeoMechGeometrySelectionItem +GeoMechPropertyFilter +GeoMechPropertyFilters +GeoMechResultDefinition +GeoMechResultSlot +GeoMechView +GridCollection +GridInfo +GridInfoCollection +GridSummaryCase +GridTimeHistoryCurve +Intersection2dView +Intersection2dViewCollection +IntersectionBox +Legend +MainPlotCollection +MdiWindowController +MockModelSettings +ModeledWellPath +MultiSnapshotDefinition +NoCommonAreaNNC +ObservedDataCollection +PdmDocument +PdmObjectCollection +PdmObjectGroup +Perforation +PerforationCollection +PropertyFilter +ResInsightAnalysisModels +ResInsightGeoMechCase +ResInsightGeoMechModels +ResInsightOilField +ResInsightProject +ReservoirCellResultStorage +ReservoirView +ResultDefinition +ResultSlot +ResultStorageEntryInfo +RftAddress +RiaMemoryCleanup +RiaPreferences +RiaRegressionTest +RicCaseAndFileExportSettingsUi +RicCellRangeUi +RicDeleteItemExecData +RicExportCarfinUi +RicExportCompletionDataSettingsUi +RicExportLgrUi +RicExportToLasFileObj +RicExportToLasFileResampleUi +RicExportWellPathsUi +RicHoloLensCreateSessionUi +RicHoloLensExportToFolderUi +RicHoloLensServerSettings +RicLinkVisibleViewsFeatureUi +RicPasteAsciiDataToSummaryPlotFeatureUi +RicSaveEclipseInputVisibleCellsUi +RicSelectSummaryPlotUI +RicSelectViewUI +RicSummaryAddressSelection +RicSummaryCurveCalculator +RicSummaryCurveCreator +RicWellPathsUnitSystemSettingsUi +RifReaderSettings +Rim3dWellLogCurveCollection +Rim3dWellLogExtractionCurve +Rim3dWellLogFileCurve +Rim3dWellLogRftCurve +RimBinaryExportSettings +RimCaseCollection +RimCommandExecuteScript +RimCommandIssueFieldChanged +RimCommandObject +RimContourMapNameConfig +RimContourMapProjection +RimContourMapView +RimCsvUserData +RimCurveNameConfig +RimDerivedEnsembleCaseCollection +RimDialogData +RimEllipseFractureTemplate +RimEnsembleCurveFilter +RimEnsembleCurveFilterCollection +RimEnsembleCurveSet +RimEnsembleCurveSetCollection +RimEnsembleStatistics +RimExportInputSettings +RimFaultResultSlot +RimFractureExportSettings +RimIdenticalGridCaseGroup +RimInputProperty +RimInputPropertyCollection +RimInputReservoir +RimMswCompletionParameters +RimMultipleValveLocations +RimNoCommonAreaNncCollection +RimNonDarcyPerforationParameters +RimObservedEclipseUserData +RimOilFieldEntry +RimOilRegionEntry +RimStatisticalCalculation +RimStatisticalCollection +RimStimPlanColors +RimStimPlanFractureTemplate +RimStimPlanLegendConfig +RimSummaryCalculation +RimSummaryCalculationCollection +RimSummaryCalculationVariable +RimSummaryCurveCollection +RimSummaryCurveCollectionModifier +RimTensorResults +RimTernaryLegendConfig +RimTimeStepFilter +RimViewLinkerCollection +RimVirtualPerforationResults +RimWellLogExtractionCurve +RimWellLogExtractionCurveNameConfig +RimWellLogFileCurveNameConfig +RimWellLogPlotNameConfig +RimWellLogRftCurveNameConfig +RimWellPathEntry +RimWellPathImport +RiuCreateMultipleFractionsUi +RiuMultipleFractionsOptions +ScriptLocation +SimWellFracture +SimWellFractureCollection +SummaryAddress +SummaryCaseCollection +SummaryCaseSubCollection +SummaryCrossPlot +SummaryCrossPlotCollection +SummaryCurve +SummaryCurveAutoName +SummaryCurveFilter +SummaryFilterSettings +SummaryObservedDataFile +SummaryPageDownloadEntity +SummaryPlot +SummaryPlotCollection +SummaryTimeAxisProperties +SummaryYAxisProperties +TC2 +TestCommand1 +TofAccumulatedPhaseFractionsPlot +TotalWellAllocationPlot +View3dOverlayInfoConfig +ViewController +ViewLinker +Well +WellAllocationPlot +WellAllocationPlotLegend +WellFlowRateCurve +WellLogFile +WellLogFileChannel +WellLogFileCurve +WellLogPlot +WellLogPlotCollection +WellLogPlotTrack +WellLogRftCurve +WellPath +WellPathAttribute +WellPathAttributes +WellPathBase +WellPathCompletion +WellPathCompletionCollection +WellPathCompletions +WellPathFracture +WellPathFractureCollection +WellPathGeometryDef +WellPathTarget +WellPathValve +WellPaths +WellPltPlot +WellPltPlotCollection +WellRftPlot +WellRftPlotCollection +Wells +closeProject +computeCaseGroupStatistics +createLgrForCompletions +createMultipleFractures +exportLgrForCompletions +exportMsw +exportMultiCaseSnapshots +exportProperty +exportPropertyInViews +exportSimWellFractureCompletions +exportSnapshots +exportVisibleCells +exportWellPathCompletions +exportWellPaths +loadCase +openProject +replaceCase +replaceCaseImpl_no_support_for_command_file_text_parsing +replaceSourceCases +runOctaveScript +scaleFractureTemplate +setExportFolder +setFractureContainment +setMainWindowSize +setStartDir +setTimeStep diff --git a/ApplicationCode/Adm/sourceCodeMaintenance/2019-04-21-delete-unused_functions.txt b/ApplicationCode/Adm/sourceCodeMaintenance/2019-04-21-delete-unused_functions.txt new file mode 100644 index 0000000000..c580631be2 --- /dev/null +++ b/ApplicationCode/Adm/sourceCodeMaintenance/2019-04-21-delete-unused_functions.txt @@ -0,0 +1,121 @@ + + +Nothing to do +------------- +unchanged ApplicationCode\Commands\HoloLensCommands\farmhash\farmhash.cc 1948 style unusedFunction false The function 'Hash128WithSeed' is never used. +unchanged ApplicationCode\ReservoirDataModel\cvfGeometryTools.cpp 614 style unusedFunction false The function 'addMidEdgeNodes' is never used. +unchanged ApplicationCode\WellPathImportSsihub\RiuWellImportWizard.cpp 147 style unusedFunction false The function 'cancelDownload' is never used. +unchanged ApplicationCode\GeoMech\GeoMechDataModel\RigFemPartGrid.cpp 453 style unusedFunction false The function 'cellIJKFromCoordinate' is never used. +unchanged ApplicationCode\GeoMech\GeoMechDataModel\RigFemPartGrid.cpp 486 style unusedFunction false The function 'cellMinMaxCordinates' is never used. +unchanged ApplicationCode\UserInterface\RiuWellLogPlot.cpp 527 style unusedFunction false The function 'changeEvent' is never used. +unchanged ApplicationCode\Commands\AnnotationCommands\RicTextAnnotation3dEditor.cpp 133 style unusedFunction false The function 'cleanupBeforeSettingPdmObject' is never used. +unchanged ApplicationCode\Commands\AnnotationCommands\RicTextAnnotation3dEditor.cpp 73 style unusedFunction false The function 'configureAndUpdateUi' is never used. + +WIP +--- +unchanged ApplicationCode\UserInterface\RiuGridCrossQwtPlot.cpp 359 style unusedFunction false The function 'contextMenuEvent' is never used. +unchanged ApplicationCode\Commands\HoloLensCommands\VdeCachingHashedIdFactory.cpp 233 style unusedFunction false The function 'crc' is never used. +unchanged ApplicationCode\Application\Tools\RiaColorTables.cpp 580 style unusedFunction false The function 'createBrightnessBasedColorTable' is never used. +unchanged ApplicationCode\GeoMech\GeoMechVisualization\RivFemPartGeometryGenerator.cpp 106 style unusedFunction false The function 'createOutlineMeshDrawable' is never used. +unchanged ApplicationCode\ModelVisualization\RivWellConnectionFactorGeometryGenerator.cpp 202 style unusedFunction false The function 'createStarGeometry' is never used. +unchanged ApplicationCode\Commands\SummaryPlotCommands\RicSummaryCurveCalculatorEditor.cpp 119 style unusedFunction false The function 'createWidget' is never used. +unchanged ApplicationCode\Commands\HoloLensCommands\VdeVizDataExtractor.cpp 397 style unusedFunction false The function 'debugComparePackets' is never used. +unchanged ApplicationCode\Application\RiaApplication.cpp 2355 style unusedFunction false The function 'defaultAnnotationFont' is never used. +unchanged ApplicationCode\Commands\FractureCommands\RicCreateMultipleFracturesUi.cpp 201 style unusedFunction false The function 'defineCustomContextMenu' is never used. +unchanged ApplicationCode\ProjectDataModel\Annotations\RimUserDefinedPolylinesAnnotation.cpp 271 style unusedFunction false The function 'defineObjectEditorAttribute' is never used. +unchanged ApplicationCode\GeoMech\GeoMechDataModel\RigFemPartResultsCollection.cpp 2267 style unusedFunction false The function 'deleteResultFrame' is never used. +unchanged ApplicationCode\ProjectDataModel\RimEclipseResultDefinition.cpp 944 style unusedFunction false The function 'diffResultUiShortNameHTML' is never used. +unchanged ApplicationCode\UserInterface\RiuDragDrop.cpp 254 style unusedFunction false The function 'dropMimeData' is never used. +unchanged ApplicationCode\FileInterface\RifEclipseSummaryTools.cpp 123 style unusedFunction false The function 'dumpMetaData' is never used. +unchanged ApplicationCode\FileInterface\RifJsonEncodeDecode.cpp 45 style unusedFunction false The function 'dumpToFile' is never used. +unchanged ApplicationCode\GeoMech\OdbReader\RifOdbReader.cpp 551 style unusedFunction false The function 'elementSet' is never used. +unchanged ApplicationCode\Application\RiaEclipseFileNameTools.cpp 73 style unusedFunction false The function 'findRelatedDataFile' is never used. +unchanged ApplicationCode\Commands\HoloLensCommands\VdeArrayDataPacket.cpp 221 style unusedFunction false The function 'fromRawPacketBuffer' is never used. +unchanged ApplicationCode\GeoMech\GeoMechDataModel\RigFemPartGrid.cpp 503 style unusedFunction false The function 'gridPointCoordinate' is never used. +unchanged ApplicationCode\GeoMech\GeoMechDataModel\RigFemPartGrid.cpp 362 style unusedFunction false The function 'gridPointCountI' is never used. +unchanged ApplicationCode\GeoMech\GeoMechDataModel\RigFemPartGrid.cpp 371 style unusedFunction false The function 'gridPointCountJ' is never used. +unchanged ApplicationCode\GeoMech\GeoMechDataModel\RigFemPartGrid.cpp 494 style unusedFunction false The function 'gridPointIndexFromIJK' is never used. +unchanged ApplicationCode\UserInterface\RiuCadNavigation.cpp 49 style unusedFunction false The function 'handleInputEvent' is never used. +unchanged ApplicationCode\Commands\Ric3dViewPickEventHandler.cpp 42 style unusedFunction false The function 'handlePickEvent' is never used. +unchanged ApplicationCode\ProjectDataModel\RimMimeData.cpp 56 style unusedFunction false The function 'hasFormat' is never used. +unchanged ApplicationCode\Commands\HoloLensCommands\VdeArrayDataPacket.cpp 173 style unusedFunction false The function 'imageComponentCount' is never used. +unchanged ApplicationCode\Application\Tools\RiaImageFileCompare.cpp 126 style unusedFunction false The function 'imagesEqual' is never used. +unchanged ApplicationCode\WellPathImportSsihub\RiuWellImportWizard.cpp 760 style unusedFunction false The function 'initializePage' is never used. +unchanged ApplicationCode\UserInterface\RiuViewer.cpp 860 style unusedFunction false The function 'leaveEvent' is never used. +unchanged ApplicationCode\GeoMech\GeoMechDataModel\RigFemPartGrid.cpp 405 style unusedFunction false The function 'maxCoordinate' is never used. +unchanged ApplicationCode\UserInterface\RiuDragDrop.cpp 332 style unusedFunction false The function 'mimeTypes' is never used. +unchanged ApplicationCode\GeoMech\GeoMechDataModel\RigFemPartGrid.cpp 396 style unusedFunction false The function 'minCoordinate' is never used. +unchanged ApplicationCode\UserInterface\RiuFlowCharacteristicsPlot.cpp 271 style unusedFunction false The function 'minimumSizeHint' is never used. +unchanged ApplicationCode\UserInterface\RiuViewer.cpp 539 style unusedFunction false The function 'mousePressEvent' is never used. +unchanged ApplicationCode\UserInterface\RiuViewer.cpp 236 style unusedFunction false The function 'mouseReleaseEvent' is never used. +unchanged ApplicationCode\Commands\AnnotationCommands\RicCreateReachCircleAnnotationFeature.cpp 59 style unusedFunction false The function 'onActionTriggered' is never used. +unchanged ApplicationCode\UserInterface\RiuDragDrop.cpp 342 style unusedFunction false The function 'onDragCanceled' is never used. +unchanged ApplicationCode\Commands\SummaryPlotCommands\RicSummaryCurveCalculator.cpp 276 style unusedFunction false The function 'onEditorWidgetsCreated' is never used. +unchanged ApplicationCode\UserInterface\RiuDragDrop.cpp 565 style unusedFunction false The function 'onProposedDropActionUpdated' is never used. +unchanged ApplicationCode\UserInterface\RiuMultiCaseImportDialog.cpp 105 style unusedFunction false The function 'on_m_addSearchFolderButton_clicked' is never used. +unchanged ApplicationCode\UserInterface\RiuMultiCaseImportDialog.cpp 247 style unusedFunction false The function 'on_m_removeEclipseCaseButton_clicked' is never used. +unchanged ApplicationCode\UserInterface\RiuMultiCaseImportDialog.cpp 129 style unusedFunction false The function 'on_m_removeSearchFolderButton_clicked' is never used. +unchanged ApplicationCode\UserInterface\RiuViewer.cpp 345 style unusedFunction false The function 'paintOverlayItems' is never used. +unchanged ApplicationCode\ProjectDataModel\RimProject.cpp 1066 style unusedFunction false The function 'polylineAnnotations' is never used. +unchanged ApplicationCode\Application\RiaApplication.cpp 326 style unusedFunction false The function 'processNonGuiEvents' is never used. +unchanged ApplicationCode\Commands\SummaryPlotCommands\RicSummaryCurveCalculatorEditor.cpp 65 style unusedFunction false The function 'recursivelyConfigureAndUpdateTopLevelUiOrdering' is never used. +unchanged ApplicationCode\ProjectDataModel\RimEclipseResultDefinition.cpp 755 style unusedFunction false The function 'setFromEclipseResultAddress' is never used. +unchanged ApplicationCode\ProjectDataModel\Completions\RimWellPathAicdParameters.cpp 189 style unusedFunction false The function 'setUnitLabels' is never used. +unchanged ApplicationCode\ProjectDataModel\Flow\RimWellPltPlot.cpp 1067 style unusedFunction false The function 'setupBeforeSave' is never used. +unchanged ApplicationCode\UserInterface\RiuWellLogPlot.cpp 519 style unusedFunction false The function 'showEvent' is never used. +unchanged ApplicationCode\ReservoirDataModel\RigSimulationWellCenterLineCalculator.cpp 1064 style unusedFunction false The function 'splitIntoBranches' is never used. +unchanged ApplicationCode\UserInterface\RiuDragDrop.cpp 126 style unusedFunction false The function 'supportedDropActions' is never used. +unchanged ApplicationCode\ReservoirDataModel\RigFlowDiagResultAddress.cpp 67 style unusedFunction false The function 'uiShortText' is never used. +unchanged ApplicationCode\Commands\CrossSectionCommands\RicAppendIntersectionFeature.cpp 121 style unusedFunction false The function 'undo' is never used. +unchanged ApplicationCode\ModelVisualization\RivCellEdgeEffectGenerator.cpp 281 style unusedFunction false The function 'updateForFixedFunctionRendering' is never used. +unchanged ApplicationCode\ModelVisualization\RivCellEdgeEffectGenerator.cpp 135 style unusedFunction false The function 'updateForShaderBasedRendering' is never used. +unchanged ApplicationCode\UnitTests\ListKeywordsForObjectsAndFields-Test.cpp 16 style unusedFunction false The function 'writeTextToFile' is never used. +unchanged ApplicationCode\Commands\HoloLensCommands\RicHoloLensSessionManager.h 47 style unusedPrivateFunction false Unused private function: 'RicHoloLensSessionManager::handleSessionNotification' +unchanged ApplicationCode\Commands\HoloLensCommands\VdeVizDataExtractor.h 106 style unusedPrivateFunction false Unused private function: 'VdeVizDataExtractor::debugComparePackets' +unchanged ApplicationCode\FileInterface\RifCaseRealizationParametersReader.h 101 style unusedPrivateFunction false Unused private function: 'RifCaseRealizationRunspecificationReader::closeDataStream' +unchanged ApplicationCode\ReservoirDataModel\RigSimulationWellCenterLineCalculator.h 52 style unusedPrivateFunction false Unused private function: 'RigSimulationWellCenterLineCalculator::splitIntoBranches' + + +Candidate for later use +----------------------- + +Issue on GitHub +---- + +Must be changed +---------------- + +Deleted +------- +unchanged ApplicationCode\FileInterface\RifEclipseDataTableFormatter.cpp 278 style unusedFunction false The function 'addValueTable' is never used. +unchanged ApplicationCode\ReservoirDataModel\Completions\RigEclipseToStimPlanCellTransmissibilityCalculator.cpp 109 style unusedFunction false The function 'aggregatedMatrixTransmissibility' is never used. +unchanged ApplicationCode\ProjectDataModel\Annotations\RimAnnotationInViewCollection.cpp 231 style unusedFunction false The function 'annotationsCount' is never used. +unchanged ApplicationCode\Commands\ExportCommands\RicExportLgrFeature.cpp 848 style unusedFunction false The function 'appendIntersectedCells' is never used. +unchanged ApplicationCode\Application\Tools\RiaQIconTools.cpp 26 style unusedFunction false The function 'appendPixmapUpperLeft' is never used. +unchanged ApplicationCode\ReservoirDataModel\RigEclipseResultBinSorter.cpp 48 style unusedFunction false The function 'binRange' is never used. +unchanged ApplicationCode\Commands\ExportCommands\RicExportLgrFeature.cpp 684 style unusedFunction false The function 'cellsIntersectingCompletion' is never used. +unchanged ApplicationCode\Commands\ExportCommands\RicExportLgrFeature.cpp 702 style unusedFunction false The function 'createOrderedIntersectionList' is never used. +unchanged ApplicationCode\Commands\ExportCommands\RicExportLgrFeature.cpp 1129 style unusedFunction false The function 'resetNumbering' is never used. +unchanged ApplicationCode\Commands\RicCreateTemporaryLgrFeature.cpp 350 style unusedFunction false The function 'containsAnyNonMainGridCells' is never used. +unchanged ApplicationCode\Application\Tools\RiaColorTools.cpp 147 style unusedFunction false The function 'contrastRatio' is never used. +unchanged ApplicationCode\ProjectDataModel\Completions\RimPerforationInterval.cpp 105 style unusedFunction false The function 'enableCustomEndDate' is never used. +unchanged ApplicationCode\ProjectDataModel\Rim3dView.cpp 1099 style unusedFunction false The function 'enablePerspectiveProjectionField' is never used. +unchanged ApplicationCode\ReservoirDataModel\RigMainGrid.cpp 166 style unusedFunction false The function 'findAllReservoirCellIndicesMatching2dPoint' is never used. +unchanged ApplicationCode\ProjectDataModel\GridCrossPlots\RimGridCrossPlotDataSet.cpp 400 style unusedFunction false The function 'groupStrings' is never used. +unchanged ApplicationCode\ProjectDataModel\RimContourMapProjection.cpp 354 style unusedFunction false The function 'hasResultAtVertex' is never used. +unchanged ApplicationCode\ProjectDataModel\RimContourMapProjection.cpp 1417 style unusedFunction false The function 'isSummationResult' is never used. +unchanged ApplicationCode\ProjectDataModel\RimContourMapProjection.cpp 223 style unusedFunction false The function 'resultAggregation' is never used. +unchanged ApplicationCode\ProjectDataModel\RimContourMapProjection.cpp 255 style unusedFunction false The function 'showContourLabels' is never used. +unchanged ApplicationCode\ProjectDataModel\Annotations\RimUserDefinedPolylinesAnnotation.cpp 42 style unusedFunction false The function 'xydToXyzVector' is never used. +unchanged ApplicationCode\ProjectDataModel\Completions\RimSimWellFracture.cpp 117 style unusedFunction false The function 'wellDipAtFracturePosition' is never used. +unchanged ApplicationCode\ReservoirDataModel\RigLocalGrid.cpp 65 style unusedFunction false The function 'setPositionInParentGrid' is never used. +unchanged ApplicationCode\ProjectDataModel\Annotations\RimPolylinesAnnotationInView.cpp 66 style unusedFunction false The function 'setSourceAnnotation' is never used. +unchanged ApplicationCode\ProjectDataModel\Annotations\RimAnnotationTextAppearance.cpp 75 style unusedFunction false The function 'setAnchorLineColor' is never used. +unchanged ApplicationCode\ProjectDataModel\Annotations\RimAnnotationTextAppearance.cpp 59 style unusedFunction false The function 'setFontColor' is never used. +unchanged ApplicationCode\ProjectDataModel\RimScaleLegendConfig.cpp 447 style unusedFunction false The function 'setCurrentScale' is never used. +unchanged ApplicationCode\ProjectDataModel\Rim3dOverlayInfoConfig.cpp 278 style unusedFunction false The function 'setIsActive' is never used. +unchanged ApplicationCode\FileInterface\RifEclipseDataTableFormatter.cpp 137 style unusedFunction false The function 'setMaxDataRowWidth' is never used. +unchanged ApplicationCode\ProjectDataModel\RimRegularLegendConfig.cpp 737 style unusedFunction false The function 'setShowLegend' is never used. + +Backlog +------- diff --git a/ApplicationCode/Application/CMakeLists_files.cmake b/ApplicationCode/Application/CMakeLists_files.cmake index e22ea375b9..f9828e8acf 100644 --- a/ApplicationCode/Application/CMakeLists_files.cmake +++ b/ApplicationCode/Application/CMakeLists_files.cmake @@ -11,6 +11,8 @@ ${CMAKE_CURRENT_LIST_DIR}/RiaCurveSetDefinition.h ${CMAKE_CURRENT_LIST_DIR}/RiaRftPltCurveDefinition.h ${CMAKE_CURRENT_LIST_DIR}/RiaViewRedrawScheduler.h ${CMAKE_CURRENT_LIST_DIR}/RiaMemoryCleanup.h +${CMAKE_CURRENT_LIST_DIR}/RiaFontCache.h +${CMAKE_CURRENT_LIST_DIR}/RiaEclipseFileNameTools.h ) set (SOURCE_GROUP_SOURCE_FILES @@ -26,6 +28,8 @@ ${CMAKE_CURRENT_LIST_DIR}/RiaCurveSetDefinition.cpp ${CMAKE_CURRENT_LIST_DIR}/RiaRftPltCurveDefinition.cpp ${CMAKE_CURRENT_LIST_DIR}/RiaViewRedrawScheduler.cpp ${CMAKE_CURRENT_LIST_DIR}/RiaMemoryCleanup.cpp +${CMAKE_CURRENT_LIST_DIR}/RiaFontCache.cpp +${CMAKE_CURRENT_LIST_DIR}/RiaEclipseFileNameTools.cpp ) list(APPEND CODE_HEADER_FILES diff --git a/ApplicationCode/Application/RiaApplication.cpp b/ApplicationCode/Application/RiaApplication.cpp index 1fcf0d285f..9f994bef10 100644 --- a/ApplicationCode/Application/RiaApplication.cpp +++ b/ApplicationCode/Application/RiaApplication.cpp @@ -3,17 +3,17 @@ // Copyright (C) 2011- Statoil ASA // Copyright (C) 2013- Ceetron Solutions AS // Copyright (C) 2011-2012 Ceetron AS -// +// // ResInsight 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 3 of the License, or // (at your option) any later version. -// +// // ResInsight 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 at +// +// See the GNU General Public License at // for more details. // ///////////////////////////////////////////////////////////////////////////////// @@ -22,7 +22,9 @@ #include "RiaArgumentParser.h" #include "RiaBaseDefs.h" +#include "RiaColorTables.h" #include "RiaFilePathTools.h" +#include "RiaFontCache.h" #include "RiaImportEclipseCaseTools.h" #include "RiaLogging.h" #include "RiaPreferences.h" @@ -31,12 +33,14 @@ #include "RiaVersionInfo.h" #include "RiaViewRedrawScheduler.h" -#include "RicImportInputEclipseCaseFeature.h" -#include "RicImportSummaryCasesFeature.h" #include "ExportCommands/RicSnapshotAllViewsToFileFeature.h" #include "HoloLensCommands/RicHoloLensSessionManager.h" +#include "RicImportGeneralDataFeature.h" #include "Rim2dIntersectionViewCollection.h" +#include "RimAnnotationCollection.h" +#include "RimAnnotationInViewCollection.h" +#include "RimAnnotationTextAppearance.h" #include "RimCellRangeFilterCollection.h" #include "RimCommandObject.h" #include "RimEclipseCaseCollection.h" @@ -48,6 +52,8 @@ #include "RimGeoMechCellColors.h" #include "RimGeoMechModels.h" #include "RimGeoMechView.h" +#include "RimGridCrossPlot.h" +#include "RimGridCrossPlotCollection.h" #include "RimIdenticalGridCaseGroup.h" #include "RimMainPlotCollection.h" #include "RimObservedData.h" @@ -56,6 +62,9 @@ #include "RimPltPlotCollection.h" #include "RimProject.h" #include "RimRftPlotCollection.h" +#include "RimSaturationPressurePlot.h" +#include "RimSaturationPressurePlotCollection.h" +#include "RimSimWellInViewCollection.h" #include "RimStimPlanColors.h" #include "RimSummaryCase.h" #include "RimSummaryCaseCollection.h" @@ -63,6 +72,8 @@ #include "RimSummaryCrossPlotCollection.h" #include "RimSummaryPlot.h" #include "RimSummaryPlotCollection.h" +#include "RimTextAnnotation.h" +#include "RimTextAnnotationInView.h" #include "RimViewLinker.h" #include "RimViewLinkerCollection.h" #include "RimWellLogFile.h" @@ -73,12 +84,13 @@ #include "RimWellPltPlot.h" #include "RimWellRftPlot.h" +#include "Riu3dSelectionManager.h" #include "RiuDockWidgetTools.h" -#include "RiuPlotMainWindow.h" #include "RiuMainWindow.h" +#include "RiuMessagePanel.h" +#include "RiuPlotMainWindow.h" #include "RiuProcessMonitor.h" #include "RiuRecentFileActionProvider.h" -#include "RiuSelectionManager.h" #include "RiuViewer.h" #include "cafAppEnum.h" @@ -103,10 +115,9 @@ #include #include - #ifndef WIN32 -#include // for usleep -#endif //WIN32 +#include // for usleep +#endif // WIN32 #ifdef USE_UNIT_TESTS #include "gtest/gtest.h" @@ -115,18 +126,15 @@ namespace caf { template<> -void AppEnum< RiaApplication::RINavigationPolicy >::setUp() +void AppEnum::setUp() { - addItem(RiaApplication::NAVIGATION_POLICY_CEETRON, "NAVIGATION_POLICY_CEETRON", "Ceetron"); - addItem(RiaApplication::NAVIGATION_POLICY_CAD, "NAVIGATION_POLICY_CAD", "CAD"); - addItem(RiaApplication::NAVIGATION_POLICY_GEOQUEST, "NAVIGATION_POLICY_GEOQUEST", "GEOQUEST"); - addItem(RiaApplication::NAVIGATION_POLICY_RMS, "NAVIGATION_POLICY_RMS", "RMS"); + addItem(RiaApplication::NAVIGATION_POLICY_CEETRON, "NAVIGATION_POLICY_CEETRON", "Ceetron"); + addItem(RiaApplication::NAVIGATION_POLICY_CAD, "NAVIGATION_POLICY_CAD", "CAD"); + addItem(RiaApplication::NAVIGATION_POLICY_GEOQUEST, "NAVIGATION_POLICY_GEOQUEST", "GEOQUEST"); + addItem(RiaApplication::NAVIGATION_POLICY_RMS, "NAVIGATION_POLICY_RMS", "RMS"); setDefault(RiaApplication::NAVIGATION_POLICY_RMS); } -} - - - +} // namespace caf //================================================================================================== /// @@ -136,23 +144,23 @@ void AppEnum< RiaApplication::RINavigationPolicy >::setUp() /// //================================================================================================== - //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- bool RiaApplication::notify(QObject* receiver, QEvent* event) { - // Pre-allocating a memory exhaustion message + // Pre-allocating a memory exhaustion message // Doing som e trickery to avoid deadlock, as creating a messagebox actually triggers a call to this notify method. - static QMessageBox* memoryExhaustedBox = nullptr; - static bool allocatingMessageBox = false; + static QMessageBox* memoryExhaustedBox = nullptr; + static bool allocatingMessageBox = false; if (!memoryExhaustedBox && !allocatingMessageBox) { allocatingMessageBox = true; - memoryExhaustedBox = new QMessageBox(QMessageBox::Critical, - "ResInsight Exhausted Memory", - "Memory is Exhausted!\n ResInsight could not allocate the memory needed, and is now unstable and will probably crash soon."); + memoryExhaustedBox = new QMessageBox(QMessageBox::Critical, + "ResInsight Exhausted Memory", + "Memory is Exhausted!\n ResInsight could not allocate the memory needed, and is now " + "unstable and will probably crash soon."); } bool done = true; @@ -160,11 +168,13 @@ bool RiaApplication::notify(QObject* receiver, QEvent* event) { done = QApplication::notify(receiver, event); } - catch ( const std::bad_alloc& ) + catch (const std::bad_alloc&) { if (memoryExhaustedBox) memoryExhaustedBox->exec(); - std::cout << "ResInsight: Memory is Exhausted!\n ResInsight could not allocate the memory needed, and is now unstable and will probably crash soon." << std::endl; - // If we really want to crash instead of limping forward: + std::cout << "ResInsight: Memory is Exhausted!\n ResInsight could not allocate the memory needed, and is now unstable " + "and will probably crash soon." + << std::endl; + // If we really want to crash instead of limping forward: // throw; } @@ -172,20 +182,26 @@ bool RiaApplication::notify(QObject* receiver, QEvent* event) } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- RiaApplication::RiaApplication(int& argc, char** argv) -: QApplication(argc, argv) + : QApplication(argc, argv) + , m_socketServer(nullptr) + , m_workerProcess(nullptr) + , m_preferences(nullptr) + , m_runningWorkerProcess(false) + , m_mainWindow(nullptr) + , m_mainPlotWindow(nullptr) { // USed to get registry settings in the right place QCoreApplication::setOrganizationName(RI_COMPANY_NAME); QCoreApplication::setApplicationName(RI_APPLICATION_NAME); // For idle processing -// m_idleTimerStarted = false; + // m_idleTimerStarted = false; installEventFilter(this); - //cvf::Trace::enable(false); + // cvf::Trace::enable(false); m_preferences = new RiaPreferences; caf::PdmSettings::readFieldsFromApplicationStore(m_preferences); @@ -202,11 +218,8 @@ RiaApplication::RiaApplication(int& argc, char** argv) // Start with a project m_project = new RimProject; - - setWindowIcon(QIcon(":/AppLogo48x48.png")); - m_socketServer = new RiaSocketServer( this); - m_workerProcess = nullptr; + setWindowIcon(QIcon(":/AppLogo48x48.png")); #ifdef WIN32 m_startupDefaultDirectory = QDir::homePath(); @@ -216,36 +229,40 @@ RiaApplication::RiaApplication(int& argc, char** argv) setLastUsedDialogDirectory("MULTICASEIMPORT", "/"); - // The creation of a font is time consuming, so make sure you really need your own font - // instead of using the application font - m_standardFont = new caf::FixedAtlasFont(caf::FixedAtlasFont::POINT_SIZE_8); + m_recentFileActionProvider = std::unique_ptr(new RiuRecentFileActionProvider); - m_runningWorkerProcess = false; + // Create main windows + // The plot window is created to be able to set expanded state on created objects, but hidden by default + getOrCreateAndShowMainWindow(); + getOrCreateMainPlotWindow(); - m_mainPlotWindow = nullptr; + RiaLogging::setLoggerInstance(new RiuMessagePanelLogger(m_mainWindow->messagePanel())); + RiaLogging::loggerInstance()->setLevel(RI_LL_DEBUG); - m_recentFileActionProvider = std::unique_ptr(new RiuRecentFileActionProvider); + m_socketServer = new RiaSocketServer(this); } - //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- RiaApplication::~RiaApplication() { RiuDockWidgetTools::instance()->saveDockWidgetsState(); deleteMainPlotWindow(); + deleteMainWindow(); delete m_preferences; + + RiaLogging::deleteLoggerInstance(); } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- RiaApplication* RiaApplication::instance() { - return static_castqApp; + return static_cast qApp; } //-------------------------------------------------------------------------------------------------- @@ -278,12 +295,11 @@ int RiaApplication::parseArgumentsAndRunUnitTestsIfRequested() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RiaApplication::setWindowCaptionFromAppState() { - RiuMainWindow* mainWnd = RiuMainWindow::instance(); - if (!mainWnd) return; + if (!m_mainWindow) return; // The stuff being done here should really be handled by Qt automatically as a result of // setting applicationName and windowFilePath @@ -296,26 +312,24 @@ void RiaApplication::setWindowCaptionFromAppState() { QString projFileName = m_project->fileName(); - if (projFileName.isEmpty()) projFileName = "Untitled project"; + if (projFileName.isEmpty()) projFileName = "Untitled project"; capt = projFileName + QString("[*]") + QString(" - ") + capt; } - mainWnd->setWindowTitle(capt); + m_mainWindow->setWindowTitle(capt); } - //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RiaApplication::processNonGuiEvents() { processEvents(QEventLoop::ExcludeUserInputEvents); } - //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- const char* RiaApplication::getVersionStringApp(bool includeCrtInfo) { @@ -339,17 +353,65 @@ const char* RiaApplication::getVersionStringApp(bool includeCrtInfo) return szBuf; } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +class RiaMdiMaximizeWindowGuard +{ +public: + RiaMdiMaximizeWindowGuard() + { + { + RiuMainWindow* mainWindow = RiaApplication::instance()->mainWindow(); + if (mainWindow) + { + mainWindow->enableShowFirstVisibleMdiWindowMaximized(false); + } + } + { + RiuPlotMainWindow* plotMainWindow = RiaApplication::instance()->mainPlotWindow(); + if (plotMainWindow) + { + plotMainWindow->enableShowFirstVisibleMdiWindowMaximized(false); + } + } + } + + ~RiaMdiMaximizeWindowGuard() + { + { + RiuMainWindow* mainWindow = RiaApplication::instance()->mainWindow(); + if (mainWindow) + { + mainWindow->enableShowFirstVisibleMdiWindowMaximized(true); + } + } + + { + RiuPlotMainWindow* plotMainWindow = RiaApplication::instance()->mainPlotWindow(); + if (plotMainWindow) + { + plotMainWindow->enableShowFirstVisibleMdiWindowMaximized(true); + } + } + } +}; //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- -bool RiaApplication::loadProject(const QString& projectFileName, ProjectLoadAction loadAction, RiaProjectModifier* projectModifier) +bool RiaApplication::loadProject(const QString& projectFileName, + ProjectLoadAction loadAction, + RiaProjectModifier* projectModifier) { // First Close the current project closeProject(); + // When importing a project, do not maximize the first MDI window to be created + RiaMdiMaximizeWindowGuard maximizeWindowGuard; + RiaLogging::info(QString("Starting to open project file : '%1'").arg(projectFileName)); // Create a absolute path file name, as this is required for update of file references in the project modifier object @@ -379,11 +441,11 @@ bool RiaApplication::loadProject(const QString& projectFileName, ProjectLoadActi { closeProject(); - QString tmp = QString("Unknown project file version detected in file \n%1\n\nCould not open project.").arg(fullPathProjectFileName); + QString tmp = + QString("Unknown project file version detected in file \n%1\n\nCould not open project.").arg(fullPathProjectFileName); QMessageBox::warning(nullptr, "Error when opening project file", tmp); - RiuMainWindow* mainWnd = RiuMainWindow::instance(); - mainWnd->setPdmRoot(nullptr); + m_mainWindow->setPdmRoot(nullptr); // Delete all object possibly generated by readFile() delete m_project; @@ -396,11 +458,11 @@ bool RiaApplication::loadProject(const QString& projectFileName, ProjectLoadActi if (m_project->show3DWindow()) { - RiuMainWindow::instance()->show(); + m_mainWindow->show(); } else { - RiuMainWindow::instance()->hide(); + m_mainWindow->hide(); } if (m_project->showPlotWindow()) @@ -421,10 +483,9 @@ bool RiaApplication::loadProject(const QString& projectFileName, ProjectLoadActi mainPlotWindow()->hide(); } - /////// // Load the external data, and initialize stuff that needs specific ordering - + // VL check regarding specific order mentioned in comment above... m_preferences->lastUsedProjectFileName = fullPathProjectFileName; @@ -432,7 +493,7 @@ bool RiaApplication::loadProject(const QString& projectFileName, ProjectLoadActi for (size_t oilFieldIdx = 0; oilFieldIdx < m_project->oilFields().size(); oilFieldIdx++) { - RimOilField* oilField = m_project->oilFields[oilFieldIdx]; + RimOilField* oilField = m_project->oilFields[oilFieldIdx]; RimEclipseCaseCollection* analysisModels = oilField ? oilField->analysisModels() : nullptr; if (analysisModels == nullptr) continue; @@ -446,24 +507,23 @@ bool RiaApplication::loadProject(const QString& projectFileName, ProjectLoadActi // Load the formation names - for(RimOilField* oilField: m_project->oilFields) + for (RimOilField* oilField : m_project->oilFields) { - if (oilField == nullptr) continue; - if(oilField->formationNamesCollection() != nullptr) + if (oilField == nullptr) continue; + if (oilField->formationNamesCollection() != nullptr) { oilField->formationNamesCollection()->readAllFormationNames(); } } - // Add well paths for each oil field for (size_t oilFieldIdx = 0; oilFieldIdx < m_project->oilFields().size(); oilFieldIdx++) { RimOilField* oilField = m_project->oilFields[oilFieldIdx]; - if (oilField == nullptr) continue; + if (oilField == nullptr) continue; if (oilField->wellPathCollection == nullptr) { - //printf("Create well path collection for oil field %i in loadProject.\n", oilFieldIdx); + // printf("Create well path collection for oil field %i in loadProject.\n", oilFieldIdx); oilField->wellPathCollection = new RimWellPathCollection(); } @@ -474,11 +534,11 @@ bool RiaApplication::loadProject(const QString& projectFileName, ProjectLoadActi } } - for (RimOilField* oilField: m_project->oilFields) + for (RimOilField* oilField : m_project->oilFields) { - if (oilField == nullptr) continue; + if (oilField == nullptr) continue; // Temporary - if(!oilField->summaryCaseMainCollection()) + if (!oilField->summaryCaseMainCollection()) { oilField->summaryCaseMainCollection = new RimSummaryCaseMainCollection(); } @@ -488,17 +548,12 @@ bool RiaApplication::loadProject(const QString& projectFileName, ProjectLoadActi { oilField->observedDataCollection = new RimObservedDataCollection(); } - for (auto observedCases : oilField->observedDataCollection()->allObservedData()) + for (RimObservedData* observedData : oilField->observedDataCollection()->allObservedData()) { - observedCases->createSummaryReaderInterface(); - - RimObservedData* rimObservedData = dynamic_cast(observedCases); - if (rimObservedData) - { - rimObservedData->updateMetaData(); - } + observedData->createSummaryReaderInterface(); + observedData->updateMetaData(); } - + oilField->fractureDefinitionCollection()->loadAndUpdateData(); oilField->fractureDefinitionCollection()->createAndAssignTemplateCopyForNonMatchingUnit(); @@ -511,7 +566,6 @@ bool RiaApplication::loadProject(const QString& projectFileName, ProjectLoadActi fracture->loadDataAndUpdate(); } } - } // If load action is specified to recalculate statistics, do it now. @@ -520,7 +574,7 @@ bool RiaApplication::loadProject(const QString& projectFileName, ProjectLoadActi { for (size_t oilFieldIdx = 0; oilFieldIdx < m_project->oilFields().size(); oilFieldIdx++) { - RimOilField* oilField = m_project->oilFields[oilFieldIdx]; + RimOilField* oilField = m_project->oilFields[oilFieldIdx]; RimEclipseCaseCollection* analysisModels = oilField ? oilField->analysisModels() : nullptr; if (analysisModels) { @@ -529,8 +583,6 @@ bool RiaApplication::loadProject(const QString& projectFileName, ProjectLoadActi } } - - // Now load the ReservoirViews for the cases // Add all "native" cases in the project std::vector casesToLoad; @@ -549,7 +601,7 @@ bool RiaApplication::loadProject(const QString& projectFileName, ProjectLoadActi caf::ProgressInfo viewProgress(views.size(), "Creating Views"); size_t j; - for ( j = 0; j < views.size(); j++ ) + for (j = 0; j < views.size(); j++) { Rim3dView* riv = views[j]; CVF_ASSERT(riv); @@ -565,13 +617,13 @@ bool RiaApplication::loadProject(const QString& projectFileName, ProjectLoadActi stimPlanColors[0]->updateConductivityResultName(); } } - + riv->loadDataAndUpdate(); - if ( m_project->isProjectFileVersionEqualOrOlderThan("2018.1.1.110") ) + if (m_project->isProjectFileVersionEqualOrOlderThan("2018.1.1.110")) { auto* geoView = dynamic_cast(riv); - if ( geoView ) + if (geoView) { geoView->convertCameraPositionFromOldProjectFiles(); } @@ -593,10 +645,10 @@ bool RiaApplication::loadProject(const QString& projectFileName, ProjectLoadActi { m_project->viewLinkerCollection()->viewLinker()->updateOverrides(); } - + // Intersection Views: Sync from intersections in the case. - for (RimCase* cas: casesToLoad) + for (RimCase* cas : casesToLoad) { cas->intersectionViewCollection()->syncFromExistingIntersections(false); } @@ -605,17 +657,19 @@ bool RiaApplication::loadProject(const QString& projectFileName, ProjectLoadActi for (RimOilField* oilField : m_project->oilFields) { auto sumMainCollection = oilField->summaryCaseMainCollection(); - if(!sumMainCollection) continue; + if (!sumMainCollection) continue; for (auto sumCaseGroup : sumMainCollection->summaryCaseCollections()) { sumCaseGroup->loadDataAndUpdate(); } + + oilField->annotationCollection()->loadDataAndUpdate(); } loadAndUpdatePlotData(); - // NB! This function must be called before executing command objects, + // NB! This function must be called before executing command objects, // because the tree view state is restored from project file and sets // current active view ( see restoreTreeViewState() ) // Default behavior for scripts is to use current active view for data read/write @@ -640,7 +694,7 @@ bool RiaApplication::loadProject(const QString& projectFileName, ProjectLoadActi } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- bool RiaApplication::loadProject(const QString& projectFileName) { @@ -648,16 +702,18 @@ bool RiaApplication::loadProject(const QString& projectFileName) } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RiaApplication::loadAndUpdatePlotData() { - RimWellLogPlotCollection* wlpColl = nullptr; - RimSummaryPlotCollection* spColl = nullptr; - RimSummaryCrossPlotCollection* scpColl = nullptr; - RimFlowPlotCollection* flowColl = nullptr; - RimRftPlotCollection* rftColl = nullptr; - RimPltPlotCollection* pltColl = nullptr; + RimWellLogPlotCollection* wlpColl = nullptr; + RimSummaryPlotCollection* spColl = nullptr; + RimSummaryCrossPlotCollection* scpColl = nullptr; + RimFlowPlotCollection* flowColl = nullptr; + RimRftPlotCollection* rftColl = nullptr; + RimPltPlotCollection* pltColl = nullptr; + RimGridCrossPlotCollection* gcpColl = nullptr; + RimSaturationPressurePlotCollection* sppColl = nullptr; if (m_project->mainPlotCollection() && m_project->mainPlotCollection()->wellLogPlotCollection()) { @@ -683,6 +739,14 @@ void RiaApplication::loadAndUpdatePlotData() { pltColl = m_project->mainPlotCollection()->pltPlotCollection(); } + if (m_project->mainPlotCollection() && m_project->mainPlotCollection()->gridCrossPlotCollection()) + { + gcpColl = m_project->mainPlotCollection()->gridCrossPlotCollection(); + } + if (m_project->mainPlotCollection() && m_project->mainPlotCollection()->saturationPressurePlotCollection()) + { + sppColl = m_project->mainPlotCollection()->saturationPressurePlotCollection(); + } size_t plotCount = 0; plotCount += wlpColl ? wlpColl->wellLogPlots().size() : 0; @@ -691,63 +755,86 @@ void RiaApplication::loadAndUpdatePlotData() plotCount += flowColl ? flowColl->plotCount() : 0; plotCount += rftColl ? rftColl->rftPlots().size() : 0; plotCount += pltColl ? pltColl->pltPlots().size() : 0; + plotCount += gcpColl ? gcpColl->gridCrossPlots().size() : 0; + plotCount += sppColl ? sppColl->plots().size() : 0; - caf::ProgressInfo plotProgress(plotCount, "Loading Plot Data"); - if (wlpColl) + if (plotCount > 0) { - for (size_t wlpIdx = 0; wlpIdx < wlpColl->wellLogPlots().size(); ++wlpIdx) + caf::ProgressInfo plotProgress(plotCount, "Loading Plot Data"); + if (wlpColl) { - wlpColl->wellLogPlots[wlpIdx]->loadDataAndUpdate(); - plotProgress.incrementProgress(); + for (size_t wlpIdx = 0; wlpIdx < wlpColl->wellLogPlots().size(); ++wlpIdx) + { + wlpColl->wellLogPlots[wlpIdx]->loadDataAndUpdate(); + plotProgress.incrementProgress(); + } } - } - if (spColl) - { - for (size_t wlpIdx = 0; wlpIdx < spColl->summaryPlots().size(); ++wlpIdx) + if (spColl) { - spColl->summaryPlots[wlpIdx]->loadDataAndUpdate(); - plotProgress.incrementProgress(); + for (size_t wlpIdx = 0; wlpIdx < spColl->summaryPlots().size(); ++wlpIdx) + { + spColl->summaryPlots[wlpIdx]->loadDataAndUpdate(); + plotProgress.incrementProgress(); + } } - } - - if (scpColl) - { - for (auto plot : scpColl->summaryPlots()) + + if (scpColl) + { + for (auto plot : scpColl->summaryPlots()) + { + plot->loadDataAndUpdate(); + plotProgress.incrementProgress(); + } + } + + if (flowColl) { - plot->loadDataAndUpdate(); + plotProgress.setNextProgressIncrement(flowColl->plotCount()); + flowColl->loadDataAndUpdate(); plotProgress.incrementProgress(); } - } - if (flowColl) - { - plotProgress.setNextProgressIncrement(flowColl->plotCount()); - flowColl->loadDataAndUpdate(); - plotProgress.incrementProgress(); - } + if (rftColl) + { + for (const auto& rftPlot : rftColl->rftPlots()) + { + rftPlot->loadDataAndUpdate(); + plotProgress.incrementProgress(); + } + } - if (rftColl) - { - for (const auto& rftPlot : rftColl->rftPlots()) + if (pltColl) { - rftPlot->loadDataAndUpdate(); - plotProgress.incrementProgress(); + for (const auto& pltPlot : pltColl->pltPlots()) + { + pltPlot->loadDataAndUpdate(); + plotProgress.incrementProgress(); + } } - } - if (pltColl) - { - for (const auto& pltPlot : pltColl->pltPlots()) + if (gcpColl) { - pltPlot->loadDataAndUpdate(); - plotProgress.incrementProgress(); + for (const auto& gcpPlot : gcpColl->gridCrossPlots()) + { + gcpPlot->loadDataAndUpdate(); + plotProgress.incrementProgress(); + } + } + + if (sppColl) + { + for (const auto& sppPlot : sppColl->plots()) + { + sppPlot->loadDataAndUpdate(); + plotProgress.incrementProgress(); + } } } } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RiaApplication::storeTreeViewState() { @@ -764,13 +851,13 @@ void RiaApplication::storeTreeViewState() QString encodedModelIndexString; caf::QTreeViewStateSerializer::encodeStringFromModelIndex(mi, encodedModelIndexString); - project()->plotWindowTreeViewState = treeViewState; + project()->plotWindowTreeViewState = treeViewState; project()->plotWindowCurrentModelIndexPath = encodedModelIndexString; } } { - caf::PdmUiTreeView* projectTreeView = RiuMainWindow::instance()->projectTreeView(); + caf::PdmUiTreeView* projectTreeView = m_mainWindow->projectTreeView(); if (projectTreeView) { QString treeViewState; @@ -781,7 +868,7 @@ void RiaApplication::storeTreeViewState() QString encodedModelIndexString; caf::QTreeViewStateSerializer::encodeStringFromModelIndex(mi, encodedModelIndexString); - project()->mainWindowTreeViewState = treeViewState; + project()->mainWindowTreeViewState = treeViewState; project()->mainWindowCurrentModelIndexPath = encodedModelIndexString; } } @@ -799,19 +886,19 @@ void RiaApplication::addWellPathsToModel(QList wellPathFilePaths) if (oilField->wellPathCollection == nullptr) { - //printf("Create well path collection.\n"); + // printf("Create well path collection.\n"); oilField->wellPathCollection = new RimWellPathCollection(); m_project->updateConnectedEditors(); } if (oilField->wellPathCollection) oilField->wellPathCollection->addWellPaths(wellPathFilePaths); - + oilField->wellPathCollection->updateConnectedEditors(); } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RiaApplication::addWellPathFormationsToModel(QList wellPathFormationsFilePaths) { @@ -855,13 +942,12 @@ void RiaApplication::addWellLogsToModel(const QList& wellLogFilePaths) RimWellLogFile* wellLogFile = oilField->wellPathCollection->addWellLogs(wellLogFilePaths); oilField->wellPathCollection->updateConnectedEditors(); - - RiuMainWindow::instance()->selectAsCurrentItem(wellLogFile); -} + m_mainWindow->selectAsCurrentItem(wellLogFile); +} //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- bool RiaApplication::saveProject() { @@ -877,13 +963,12 @@ bool RiaApplication::saveProject() } } - //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- bool RiaApplication::saveProjectPromptForFileName() { - //if (m_project.isNull()) return true; + // if (m_project.isNull()) return true; RiaApplication* app = RiaApplication::instance(); @@ -898,7 +983,8 @@ bool RiaApplication::saveProjectPromptForFileName() startPath += "/ResInsightProject.rsp"; } - QString fileName = QFileDialog::getSaveFileName(nullptr, tr("Save File"), startPath, tr("Project Files (*.rsp);;All files(*.*)")); + QString fileName = + QFileDialog::getSaveFileName(nullptr, tr("Save File"), startPath, tr("Project Files (*.rsp);;All files(*.*)")); if (fileName.isEmpty()) { return false; @@ -915,7 +1001,7 @@ bool RiaApplication::saveProjectPromptForFileName() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- bool RiaApplication::hasValidProjectFileExtension(const QString& fileName) { @@ -928,11 +1014,11 @@ bool RiaApplication::hasValidProjectFileExtension(const QString& fileName) } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- bool RiaApplication::askUserToSaveModifiedProject() { - if (caf::PdmUiModelChangeDetector::instance()->isModelChanged()) + if (m_preferences->showProjectChangedDialog() && caf::PdmUiModelChangeDetector::instance()->isModelChanged()) { QMessageBox msgBox; msgBox.setIcon(QMessageBox::Question); @@ -965,7 +1051,7 @@ bool RiaApplication::askUserToSaveModifiedProject() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- bool RiaApplication::saveProjectAs(const QString& fileName) { @@ -976,7 +1062,12 @@ bool RiaApplication::saveProjectAs(const QString& fileName) if (!m_project->writeFile()) { - QMessageBox::warning(nullptr, "Error when saving project file", QString("Not possible to save project file. Make sure you have sufficient access rights.\n\nProject file location : %1").arg(fileName)); + QMessageBox::warning( + nullptr, + "Error when saving project file", + QString( + "Not possible to save project file. Make sure you have sufficient access rights.\n\nProject file location : %1") + .arg(fileName)); return false; } @@ -992,22 +1083,20 @@ bool RiaApplication::saveProjectAs(const QString& fileName) } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RiaApplication::closeProject() { RicHoloLensSessionManager::instance()->terminateSession(); RicHoloLensSessionManager::refreshToolbarState(); - RiuMainWindow* mainWnd = RiuMainWindow::instance(); - RiaViewRedrawScheduler::instance()->clearViewsScheduledForUpdate(); terminateProcess(); RiaApplication::clearAllSelections(); - mainWnd->cleanupGuiBeforeProjectClose(); + m_mainWindow->cleanupGuiBeforeProjectClose(); if (m_mainPlotWindow) { @@ -1026,14 +1115,13 @@ void RiaApplication::closeProject() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RiaApplication::onProjectOpenedOrClosed() { - RiuMainWindow* mainWnd = RiuMainWindow::instance(); - if (mainWnd) + if (m_mainWindow) { - mainWnd->initializeGuiNewProjectLoaded(); + m_mainWindow->initializeGuiNewProjectLoaded(); } if (m_mainPlotWindow) { @@ -1044,7 +1132,7 @@ void RiaApplication::onProjectOpenedOrClosed() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- QString RiaApplication::currentProjectPath() const { @@ -1065,7 +1153,7 @@ QString RiaApplication::currentProjectPath() const //-------------------------------------------------------------------------------------------------- /// Create an absolute path from a path that is specified relative to the project directory -/// +/// /// If the path specified in \a projectRelativePath is already absolute, no changes will be made //-------------------------------------------------------------------------------------------------- QString RiaApplication::createAbsolutePathFromProjectRelativePath(QString projectRelativePath) @@ -1092,30 +1180,31 @@ QString RiaApplication::createAbsolutePathFromProjectRelativePath(QString projec } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- bool RiaApplication::openOdbCaseFromFile(const QString& fileName, bool applyTimeStepFilter) { if (!caf::Utils::fileExists(fileName)) return false; QFileInfo gridFileName(fileName); - QString caseName = gridFileName.completeBaseName(); + QString caseName = gridFileName.completeBaseName(); RimGeoMechCase* geoMechCase = new RimGeoMechCase(); geoMechCase->setFileName(fileName); geoMechCase->caseUserDescription = caseName; geoMechCase->setApplyTimeFilter(applyTimeStepFilter); - - RimGeoMechModels* geoMechModelCollection = m_project->activeOilField() ? m_project->activeOilField()->geoMechModels() : nullptr; + + RimGeoMechModels* geoMechModelCollection = + m_project->activeOilField() ? m_project->activeOilField()->geoMechModels() : nullptr; // Create the geoMech model container if it is not there already if (geoMechModelCollection == nullptr) { - geoMechModelCollection = new RimGeoMechModels(); + geoMechModelCollection = new RimGeoMechModels(); m_project->activeOilField()->geoMechModels = geoMechModelCollection; } - RimGeoMechView* riv = geoMechCase->createAndAddReservoirView(); + RimGeoMechView* riv = geoMechCase->createAndAddReservoirView(); caf::ProgressInfo progress(11, "Loading Case"); progress.setNextProgressIncrement(10); @@ -1128,7 +1217,7 @@ bool RiaApplication::openOdbCaseFromFile(const QString& fileName, bool applyTime } geoMechModelCollection->cases.push_back(geoMechCase); - //if (!riv->cellResult()->hasResult()) + // if (!riv->cellResult()->hasResult()) //{ // riv->cellResult()->setResultVariable(RiaDefines::undefinedResultName()); //} @@ -1137,13 +1226,13 @@ bool RiaApplication::openOdbCaseFromFile(const QString& fileName, bool applyTime m_project->updateConnectedEditors(); - RiuMainWindow::instance()->selectAsCurrentItem(riv->cellResult()); - + m_mainWindow->selectAsCurrentItem(riv->cellResult()); + return true; } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RiaApplication::createMockModel() { @@ -1151,25 +1240,23 @@ void RiaApplication::createMockModel() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RiaApplication::createResultsMockModel() { RiaImportEclipseCaseTools::openMockModel(RiaDefines::mockModelBasicWithResults()); } - //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RiaApplication::createLargeResultsMockModel() { RiaImportEclipseCaseTools::openMockModel(RiaDefines::mockModelLargeWithResults()); } - //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RiaApplication::createMockModelCustomized() { @@ -1177,15 +1264,15 @@ void RiaApplication::createMockModelCustomized() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RiaApplication::createInputMockModel() { - RicImportInputEclipseCaseFeature::openInputEclipseCaseFromFileNames(QStringList(RiaDefines::mockModelBasicInputCase())); + RiaImportEclipseCaseTools::openEclipseInputCaseFromFileNames(QStringList(RiaDefines::mockModelBasicInputCase())); } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- const Rim3dView* RiaApplication::activeReservoirView() const { @@ -1197,28 +1284,28 @@ const Rim3dView* RiaApplication::activeReservoirView() const //-------------------------------------------------------------------------------------------------- Rim3dView* RiaApplication::activeReservoirView() { - return m_activeReservoirView; + return m_activeReservoirView; } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- RimGridView* RiaApplication::activeGridView() { - return dynamic_cast( m_activeReservoirView.p()); + return dynamic_cast(m_activeReservoirView.p()); } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- RimViewWindow* RiaApplication::activePlotWindow() const { RimViewWindow* viewWindow = nullptr; - if ( m_mainPlotWindow ) + if (m_mainPlotWindow) { QList subwindows = m_mainPlotWindow->subWindowList(QMdiArea::StackingOrder); - if ( subwindows.size() > 0 ) + if (subwindows.size() > 0) { viewWindow = RiuInterfaceToViewWindow::viewWindowFromWidget(subwindows.back()->widget()); } @@ -1228,7 +1315,7 @@ RimViewWindow* RiaApplication::activePlotWindow() const } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RiaApplication::setActiveReservoirView(Rim3dView* rv) { @@ -1238,7 +1325,7 @@ void RiaApplication::setActiveReservoirView(Rim3dView* rv) } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- bool RiaApplication::useShaders() const { @@ -1250,27 +1337,24 @@ bool RiaApplication::useShaders() const return true; } - //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- RiaApplication::RINavigationPolicy RiaApplication::navigationPolicy() const { return m_preferences->navigationPolicy(); } - //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- bool RiaApplication::showPerformanceInfo() const { return m_preferences->showHud; } - //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- bool RiaApplication::parseArguments() { @@ -1285,15 +1369,35 @@ bool RiaApplication::parseArguments() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- int RiaApplication::launchUnitTests() { #ifdef USE_UNIT_TESTS + + caf::ProgressInfoBlocker progressBlocker; cvf::Assert::setReportMode(cvf::Assert::CONSOLE); - int argc = QCoreApplication::argc(); - testing::InitGoogleTest(&argc, QCoreApplication::argv()); +#if QT_VERSION < 0x050000 + int argc = QCoreApplication::argc(); + char** argv = QCoreApplication::argv(); +#else + int argc = QCoreApplication::arguments().size(); + QStringList arguments = QCoreApplication::arguments(); + std::vector argumentsStd; + for (QString qstring : arguments) + { + argumentsStd.push_back(qstring.toStdString()); + } + std::vector argVector; + for (std::string& string : argumentsStd) + { + argVector.push_back(&string.front()); + } + char** argv = argVector.data(); +#endif + + testing::InitGoogleTest(&argc, argv); // Use this macro in main() to run all tests. It returns 0 if all // tests are successful, or 1 otherwise. @@ -1302,13 +1406,14 @@ int RiaApplication::launchUnitTests() // parsed by InitGoogleTest(). return RUN_ALL_TESTS(); + #else return -1; #endif } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- int RiaApplication::launchUnitTestsWithConsole() { @@ -1332,6 +1437,26 @@ int RiaApplication::launchUnitTestsWithConsole() return launchUnitTests(); } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RiuMainWindow* RiaApplication::getOrCreateAndShowMainWindow() +{ + if (!m_mainWindow) + { + createMainWindow(); + } + return m_mainWindow; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RiuMainWindow* RiaApplication::mainWindow() +{ + return m_mainWindow; +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -1347,7 +1472,34 @@ RiuPlotMainWindow* RiaApplication::getOrCreateMainPlotWindow() } //-------------------------------------------------------------------------------------------------- -/// +/// +//-------------------------------------------------------------------------------------------------- +void RiaApplication::createMainWindow() +{ + CVF_ASSERT(m_mainWindow == nullptr); + m_mainWindow = new RiuMainWindow; + QString platform = cvf::System::is64Bit() ? "(64bit)" : "(32bit)"; + m_mainWindow->setWindowTitle("ResInsight " + platform); + m_mainWindow->setDefaultWindowSize(); + m_mainWindow->setDefaultToolbarVisibility(); + m_mainWindow->loadWinGeoAndDockToolBarLayout(); + m_mainWindow->showWindow(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiaApplication::deleteMainWindow() +{ + if (m_mainWindow) + { + delete m_mainWindow; + m_mainWindow = nullptr; + } +} + +//-------------------------------------------------------------------------------------------------- +/// //-------------------------------------------------------------------------------------------------- void RiaApplication::createMainPlotWindow() { @@ -1361,7 +1513,7 @@ void RiaApplication::createMainPlotWindow() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RiaApplication::deleteMainPlotWindow() { @@ -1373,7 +1525,7 @@ void RiaApplication::deleteMainPlotWindow() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- RiuPlotMainWindow* RiaApplication::getOrCreateAndShowMainPlotWindow() { @@ -1400,7 +1552,7 @@ RiuPlotMainWindow* RiaApplication::getOrCreateAndShowMainPlotWindow() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- RiuPlotMainWindow* RiaApplication::mainPlotWindow() { @@ -1408,17 +1560,20 @@ RiuPlotMainWindow* RiaApplication::mainPlotWindow() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- RiuMainWindowBase* RiaApplication::mainWindowByID(int mainWindowID) { - if (mainWindowID == 0) return RiuMainWindow::instance(); - else if (mainWindowID == 1) return m_mainPlotWindow; - else return nullptr; + if (mainWindowID == 0) + return m_mainWindow; + else if (mainWindowID == 1) + return m_mainPlotWindow; + else + return nullptr; } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- RimViewWindow* RiaApplication::activeViewWindow() { @@ -1445,77 +1600,65 @@ RimViewWindow* RiaApplication::activeViewWindow() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- bool RiaApplication::isMain3dWindowVisible() const { - return RiuMainWindow::instance()->isVisible(); + return m_mainWindow && m_mainWindow->isVisible(); } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- bool RiaApplication::isMainPlotWindowVisible() const { - if (!m_mainPlotWindow) return false; - - return m_mainPlotWindow->isVisible(); + return m_mainPlotWindow && m_mainPlotWindow->isVisible(); } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- -bool RiaApplication::tryCloseMainWindow() +void RiaApplication::closeMainWindowIfOpenButHidden() { - RiuMainWindow* mainWindow = RiuMainWindow::instance(); - if (mainWindow && !mainWindow->isVisible()) + if (m_mainWindow && !m_mainWindow->isVisible()) { - mainWindow->close(); - - return true; + m_mainWindow->close(); } - - return false; } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- -bool RiaApplication::tryClosePlotWindow() +void RiaApplication::closeMainPlotWindowIfOpenButHidden() { - if (!m_mainPlotWindow) - { - return true; - } - if (m_mainPlotWindow && !m_mainPlotWindow->isVisible()) { m_mainPlotWindow->close(); - - return true; } - - return false; } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RiaApplication::addToRecentFiles(const QString& fileName) { + CVF_ASSERT(m_recentFileActionProvider && + "The provider needs to be created before any attempts to use the recent file actions"); m_recentFileActionProvider->addFileName(fileName); } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- std::vector RiaApplication::recentFileActions() const { + CVF_ASSERT(m_recentFileActionProvider && + "The provider needs to be created before any attempts to use the recent file actions"); return m_recentFileActionProvider->actions(); } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RiaApplication::setStartDir(const QString& startDir) { @@ -1523,7 +1666,7 @@ void RiaApplication::setStartDir(const QString& startDir) } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- std::vector RiaApplication::readFileListFromTextFile(QString listFileName) { @@ -1536,7 +1679,7 @@ std::vector RiaApplication::readFileListFromTextFile(QString listFileNa } QTextStream in(&file); - QString line = in.readLine(); + QString line = in.readLine(); while (!line.isNull()) { line = line.trimmed(); @@ -1552,33 +1695,42 @@ std::vector RiaApplication::readFileListFromTextFile(QString listFileNa } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RiaApplication::waitUntilCommandObjectsHasBeenProcessed() { // Wait until all command objects have completed - while (!m_commandQueueLock.tryLock()) + bool mutexLockedSuccessfully = m_commandQueueLock.tryLock(); + + while (!mutexLockedSuccessfully) { processEvents(); + + mutexLockedSuccessfully = m_commandQueueLock.tryLock(); } m_commandQueueLock.unlock(); } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- -void RiaApplication::saveWinGeoAndDockToolBarLayout() +void RiaApplication::saveMainWinGeoAndDockToolBarLayout() { - if (m_mainPlotWindow) + if (isMain3dWindowVisible()) { - m_mainPlotWindow->saveWinGeoAndDockToolBarLayout(); + m_mainWindow->saveWinGeoAndDockToolBarLayout(); } +} - if (RiuMainWindow::instance()) +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiaApplication::savePlotWinGeoAndDockToolBarLayout() +{ + if (isMainPlotWindowVisible()) { - RiuMainWindow::instance()->saveWinGeoAndDockToolBarLayout(); + m_mainPlotWindow->saveWinGeoAndDockToolBarLayout(); } - } //-------------------------------------------------------------------------------------------------- @@ -1591,17 +1743,17 @@ bool RiaApplication::enableDevelopmentFeatures() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RiaApplication::clearAllSelections() { - RiuSelectionManager::instance()->deleteAllItems(RiuSelectionManager::RUI_APPLICATION_GLOBAL); - RiuSelectionManager::instance()->deleteAllItems(RiuSelectionManager::RUI_TEMPORARY); + Riu3dSelectionManager::instance()->deleteAllItems(Riu3dSelectionManager::RUI_APPLICATION_GLOBAL); + Riu3dSelectionManager::instance()->deleteAllItems(Riu3dSelectionManager::RUI_TEMPORARY); caf::SelectionManager::instance()->clearAll(); } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- QString RiaApplication::scriptDirectories() const { @@ -1609,7 +1761,7 @@ QString RiaApplication::scriptDirectories() const } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- QString RiaApplication::scriptEditorPath() const { @@ -1617,7 +1769,7 @@ QString RiaApplication::scriptEditorPath() const } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- QString RiaApplication::octavePath() const { @@ -1625,7 +1777,7 @@ QString RiaApplication::octavePath() const } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- QStringList RiaApplication::octaveArguments() const { @@ -1636,7 +1788,6 @@ QStringList RiaApplication::octaveArguments() const // will override any value of OCTAVE_PATH found in the environment, but not any commands in the system or // user startup files that set the internal load path through one of the path functions. - QStringList arguments; arguments.append("--path"); arguments << QApplication::applicationDirPath(); @@ -1653,11 +1804,11 @@ QStringList RiaApplication::octaveArguments() const } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RiaApplication::slotWorkerProcessFinished(int exitCode, QProcess::ExitStatus exitStatus) { - RiuMainWindow::instance()->processMonitor()->stopMonitorWorkProcess(); + m_mainWindow->processMonitor()->stopMonitorWorkProcess(); // Execute delete later so that other slots that are hooked up // get a chance to run before we delete the object @@ -1670,24 +1821,22 @@ void RiaApplication::slotWorkerProcessFinished(int exitCode, QProcess::ExitStatu // Either the work process crashed or was aborted by the user if (exitStatus == QProcess::CrashExit) { - // MFLog::error("Simulation execution crashed or was aborted."); + // MFLog::error("Simulation execution crashed or was aborted."); m_runningWorkerProcess = false; return; } - executeCommandObjects(); - // Exit code != 0 means we have an error if (exitCode != 0) { - // MFLog::error(QString("Simulation execution failed (exit code %1).").arg(exitCode)); + // MFLog::error(QString("Simulation execution failed (exit code %1).").arg(exitCode)); m_runningWorkerProcess = false; return; } - // If multiple cases are present, invoke launchProcess() which will set next current case, and run script on this case + // If multiple cases are present, invoke launchProcess() which will set next current case, and run script on this case if (!m_currentCaseIds.empty()) { launchProcess(m_currentProgram, m_currentArguments); @@ -1701,7 +1850,7 @@ void RiaApplication::slotWorkerProcessFinished(int exitCode, QProcess::ExitStatu } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- bool RiaApplication::launchProcess(const QString& program, const QStringList& arguments) { @@ -1722,47 +1871,57 @@ bool RiaApplication::launchProcess(const QString& program, const QStringList& ar } m_runningWorkerProcess = true; - m_workerProcess = new caf::UiProcess(this); + m_workerProcess = new caf::UiProcess(this); QProcessEnvironment penv = QProcessEnvironment::systemEnvironment(); #ifdef WIN32 // Octave plugins compiled by ResInsight are dependent on Qt (currently Qt 32-bit only) - // Some Octave installations for Windows have included Qt, and some don't. To make sure these plugins always can be executed, - // the path to octave_plugin_dependencies is added to global path - + // Some Octave installations for Windows have included Qt, and some don't. To make sure these plugins always can be + // executed, the path to octave_plugin_dependencies is added to global path + QString pathString = penv.value("PATH", ""); - if (pathString == "") pathString = QApplication::applicationDirPath() + "\\octave_plugin_dependencies"; - else pathString = QApplication::applicationDirPath() + "\\octave_plugin_dependencies" + ";" + pathString; + if (pathString == "") + pathString = QApplication::applicationDirPath() + "\\octave_plugin_dependencies"; + else + pathString = QApplication::applicationDirPath() + "\\octave_plugin_dependencies" + ";" + pathString; penv.insert("PATH", pathString); #else - // Set the LD_LIBRARY_PATH to make the octave plugins find the embedded Qt - QString ldPath = penv.value("LD_LIBRARY_PATH", ""); + // Set the LD_LIBRARY_PATH to make the octave plugins find the embedded Qt + QString ldPath = penv.value("LD_LIBRARY_PATH", ""); - if (ldPath == "") ldPath = QApplication::applicationDirPath(); - else ldPath = QApplication::applicationDirPath() + ":" + ldPath; + if (ldPath == "") + ldPath = QApplication::applicationDirPath(); + else + ldPath = QApplication::applicationDirPath() + ":" + ldPath; - penv.insert("LD_LIBRARY_PATH", ldPath); + penv.insert("LD_LIBRARY_PATH", ldPath); #endif m_workerProcess->setProcessEnvironment(penv); - connect(m_workerProcess, SIGNAL(finished(int, QProcess::ExitStatus)), SLOT(slotWorkerProcessFinished(int, QProcess::ExitStatus))); + connect(m_workerProcess, + SIGNAL(finished(int, QProcess::ExitStatus)), + SLOT(slotWorkerProcessFinished(int, QProcess::ExitStatus))); - RiuMainWindow::instance()->processMonitor()->startMonitorWorkProcess(m_workerProcess); + m_mainWindow->processMonitor()->startMonitorWorkProcess(m_workerProcess); m_workerProcess->start(program, arguments); - if (!m_workerProcess->waitForStarted(1000)) + + // The wait time is a compromise between large wait time when processing many octave runs after each other and short wait + // time when starting octave processes interactively + int waitTimeMilliseconds = 7 * 1000; + if (!m_workerProcess->waitForStarted(waitTimeMilliseconds)) { m_workerProcess->close(); - m_workerProcess = nullptr; + m_workerProcess = nullptr; m_runningWorkerProcess = false; - RiuMainWindow::instance()->processMonitor()->stopMonitorWorkProcess(); + m_mainWindow->processMonitor()->stopMonitorWorkProcess(); - QMessageBox::warning(RiuMainWindow::instance(), "Script execution", "Failed to start script executable located at\n" + program); + QMessageBox::warning(m_mainWindow, "Script execution", "Failed to start script executable located at\n" + program); return false; } @@ -1771,27 +1930,31 @@ bool RiaApplication::launchProcess(const QString& program, const QStringList& ar } else { - QMessageBox::warning(nullptr, "Script execution", "An Octave process is still running. Please stop this process before executing a new script."); + QMessageBox::warning(nullptr, + "Script execution", + "An Octave process is still running. Please stop this process before executing a new script."); return false; } } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- -bool RiaApplication::launchProcessForMultipleCases(const QString& program, const QStringList& arguments, const std::vector& caseIds) +bool RiaApplication::launchProcessForMultipleCases(const QString& program, + const QStringList& arguments, + const std::vector& caseIds) { m_currentCaseIds.clear(); - std::copy( caseIds.begin(), caseIds.end(), std::back_inserter( m_currentCaseIds ) ); + std::copy(caseIds.begin(), caseIds.end(), std::back_inserter(m_currentCaseIds)); - m_currentProgram = program; + m_currentProgram = program; m_currentArguments = arguments; return launchProcess(m_currentProgram, m_currentArguments); } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- RiaPreferences* RiaApplication::preferences() { @@ -1799,9 +1962,9 @@ RiaPreferences* RiaApplication::preferences() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- -void RiaApplication::applyPreferences() +void RiaApplication::applyPreferences(const RiaPreferences* oldPreferences) { if (m_activeReservoirView && m_activeReservoirView->viewer()) { @@ -1818,52 +1981,187 @@ void RiaApplication::applyPreferences() caf::EffectGenerator::setRenderingMode(caf::EffectGenerator::FIXED_FUNCTION); } - if (RiuMainWindow::instance() && RiuMainWindow::instance()->projectTreeView()) + if (m_mainWindow && m_mainWindow->projectTreeView()) { - RiuMainWindow::instance()->projectTreeView()->enableAppendOfClassNameToUiItemText(m_preferences->appendClassNameToUiText()); - if (mainPlotWindow()) mainPlotWindow()->projectTreeView()->enableAppendOfClassNameToUiItemText(m_preferences->appendClassNameToUiText()); + m_mainWindow->projectTreeView()->enableAppendOfClassNameToUiItemText(m_preferences->appendClassNameToUiText()); + if (mainPlotWindow()) + mainPlotWindow()->projectTreeView()->enableAppendOfClassNameToUiItemText(m_preferences->appendClassNameToUiText()); } - caf::FixedAtlasFont::FontSize fontSizeType = caf::FixedAtlasFont::POINT_SIZE_16; - if (m_preferences->fontSizeInScene() == "8") - { - fontSizeType = caf::FixedAtlasFont::POINT_SIZE_8; - } - else if (m_preferences->fontSizeInScene() == "12") - { - fontSizeType = caf::FixedAtlasFont::POINT_SIZE_12; - } - else if (m_preferences->fontSizeInScene() == "16") - { - fontSizeType = caf::FixedAtlasFont::POINT_SIZE_16; - } - else if (m_preferences->fontSizeInScene() == "24") - { - fontSizeType = caf::FixedAtlasFont::POINT_SIZE_24; - } - else if (m_preferences->fontSizeInScene() == "32") - { - fontSizeType = caf::FixedAtlasFont::POINT_SIZE_32; - } - - m_customFont = new caf::FixedAtlasFont(fontSizeType); + // The creation of a font is time consuming, so make sure you really need your own font + // instead of using the application font + std::map fontSizes = m_preferences->defaultFontSizes(); + + m_defaultSceneFont = RiaFontCache::getFont(fontSizes[RiaDefines::SCENE_FONT]); + m_defaultAnnotationFont = RiaFontCache::getFont(fontSizes[RiaDefines::ANNOTATION_FONT]); + m_defaultWellLabelFont = RiaFontCache::getFont(fontSizes[RiaDefines::WELL_LABEL_FONT]); if (this->project()) { this->project()->setScriptDirectories(m_preferences->scriptDirectories()); this->project()->updateConnectedEditors(); - std::vector visibleViews; - this->project()->allVisibleViews(visibleViews); + RimWellPathCollection* wellPathCollection = this->project()->activeOilField()->wellPathCollection(); - for (auto view : visibleViews) + std::vector allViewWindows; + project()->descendantsIncludingThisOfType(allViewWindows); + + bool existingViewsWithDifferentMeshLines = false; + bool existingViewsWithCustomColors = false; + bool existingViewsWithCustomZScale = false; + bool existingObjectsWithCustomFonts = false; + if (oldPreferences) { - RimEclipseView* eclipseView = dynamic_cast(view); - if (eclipseView) + for (auto viewWindow : allViewWindows) { - eclipseView->scheduleReservoirGridGeometryRegen(); + auto rim3dView = dynamic_cast(viewWindow); + if (rim3dView) + { + if (rim3dView->meshMode() != oldPreferences->defaultMeshModeType()) + { + existingViewsWithDifferentMeshLines = true; + } + if (rim3dView->backgroundColor() != oldPreferences->defaultViewerBackgroundColor()) + { + existingViewsWithCustomColors = true; + } + if (rim3dView->scaleZ() != static_cast(oldPreferences->defaultScaleFactorZ)) + { + existingViewsWithCustomZScale = true; + } + + RimGridView* gridView = dynamic_cast(rim3dView); + if (gridView && gridView->annotationCollection()) + { + RiaFontCache::FontSize oldFontSize = oldPreferences->defaultAnnotationFontSize(); + existingObjectsWithCustomFonts = gridView->annotationCollection()->hasTextAnnotationsWithCustomFontSize(oldFontSize); + } + RimEclipseView* eclipseView = dynamic_cast(rim3dView); + if (eclipseView) + { + if (eclipseView->wellCollection()->wellLabelColor() != oldPreferences->defaultWellLabelColor()) + { + existingViewsWithCustomColors = true; + } + } + } + + for (auto fontTypeSizePair : fontSizes) + { + RiaFontCache::FontSize oldFontSizeEnum = oldPreferences->defaultFontSizes()[fontTypeSizePair.first]; + if (oldFontSizeEnum != fontTypeSizePair.second) + { + int oldFontSize = RiaFontCache::pointSizeFromFontSizeEnum(oldFontSizeEnum); + if (viewWindow->hasCustomFontSizes(fontTypeSizePair.first, oldFontSize)) + { + existingObjectsWithCustomFonts = true; + } + } + } + } + + if (oldPreferences->defaultWellLabelColor() != wellPathCollection->wellPathLabelColor()) + { + existingViewsWithCustomColors = true; + } + } + + bool applySettingsToAllViews = false; + if (existingViewsWithCustomColors || existingViewsWithCustomZScale || + existingViewsWithDifferentMeshLines || existingObjectsWithCustomFonts) + { + QStringList changedData; + if (existingViewsWithDifferentMeshLines) changedData << "Mesh Visibility"; + if (existingViewsWithCustomColors) changedData << "Colors"; + if (existingViewsWithCustomZScale) changedData << "Z-Scale"; + if (existingObjectsWithCustomFonts) changedData << "Fonts Sizes"; + + QString listString = changedData.takeLast(); + if (!changedData.empty()) + { + listString = changedData.join(", ") + " and " + listString; + } + + QMessageBox::StandardButton reply; + reply = QMessageBox::question(m_mainWindow, + QString("Apply %1 to Existing Views or Plots?").arg(listString), + QString("You have changed default %1 and have existing views or plots with different settings.\n").arg(listString) + + QString("Do you want to apply the new default settings to all existing views?"), + QMessageBox::Ok | QMessageBox::Cancel); + applySettingsToAllViews = (reply == QMessageBox::Ok); + } + + for (auto viewWindow : allViewWindows) + { + for (auto fontTypeSizePair : fontSizes) + { + RiaFontCache::FontSize oldFontSizeEnum = oldPreferences->defaultFontSizes()[fontTypeSizePair.first]; + if (oldFontSizeEnum != fontTypeSizePair.second) + { + int oldFontSize = RiaFontCache::pointSizeFromFontSizeEnum(oldFontSizeEnum); + int newFontSize = RiaFontCache::pointSizeFromFontSizeEnum(fontTypeSizePair.second); + viewWindow->applyFontSize(fontTypeSizePair.first, oldFontSize, newFontSize, applySettingsToAllViews); + } + + } + + auto rim3dView = dynamic_cast(viewWindow); + if (rim3dView) + { + if (oldPreferences && (applySettingsToAllViews || rim3dView->meshMode() == oldPreferences->defaultMeshModeType())) + { + rim3dView->meshMode = m_preferences->defaultMeshModeType(); + } + + if (oldPreferences && (applySettingsToAllViews || rim3dView->backgroundColor() == oldPreferences->defaultViewerBackgroundColor())) + { + rim3dView->setBackgroundColor(m_preferences->defaultViewerBackgroundColor()); + rim3dView->applyBackgroundColorAndFontChanges(); + } + + if (oldPreferences && (applySettingsToAllViews || rim3dView->scaleZ == static_cast(oldPreferences->defaultScaleFactorZ()))) + { + rim3dView->scaleZ = static_cast(m_preferences->defaultScaleFactorZ()); + rim3dView->updateScaling(); + if (rim3dView == activeViewWindow()) + { + RiuMainWindow::instance()->updateScaleValue(); + } + } + + RimEclipseView* eclipseView = dynamic_cast(rim3dView); + if (eclipseView) + { + if (oldPreferences && (applySettingsToAllViews || eclipseView->wellCollection()->wellLabelColor() == oldPreferences->defaultWellLabelColor())) + { + eclipseView->wellCollection()->wellLabelColor = m_preferences->defaultWellLabelColor(); + } + eclipseView->scheduleReservoirGridGeometryRegen(); + } + rim3dView->scheduleCreateDisplayModelAndRedraw(); + } + } + + if (oldPreferences) + { + bool matchingColor = wellPathCollection->wellPathLabelColor() == oldPreferences->defaultWellLabelColor(); + if (applySettingsToAllViews || matchingColor) + { + wellPathCollection->wellPathLabelColor = oldPreferences->defaultWellLabelColor(); + } + + if (oldPreferences->defaultPlotFontSize() != m_preferences->defaultPlotFontSize()) + { + m_mainWindow->applyFontSizesToDockedPlots(); } - view->scheduleCreateDisplayModelAndRedraw(); + } + + std::vector uiEditorsToUpdate; + caf::SelectionManager::instance()->selectedItems(uiEditorsToUpdate); + + for (caf::PdmUiItem* uiItem : uiEditorsToUpdate) + { + uiItem->updateConnectedEditors(); } } @@ -1871,7 +2169,7 @@ void RiaApplication::applyPreferences() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RiaApplication::terminateProcess() { @@ -1881,11 +2179,11 @@ void RiaApplication::terminateProcess() } m_runningWorkerProcess = false; - m_workerProcess = nullptr; + m_workerProcess = nullptr; } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RiaApplication::waitForProcess() const { @@ -1901,7 +2199,7 @@ void RiaApplication::waitForProcess() const } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- QString RiaApplication::lastUsedDialogDirectory(const QString& dialogName) { @@ -1917,7 +2215,7 @@ QString RiaApplication::lastUsedDialogDirectory(const QString& dialogName) } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- QString RiaApplication::lastUsedDialogDirectoryWithFallback(const QString& dialogName, const QString& fallbackDirectory) { @@ -1937,7 +2235,7 @@ QString RiaApplication::lastUsedDialogDirectoryWithFallback(const QString& dialo } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- QString RiaApplication::lastUsedDialogDirectoryWithFallbackToProjectFolder(const QString& dialogName) { @@ -1945,16 +2243,15 @@ QString RiaApplication::lastUsedDialogDirectoryWithFallbackToProjectFolder(const } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RiaApplication::setLastUsedDialogDirectory(const QString& dialogName, const QString& directory) { m_fileDialogDefaultDirectories[dialogName] = directory; } - //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- bool RiaApplication::openFile(const QString& fileName) { @@ -1962,48 +2259,58 @@ bool RiaApplication::openFile(const QString& fileName) bool loadingSucceded = false; - if (RiaApplication::hasValidProjectFileExtension(fileName)) + QString lastUsedDialogTag; + + RiaDefines::ImportFileType fileType = RiaDefines::obtainFileTypeFromFileName(fileName); + + if (fileType == RiaDefines::RESINSIGHT_PROJECT_FILE) { loadingSucceded = loadProject(fileName); } - else if (fileName.contains(".egrid", Qt::CaseInsensitive) || fileName.contains(".grid", Qt::CaseInsensitive)) - { - loadingSucceded = RiaImportEclipseCaseTools::openEclipseCasesFromFile(QStringList({ fileName })); - } - else if (fileName.contains(".grdecl", Qt::CaseInsensitive)) - { - loadingSucceded = RicImportInputEclipseCaseFeature::openInputEclipseCaseFromFileNames(QStringList(fileName)); - } - else if (fileName.contains(".odb", Qt::CaseInsensitive)) + else if (fileType == RiaDefines::GEOMECH_ODB_FILE) { loadingSucceded = openOdbCaseFromFile(fileName); + if (loadingSucceded) lastUsedDialogTag = "GEOMECH_MODEL"; } - else if (fileName.contains(".smspec", Qt::CaseInsensitive)) + else if ( fileType & RiaDefines::ANY_ECLIPSE_FILE) { - loadingSucceded = RicImportSummaryCasesFeature::createAndAddSummaryCasesFromFiles(QStringList({ fileName })); + loadingSucceded = RicImportGeneralDataFeature::openEclipseFilesFromFileNames(QStringList{ fileName }); if (loadingSucceded) { - getOrCreateAndShowMainPlotWindow(); + lastUsedDialogTag = RiaDefines::defaultDirectoryLabel(fileType); + + if (fileType & RiaDefines::ECLIPSE_SUMMARY_FILE) + { + getOrCreateAndShowMainPlotWindow(); + } } } - if (loadingSucceded && !RiaApplication::hasValidProjectFileExtension(fileName)) + if (loadingSucceded) { - caf::PdmUiModelChangeDetector::instance()->setModelChanged(); + if (!lastUsedDialogTag.isEmpty()) + { + RiaApplication::instance()->setLastUsedDialogDirectory(lastUsedDialogTag, QFileInfo(fileName).absolutePath()); + } + if (!RiaApplication::hasValidProjectFileExtension(fileName)) + { + caf::PdmUiModelChangeDetector::instance()->setModelChanged(); + } } return loadingSucceded; } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- -void RiaApplication::runMultiCaseSnapshots(const QString& templateProjectFileName, std::vector gridFileNames, const QString& snapshotFolderName) +void RiaApplication::runMultiCaseSnapshots(const QString& templateProjectFileName, + std::vector gridFileNames, + const QString& snapshotFolderName) { - RiuMainWindow* mainWnd = RiuMainWindow::instance(); - if (!mainWnd) return; + if (!m_mainWindow) return; - mainWnd->hideAllDockWindows(); + m_mainWindow->hideAllDockWindows(); const size_t numGridFiles = gridFileNames.size(); for (size_t i = 0; i < numGridFiles; i++) @@ -2020,34 +2327,44 @@ void RiaApplication::runMultiCaseSnapshots(const QString& templateProjectFileNam } } - mainWnd->loadWinGeoAndDockToolBarLayout(); + m_mainWindow->loadWinGeoAndDockToolBarLayout(); } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- -cvf::Font* RiaApplication::standardFont() +cvf::Font* RiaApplication::defaultSceneFont() { - CVF_ASSERT(m_standardFont.notNull()); + CVF_ASSERT(m_defaultSceneFont.notNull()); // The creation of a font is time consuming, so make sure you really need your own font // instead of using the application font - return m_standardFont.p(); + return m_defaultSceneFont.p(); } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- -cvf::Font* RiaApplication::customFont() +cvf::Font* RiaApplication::defaultAnnotationFont() { - CVF_ASSERT(m_customFont.notNull()); + CVF_ASSERT(m_defaultAnnotationFont.notNull()); - return m_customFont.p(); + return m_defaultAnnotationFont.p(); } //-------------------------------------------------------------------------------------------------- -/// +/// +//-------------------------------------------------------------------------------------------------- +cvf::Font* RiaApplication::defaultWellLabelFont() +{ + CVF_ASSERT(m_defaultWellLabelFont.notNull()); + + return m_defaultWellLabelFont.p(); +} + +//-------------------------------------------------------------------------------------------------- +/// //-------------------------------------------------------------------------------------------------- RimProject* RiaApplication::project() { @@ -2055,7 +2372,7 @@ RimProject* RiaApplication::project() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RiaApplication::showFormattedTextInMessageBox(const QString& text) { @@ -2076,51 +2393,15 @@ void RiaApplication::showFormattedTextInMessageBox(const QString& text) } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- QString RiaApplication::commandLineParameterHelp() const { return m_helpText; +} - /* - QString text = QString("\n%1 v. %2\n").arg(RI_APPLICATION_NAME).arg(getVersionStringApp(false)); - text += "Copyright Statoil ASA, Ceetron AS 2011, 2012\n\n"; - - text += - "\nParameter Description\n" - "-----------------------------------------------------------------\n" - "-last Open last used project\n" - "\n" - "-project Open project file \n" - "\n" - "-case Import Eclipse case \n" - " (do not include .GRID/.EGRID)\n" - "\n" - "-savesnapshots Save snapshot of all views to 'snapshots' folder in project file folder\n" - " Application closes after snapshots are written to file\n" - "\n" - "-regressiontest Run a regression test on all sub-folders starting with \"" + RegTestNames::testFolderFilter + "\" of the given folder: \n" - " " + RegTestNames::testProjectName + " files in the sub-folders will be opened and \n" - " snapshots of all the views is written to the sub-sub-folder " + RegTestNames::generatedFolderName + ". \n" - " Then difference images is generated in the sub-sub-folder " + RegTestNames::diffFolderName + " based \n" - " on the images in sub-sub-folder " + RegTestNames::baseFolderName + ".\n" - " The results are presented in " + RegTestNames::reportFileName + " that is\n" - " written in the given folder.\n" - "\n" - "-updateregressiontestbase For all sub-folders starting with \"" + RegTestNames::testFolderFilter + "\" of the given folder: \n" - " Copy the images in the sub-sub-folder " + RegTestNames::generatedFolderName + " to the sub-sub-folder\n" - " " + RegTestNames::baseFolderName + " after deleting " + RegTestNames::baseFolderName + " completely.\n" - "\n" - "-help, -? Displays help text\n" - "-----------------------------------------------------------------"; - - return text; - */ -} - - -//-------------------------------------------------------------------------------------------------- -/// +//-------------------------------------------------------------------------------------------------- +/// //-------------------------------------------------------------------------------------------------- void RiaApplication::setCacheDataObject(const QString& key, const QVariant& dataObject) { @@ -2128,7 +2409,7 @@ void RiaApplication::setCacheDataObject(const QString& key, const QVariant& data } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- QVariant RiaApplication::cacheDataObject(const QString& key) const { @@ -2143,7 +2424,7 @@ QVariant RiaApplication::cacheDataObject(const QString& key) const } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RiaApplication::addCommandObject(RimCommandObject* commandObject) { @@ -2151,7 +2432,7 @@ void RiaApplication::addCommandObject(RimCommandObject* commandObject) } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RiaApplication::executeCommandObjects() { @@ -2176,7 +2457,7 @@ void RiaApplication::executeCommandObjects() if (!m_commandQueue.empty()) { - std::list< RimCommandObject* >::iterator it = m_commandQueue.begin(); + std::list::iterator it = m_commandQueue.begin(); RimCommandObject* first = *it; first->redo(); @@ -2186,12 +2467,14 @@ void RiaApplication::executeCommandObjects() else { // Unlock the command queue lock when the command queue is empty + // Required to lock the mutex before unlocking to avoid undefined behavior + m_commandQueueLock.tryLock(); m_commandQueueLock.unlock(); } } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RiaApplication::setHelpText(const QString& helpText) { diff --git a/ApplicationCode/Application/RiaApplication.h b/ApplicationCode/Application/RiaApplication.h index 4820c0dafc..4efbe370d5 100644 --- a/ApplicationCode/Application/RiaApplication.h +++ b/ApplicationCode/Application/RiaApplication.h @@ -30,6 +30,8 @@ #include "cvfObject.h" #include "cvfFont.h" +#include "RiaFontCache.h" + #include #include @@ -56,6 +58,7 @@ class RimViewWindow; class RimWellLogPlot; class RimWellAllocationPlot; +class RiuMainWindow; class RiuMainWindowBase; class RiuPlotMainWindow; class RiuRecentFileActionProvider; @@ -90,6 +93,8 @@ class RiaApplication : public QApplication PLA_CALCULATE_STATISTICS = 1 }; + typedef RiaFontCache::FontSize FontSize; + public: RiaApplication(int& argc, char** argv); ~RiaApplication() override; @@ -162,10 +167,11 @@ class RiaApplication : public QApplication void waitForProcess() const; RiaPreferences* preferences(); - void applyPreferences(); + void applyPreferences(const RiaPreferences* oldPreferences = nullptr); - cvf::Font* standardFont(); - cvf::Font* customFont(); + cvf::Font* defaultSceneFont(); + cvf::Font* defaultAnnotationFont(); + cvf::Font* defaultWellLabelFont(); QString commandLineParameterHelp() const; void showFormattedTextInMessageBox(const QString& text); @@ -179,6 +185,9 @@ class RiaApplication : public QApplication int launchUnitTests(); int launchUnitTestsWithConsole(); + RiuMainWindow* getOrCreateAndShowMainWindow(); + RiuMainWindow* mainWindow(); + RiuPlotMainWindow* getOrCreateMainPlotWindow(); RiuPlotMainWindow* getOrCreateAndShowMainPlotWindow(); RiuPlotMainWindow* mainPlotWindow(); @@ -189,8 +198,8 @@ class RiaApplication : public QApplication bool isMain3dWindowVisible() const; bool isMainPlotWindowVisible() const; - bool tryCloseMainWindow(); - bool tryClosePlotWindow(); + void closeMainWindowIfOpenButHidden(); + void closeMainPlotWindowIfOpenButHidden(); void addToRecentFiles(const QString& fileName); std::vector recentFileActions() const; @@ -200,7 +209,8 @@ class RiaApplication : public QApplication static std::vector readFileListFromTextFile(QString listFileName); void waitUntilCommandObjectsHasBeenProcessed(); - void saveWinGeoAndDockToolBarLayout(); + void saveMainWinGeoAndDockToolBarLayout(); + void savePlotWinGeoAndDockToolBarLayout(); static bool enableDevelopmentFeatures(); static void clearAllSelections(); @@ -209,6 +219,9 @@ class RiaApplication : public QApplication void onProjectOpenedOrClosed(); void setWindowCaptionFromAppState(); + void createMainWindow(); + void deleteMainWindow(); + void createMainPlotWindow(); void deleteMainPlotWindow(); @@ -242,8 +255,9 @@ private slots: std::map m_fileDialogDefaultDirectories; QString m_startupDefaultDirectory; - cvf::ref m_standardFont; - cvf::ref m_customFont; + cvf::ref m_defaultSceneFont; + cvf::ref m_defaultAnnotationFont; + cvf::ref m_defaultWellLabelFont; QMap m_sessionCache; // Session cache used to store username/passwords per session @@ -254,6 +268,7 @@ private slots: bool m_runningWorkerProcess; + RiuMainWindow* m_mainWindow; RiuPlotMainWindow* m_mainPlotWindow; std::unique_ptr m_recentFileActionProvider; diff --git a/ApplicationCode/Application/RiaCompletionTypeCalculationScheduler.cpp b/ApplicationCode/Application/RiaCompletionTypeCalculationScheduler.cpp index 85399bcbbc..eb6e0cba69 100644 --- a/ApplicationCode/Application/RiaCompletionTypeCalculationScheduler.cpp +++ b/ApplicationCode/Application/RiaCompletionTypeCalculationScheduler.cpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018- Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by diff --git a/ApplicationCode/Application/RiaCompletionTypeCalculationScheduler.h b/ApplicationCode/Application/RiaCompletionTypeCalculationScheduler.h index 1e9850eaec..ae0ec50e17 100644 --- a/ApplicationCode/Application/RiaCompletionTypeCalculationScheduler.h +++ b/ApplicationCode/Application/RiaCompletionTypeCalculationScheduler.h @@ -1,17 +1,17 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018- Statoil ASA -// +// Copyright (C) 2018- Equinor ASA +// // ResInsight 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 3 of the License, or // (at your option) any later version. -// +// // ResInsight 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 at +// +// See the GNU General Public License at // for more details. // ///////////////////////////////////////////////////////////////////////////////// diff --git a/ApplicationCode/Application/RiaDefines.cpp b/ApplicationCode/Application/RiaDefines.cpp index 619fc20d9d..0c6445ba69 100644 --- a/ApplicationCode/Application/RiaDefines.cpp +++ b/ApplicationCode/Application/RiaDefines.cpp @@ -3,17 +3,17 @@ // Copyright (C) 2011- Statoil ASA // Copyright (C) 2013- Ceetron Solutions AS // Copyright (C) 2011-2012 Ceetron AS -// +// // ResInsight 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 3 of the License, or // (at your option) any later version. -// +// // ResInsight 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 at +// +// See the GNU General Public License at // for more details. // ///////////////////////////////////////////////////////////////////////////////// @@ -22,62 +22,70 @@ #include "cafAppEnum.h" - namespace caf { - template<> - void caf::AppEnum< RiaDefines::ResultCatType >::setUp() - { - addItem(RiaDefines::DYNAMIC_NATIVE, "DYNAMIC_NATIVE", "Dynamic"); - addItem(RiaDefines::STATIC_NATIVE, "STATIC_NATIVE", "Static"); - addItem(RiaDefines::SOURSIMRL, "SOURSIMRL", "SourSimRL"); - addItem(RiaDefines::GENERATED, "GENERATED", "Generated"); - addItem(RiaDefines::INPUT_PROPERTY, "INPUT_PROPERTY", "Input Property"); - addItem(RiaDefines::FORMATION_NAMES, "FORMATION_NAMES", "Formation Names"); - addItem(RiaDefines::FLOW_DIAGNOSTICS, "FLOW_DIAGNOSTICS", "Flow Diagnostics"); - addItem(RiaDefines::INJECTION_FLOODING, "INJECTION_FLOODING", "Injection Flooding"); - setDefault(RiaDefines::DYNAMIC_NATIVE); - } +template<> +void caf::AppEnum::setUp() +{ + addItem(RiaDefines::DYNAMIC_NATIVE, "DYNAMIC_NATIVE", "Dynamic"); + addItem(RiaDefines::STATIC_NATIVE, "STATIC_NATIVE", "Static"); + addItem(RiaDefines::SOURSIMRL, "SOURSIMRL", "SourSimRL"); + addItem(RiaDefines::GENERATED, "GENERATED", "Generated"); + addItem(RiaDefines::INPUT_PROPERTY, "INPUT_PROPERTY", "Input Property"); + addItem(RiaDefines::FORMATION_NAMES, "FORMATION_NAMES", "Formation Names"); + addItem(RiaDefines::FLOW_DIAGNOSTICS, "FLOW_DIAGNOSTICS", "Flow Diagnostics"); + addItem(RiaDefines::INJECTION_FLOODING, "INJECTION_FLOODING", "Injection Flooding"); + setDefault(RiaDefines::DYNAMIC_NATIVE); +} - template<> - void caf::AppEnum< RiaDefines::DepthUnitType >::setUp() - { - addItem(RiaDefines::UNIT_METER, "UNIT_METER", "Meter"); - addItem(RiaDefines::UNIT_FEET, "UNIT_FEET", "Feet"); - addItem(RiaDefines::UNIT_NONE, "UNIT_NONE", "None"); +template<> +void caf::AppEnum::setUp() +{ + addItem(RiaDefines::UNIT_METER, "UNIT_METER", "Meter"); + addItem(RiaDefines::UNIT_FEET, "UNIT_FEET", "Feet"); + addItem(RiaDefines::UNIT_NONE, "UNIT_NONE", "None"); + setDefault(RiaDefines::UNIT_METER); +} - setDefault(RiaDefines::UNIT_METER); - } +template<> +void caf::AppEnum::setUp() +{ + addItem(RiaDefines::PLOT_AXIS_LEFT, "PLOT_AXIS_LEFT", "Left"); + addItem(RiaDefines::PLOT_AXIS_RIGHT, "PLOT_AXIS_RIGHT", "Right"); - template<> - void caf::AppEnum< RiaDefines::PlotAxis >::setUp() - { - addItem(RiaDefines::PLOT_AXIS_LEFT, "PLOT_AXIS_LEFT", "Left"); - addItem(RiaDefines::PLOT_AXIS_RIGHT, "PLOT_AXIS_RIGHT", "Right"); + setDefault(RiaDefines::PLOT_AXIS_LEFT); +} - setDefault(RiaDefines::PLOT_AXIS_LEFT); - } +template<> +void caf::AppEnum::setUp() +{ + addItem(RiaDefines::WELL_PATH, "WELL_PATH", "Well Path"); + addItem(RiaDefines::PERFORATION_INTERVAL, "PERFORATION_INTERVAL", "Perforation Interval"); + addItem(RiaDefines::FISHBONES, "FISHBONES", "Fishbones"); + addItem(RiaDefines::FRACTURE, "FRACTURE", "Fracture"); + addItem(RiaDefines::ICD, "ICD", "ICD"); + addItem(RiaDefines::AICD, "AICD", "AICD"); + addItem(RiaDefines::ICV, "ICV", "ICV"); + addItem(RiaDefines::CASING, "CASING", "Casing"); + addItem(RiaDefines::LINER, "LINER", "Liner"); + addItem(RiaDefines::PACKER, "PACKER", "Packer"); + addItem(RiaDefines::UNDEFINED_COMPONENT, "UNDEFINED", "Undefined Component"); + setDefault(RiaDefines::WELL_PATH); +} - template<> - void caf::AppEnum< RiaDefines::WellPathComponentType >::setUp() - { - addItem(RiaDefines::WELL_PATH, "WELL_PATH", "Well Path"); - addItem(RiaDefines::PERFORATION_INTERVAL, "PERFORATION_INTERVAL", "Perforation Interval"); - addItem(RiaDefines::FISHBONES, "FISHBONES", "Fishbones"); - addItem(RiaDefines::FRACTURE, "FRACTURE", "Fracture"); - addItem(RiaDefines::ICD, "ICD", "ICD"); - addItem(RiaDefines::AICD, "AICD", "AICD"); - addItem(RiaDefines::ICV, "ICV", "ICV"); - addItem(RiaDefines::CASING, "CASING", "Casing"); - addItem(RiaDefines::LINER, "LINER", "Liner"); - addItem(RiaDefines::PACKER, "PACKER", "Packer"); - setDefault(RiaDefines::WELL_PATH); - } +template<> +void caf::AppEnum::setUp() +{ + addItem(RiaDefines::FULL_MESH, "FULL_MESH", "All"); + addItem(RiaDefines::FAULTS_MESH, "FAULTS_MESH", "Faults only"); + addItem(RiaDefines::NO_MESH, "NO_MESH", "None"); + setDefault(RiaDefines::FULL_MESH); } +} // namespace caf //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- bool RiaDefines::isPerCellFaceResult(const QString& resultName) { @@ -126,7 +134,15 @@ bool RiaDefines::isPerCellFaceResult(const QString& resultName) } //-------------------------------------------------------------------------------------------------- -/// +/// +//-------------------------------------------------------------------------------------------------- +bool RiaDefines::isNativeCategoryResult(const QString& resultName) +{ + return resultName.endsWith("NUM"); +} + +//-------------------------------------------------------------------------------------------------- +/// //-------------------------------------------------------------------------------------------------- QString RiaDefines::undefinedResultName() { @@ -134,7 +150,7 @@ QString RiaDefines::undefinedResultName() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- QString RiaDefines::undefinedGridFaultName() { @@ -142,7 +158,7 @@ QString RiaDefines::undefinedGridFaultName() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- QString RiaDefines::undefinedGridFaultWithInactiveName() { @@ -150,7 +166,7 @@ QString RiaDefines::undefinedGridFaultWithInactiveName() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- QString RiaDefines::combinedTransmissibilityResultName() { @@ -158,7 +174,7 @@ QString RiaDefines::combinedTransmissibilityResultName() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- QString RiaDefines::combinedWaterFluxResultName() { @@ -166,7 +182,7 @@ QString RiaDefines::combinedWaterFluxResultName() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- QString RiaDefines::combinedOilFluxResultName() { @@ -174,7 +190,7 @@ QString RiaDefines::combinedOilFluxResultName() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- QString RiaDefines::combinedGasFluxResultName() { @@ -182,7 +198,7 @@ QString RiaDefines::combinedGasFluxResultName() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- QString RiaDefines::ternarySaturationResultName() { @@ -190,7 +206,7 @@ QString RiaDefines::ternarySaturationResultName() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- QString RiaDefines::combinedMultResultName() { @@ -198,7 +214,15 @@ QString RiaDefines::combinedMultResultName() } //-------------------------------------------------------------------------------------------------- -/// +/// +//-------------------------------------------------------------------------------------------------- +QString RiaDefines::eqlnumResultName() +{ + return "EQLNUM"; +} + +//-------------------------------------------------------------------------------------------------- +/// //-------------------------------------------------------------------------------------------------- QString RiaDefines::riTranXResultName() { @@ -206,7 +230,7 @@ QString RiaDefines::riTranXResultName() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- QString RiaDefines::riTranYResultName() { @@ -214,7 +238,7 @@ QString RiaDefines::riTranYResultName() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- QString RiaDefines::riTranZResultName() { @@ -222,7 +246,7 @@ QString RiaDefines::riTranZResultName() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- QString RiaDefines::combinedRiTranResultName() { @@ -230,7 +254,7 @@ QString RiaDefines::combinedRiTranResultName() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- QString RiaDefines::riMultXResultName() { @@ -238,7 +262,7 @@ QString RiaDefines::riMultXResultName() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- QString RiaDefines::riMultYResultName() { @@ -246,7 +270,7 @@ QString RiaDefines::riMultYResultName() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- QString RiaDefines::riMultZResultName() { @@ -254,7 +278,7 @@ QString RiaDefines::riMultZResultName() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- QString RiaDefines::combinedRiMultResultName() { @@ -262,7 +286,7 @@ QString RiaDefines::combinedRiMultResultName() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- QString RiaDefines::riAreaNormTranXResultName() { @@ -270,7 +294,7 @@ QString RiaDefines::riAreaNormTranXResultName() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- QString RiaDefines::riAreaNormTranYResultName() { @@ -278,7 +302,7 @@ QString RiaDefines::riAreaNormTranYResultName() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- QString RiaDefines::riAreaNormTranZResultName() { @@ -286,7 +310,7 @@ QString RiaDefines::riAreaNormTranZResultName() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- QString RiaDefines::combinedRiAreaNormTranResultName() { @@ -310,7 +334,7 @@ QString RiaDefines::riOilVolumeResultName() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- QString RiaDefines::mobilePoreVolumeName() { @@ -318,7 +342,7 @@ QString RiaDefines::mobilePoreVolumeName() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- QString RiaDefines::completionTypeResultName() { @@ -326,7 +350,7 @@ QString RiaDefines::completionTypeResultName() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- QString RiaDefines::mockModelBasic() { @@ -334,7 +358,7 @@ QString RiaDefines::mockModelBasic() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- QString RiaDefines::mockModelBasicWithResults() { @@ -342,7 +366,7 @@ QString RiaDefines::mockModelBasicWithResults() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- QString RiaDefines::mockModelLargeWithResults() { @@ -350,7 +374,7 @@ QString RiaDefines::mockModelLargeWithResults() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- QString RiaDefines::mockModelCustomized() { @@ -358,7 +382,7 @@ QString RiaDefines::mockModelCustomized() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- QString RiaDefines::mockModelBasicInputCase() { @@ -366,7 +390,7 @@ QString RiaDefines::mockModelBasicInputCase() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- QString RiaDefines::activeFormationNamesResultName() { @@ -434,7 +458,7 @@ QString RiaDefines::wellPathSFGResultName() //-------------------------------------------------------------------------------------------------- std::vector RiaDefines::wellPathAngleResultNames() { - return { RiaDefines::wellPathAzimuthResultName(), RiaDefines::wellPathInclinationResultName() }; + return {RiaDefines::wellPathAzimuthResultName(), RiaDefines::wellPathInclinationResultName()}; } //-------------------------------------------------------------------------------------------------- @@ -442,13 +466,15 @@ std::vector RiaDefines::wellPathAngleResultNames() //-------------------------------------------------------------------------------------------------- std::vector RiaDefines::wellPathStabilityResultNames() { - return { RiaDefines::wellPathFGResultName(), RiaDefines::wellPathOBGResultName(), - RiaDefines::wellPathPPResultName(), RiaDefines::wellPathSFGResultName(), - RiaDefines::wellPathSHResultName() }; + return {RiaDefines::wellPathFGResultName(), + RiaDefines::wellPathOBGResultName(), + RiaDefines::wellPathPPResultName(), + RiaDefines::wellPathSFGResultName(), + RiaDefines::wellPathSHResultName()}; } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- double RiaDefines::minimumDefaultValuePlot() { @@ -456,9 +482,82 @@ double RiaDefines::minimumDefaultValuePlot() } //-------------------------------------------------------------------------------------------------- -/// +/// +//-------------------------------------------------------------------------------------------------- +double RiaDefines::minimumDefaultLogValuePlot() +{ + return 1.0; +} + +//-------------------------------------------------------------------------------------------------- +/// //-------------------------------------------------------------------------------------------------- double RiaDefines::maximumDefaultValuePlot() { return 100.0; } + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RiaDefines::ImportFileType RiaDefines::obtainFileTypeFromFileName(const QString& fileName) +{ + if (fileName.endsWith("EGRID", Qt::CaseInsensitive)) + { + return ECLIPSE_EGRID_FILE; + } + else if (fileName.endsWith("GRID", Qt::CaseInsensitive)) + { + return ECLIPSE_GRID_FILE; + } + else if (fileName.endsWith("GRDECL", Qt::CaseInsensitive)) + { + return ECLIPSE_INPUT_FILE; + } + else if (fileName.endsWith("SMSPEC", Qt::CaseInsensitive)) + { + return ECLIPSE_SUMMARY_FILE; + } + else if (fileName.endsWith("ODB", Qt::CaseInsensitive)) + { + return GEOMECH_ODB_FILE; + } + else if (fileName.endsWith(".rsp", Qt::CaseInsensitive) || fileName.endsWith(".rip", Qt::CaseInsensitive)) + { + return RESINSIGHT_PROJECT_FILE; + } + return NOT_A_VALID_IMPORT_FILE; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RiaDefines::defaultDirectoryLabel(RiaDefines::ImportFileType fileType) +{ + QString defaultDirLabel; + + if (fileType == ANY_ECLIPSE_FILE) + { + defaultDirLabel = "GENERAL_DATA"; + } + else if (fileType & ECLIPSE_RESULT_GRID) + { + defaultDirLabel = "BINARY_GRID"; + } + else if (fileType & ECLIPSE_INPUT_FILE) + { + defaultDirLabel = "INPUT_FILES"; + } + else if (fileType & ECLIPSE_SUMMARY_FILE) + { + // TODO: Summary files used "INPUT_FILES" as last used directory. + // Check if this is correct. + defaultDirLabel = "INPUT_FILES"; + } + else if (fileType & GEOMECH_ODB_FILE) + { + defaultDirLabel = "GEOMECH_MODEL"; + } + + return defaultDirLabel; +} diff --git a/ApplicationCode/Application/RiaDefines.h b/ApplicationCode/Application/RiaDefines.h index c8eb95b35a..968e80b337 100644 --- a/ApplicationCode/Application/RiaDefines.h +++ b/ApplicationCode/Application/RiaDefines.h @@ -40,6 +40,8 @@ namespace RiaDefines UNDEFINED = 999 }; + // WARNING: DO NOT CHANGE THE ORDER WITHOUT KNOWING WHAT YOU ARE DOING! + // You may well change the behaviour of property filters. enum WellPathComponentType { // Production Tube WELL_PATH, @@ -53,10 +55,19 @@ namespace RiaDefines // Well path construction features CASING, LINER, - PACKER + PACKER, + UNDEFINED_COMPONENT + }; + + enum MeshModeType + { + FULL_MESH, + FAULTS_MESH, + NO_MESH }; bool isPerCellFaceResult(const QString& resultName); + bool isNativeCategoryResult(const QString& resultName); QString undefinedResultName(); QString undefinedGridFaultName(); @@ -69,6 +80,8 @@ namespace RiaDefines QString ternarySaturationResultName(); QString combinedMultResultName(); + QString eqlnumResultName(); + QString riTranXResultName(); QString riTranYResultName(); QString riTranZResultName(); @@ -131,6 +144,7 @@ namespace RiaDefines }; double minimumDefaultValuePlot(); + double minimumDefaultLogValuePlot(); double maximumDefaultValuePlot(); enum PhaseType { @@ -138,5 +152,31 @@ namespace RiaDefines GAS_PHASE, WATER_PHASE }; + + enum ImportFileType + { + NOT_A_VALID_IMPORT_FILE = 0x00, + ECLIPSE_GRID_FILE = 0x01, + ECLIPSE_EGRID_FILE = 0x02, + ECLIPSE_INPUT_FILE = 0x04, + ECLIPSE_SUMMARY_FILE = 0x08, + GEOMECH_ODB_FILE = 0x10, + RESINSIGHT_PROJECT_FILE = 0x20, + ECLIPSE_RESULT_GRID = ECLIPSE_GRID_FILE | ECLIPSE_EGRID_FILE, + ANY_ECLIPSE_FILE = ECLIPSE_RESULT_GRID | ECLIPSE_INPUT_FILE | ECLIPSE_SUMMARY_FILE, + ANY_IMPORT_FILE = 0xFF + }; + + ImportFileType obtainFileTypeFromFileName(const QString& fileName); + QString defaultDirectoryLabel(ImportFileType fileTypes); + + enum FontSettingType + { + SCENE_FONT, + ANNOTATION_FONT, + WELL_LABEL_FONT, + PLOT_FONT + }; + }; diff --git a/ApplicationCode/Application/RiaEclipseFileNameTools.cpp b/ApplicationCode/Application/RiaEclipseFileNameTools.cpp new file mode 100644 index 0000000000..4a6078d83a --- /dev/null +++ b/ApplicationCode/Application/RiaEclipseFileNameTools.cpp @@ -0,0 +1,149 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2019- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "RiaEclipseFileNameTools.h" + +#include "QFileInfo" + +namespace caf +{ +template<> +void caf::AppEnum::setUp() +{ + addItem(RiaEclipseFileNameTools::ECLIPSE_DATA, "DATA", "Data Deck"); + addItem(RiaEclipseFileNameTools::ECLIPSE_GRID, "GRID", "Grid"); + addItem(RiaEclipseFileNameTools::ECLIPSE_EGRID, "EGRID", "Grid"); + addItem(RiaEclipseFileNameTools::ECLIPSE_UNRST, "UNRST", "Unified Restart"); + addItem(RiaEclipseFileNameTools::ECLIPSE_SMSPEC, "SMSPEC", "Summary Specification"); + addItem(RiaEclipseFileNameTools::ECLIPSE_UNSMRY, "UNSMR", "Summary Vectors"); + + addItem(RiaEclipseFileNameTools::RESINSIGHT_PROJECT, "rsp", "ResInsight Project"); +} + +} // End namespace caf + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RiaEclipseFileNameTools::RiaEclipseFileNameTools(const QString& inputFilePath) +{ + m_baseName = findBaseName(inputFilePath); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RiaEclipseFileNameTools::findRelatedSummarySpecFile() +{ + return relatedFilePath(ECLIPSE_SMSPEC); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RiaEclipseFileNameTools::findRelatedGridFile() +{ + QString candidate = relatedFilePath(ECLIPSE_EGRID); + if (!candidate.isEmpty()) + { + return candidate; + } + + return relatedFilePath(ECLIPSE_GRID); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RiaEclipseFileNameTools::findRelatedDataFile() +{ + return relatedFilePath(ECLIPSE_DATA); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RiaEclipseFileNameTools::isProjectFile(const QString& fileName) +{ + return hasMatchingSuffix(fileName, RESINSIGHT_PROJECT); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RiaEclipseFileNameTools::isGridFile(const QString& fileName) +{ + if (hasMatchingSuffix(fileName, ECLIPSE_EGRID)) + { + return true; + } + + return hasMatchingSuffix(fileName, ECLIPSE_GRID); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RiaEclipseFileNameTools::isSummarySpecFile(const QString& fileName) +{ + return hasMatchingSuffix(fileName, ECLIPSE_SMSPEC); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RiaEclipseFileNameTools::findBaseName(const QString& inputFilePath) const +{ + QFileInfo fi(inputFilePath); + + return fi.baseName(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RiaEclipseFileNameTools::relatedFilePath(EclipseFileType fileType) const +{ + const QString extension = caf::AppEnum::text(fileType); + const QString completeFilePath = m_baseName + "." + extension; + + QFileInfo fi(completeFilePath); + if (fi.exists()) + { + return fi.absoluteFilePath(); + } + + return ""; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RiaEclipseFileNameTools::hasMatchingSuffix(const QString& fileName, EclipseFileType fileType) +{ + QFileInfo fi(fileName); + + QString suffix = fi.completeSuffix(); + + if (suffix.compare(caf::AppEnum::text(fileType), Qt::CaseInsensitive) == 0) + { + return true; + } + + return false; +} diff --git a/ApplicationCode/Application/RiaEclipseFileNameTools.h b/ApplicationCode/Application/RiaEclipseFileNameTools.h new file mode 100644 index 0000000000..c18b6c72e6 --- /dev/null +++ b/ApplicationCode/Application/RiaEclipseFileNameTools.h @@ -0,0 +1,64 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2019- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "cafAppEnum.h" + +#include + +#include + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +class RiaEclipseFileNameTools +{ +public: + enum EclipseFileType + { + ECLIPSE_DATA, + ECLIPSE_GRID, + ECLIPSE_EGRID, + ECLIPSE_UNRST, + ECLIPSE_SMSPEC, + ECLIPSE_UNSMRY, + RESINSIGHT_PROJECT, + UNKNOWN + }; + +public: + explicit RiaEclipseFileNameTools(const QString& fileName); + + QString findRelatedGridFile(); + QString findRelatedSummarySpecFile(); + QString findRelatedDataFile(); + + static bool isProjectFile(const QString& fileName); + static bool isGridFile(const QString& fileName); + static bool isSummarySpecFile(const QString& fileName); + +private: + QString findBaseName(const QString& inputFilePath) const; + QString relatedFilePath(EclipseFileType fileType) const; + + static bool hasMatchingSuffix(const QString& fileName, EclipseFileType fileType); + +private: + QString m_baseName; +}; diff --git a/ApplicationCode/Application/RiaFontCache.cpp b/ApplicationCode/Application/RiaFontCache.cpp new file mode 100644 index 0000000000..60639683a9 --- /dev/null +++ b/ApplicationCode/Application/RiaFontCache.cpp @@ -0,0 +1,131 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2017 Statoil ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "RiaFontCache.h" + +#include "cafAppEnum.h" +#include "cafFixedAtlasFont.h" + +namespace caf +{ +template<> +void RiaFontCache::FontSizeType::setUp() +{ + addItem(RiaFontCache::FONT_SIZE_8, "8", "8"); + addItem(RiaFontCache::FONT_SIZE_10, "10", "10"); + addItem(RiaFontCache::FONT_SIZE_12, "12", "12"); + addItem(RiaFontCache::FONT_SIZE_14, "14", "14"); + addItem(RiaFontCache::FONT_SIZE_16, "16", "16"); + addItem(RiaFontCache::FONT_SIZE_24, "24", "24"); + addItem(RiaFontCache::FONT_SIZE_32, "32", "32"); + + setDefault(RiaFontCache::FONT_SIZE_8); +} +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +caf::FixedAtlasFont::FontSize mapToAtlasFontSize(RiaFontCache::FontSize fontSize) +{ + switch (fontSize) + { + case RiaFontCache::FONT_SIZE_8: + return caf::FixedAtlasFont::POINT_SIZE_8; + case RiaFontCache::FONT_SIZE_10: + return caf::FixedAtlasFont::POINT_SIZE_10; + case RiaFontCache::FONT_SIZE_12: + return caf::FixedAtlasFont::POINT_SIZE_12; + case RiaFontCache::FONT_SIZE_14: + return caf::FixedAtlasFont::POINT_SIZE_14; + case RiaFontCache::FONT_SIZE_16: + return caf::FixedAtlasFont::POINT_SIZE_16; + case RiaFontCache::FONT_SIZE_24: + return caf::FixedAtlasFont::POINT_SIZE_24; + case RiaFontCache::FONT_SIZE_32: + return caf::FixedAtlasFont::POINT_SIZE_32; + default: + return caf::FixedAtlasFont::POINT_SIZE_16; + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::map> RiaFontCache::ms_fonts; + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +cvf::ref RiaFontCache::getFont(FontSize size) +{ + if (ms_fonts.count(size) == 0) + { + auto newFont = new caf::FixedAtlasFont(mapToAtlasFontSize(size)); + ms_fonts.insert(std::make_pair(size, newFont)); + } + return ms_fonts[size]; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +int RiaFontCache::pointSizeFromFontSizeEnum(FontSize fontSize) +{ + switch (fontSize) + { + case RiaFontCache::FONT_SIZE_8: + return 8; + case RiaFontCache::FONT_SIZE_10: + return 10; + case RiaFontCache::FONT_SIZE_12: + return 12; + case RiaFontCache::FONT_SIZE_14: + return 14; + case RiaFontCache::FONT_SIZE_16: + return 16; + case RiaFontCache::FONT_SIZE_24: + return 24; + case RiaFontCache::FONT_SIZE_32: + return 32; + default: + return 16; + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RiaFontCache::FontSize RiaFontCache::fontSizeEnumFromPointSize(int pointSize) +{ + std::vector allValues = + { FONT_SIZE_8, FONT_SIZE_10, FONT_SIZE_12, FONT_SIZE_14, FONT_SIZE_16, FONT_SIZE_24, FONT_SIZE_32 }; + + FontSize closestEnumValue = FONT_SIZE_8; + int closestDiff = std::numeric_limits::max(); + for (FontSize enumValue : allValues) + { + int diff = std::abs(pointSizeFromFontSizeEnum(enumValue) - pointSize); + if (diff < closestDiff) + { + closestEnumValue = enumValue; + closestDiff = diff; + } + } + return closestEnumValue; +} diff --git a/ApplicationCode/Application/RiaFontCache.h b/ApplicationCode/Application/RiaFontCache.h new file mode 100644 index 0000000000..2ee45ba949 --- /dev/null +++ b/ApplicationCode/Application/RiaFontCache.h @@ -0,0 +1,59 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2017 Statoil ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "cvfBase.h" +#include "cvfObject.h" + +#include + +namespace caf +{ +class FixedAtlasFont; +template class AppEnum; +} + +class RimSummaryCaseCollection; + +//================================================================================================== +/// +//================================================================================================== +class RiaFontCache +{ +public: + enum FontSize + { + FONT_SIZE_8, + FONT_SIZE_10, + FONT_SIZE_12, + FONT_SIZE_14, + FONT_SIZE_16, + FONT_SIZE_24, + FONT_SIZE_32 + }; + + typedef caf::AppEnum FontSizeType; + + static cvf::ref getFont(FontSize fontSize); + static int pointSizeFromFontSizeEnum(FontSize fontSize); + static FontSize fontSizeEnumFromPointSize(int pointSize); + +private: + static std::map> ms_fonts; +}; diff --git a/ApplicationCode/Application/RiaFractureDefines.cpp b/ApplicationCode/Application/RiaFractureDefines.cpp index 57054a44a5..82be6559b3 100644 --- a/ApplicationCode/Application/RiaFractureDefines.cpp +++ b/ApplicationCode/Application/RiaFractureDefines.cpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018 Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by diff --git a/ApplicationCode/Application/RiaFractureDefines.h b/ApplicationCode/Application/RiaFractureDefines.h index 238ae71c98..c12f9ec9f3 100644 --- a/ApplicationCode/Application/RiaFractureDefines.h +++ b/ApplicationCode/Application/RiaFractureDefines.h @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018 Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by diff --git a/ApplicationCode/Application/RiaMain.cpp b/ApplicationCode/Application/RiaMain.cpp index 69aff03b8d..6d1ec7ba41 100644 --- a/ApplicationCode/Application/RiaMain.cpp +++ b/ApplicationCode/Application/RiaMain.cpp @@ -19,9 +19,6 @@ #include "RiaApplication.h" #include "RiaLogging.h" -#include "RiuMainWindow.h" -#include "RiuMessagePanel.h" - int main(int argc, char *argv[]) { RiaLogging::loggerInstance()->setLevel(RI_LL_DEBUG); @@ -36,24 +33,9 @@ int main(int argc, char *argv[]) { return unitTestResult; } - - RiuMainWindow window; - QString platform = cvf::System::is64Bit() ? "(64bit)" : "(32bit)"; - window.setWindowTitle("ResInsight " + platform); - window.setDefaultWindowSize(); - window.setDefaultToolbarVisibility(); - window.loadWinGeoAndDockToolBarLayout(); - window.showWindow(); - - // Create plot main window to be able to set expanded state on created objects - // The plot window is hidden by default - RiaApplication::instance()->getOrCreateMainPlotWindow(); - + if (app.parseArguments()) { - RiaLogging::setLoggerInstance(new RiuMessagePanelLogger(window.messagePanel())); - RiaLogging::loggerInstance()->setLevel(RI_LL_DEBUG); - int exitCode = 0; try { @@ -70,13 +52,9 @@ int main(int argc, char *argv[]) throw; } - RiaLogging::deleteLoggerInstance(); - return exitCode; } - RiaLogging::deleteLoggerInstance(); - return 0; } diff --git a/ApplicationCode/Application/RiaMemoryCleanup.cpp b/ApplicationCode/Application/RiaMemoryCleanup.cpp index 15deb8b822..48c3af41ce 100644 --- a/ApplicationCode/Application/RiaMemoryCleanup.cpp +++ b/ApplicationCode/Application/RiaMemoryCleanup.cpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018- Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -33,6 +33,7 @@ #include "cafPdmUiListEditor.h" #include "cafPdmUiPushButtonEditor.h" #include "cafPdmUiTreeSelectionEditor.h" +#include "RigEclipseResultInfo.h" //================================================================================================== /// @@ -81,10 +82,10 @@ void RiaMemoryCleanup::clearSelectedResultsFromMemory() RigCaseCellResultsData* caseData = eclipseCase->results(RiaDefines::MATRIX_MODEL); if (caseData) { - std::vector resultsToDelete = selectedEclipseResults(); - for (const RigEclipseResultInfo& resultInfo : resultsToDelete) + std::vector resultsToDelete = selectedEclipseResults(); + for (const RigEclipseResultAddress& resultAddr : resultsToDelete) { - caseData->clearScalarResult(resultInfo); + caseData->clearScalarResult(resultAddr); } } } @@ -129,9 +130,9 @@ std::vector RiaMemoryCleanup::selectedGeoMechResults() cons //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -std::vector RiaMemoryCleanup::selectedEclipseResults() const +std::vector RiaMemoryCleanup::selectedEclipseResults() const { - std::vector results; + std::vector results; if (dynamic_cast(m_case())) { for (size_t index : m_resultsToDelete()) @@ -170,9 +171,9 @@ std::set RiaMemoryCleanup::findGeoMechCaseResultsInUse() co //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -std::set RiaMemoryCleanup::findEclipseResultsInUse() const +std::set RiaMemoryCleanup::findEclipseResultsInUse() const { - std::set resultsInUse; + std::set resultsInUse; RimEclipseCase* eclipseCase = dynamic_cast(m_case()); if (eclipseCase) { @@ -180,10 +181,11 @@ std::set RiaMemoryCleanup::findEclipseResultsInUse() const eclipseCase->descendantsIncludingThisOfType(eclipseResultDefs); for (RimEclipseResultDefinition* resultDef : eclipseResultDefs) { - RigEclipseResultInfo resultInfo(resultDef->resultType(), resultDef->resultVariable()); - resultsInUse.insert(resultInfo); + RigEclipseResultAddress resultAddr(resultDef->resultType(), resultDef->resultVariable()); + resultsInUse.insert(resultAddr); } } + return resultsInUse; } @@ -237,20 +239,23 @@ QList RiaMemoryCleanup::calculateValueOptions(const caf: RimGeoMechCase* geoMechCase = dynamic_cast(m_case()); if (eclipseCase) { - std::set resultsInUse = findEclipseResultsInUse(); + std::set resultsInUse = findEclipseResultsInUse(); RigCaseCellResultsData* caseData = eclipseCase->results(RiaDefines::MATRIX_MODEL); if (caseData) { - m_eclipseResultAddresses = caseData->infoForEachResultIndex(); + m_eclipseResultAddresses = caseData->existingResults(); for (size_t i = 0; i < m_eclipseResultAddresses.size(); ++i) { - const RigEclipseResultInfo& result = m_eclipseResultAddresses[i]; - if (caseData->isResultLoaded(result)) + const RigEclipseResultAddress& resultAddr = m_eclipseResultAddresses[i]; + if (caseData->isResultLoaded(resultAddr)) { - bool inUse = resultsInUse.count(result); - QString posText = caf::AppEnum::uiTextFromIndex(result.resultType()); - QString resultsText = QString("%1, %2").arg(posText).arg(result.resultName()); + bool inUse = resultsInUse.count(resultAddr); + + const RigEclipseResultInfo* resInfo = caseData->resultInfo(resultAddr); + + QString posText = caf::AppEnum::uiTextFromIndex(resInfo->resultType()); + QString resultsText = QString("%1, %2").arg(posText).arg(resInfo->resultName()); if (inUse) { resultsText += QString(" [used in view]"); diff --git a/ApplicationCode/Application/RiaMemoryCleanup.h b/ApplicationCode/Application/RiaMemoryCleanup.h index a2d8f58b72..2e87b9121e 100644 --- a/ApplicationCode/Application/RiaMemoryCleanup.h +++ b/ApplicationCode/Application/RiaMemoryCleanup.h @@ -1,25 +1,23 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018- Statoil ASA -// +// Copyright (C) 2018- Equinor ASA +// // ResInsight 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 3 of the License, or // (at your option) any later version. -// +// // ResInsight 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 at +// +// See the GNU General Public License at // for more details. // ///////////////////////////////////////////////////////////////////////////////// #pragma once -#include "RigFemResultAddress.h" -#include "RigEclipseResultInfo.h" #include "cafPdmField.h" #include "cafPdmChildArrayField.h" @@ -29,6 +27,8 @@ class RimCase; class Rim3dView; +class RigFemResultAddress; +class RigEclipseResultAddress; class RiaMemoryCleanup : public caf::PdmObject { @@ -42,9 +42,9 @@ class RiaMemoryCleanup : public caf::PdmObject void fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue) override; private: std::vector selectedGeoMechResults() const; - std::vector selectedEclipseResults() const; + std::vector selectedEclipseResults() const; std::set findGeoMechCaseResultsInUse() const; - std::set findEclipseResultsInUse() const; + std::set findEclipseResultsInUse() const; QList calculateValueOptions(const caf::PdmFieldHandle* fieldNeedingOptions, bool* useOptionsOnly) override; @@ -54,6 +54,6 @@ class RiaMemoryCleanup : public caf::PdmObject caf::PdmPtrField m_case; caf::PdmField> m_resultsToDelete; std::vector m_geomResultAddresses; - std::vector m_eclipseResultAddresses; + std::vector m_eclipseResultAddresses; caf::PdmField m_performDelete; }; \ No newline at end of file diff --git a/ApplicationCode/Application/RiaPreferences.cpp b/ApplicationCode/Application/RiaPreferences.cpp index 5431f8f102..c382da6224 100644 --- a/ApplicationCode/Application/RiaPreferences.cpp +++ b/ApplicationCode/Application/RiaPreferences.cpp @@ -1,6 +1,7 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2011- Statoil ASA +// Copyright (C) 2019- Equinor ASA +// Copyright (C) 2011-2018 Statoil ASA // Copyright (C) 2013- Ceetron Solutions AS // Copyright (C) 2011-2012 Ceetron AS // @@ -20,9 +21,11 @@ #include "RiaPreferences.h" +#include "RiaColorTables.h" #include "RifReaderSettings.h" #include "cafPdmFieldCvfColor.h" +#include "cafPdmUiComboBoxEditor.h" #include "cafPdmUiCheckBoxEditor.h" #include "cafPdmUiFieldHandle.h" #include "cafPdmUiFilePathEditor.h" @@ -64,15 +67,20 @@ RiaPreferences::RiaPreferences(void) CAF_PDM_InitField(&ssihubAddress, "ssihubAddress", QString("http://"), "SSIHUB Address", "", "", ""); ssihubAddress.uiCapability()->setUiLabelPosition(caf::PdmUiItemInfo::TOP); - CAF_PDM_InitField(&defaultGridLines, "defaultGridLines", true, "Gridlines", "", "", ""); - CAF_PDM_InitField(&defaultGridLineColors, "defaultGridLineColors", cvf::Color3f(0.92f, 0.92f, 0.92f), "Mesh Color", "", "", ""); - CAF_PDM_InitField(&defaultFaultGridLineColors, "defaultFaultGridLineColors", cvf::Color3f(0.08f, 0.08f, 0.08f), "Mesh Color Along Faults", "", "", ""); - CAF_PDM_InitField(&defaultWellLabelColor, "defaultWellLableColor", cvf::Color3f(0.92f, 0.92f, 0.92f), "Well Label Color", "", "The default well label color in new views", ""); + CAF_PDM_InitFieldNoDefault(&defaultMeshModeType, "defaultMeshModeType", "Show Grid Lines", "", "", ""); + CAF_PDM_InitField(&defaultGridLineColors, "defaultGridLineColors", RiaColorTables::defaultGridLineColor(), "Mesh Color", "", "", ""); + CAF_PDM_InitField(&defaultFaultGridLineColors, "defaultFaultGridLineColors", RiaColorTables::defaultFaultLineColor(), "Mesh Color Along Faults", "", "", ""); + CAF_PDM_InitField(&defaultWellLabelColor, "defaultWellLableColor", RiaColorTables::defaultWellLabelColor(), "Well Label Color", "", "The default well label color in new views", ""); - CAF_PDM_InitField(&defaultViewerBackgroundColor, "defaultViewerBackgroundColor", cvf::Color3f(0.69f, 0.77f, 0.87f), "Viewer Background", "", "The viewer background color for new views", ""); + CAF_PDM_InitField(&defaultViewerBackgroundColor, "defaultViewerBackgroundColor", RiaColorTables::defaultViewerBackgroundColor(), "Viewer Background", "", "The viewer background color for new views", ""); - CAF_PDM_InitField(&defaultScaleFactorZ, "defaultScaleFactorZ", 5, "Default Z Scale Factor", "", "", ""); - CAF_PDM_InitField(&fontSizeInScene, "fontSizeInScene", QString("8"), "Font Size", "", "", ""); + CAF_PDM_InitField(&defaultScaleFactorZ, "defaultScaleFactorZ", 5, "Default Z Scale Factor", "", "", ""); + + CAF_PDM_InitFieldNoDefault(&defaultSceneFontSize, "fontSizeInScene", "Viewer Font Size", "", "", ""); + CAF_PDM_InitFieldNoDefault(&defaultAnnotationFontSize, "defaultAnnotationFontSize", "Annotation Font Size", "", "", ""); + CAF_PDM_InitFieldNoDefault(&defaultWellLabelFontSize, "wellLabelFontSize", "Well Label Font Size", "", "", ""); + CAF_PDM_InitFieldNoDefault(&defaultPlotFontSize, "defaultPlotFontSize", "Plot Font Size", "", "", ""); + defaultPlotFontSize = RiaFontCache::FONT_SIZE_8; CAF_PDM_InitField(&showLasCurveWithoutTvdWarning, "showLasCurveWithoutTvdWarning", true, "Show LAS Curve Without TVD Warning", "", "", ""); showLasCurveWithoutTvdWarning.uiCapability()->setUiLabelPosition(caf::PdmUiItemInfo::HIDDEN); @@ -90,7 +98,8 @@ RiaPreferences::RiaPreferences(void) CAF_PDM_InitField(&m_includeFractureDebugInfoFile, "includeFractureDebugInfoFile", false, "Include Fracture Debug Info for Completion Export", "", "", ""); m_includeFractureDebugInfoFile.uiCapability()->setUiLabelPosition(caf::PdmUiItemInfo::HIDDEN); - CAF_PDM_InitField(&showLegendBackground, "showLegendBackground", true, "Enable Legend Background", "", "", ""); + CAF_PDM_InitField(&showLegendBackground, "showLegendBackground", true, "Show Box around Legends", "", "", ""); + showLegendBackground.uiCapability()->setUiLabelPosition(caf::PdmUiItemInfo::HIDDEN); CAF_PDM_InitFieldNoDefault(&lastUsedProjectFileName,"lastUsedProjectFileName", "Last Used Project File", "", "", ""); lastUsedProjectFileName.uiCapability()->setUiHidden(true); @@ -109,6 +118,12 @@ RiaPreferences::RiaPreferences(void) m_holoLensExportFolder.uiCapability()->setUiLabelPosition(caf::PdmUiItemInfo::TOP); m_holoLensExportFolder.uiCapability()->setUiEditorTypeName(caf::PdmUiFilePathEditor::uiEditorTypeName()); + CAF_PDM_InitField(&holoLensDisableCertificateVerification, "holoLensDisableCertificateVerification", false, "Disable SSL Certificate Verification (HoloLens)", "", "", ""); + holoLensDisableCertificateVerification.uiCapability()->setUiLabelPosition(caf::PdmUiItemInfo::HIDDEN); + + CAF_PDM_InitField(&m_showProjectChangedDialog, "showProjectChangedDialog", true, "Show 'Project has changed' dialog", "", "", ""); + m_showProjectChangedDialog.uiCapability()->setUiLabelPosition(caf::PdmUiItemInfo::HIDDEN); + CAF_PDM_InitFieldNoDefault(&m_readerSettings, "readerSettings", "Reader Settings", "", "", ""); m_readerSettings = new RifReaderSettings; @@ -154,7 +169,10 @@ void RiaPreferences::defineEditorAttribute(const caf::PdmFieldHandle* field, QSt field == &m_appendFieldKeywordToToolTipText || field == &m_showTestToolbar || field == &m_includeFractureDebugInfoFile || - field == &showLasCurveWithoutTvdWarning) + field == &showLasCurveWithoutTvdWarning || + field == &holoLensDisableCertificateVerification || + field == &m_showProjectChangedDialog || + field == &showLegendBackground) { caf::PdmUiCheckBoxEditorAttribute* myAttr = dynamic_cast(attribute); if (myAttr) @@ -170,6 +188,12 @@ void RiaPreferences::defineEditorAttribute(const caf::PdmFieldHandle* field, QSt myAttr->m_selectDirectory = true; } } + if (field == &defaultSceneFontSize || field == &defaultWellLabelFontSize || + field == &defaultAnnotationFontSize || field == &defaultPlotFontSize) + { + caf::PdmUiComboBoxEditorAttribute* myAttr = dynamic_cast(attribute); + myAttr->minimumContentsLength = 2; + } } //-------------------------------------------------------------------------------------------------- @@ -179,26 +203,30 @@ void RiaPreferences::defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& { if (uiConfigName == m_tabNames[0]) { - caf::PdmUiGroup* defaultSettingsGroup = uiOrdering.addNewGroup("Default Settings"); - defaultSettingsGroup->add(&defaultViewerBackgroundColor); - defaultSettingsGroup->add(&defaultGridLines); - defaultSettingsGroup->add(&defaultGridLineColors); - defaultSettingsGroup->add(&defaultFaultGridLineColors); - defaultSettingsGroup->add(&defaultWellLabelColor); - defaultSettingsGroup->add(&fontSizeInScene); - defaultSettingsGroup->add(&defaultScaleFactorZ); - defaultSettingsGroup->add(&showLegendBackground); - - caf::PdmUiGroup* viewsGroup = uiOrdering.addNewGroup("3D Views"); + caf::PdmUiGroup* colorGroup = uiOrdering.addNewGroup("Default Colors"); + colorGroup->add(&defaultViewerBackgroundColor); + colorGroup->add(&defaultGridLineColors, false); + colorGroup->add(&defaultFaultGridLineColors); + colorGroup->add(&defaultWellLabelColor, false); + + caf::PdmUiGroup* fontGroup = uiOrdering.addNewGroup("Default Font Sizes"); + fontGroup->add(&defaultSceneFontSize); + fontGroup->add(&defaultAnnotationFontSize, false); + fontGroup->add(&defaultWellLabelFontSize); + fontGroup->add(&defaultPlotFontSize, false); + + caf::PdmUiGroup* viewsGroup = uiOrdering.addNewGroup("3d Views"); + viewsGroup->add(&defaultMeshModeType); viewsGroup->add(&navigationPolicy); + viewsGroup->add(&defaultScaleFactorZ); + viewsGroup->add(&showLegendBackground); viewsGroup->add(&useShaders); viewsGroup->add(&showHud); - - + caf::PdmUiGroup* otherGroup = uiOrdering.addNewGroup("Other"); otherGroup->add(&ssihubAddress); otherGroup->add(&showLasCurveWithoutTvdWarning); - + otherGroup->add(&holoLensDisableCertificateVerification); } else if (uiConfigName == m_tabNames[1]) { @@ -207,7 +235,7 @@ void RiaPreferences::defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& newCaseBehaviourGroup->add(&loadAndShowSoil); m_readerSettings->defineUiOrdering(uiConfigName, *newCaseBehaviourGroup); - + caf::PdmUiGroup* restartBehaviourGroup = uiOrdering.addNewGroup("Origin Files"); restartBehaviourGroup->add(&summaryRestartFilesShowImportDialog); caf::PdmUiGroup* summaryImportOptionGroup = restartBehaviourGroup->addNewGroup("Origin Summary Files"); @@ -229,6 +257,9 @@ void RiaPreferences::defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& { uiOrdering.add(&m_appendClassNameToUiText); uiOrdering.add(&m_appendFieldKeywordToToolTipText); + + uiOrdering.add(&m_showProjectChangedDialog); + uiOrdering.add(&m_showTestToolbar); uiOrdering.add(&m_includeFractureDebugInfoFile); uiOrdering.add(&m_holoLensExportFolder); @@ -245,21 +276,7 @@ QList RiaPreferences::calculateValueOptions(const caf::P QList options; *useOptionsOnly = true; - if (&fontSizeInScene == fieldNeedingOptions) - { - QStringList fontSizes; - fontSizes << "8"; - fontSizes << "12"; - fontSizes << "16"; - fontSizes << "24"; - fontSizes << "32"; - - for (int oIdx = 0; oIdx < fontSizes.size(); ++oIdx) - { - options.push_back(caf::PdmOptionItemInfo(fontSizes[oIdx], fontSizes[oIdx])); - } - } - else if (fieldNeedingOptions == &gridImportMode) + if (fieldNeedingOptions == &gridImportMode) { // Manual option handling in order to one only a subset of the enum values SummaryRestartFilesImportModeType skip(RiaPreferences::NOT_IMPORT); @@ -320,6 +337,19 @@ bool RiaPreferences::includeFractureDebugInfoFile() const return RiaApplication::enableDevelopmentFeatures() && m_includeFractureDebugInfoFile(); } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RiaPreferences::showProjectChangedDialog() const +{ + if (!RiaApplication::enableDevelopmentFeatures()) + { + return true; + } + + return m_showProjectChangedDialog(); +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -328,3 +358,15 @@ QString RiaPreferences::holoLensExportFolder() const return m_holoLensExportFolder(); } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::map RiaPreferences::defaultFontSizes() const +{ + std::map fontSizes; + fontSizes[RiaDefines::SCENE_FONT] = defaultSceneFontSize(); + fontSizes[RiaDefines::ANNOTATION_FONT] = defaultAnnotationFontSize(); + fontSizes[RiaDefines::WELL_LABEL_FONT] = defaultWellLabelFontSize(); + fontSizes[RiaDefines::PLOT_FONT] = defaultPlotFontSize(); + return fontSizes; +} diff --git a/ApplicationCode/Application/RiaPreferences.h b/ApplicationCode/Application/RiaPreferences.h index eba31f902e..d7c8139153 100644 --- a/ApplicationCode/Application/RiaPreferences.h +++ b/ApplicationCode/Application/RiaPreferences.h @@ -1,6 +1,7 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2011- Statoil ASA +// Copyright (C) 2019- Equinor ASA +// Copyright (C) 2011-2018 Statoil ASA // Copyright (C) 2013- Ceetron Solutions AS // Copyright (C) 2011-2012 Ceetron AS // @@ -21,6 +22,9 @@ #pragma once #include "RiaApplication.h" +#include "RiaDefines.h" +#include "RiaFontCache.h" + #include "cafAppEnum.h" #include "cafPdmChildField.h" @@ -30,6 +34,8 @@ // Include to make Pdm work for cvf::Color #include "cafPdmFieldCvfColor.h" +#include + class RifReaderSettings; class RiaPreferences : public caf::PdmObject @@ -39,6 +45,7 @@ class RiaPreferences : public caf::PdmObject public: enum SummaryRestartFilesImportMode { IMPORT, NOT_IMPORT, SEPARATE_CASES }; typedef caf::AppEnum SummaryRestartFilesImportModeType; + typedef RiaFontCache::FontSizeType FontSizeType; RiaPreferences(void); ~RiaPreferences(void) override; @@ -52,8 +59,11 @@ class RiaPreferences : public caf::PdmObject bool appendFieldKeywordToToolTipText() const; bool showTestToolbar() const; bool includeFractureDebugInfoFile() const; + bool showProjectChangedDialog() const; QString holoLensExportFolder() const; + std::map defaultFontSizes() const; + public: // Pdm Fields caf::PdmField > navigationPolicy; @@ -65,14 +75,20 @@ class RiaPreferences : public caf::PdmObject caf::PdmField ssihubAddress; - caf::PdmField defaultScaleFactorZ; - caf::PdmField defaultGridLines; + caf::PdmField> defaultMeshModeType; + + caf::PdmField defaultScaleFactorZ; caf::PdmField defaultGridLineColors; caf::PdmField defaultFaultGridLineColors; caf::PdmField defaultViewerBackgroundColor; caf::PdmField defaultWellLabelColor; - caf::PdmField showLasCurveWithoutTvdWarning; - caf::PdmField fontSizeInScene; + caf::PdmField showLasCurveWithoutTvdWarning; + + caf::PdmField defaultSceneFontSize; + caf::PdmField defaultWellLabelFontSize; + caf::PdmField defaultAnnotationFontSize; + caf::PdmField defaultPlotFontSize; + caf::PdmField showLegendBackground; caf::PdmField useShaders; @@ -87,6 +103,8 @@ class RiaPreferences : public caf::PdmObject caf::PdmField summaryImportMode; caf::PdmField gridImportMode; + caf::PdmField holoLensDisableCertificateVerification; + protected: void defineEditorAttribute(const caf::PdmFieldHandle* field, QString uiConfigName, caf::PdmUiEditorAttribute* attribute) override; void defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering) override; @@ -96,8 +114,12 @@ class RiaPreferences : public caf::PdmObject caf::PdmChildField m_readerSettings; caf::PdmField m_appendClassNameToUiText; caf::PdmField m_appendFieldKeywordToToolTipText; + + caf::PdmField m_showProjectChangedDialog; + caf::PdmField m_showTestToolbar; caf::PdmField m_includeFractureDebugInfoFile; caf::PdmField m_holoLensExportFolder; - QStringList m_tabNames; + QStringList m_tabNames; + }; diff --git a/ApplicationCode/Application/RiaViewRedrawScheduler.cpp b/ApplicationCode/Application/RiaViewRedrawScheduler.cpp index b1d31a499a..1397dd1c7b 100644 --- a/ApplicationCode/Application/RiaViewRedrawScheduler.cpp +++ b/ApplicationCode/Application/RiaViewRedrawScheduler.cpp @@ -1,17 +1,17 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018- Statoil ASA -// +// Copyright (C) 2018- Equinor ASA +// // ResInsight 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 3 of the License, or // (at your option) any later version. -// +// // ResInsight 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 at +// +// See the GNU General Public License at // for more details. // ///////////////////////////////////////////////////////////////////////////////// diff --git a/ApplicationCode/Application/RiaViewRedrawScheduler.h b/ApplicationCode/Application/RiaViewRedrawScheduler.h index c30eb67586..4a8acdb589 100644 --- a/ApplicationCode/Application/RiaViewRedrawScheduler.h +++ b/ApplicationCode/Application/RiaViewRedrawScheduler.h @@ -1,17 +1,17 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018- Statoil ASA -// +// Copyright (C) 2018- Equinor ASA +// // ResInsight 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 3 of the License, or // (at your option) any later version. -// +// // ResInsight 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 at +// +// See the GNU General Public License at // for more details. // ///////////////////////////////////////////////////////////////////////////////// diff --git a/ApplicationCode/Application/Tools/CMakeLists_files.cmake b/ApplicationCode/Application/Tools/CMakeLists_files.cmake index 8644cd3742..a18cfd9c28 100644 --- a/ApplicationCode/Application/Tools/CMakeLists_files.cmake +++ b/ApplicationCode/Application/Tools/CMakeLists_files.cmake @@ -7,6 +7,7 @@ ${CMAKE_CURRENT_LIST_DIR}/RiaColorTools.h ${CMAKE_CURRENT_LIST_DIR}/RiaEclipseUnitTools.h ${CMAKE_CURRENT_LIST_DIR}/RiaImageCompareReporter.h ${CMAKE_CURRENT_LIST_DIR}/RiaImageFileCompare.h +${CMAKE_CURRENT_LIST_DIR}/RiaImageTools.h ${CMAKE_CURRENT_LIST_DIR}/RiaLogging.h ${CMAKE_CURRENT_LIST_DIR}/RiaProjectModifier.h ${CMAKE_CURRENT_LIST_DIR}/RiaRegressionTest.h @@ -35,9 +36,9 @@ ${CMAKE_CURRENT_LIST_DIR}/RiaWeightedGeometricMeanCalculator.h ${CMAKE_CURRENT_LIST_DIR}/RiaWeightedHarmonicMeanCalculator.h ${CMAKE_CURRENT_LIST_DIR}/RiaOptionItemFactory.h ${CMAKE_CURRENT_LIST_DIR}/RiaGitDiff.h -${CMAKE_CURRENT_LIST_DIR}/RiaQIconTools.h ${CMAKE_CURRENT_LIST_DIR}/RiaCellDividingTools.h ${CMAKE_CURRENT_LIST_DIR}/RiaFieldHandleTools.h +${CMAKE_CURRENT_LIST_DIR}/RiaBoundingBoxTools.h ) set (SOURCE_GROUP_SOURCE_FILES @@ -48,6 +49,7 @@ ${CMAKE_CURRENT_LIST_DIR}/RiaColorTools.cpp ${CMAKE_CURRENT_LIST_DIR}/RiaEclipseUnitTools.cpp ${CMAKE_CURRENT_LIST_DIR}/RiaImageCompareReporter.cpp ${CMAKE_CURRENT_LIST_DIR}/RiaImageFileCompare.cpp +${CMAKE_CURRENT_LIST_DIR}/RiaImageTools.cpp ${CMAKE_CURRENT_LIST_DIR}/RiaLogging.cpp ${CMAKE_CURRENT_LIST_DIR}/RiaProjectModifier.cpp ${CMAKE_CURRENT_LIST_DIR}/RiaRegressionTest.cpp @@ -73,9 +75,9 @@ ${CMAKE_CURRENT_LIST_DIR}/RiaWeightedGeometricMeanCalculator.cpp ${CMAKE_CURRENT_LIST_DIR}/RiaWeightedHarmonicMeanCalculator.cpp ${CMAKE_CURRENT_LIST_DIR}/RiaOptionItemFactory.cpp ${CMAKE_CURRENT_LIST_DIR}/RiaGitDiff.cpp -${CMAKE_CURRENT_LIST_DIR}/RiaQIconTools.cpp ${CMAKE_CURRENT_LIST_DIR}/RiaCellDividingTools.cpp ${CMAKE_CURRENT_LIST_DIR}/RiaFieldHandleTools.cpp +${CMAKE_CURRENT_LIST_DIR}/RiaBoundingBoxTools.cpp ) list(APPEND CODE_HEADER_FILES diff --git a/ApplicationCode/Application/Tools/RiaArgumentParser.cpp b/ApplicationCode/Application/Tools/RiaArgumentParser.cpp index 75ddadee45..a0c054a30a 100644 --- a/ApplicationCode/Application/Tools/RiaArgumentParser.cpp +++ b/ApplicationCode/Application/Tools/RiaArgumentParser.cpp @@ -1,17 +1,17 @@ ///////////////////////////////////////////////////////////////////////////////// // // Copyright (C) 2017 Statoil ASA -// +// // ResInsight 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 3 of the License, or // (at your option) any later version. -// +// // ResInsight 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 at +// +// See the GNU General Public License at // for more details. // ///////////////////////////////////////////////////////////////////////////////// @@ -20,7 +20,9 @@ #include "RiaApplication.h" #include "RiaBaseDefs.h" +#include "RiaEclipseFileNameTools.h" #include "RiaImportEclipseCaseTools.h" +#include "RiaLogging.h" #include "RiaPreferences.h" #include "RiaProjectModifier.h" #include "RiaRegressionTestRunner.h" @@ -30,48 +32,81 @@ #include "RiuMainWindow.h" #include "RiuPlotMainWindow.h" -#include "RicfMessages.h" #include "RicfCommandFileExecutor.h" +#include "RicfMessages.h" -#include "ExportCommands/RicSnapshotViewToFileFeature.h" #include "ExportCommands/RicSnapshotAllPlotsToFileFeature.h" #include "ExportCommands/RicSnapshotAllViewsToFileFeature.h" +#include "ExportCommands/RicSnapshotViewToFileFeature.h" +#include "RicImportSummaryCasesFeature.h" #include "cvfProgramOptions.h" #include "cvfqtUtils.h" #include "cafUtils.h" -#include -#include #include #include +#include +#include //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- bool RiaArgumentParser::parseArguments() { cvf::ProgramOptions progOpt; - progOpt.registerOption("last", "", "Open last used project."); - progOpt.registerOption("project", "", "Open project file .", cvf::ProgramOptions::SINGLE_VALUE); - progOpt.registerOption("case", "", "Import Eclipse case (do not include the .GRID/.EGRID extension.)", cvf::ProgramOptions::MULTI_VALUE); - progOpt.registerOption("startdir", "", "Set startup directory.", cvf::ProgramOptions::SINGLE_VALUE); - progOpt.registerOption("savesnapshots", "all|views|plots", "Save snapshot of all views or plots to project file location sub folder 'snapshots'. Option 'all' will include both views and plots. Application closes after snapshots have been written.", cvf::ProgramOptions::OPTIONAL_MULTI_VALUE); - progOpt.registerOption("size", " ", "Set size of the main application window.", cvf::ProgramOptions::MULTI_VALUE); - progOpt.registerOption("replaceCase", "[] ", "Replace grid in or first case with . Repeat parameter for multiple replace operations.", cvf::ProgramOptions::MULTI_VALUE, cvf::ProgramOptions::COMBINE_REPEATED); - progOpt.registerOption("replaceSourceCases", "[] ", "Replace source cases in or first grid case group with the grid files listed in the file. Repeat parameter for multiple replace operations.", cvf::ProgramOptions::MULTI_VALUE, cvf::ProgramOptions::COMBINE_REPEATED); - progOpt.registerOption("replacePropertiesFolder", "[] ", "Replace the folder containing property files for an eclipse input case.", cvf::ProgramOptions::MULTI_VALUE); - progOpt.registerOption("multiCaseSnapshots", "", "For each grid file listed in the file, replace the first case in the project and save snapshot of all views.", cvf::ProgramOptions::SINGLE_VALUE); - progOpt.registerOption("commandFile", "", "Execute the command file.", cvf::ProgramOptions::SINGLE_VALUE); - progOpt.registerOption("commandFileProject", "", "Project to use if performing case looping for command file. Used in conjunction with 'commandFileReplaceCases'.", cvf::ProgramOptions::SINGLE_VALUE); - progOpt.registerOption("commandFileReplaceCases", "[] ", "Supply list of cases to replace in project, performing command file for each case.", cvf::ProgramOptions::SINGLE_VALUE); - progOpt.registerOption("help", "", "Displays help text."); - progOpt.registerOption("?", "", "Displays help text."); - progOpt.registerOption("regressiontest", "", "System command", cvf::ProgramOptions::SINGLE_VALUE); - progOpt.registerOption("updateregressiontestbase", "", "System command", cvf::ProgramOptions::SINGLE_VALUE); - progOpt.registerOption("unittest", "", "System command"); - progOpt.registerOption("ignoreArgs", "", "Ignore all arguments. Mostly for testing purposes"); + progOpt.registerOption("last", "", "Open last used project."); + progOpt.registerOption("project", "", "Open project file .", cvf::ProgramOptions::SINGLE_VALUE); + progOpt.registerOption("case", + "", + "Import Eclipse case (do not include the .GRID/.EGRID extension.)", + cvf::ProgramOptions::MULTI_VALUE); + progOpt.registerOption("startdir", "", "Set startup directory.", cvf::ProgramOptions::SINGLE_VALUE); + progOpt.registerOption("savesnapshots", + "all|views|plots", + "Save snapshot of all views or plots to project file location sub folder 'snapshots'. Option 'all' " + "will include both views and plots. Application closes after snapshots have been written.", + cvf::ProgramOptions::OPTIONAL_MULTI_VALUE); + progOpt.registerOption( + "size", " ", "Set size of the main application window.", cvf::ProgramOptions::MULTI_VALUE); + progOpt.registerOption( + "replaceCase", + "[] ", + "Replace grid in or first case with . Repeat parameter for multiple replace operations.", + cvf::ProgramOptions::MULTI_VALUE, + cvf::ProgramOptions::COMBINE_REPEATED); + progOpt.registerOption("replaceSourceCases", + "[] ", + "Replace source cases in or first grid case group with the grid files listed in the " + " file. Repeat parameter for multiple replace operations.", + cvf::ProgramOptions::MULTI_VALUE, + cvf::ProgramOptions::COMBINE_REPEATED); + progOpt.registerOption("replacePropertiesFolder", + "[] ", + "Replace the folder containing property files for an eclipse input case.", + cvf::ProgramOptions::MULTI_VALUE); + progOpt.registerOption("multiCaseSnapshots", + "", + "For each grid file listed in the file, replace the first case in the project and save " + "snapshot of all views.", + cvf::ProgramOptions::SINGLE_VALUE); + progOpt.registerOption("commandFile", "", "Execute the command file.", cvf::ProgramOptions::SINGLE_VALUE); + progOpt.registerOption( + "commandFileProject", + "", + "Project to use if performing case looping for command file. Used in conjunction with 'commandFileReplaceCases'.", + cvf::ProgramOptions::SINGLE_VALUE); + progOpt.registerOption("commandFileReplaceCases", + "[] ", + "Supply list of cases to replace in project, performing command file for each case.", + cvf::ProgramOptions::SINGLE_VALUE); + progOpt.registerOption("help", "", "Displays help text."); + progOpt.registerOption("?", "", "Displays help text."); + progOpt.registerOption("regressiontest", "", "System command", cvf::ProgramOptions::SINGLE_VALUE); + progOpt.registerOption("updateregressiontestbase", "", "System command", cvf::ProgramOptions::SINGLE_VALUE); + progOpt.registerOption("unittest", "", "System command"); + progOpt.registerOption("ignoreArgs", "", "Ignore all arguments. Mostly for testing purposes"); progOpt.setOptionPrefix(cvf::ProgramOptions::DOUBLE_DASH); @@ -89,21 +124,17 @@ bool RiaArgumentParser::parseArguments() // If positional parameter functionality is to be supported, the test for existence of positionalParameters must be removed // This is based on a pull request by @andlaus https://github.com/OPM/ResInsight/pull/162 - if (!parseOk || - progOpt.hasOption("help") || - progOpt.hasOption("?") || - progOpt.positionalParameters().size() > 0) + if (!parseOk || progOpt.hasOption("help") || progOpt.hasOption("?") || !progOpt.positionalParameters().empty()) { #if defined(_MSC_VER) && defined(_WIN32) RiaApplication::instance()->showFormattedTextInMessageBox(helpText); #else - fprintf(stdout, "%s\n", helpText.toAscii().data()); + fprintf(stdout, "%s\n", helpText.toLatin1().data()); fflush(stdout); #endif return false; } - // Handling of the actual command line options // -------------------------------------------------------- @@ -116,6 +147,15 @@ bool RiaArgumentParser::parseArguments() { CVF_ASSERT(o.valueCount() == 1); QString regressionTestPath = cvfqt::Utils::toQString(o.value(0)); + + // Use a logger writing to stdout instead of message panel + // This is useful when executing regression tests on a build server, and this is the reason for creating the logger when + // parsing the command line options + auto stdLogger = new RiaStdOutLogger; + stdLogger->setLevel(RI_LL_DEBUG); + + RiaLogging::setLoggerInstance(stdLogger); + RiaRegressionTestRunner::instance()->executeRegressionTests(regressionTestPath, QStringList()); return false; } @@ -137,15 +177,14 @@ bool RiaArgumentParser::parseArguments() if (cvf::Option o = progOpt.option("size")) { RiuMainWindow* mainWnd = RiuMainWindow::instance(); - int width = o.safeValue(0).toInt(-1); - int height = o.safeValue(1).toInt(-1); + int width = o.safeValue(0).toInt(-1); + int height = o.safeValue(1).toInt(-1); if (mainWnd && width > 0 && height > 0) { mainWnd->resize(width, height); } } - QString projectFileName; if (progOpt.hasOption("last")) @@ -159,23 +198,21 @@ bool RiaArgumentParser::parseArguments() projectFileName = cvfqt::Utils::toQString(o.value(0)); } - if (!projectFileName.isEmpty()) { if (cvf::Option o = progOpt.option("multiCaseSnapshots")) { - QString gridListFile = cvfqt::Utils::toQString(o.safeValue(0)); - std::vector gridFiles = RiaApplication::readFileListFromTextFile(gridListFile); + QString gridListFile = cvfqt::Utils::toQString(o.safeValue(0)); + std::vector gridFiles = RiaApplication::readFileListFromTextFile(gridListFile); RiaApplication::instance()->runMultiCaseSnapshots(projectFileName, gridFiles, "multiCaseSnapshots"); return false; } } - if (!projectFileName.isEmpty()) { - cvf::ref projectModifier; + cvf::ref projectModifier; RiaApplication::ProjectLoadAction projectLoadAction = RiaApplication::PLA_NONE; if (cvf::Option o = progOpt.option("replaceCase")) @@ -194,8 +231,8 @@ bool RiaArgumentParser::parseArguments() size_t optionIdx = 0; while (optionIdx < o.valueCount()) { - const int caseId = o.safeValue(optionIdx++).toInt(-1); - QString gridFileName = cvfqt::Utils::toQString(o.safeValue(optionIdx++)); + const int caseId = o.safeValue(optionIdx++).toInt(-1); + QString gridFileName = cvfqt::Utils::toQString(o.safeValue(optionIdx++)); if (caseId != -1 && !gridFileName.isEmpty()) { @@ -213,7 +250,8 @@ bool RiaArgumentParser::parseArguments() { // One argument is available, use replace case for first occurrence in the project - std::vector gridFileNames = RiaApplication::readFileListFromTextFile(cvfqt::Utils::toQString(o.safeValue(0))); + std::vector gridFileNames = + RiaApplication::readFileListFromTextFile(cvfqt::Utils::toQString(o.safeValue(0))); projectModifier->setReplaceSourceCasesFirstOccurrence(gridFileNames); } else @@ -221,10 +259,11 @@ bool RiaArgumentParser::parseArguments() size_t optionIdx = 0; while (optionIdx < o.valueCount()) { - const int groupId = o.safeValue(optionIdx++).toInt(-1); - std::vector gridFileNames = RiaApplication::readFileListFromTextFile(cvfqt::Utils::toQString(o.safeValue(optionIdx++))); + const int groupId = o.safeValue(optionIdx++).toInt(-1); + std::vector gridFileNames = + RiaApplication::readFileListFromTextFile(cvfqt::Utils::toQString(o.safeValue(optionIdx++))); - if (groupId != -1 && gridFileNames.size() > 0) + if (groupId != -1 && !gridFileNames.empty()) { projectModifier->setReplaceSourceCasesById(groupId, gridFileNames); } @@ -248,8 +287,8 @@ bool RiaArgumentParser::parseArguments() size_t optionIdx = 0; while (optionIdx < o.valueCount()) { - const int caseId = o.safeValue(optionIdx++).toInt(-1); - QString propertiesFolder = cvfqt::Utils::toQString(o.safeValue(optionIdx++)); + const int caseId = o.safeValue(optionIdx++).toInt(-1); + QString propertiesFolder = cvfqt::Utils::toQString(o.safeValue(optionIdx++)); if (caseId != -1 && !propertiesFolder.isEmpty()) { @@ -262,51 +301,28 @@ bool RiaArgumentParser::parseArguments() RiaApplication::instance()->loadProject(projectFileName, projectLoadAction, projectModifier.p()); } - if (cvf::Option o = progOpt.option("case")) { QStringList caseNames = cvfqt::Utils::toQStringList(o.values()); - foreach (QString caseName, caseNames) + for (const QString& caseName : caseNames) { - QString fileExtension = caf::Utils::fileExtension(caseName); - if (caf::Utils::fileExists(caseName) && - (fileExtension == "EGRID" || fileExtension == "GRID")) - { - RiaImportEclipseCaseTools::openEclipseCasesFromFile(QStringList({ caseName }), nullptr, true); - } - else - { - QString caseFileNameWithExt = caseName + ".EGRID"; - if (caf::Utils::fileExists(caseFileNameWithExt)) - { - RiaImportEclipseCaseTools::openEclipseCasesFromFile(QStringList({ caseFileNameWithExt }), nullptr, true); - } - else - { - caseFileNameWithExt = caseName + ".GRID"; - if (caf::Utils::fileExists(caseFileNameWithExt)) - { - RiaImportEclipseCaseTools::openEclipseCasesFromFile(QStringList({ caseFileNameWithExt }), nullptr, true); - } - } - } + openCaseFromCommandLineParameter(caseName); } } - if (cvf::Option o = progOpt.option("savesnapshots")) { bool snapshotViews = false; bool snapshotPlots = false; QStringList snapshotItemTexts = cvfqt::Utils::toQStringList(o.values()); - if (snapshotItemTexts.size() == 0) + if (snapshotItemTexts.empty()) { // No options will keep backwards compatibility before we introduced snapshot of plots snapshotViews = true; } - for (QString s : snapshotItemTexts) + for (const QString& s : snapshotItemTexts) { if (s.toLower() == "all") { @@ -331,9 +347,10 @@ bool RiaArgumentParser::parseArguments() CVF_ASSERT(mainWnd); mainWnd->hideAllDockWindows(); - // 2016-11-09 : Location of snapshot folder was previously located in 'snapshot' folder + // 2016-11-09 : Location of snapshot folder was previously located in 'snapshot' folder // relative to current working folder. Now harmonized to behave as RiuMainWindow::slotSnapshotAllViewsToFile() - QString absolutePathToSnapshotDir = RiaApplication::instance()->createAbsolutePathFromProjectRelativePath("snapshots"); + QString absolutePathToSnapshotDir = + RiaApplication::instance()->createAbsolutePathFromProjectRelativePath("snapshots"); RicSnapshotAllViewsToFileFeature::exportSnapshotOfAllViewsIntoFolder(absolutePathToSnapshotDir); mainWnd->loadWinGeoAndDockToolBarLayout(); @@ -362,12 +379,12 @@ bool RiaArgumentParser::parseArguments() QString commandFile = cvfqt::Utils::toQString(o.safeValue(0)); cvf::Option projectOption = progOpt.option("commandFileProject"); - cvf::Option caseOption = progOpt.option("commandFileReplaceCases"); + cvf::Option caseOption = progOpt.option("commandFileReplaceCases"); if (projectOption && caseOption) { projectFileName = cvfqt::Utils::toQString(projectOption.value(0)); - std::vector caseIds; + std::vector caseIds; std::vector caseListFiles; if (caseOption.valueCount() == 1) @@ -379,8 +396,8 @@ bool RiaArgumentParser::parseArguments() size_t optionIdx = 0; while (optionIdx < caseOption.valueCount()) { - const int caseId = caseOption.safeValue(optionIdx++).toInt(-1); - QString caseListFile = cvfqt::Utils::toQString(caseOption.safeValue(optionIdx++)); + const int caseId = caseOption.safeValue(optionIdx++).toInt(-1); + QString caseListFile = cvfqt::Utils::toQString(caseOption.safeValue(optionIdx++)); if (caseId != -1 && !caseListFile.isEmpty()) { @@ -392,8 +409,8 @@ bool RiaArgumentParser::parseArguments() if (caseIds.empty() && !caseListFiles.empty()) { - QString caseListFile = caseListFiles[0]; - std::vector caseFiles = RiaApplication::readFileListFromTextFile(caseListFile); + QString caseListFile = caseListFiles[0]; + std::vector caseFiles = RiaApplication::readFileListFromTextFile(caseListFile); for (const QString& caseFile : caseFiles) { RiaProjectModifier projectModifier; @@ -406,8 +423,8 @@ bool RiaArgumentParser::parseArguments() { CVF_ASSERT(caseIds.size() == caseListFiles.size()); - std::vector< std::vector > allCaseFiles; - size_t maxFiles = 0; + std::vector> allCaseFiles; + size_t maxFiles = 0; for (size_t i = 0; i < caseIds.size(); ++i) { @@ -443,11 +460,11 @@ bool RiaArgumentParser::parseArguments() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RiaArgumentParser::executeCommandFile(const QString& commandFile) { - QFile file(commandFile); + QFile file(commandFile); RicfMessages messages; if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { @@ -458,3 +475,64 @@ void RiaArgumentParser::executeCommandFile(const QString& commandFile) QTextStream in(&file); RicfCommandFileExecutor::instance()->executeCommands(in); } + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RiaArgumentParser::openCaseFromCommandLineParameter(const QString& parameter) +{ + if (RiaEclipseFileNameTools::isProjectFile(parameter)) + { + return RiaApplication::instance()->loadProject(parameter); + } + + QStringList gridFileNames; + QStringList summarySpecFileNames; + + if (RiaEclipseFileNameTools::isGridFile(parameter)) + { + QFileInfo fi(parameter); + + gridFileNames.push_back(fi.absoluteFilePath()); + } + else if (RiaEclipseFileNameTools::isSummarySpecFile(parameter)) + { + QFileInfo fi(parameter); + + summarySpecFileNames.push_back(fi.absoluteFilePath()); + } + else + { + RiaEclipseFileNameTools fileNameTools(parameter); + + { + QString gridFileName = fileNameTools.findRelatedGridFile(); + if (!gridFileName.isEmpty()) + { + gridFileNames.push_back(gridFileName); + } + } + + QString summarySpecFileName = fileNameTools.findRelatedSummarySpecFile(); + if (!summarySpecFileName.isEmpty()) + { + summarySpecFileNames.push_back(summarySpecFileName); + } + } + + bool openCaseResult = true; + + // Open summary cases first. Then, the open of grid file will not open an already open summary case file + if (!summarySpecFileNames.empty()) + { + openCaseResult &= RicImportSummaryCasesFeature::createAndAddSummaryCasesFromFiles(summarySpecFileNames); + RiaApplication::instance()->getOrCreateAndShowMainPlotWindow(); + } + + for (const auto& f : gridFileNames) + { + openCaseResult &= RiaImportEclipseCaseTools::openEclipseCasesFromFile(QStringList({f}), nullptr, true); + } + + return openCaseResult; +} diff --git a/ApplicationCode/Application/Tools/RiaArgumentParser.h b/ApplicationCode/Application/Tools/RiaArgumentParser.h index 75ab33072d..6a0d6dc212 100644 --- a/ApplicationCode/Application/Tools/RiaArgumentParser.h +++ b/ApplicationCode/Application/Tools/RiaArgumentParser.h @@ -32,5 +32,6 @@ class RiaArgumentParser private: static void executeCommandFile(const QString& commandFile); + static bool openCaseFromCommandLineParameter(const QString& parameter); }; diff --git a/ApplicationCode/Application/Tools/RiaBoundingBoxTools.cpp b/ApplicationCode/Application/Tools/RiaBoundingBoxTools.cpp new file mode 100644 index 0000000000..1653158ef4 --- /dev/null +++ b/ApplicationCode/Application/Tools/RiaBoundingBoxTools.cpp @@ -0,0 +1,34 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2011- Statoil ASA +// Copyright (C) 2013- Ceetron Solutions AS +// Copyright (C) 2011-2012 Ceetron AS +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "RiaBoundingBoxTools.h" + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +cvf::BoundingBox RiaBoundingBoxTools::inflate(const cvf::BoundingBox& boundingBox, double factor) +{ + cvf::Vec3d center = boundingBox.center(); + cvf::Vec3d sizes = boundingBox.extent() * factor; + + cvf::Vec3d newMin(center.x() - sizes.x() / 2.0, center.y() - sizes.y() / 2.0, center.z() - sizes.z() / 2.0); + cvf::Vec3d newMax(center.x() + sizes.x() / 2.0, center.y() + sizes.y() / 2.0, center.z() + sizes.z() / 2.0); + return cvf::BoundingBox(newMin, newMax); +} diff --git a/ApplicationCode/Application/Tools/RiaBoundingBoxTools.h b/ApplicationCode/Application/Tools/RiaBoundingBoxTools.h new file mode 100644 index 0000000000..5d632deb5a --- /dev/null +++ b/ApplicationCode/Application/Tools/RiaBoundingBoxTools.h @@ -0,0 +1,35 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2011- Statoil ASA +// Copyright (C) 2013- Ceetron Solutions AS +// Copyright (C) 2011-2012 Ceetron AS +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include +#include + +//================================================================================================== +// +// +// +//================================================================================================== +class RiaBoundingBoxTools +{ +public: + static cvf::BoundingBox inflate(const cvf::BoundingBox& boundingBox, double factor); +}; diff --git a/ApplicationCode/Application/Tools/RiaCellDividingTools.cpp b/ApplicationCode/Application/Tools/RiaCellDividingTools.cpp index 6f5ecd94ec..789460580a 100644 --- a/ApplicationCode/Application/Tools/RiaCellDividingTools.cpp +++ b/ApplicationCode/Application/Tools/RiaCellDividingTools.cpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018- Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by diff --git a/ApplicationCode/Application/Tools/RiaCellDividingTools.h b/ApplicationCode/Application/Tools/RiaCellDividingTools.h index 9dba6a7554..91fafb801c 100644 --- a/ApplicationCode/Application/Tools/RiaCellDividingTools.h +++ b/ApplicationCode/Application/Tools/RiaCellDividingTools.h @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018- Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by diff --git a/ApplicationCode/Application/Tools/RiaColorTables.cpp b/ApplicationCode/Application/Tools/RiaColorTables.cpp index c525c10691..85cdabd690 100644 --- a/ApplicationCode/Application/Tools/RiaColorTables.cpp +++ b/ApplicationCode/Application/Tools/RiaColorTables.cpp @@ -17,6 +17,9 @@ ///////////////////////////////////////////////////////////////////////////////// #include "RiaColorTables.h" +#include "RiaColorTools.h" + +#include "cvfAssert.h" #include @@ -163,6 +166,16 @@ const caf::ColorTable& RiaColorTables::categoryPaletteColors() return colorTable; } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +const caf::ColorTable& RiaColorTables::contrastCategoryPaletteColors() +{ + static caf::ColorTable colorTable = caf::ColorTable(contrastCategoryColors()); + + return colorTable; +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -515,7 +528,7 @@ cvf::Color3f RiaColorTables::undefinedCellColor() //-------------------------------------------------------------------------------------------------- RiaColorTables::WellPathComponentColors RiaColorTables::wellPathComponentColors() { - return {{RiaDefines::WELL_PATH, cvf::Color3::CEETRON}, + return {{RiaDefines::WELL_PATH, cvf::Color3::CEETRON}, {RiaDefines::PERFORATION_INTERVAL, cvf::Color3::DARK_MAGENTA}, {RiaDefines::FISHBONES, cvf::Color3::DARK_GREEN}, {RiaDefines::FRACTURE, cvf::Color3::CRIMSON}, @@ -524,7 +537,67 @@ RiaColorTables::WellPathComponentColors RiaColorTables::wellPathComponentColors( {RiaDefines::ICV, cvf::Color3::ORCHID}, {RiaDefines::CASING, cvf::Color3::SEA_GREEN}, {RiaDefines::LINER, cvf::Color3::OLIVE}, - {RiaDefines::PACKER, cvf::Color3::GRAY}}; + {RiaDefines::PACKER, cvf::Color3::GRAY}, + {RiaDefines::UNDEFINED_COMPONENT, cvf::Color3::MAGENTA}}; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +cvf::Color3f RiaColorTables::defaultGridLineColor() +{ + return cvf::Color3f(0.92f, 0.92f, 0.92f); +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +cvf::Color3f RiaColorTables::defaultFaultLineColor() +{ + return cvf::Color3f(0.08f, 0.08f, 0.08f); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +cvf::Color3f RiaColorTables::defaultWellLabelColor() +{ + return cvf::Color3f(0.92f, 0.92f, 0.92f); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +cvf::Color3f RiaColorTables::defaultViewerBackgroundColor() +{ + return cvf::Color3f(0.69f, 0.77f, 0.87f); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +caf::ColorTable RiaColorTables::createBrightnessBasedColorTable(cvf::Color3ub baseColor, int brightnessLevelCount) +{ + CVF_ASSERT(brightnessLevelCount >= 1); + QColor baseRGB(baseColor.r(), baseColor.g(), baseColor.b()); + float hueF = baseRGB.hslHueF(); + float satF = baseRGB.hslSaturationF(); + + std::vector colors; + if (brightnessLevelCount == 1) + { + colors.push_back(cvf::Color3ub(RiaColorTools::fromQColorTo3f(QColor::fromHslF(hueF, satF, 0.5)))); + } + else + { + for (int i = 0; i < brightnessLevelCount; ++i) + { + float brightness = static_cast(i) / static_cast(brightnessLevelCount - 1); + colors.push_back(cvf::Color3ub(RiaColorTools::fromQColorTo3f(QColor::fromHslF(hueF, satF, brightness)))); + } + } + return caf::ColorTable(colors); } //-------------------------------------------------------------------------------------------------- @@ -562,6 +635,42 @@ std::vector RiaColorTables::categoryColors() return colors; } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector RiaColorTables::contrastCategoryColors() +{ + // Based on http://stackoverflow.com/questions/470690/how-to-automatically-generate-n-distinct-colors + // and Kelly Colors and sorted by hue + // See also http://www.w3schools.com/colors/ for palettes etc. + + static std::vector colors{ + cvf::Color3ub(244, 200, 0), // hwb( 49, 0%, 4%) vivid_greenish_yellow + cvf::Color3ub(128, 62, 117), // hwb(310, 24%, 50%) strong_purple + cvf::Color3ub(255, 104, 0), // hwb( 24, 0%, 0%) vivid_orange + cvf::Color3ub(166, 189, 215), // hwb(212, 65%, 16%) very_light_blue + cvf::Color3ub(193, 0, 32), // hwb(350, 0%, 24%) vivid_red + cvf::Color3ub(206, 162, 98), // hwb( 36, 38%, 19%) grayish_yellow + cvf::Color3ub(129, 112, 102), // hwb( 22, 40%, 49%) medium_gray + cvf::Color3ub(0, 125, 52), // hwb(145, 0%, 51%) vivid_green + cvf::Color3ub(246, 118, 142), // hwb(349, 46%, 4%) strong_purplish_pink + cvf::Color3ub(0, 83, 138), // hwb(204, 0%, 46%) strong_blue + cvf::Color3ub(255, 122, 92), // hwb( 11, 36%, 0%) strong_yellowish_pink + cvf::Color3ub(212, 28, 132), // hwb(326, 11%, 17%) strong_purplish_red + cvf::Color3ub(255, 142, 0), // hwb( 33, 0%, 0%) vivid_orange_yellow + cvf::Color3ub(59, 84, 23), // hwb( 85, 9%, 67%) dark_olive_green + cvf::Color3ub(127, 24, 13), // hwb( 6, 5%, 50%) strong_reddish_brown + cvf::Color3ub(54, 125, 123), // hwb(178, 21%, 51%) vivid_blueish_green + cvf::Color3ub(241, 58, 19), // hwb( 11, 7%, 5%) vivid_reddish_orange + cvf::Color3ub(147, 170, 0), // hwb( 68, 0%, 33%) vivid_yellowish_green + cvf::Color3ub(46, 76, 224), // hwb(230, 18%, 12%) medium_blue + cvf::Color3ub(89, 51, 21), // hwb( 26, 8%, 65%) deep_yellowish_brown + cvf::Color3ub(0, 0, 0) // hwb(0, 0%, 100%) black + }; + + return colors; +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/Application/Tools/RiaColorTables.h b/ApplicationCode/Application/Tools/RiaColorTables.h index 77867a9d6c..721025e897 100644 --- a/ApplicationCode/Application/Tools/RiaColorTables.h +++ b/ApplicationCode/Application/Tools/RiaColorTables.h @@ -40,6 +40,7 @@ class RiaColorTables static const caf::ColorTable& blueWhiteRedPaletteColors(); static const caf::ColorTable& redWhiteBluePaletteColors(); static const caf::ColorTable& categoryPaletteColors(); + static const caf::ColorTable& contrastCategoryPaletteColors(); static const caf::ColorTable& tensorWhiteGrayBlackPaletteColors(); static const caf::ColorTable& tensorOrangeBlueWhitePaletteColors(); static const caf::ColorTable& tensorsMagentaBrownGrayPaletteColors(); @@ -63,7 +64,16 @@ class RiaColorTables static WellPathComponentColors wellPathComponentColors(); + // Default 3d View colors + static cvf::Color3f defaultGridLineColor(); + static cvf::Color3f defaultFaultLineColor(); + static cvf::Color3f defaultWellLabelColor(); + static cvf::Color3f defaultViewerBackgroundColor(); + + + static caf::ColorTable createBrightnessBasedColorTable(cvf::Color3ub baseColor, int brightnessLevelCount); private: static std::vector categoryColors(); + static std::vector contrastCategoryColors(); static std::vector invertedCategoryColors(); }; diff --git a/ApplicationCode/Application/Tools/RiaColorTools.cpp b/ApplicationCode/Application/Tools/RiaColorTools.cpp index 37d08c6072..fbbec44c89 100644 --- a/ApplicationCode/Application/Tools/RiaColorTools.cpp +++ b/ApplicationCode/Application/Tools/RiaColorTools.cpp @@ -1,31 +1,38 @@ ///////////////////////////////////////////////////////////////////////////////// // +// Copyright (C) 2018- Equinor ASA // Copyright (C) 2017 Statoil ASA -// +// // ResInsight 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 3 of the License, or // (at your option) any later version. -// +// // ResInsight 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 at +// +// See the GNU General Public License at // for more details. // ///////////////////////////////////////////////////////////////////////////////// #include "RiaColorTools.h" + #include "cvfMath.h" + #include +#include //-------------------------------------------------------------------------------------------------- -/// +/// Uses W3.org relative luminance calculation taking into account the different luminance of the different colors +/// https://www.w3.org/TR/WCAG20-TECHS/G18.html +/// Luminance is between [0, 1] so anything above 0.5 is considered in the bright half of the spectrum. +/// However, subjectively the contrast looks better if the threshold is to 0.4 so black contrast is used a bit more often. //-------------------------------------------------------------------------------------------------- bool RiaColorTools::isBrightnessAboveThreshold(cvf::Color3f backgroundColor) { - if (backgroundColor.r() + backgroundColor.g() + backgroundColor.b() > 1.5f) + if (relativeLuminance(backgroundColor) > 0.4) { return true; } @@ -34,7 +41,7 @@ bool RiaColorTools::isBrightnessAboveThreshold(cvf::Color3f backgroundColor) } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- cvf::Color3f RiaColorTools::computeOffsetColor(cvf::Color3f color, float offsetFactor) { @@ -55,13 +62,12 @@ cvf::Color3f RiaColorTools::computeOffsetColor(cvf::Color3f color, float offsetF gridB = color.b() + (1.0f - color.b()) * offsetFactor; } - return cvf::Color3f(cvf::Math::clamp(gridR, 0.0f, 1.0f), - cvf::Math::clamp(gridG, 0.0f, 1.0f), - cvf::Math::clamp(gridB, 0.0f, 1.0f)); + return cvf::Color3f( + cvf::Math::clamp(gridR, 0.0f, 1.0f), cvf::Math::clamp(gridG, 0.0f, 1.0f), cvf::Math::clamp(gridB, 0.0f, 1.0f)); } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- cvf::Color3f RiaColorTools::darkContrastColor() { @@ -69,7 +75,7 @@ cvf::Color3f RiaColorTools::darkContrastColor() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- cvf::Color3f RiaColorTools::brightContrastColor() { @@ -77,15 +83,35 @@ cvf::Color3f RiaColorTools::brightContrastColor() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- -cvf::Color3f RiaColorTools::constrastColor(cvf::Color3f backgroundColor) +cvf::Color3f RiaColorTools::darkContrastColorSofter() +{ + return cvf::Color3f::fromByteColor(30, 30, 30); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +cvf::Color3f RiaColorTools::brightContrastColorSofter() +{ + return cvf::Color3f::fromByteColor(200, 200, 200); +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +cvf::Color3f RiaColorTools::contrastColor(cvf::Color3f backgroundColor, bool softerContrast) { if (isBrightnessAboveThreshold(backgroundColor)) { + if (softerContrast) + return darkContrastColorSofter(); return darkContrastColor(); } - + if (softerContrast) + return brightContrastColorSofter(); return brightContrastColor(); } @@ -106,3 +132,32 @@ QColor RiaColorTools::toQColor(cvf::Color4f color) { return toQColor(color.toColor3f(), color.a()); } + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +cvf::Color3f RiaColorTools::fromQColorTo3f(QColor color) +{ + return cvf::Color3f(color.redF(), color.greenF(), color.blueF()); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +float RiaColorTools::relativeLuminance(cvf::Color3f backgroundColor) +{ + float R = calculateNonLinearColorValue(backgroundColor.r()); + float G = calculateNonLinearColorValue(backgroundColor.g()); + float B = calculateNonLinearColorValue(backgroundColor.b()); + + double luminance = 0.2126 * R + 0.7152 * G + 0.0722 * B; + return luminance; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +float RiaColorTools::calculateNonLinearColorValue(float colorFraction) +{ + return colorFraction <= 0.03928 ? colorFraction / 12.92 : std::pow((colorFraction + 0.055) / 1.055, 2.4); +} diff --git a/ApplicationCode/Application/Tools/RiaColorTools.h b/ApplicationCode/Application/Tools/RiaColorTools.h index 8db509194c..e99221325b 100644 --- a/ApplicationCode/Application/Tools/RiaColorTools.h +++ b/ApplicationCode/Application/Tools/RiaColorTools.h @@ -1,17 +1,18 @@ ///////////////////////////////////////////////////////////////////////////////// // +// Copyright (C) 2018- Equinor ASA // Copyright (C) 2017 Statoil ASA -// +// // ResInsight 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 3 of the License, or // (at your option) any later version. -// +// // ResInsight 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 at +// +// See the GNU General Public License at // for more details. // ///////////////////////////////////////////////////////////////////////////////// @@ -35,7 +36,14 @@ class RiaColorTools static cvf::Color3f computeOffsetColor(cvf::Color3f color, float offsetFactor); static cvf::Color3f darkContrastColor(); static cvf::Color3f brightContrastColor(); - static cvf::Color3f constrastColor(cvf::Color3f backgroundColor); + static cvf::Color3f darkContrastColorSofter(); + static cvf::Color3f brightContrastColorSofter(); + static cvf::Color3f contrastColor(cvf::Color3f backgroundColor, bool softerContrast = false); static QColor toQColor(cvf::Color3f color, float alpha = 1.0f); static QColor toQColor(cvf::Color4f color); + static cvf::Color3f fromQColorTo3f(QColor); + +private: + static float relativeLuminance(cvf::Color3f backgroundColor); + static float calculateNonLinearColorValue(float colorFraction); }; diff --git a/ApplicationCode/Application/Tools/RiaEclipseUnitTools.h b/ApplicationCode/Application/Tools/RiaEclipseUnitTools.h index 476970a941..7b7f23f0a2 100644 --- a/ApplicationCode/Application/Tools/RiaEclipseUnitTools.h +++ b/ApplicationCode/Application/Tools/RiaEclipseUnitTools.h @@ -43,6 +43,8 @@ class RiaEclipseUnitTools static double meterToInch(double meter) { return meter * feetPerMeter()*12.0; } static double inchToMeter(double inch) { return (inch / 12.0) * meterPerFeet(); } static double inchToFeet (double inch) { return (inch / 12.0); } + static double mmToMeter(double mm) { return mm / 1000.0; } + static double meterToMm(double meter) { return 1000.0 * meter; } static double darcysConstant(UnitSystem unitSystem); diff --git a/ApplicationCode/Application/Tools/RiaExtractionTools.cpp b/ApplicationCode/Application/Tools/RiaExtractionTools.cpp index a401c6b254..1ee8d8b291 100644 --- a/ApplicationCode/Application/Tools/RiaExtractionTools.cpp +++ b/ApplicationCode/Application/Tools/RiaExtractionTools.cpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018 Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by diff --git a/ApplicationCode/Application/Tools/RiaExtractionTools.h b/ApplicationCode/Application/Tools/RiaExtractionTools.h index 6b1a3bee29..a73c07c55e 100644 --- a/ApplicationCode/Application/Tools/RiaExtractionTools.h +++ b/ApplicationCode/Application/Tools/RiaExtractionTools.h @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018 Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by diff --git a/ApplicationCode/Application/Tools/RiaGitDiff.cpp b/ApplicationCode/Application/Tools/RiaGitDiff.cpp index 41894f5cb0..6227707d88 100644 --- a/ApplicationCode/Application/Tools/RiaGitDiff.cpp +++ b/ApplicationCode/Application/Tools/RiaGitDiff.cpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018 Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by diff --git a/ApplicationCode/Application/Tools/RiaGitDiff.h b/ApplicationCode/Application/Tools/RiaGitDiff.h index 82fe113659..a2a009a055 100644 --- a/ApplicationCode/Application/Tools/RiaGitDiff.h +++ b/ApplicationCode/Application/Tools/RiaGitDiff.h @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018 Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by diff --git a/ApplicationCode/Application/Tools/RiaImageTools.cpp b/ApplicationCode/Application/Tools/RiaImageTools.cpp new file mode 100644 index 0000000000..3e80929b0d --- /dev/null +++ b/ApplicationCode/Application/Tools/RiaImageTools.cpp @@ -0,0 +1,136 @@ +#include "RiaImageTools.h" + +#include "cvfAssert.h" + +#include +#include + +#include +#include + +//-------------------------------------------------------------------------------------------------- +/// Meijster, Roerdink, Hesselink +/// A GENERAL ALGORITHM FOR COMPUTING DISTANCE TRANSFORMS IN LINEAR TIME +/// http://fab.cba.mit.edu/classes/S62.12/docs/Meijster_distance.pdf +/// Currently Euclidean only, but can be easily extended by replacing the lambda functions. +//-------------------------------------------------------------------------------------------------- +void RiaImageTools::distanceTransform2d(std::vector>& image) +{ + if (image.empty()) + { + return; + } + if (image.front().empty()) + { + return; + } + const int64_t M = (int64_t)image.size(); + const int64_t N = (int64_t)image.front().size(); + + int64_t infVal = M + N; + CVF_ASSERT(infVal <= std::numeric_limits::max()); + + // First phase + std::vector> g(M); + +#pragma omp parallel for + for (int64_t x = 0; x < M; ++x) + { + g[x].resize(N, infVal); + if (image[x][0]) + { + g[x][0] = 0; + } + for (int64_t y = 1; y < N - 1; ++y) + { + if (image[x][y]) + { + g[x][y] = 0; + } + else + { + g[x][y] = 1 + g[x][y - 1]; + } + } + for (int64_t y = N - 2; y >= 0; --y) + { + if (g[x][y + 1] < g[x][y]) + { + g[x][y] = 1 + g[x][y + 1]; + } + } + } + + auto f = [](int64_t x, int64_t i, const std::vector>& g, int64_t y) { + return (x - i) * (x - i) + g[i][y] * g[i][y]; + }; + + auto sep = [](int64_t i, int64_t u, const std::vector>& g, int64_t y) { + if (i == u) return (int64_t)0; + + int64_t numerator = u * u - i * i + g[u][y] * g[u][y] - g[i][y] * g[i][y]; + int64_t divisor = 2 * (u - i); + return numerator / divisor; + }; + + // Second phase +#pragma omp parallel for + for (int64_t y = 0; y < N; ++y) + { + int64_t q = 0; + std::vector s(std::max(N, M), (int64_t) 0); + std::vector t(std::max(N, M), (int64_t) 0); + + for (int64_t u = 1; u < M - 1; ++u) + { + while (q >= 0 && f(t[q], s[q], g, y) > f(t[q], u, g, y)) + { + q--; + } + if (q < 0) + { + q = 0; + s[0] = u; + } + else + { + int64_t w = 1 + sep((int64_t)s[q], u, g, y); + if (w < M) + { + q++; + s[q] = u; + t[q] = w; + } + } + } + for (int64_t u = M - 1; u >= 0; --u) + { + int64_t fVal = f(u, s[q], g, y); + CVF_ASSERT(fVal <= std::numeric_limits::max()); + image[u][y] = static_cast(fVal); + if (u == t[q]) + { + q = q - 1; + } + } + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiaImageTools::makeGrayScale(QImage& image) +{ + for (int i = 0; i < image.height(); i++) + { + uchar* scanLine = image.scanLine(i); + for (int j = 0; j < image.width(); j++) + { + QRgb* pixel = reinterpret_cast(scanLine + j * 4); + int gray = qGray(*pixel); + int alpha = qAlpha(*pixel); + *pixel = QColor(gray, gray, gray, alpha).rgba(); + } + } +} + diff --git a/ApplicationCode/Application/Tools/RiaImageTools.h b/ApplicationCode/Application/Tools/RiaImageTools.h new file mode 100644 index 0000000000..9a7f46ed66 --- /dev/null +++ b/ApplicationCode/Application/Tools/RiaImageTools.h @@ -0,0 +1,32 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2019- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include + +class QImage; + +class RiaImageTools +{ +public: + static void distanceTransform2d(std::vector>& image); + static void makeGrayScale(QImage& image); +}; + + diff --git a/ApplicationCode/Application/Tools/RiaImportEclipseCaseTools.cpp b/ApplicationCode/Application/Tools/RiaImportEclipseCaseTools.cpp index 0a85038cd5..e4f477854d 100644 --- a/ApplicationCode/Application/Tools/RiaImportEclipseCaseTools.cpp +++ b/ApplicationCode/Application/Tools/RiaImportEclipseCaseTools.cpp @@ -31,12 +31,13 @@ #include "RigGridManager.h" #include "RimCaseCollection.h" +#include "RimCompletionTemplateCollection.h" #include "RimEclipseCaseCollection.h" #include "RimEclipseCellColors.h" +#include "RimEclipseInputCase.h" #include "RimEclipseResultCase.h" #include "RimEclipseView.h" #include "RimFileSummaryCase.h" -#include "RimFractureTemplateCollection.h" #include "RimGridSummaryCase.h" #include "RimIdenticalGridCaseGroup.h" #include "RimMainPlotCollection.h" @@ -51,6 +52,7 @@ #include "RimSummaryPlot.h" #include "RimSummaryPlotCollection.h" +#include "Riu3DMainWindowTools.h" #include "RiuMainWindow.h" #include "RiuPlotMainWindow.h" #include "RiuPlotMainWindowTools.h" @@ -170,7 +172,7 @@ bool RiaImportEclipseCaseTools::openEclipseCasesFromFile(const QStringList& file RiaLogging::error(errorMessage); } - project->activeOilField()->fractureDefinitionCollection()->setDefaultUnitSystemBasedOnLoadedCases(); + project->activeOilField()->completionTemplateCollection()->setDefaultUnitSystemBasedOnLoadedCases(); RiuPlotMainWindowTools::refreshToolbars(); @@ -197,6 +199,53 @@ bool RiaImportEclipseCaseTools::openEclipseCaseShowTimeStepFilter(const QString& return RiaImportEclipseCaseTools::openEclipseCaseShowTimeStepFilterImpl(fileName, true); } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RiaImportEclipseCaseTools::openEclipseInputCaseFromFileNames(const QStringList& fileNames, QString* fileContainingGrid/*=nullptr*/) +{ + RimEclipseInputCase* rimInputReservoir = new RimEclipseInputCase(); + + RiaApplication* app = RiaApplication::instance(); + RimProject* project = app->project(); + + project->assignCaseIdToCase(rimInputReservoir); + + bool gridImportSuccess = rimInputReservoir->openDataFileSet(fileNames); + if (!gridImportSuccess) + { + RiaLogging::error("Failed to import grid"); + return false; + } + + RimEclipseCaseCollection* analysisModels = project->activeOilField() ? project->activeOilField()->analysisModels() : nullptr; + if (analysisModels == nullptr) return false; + + analysisModels->cases.push_back(rimInputReservoir); + + RimEclipseView* riv = rimInputReservoir->createAndAddReservoirView(); + + riv->cellResult()->setResultType(RiaDefines::INPUT_PROPERTY); + + riv->loadDataAndUpdate(); + + if (!riv->cellResult()->hasResult()) + { + riv->cellResult()->setResultVariable(RiaDefines::undefinedResultName()); + } + + analysisModels->updateConnectedEditors(); + + Riu3DMainWindowTools::selectAsCurrentItem(riv->cellResult()); + + if (fileContainingGrid) + { + *fileContainingGrid = rimInputReservoir->gridFileName(); + } + + return true; +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/Application/Tools/RiaImportEclipseCaseTools.h b/ApplicationCode/Application/Tools/RiaImportEclipseCaseTools.h index 90941a0ff2..e0bf0ec6db 100644 --- a/ApplicationCode/Application/Tools/RiaImportEclipseCaseTools.h +++ b/ApplicationCode/Application/Tools/RiaImportEclipseCaseTools.h @@ -30,6 +30,7 @@ class RiaImportEclipseCaseTools static bool openEclipseCasesFromFile(const QStringList& fileNames, QStringList* openedFiles = nullptr, bool noDialog = false); static bool openEclipseCaseShowTimeStepFilter(const QString& fileName); + static bool openEclipseInputCaseFromFileNames(const QStringList& fileNames, QString* fileContainingGrid = nullptr); static bool openMockModel(const QString& name); static bool addEclipseCases(const QStringList& fileNames); diff --git a/ApplicationCode/Application/Tools/RiaLogging.cpp b/ApplicationCode/Application/Tools/RiaLogging.cpp index 51f92c9b40..449280ea3d 100644 --- a/ApplicationCode/Application/Tools/RiaLogging.cpp +++ b/ApplicationCode/Application/Tools/RiaLogging.cpp @@ -18,11 +18,16 @@ #include "RiaLogging.h" +#include #include #ifdef WIN32 #pragma warning (push) #pragma warning (disable: 4668) +// Define this one to tell windows.h to not define min() and max() as macros +#if defined WIN32 && !defined NOMINMAX +#define NOMINMAX +#endif #include #pragma warning (pop) #else @@ -34,7 +39,6 @@ - //================================================================================================== // // @@ -253,3 +257,87 @@ void RiaLogging::debug(const QString& message) } } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RiuMessageLoggerBase::RiuMessageLoggerBase() + : m_logLevel(RI_LL_WARNING) +{ +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +int RiuMessageLoggerBase::level() const +{ + return m_logLevel; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuMessageLoggerBase::setLevel(int logLevel) +{ + m_logLevel = logLevel; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuMessageLoggerBase::error(const char* message) +{ + writeMessageWithPrefixToLogger("ERROR: ", message); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuMessageLoggerBase::warning(const char* message) +{ + writeMessageWithPrefixToLogger("warning: ", message); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuMessageLoggerBase::info(const char* message) +{ + writeMessageWithPrefixToLogger("info: ", message); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuMessageLoggerBase::debug(const char* message) +{ + writeMessageWithPrefixToLogger("debug: ", message); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuMessageLoggerBase::writeMessageWithPrefixToLogger(const char* prefix, const char* message) +{ + std::ostringstream oss; + + oss << prefix; + + if (message) + { + oss << message << std::endl; + } + else + { + oss << "" << std::endl; + } + + writeMessageToLogger(oss.str()); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiaStdOutLogger::writeMessageToLogger(const std::string& str) +{ + std::cout << str; +} diff --git a/ApplicationCode/Application/Tools/RiaLogging.h b/ApplicationCode/Application/Tools/RiaLogging.h index 3a9ce668e3..62c3984e2c 100644 --- a/ApplicationCode/Application/Tools/RiaLogging.h +++ b/ApplicationCode/Application/Tools/RiaLogging.h @@ -18,6 +18,8 @@ #pragma once +#include + class QString; enum RILogLevel @@ -72,3 +74,37 @@ class RiaLogging static RiaLogger* sm_logger; }; +//================================================================================================== +// +//================================================================================================== +class RiuMessageLoggerBase : public RiaLogger +{ +public: + explicit RiuMessageLoggerBase(); + + int level() const override; + void setLevel(int logLevel) override; + + void error(const char* message) override; + void warning(const char* message) override; + void info(const char* message) override; + void debug(const char* message) override; + +protected: + virtual void writeMessageToLogger(const std::string& str) = 0; + +private: + void writeMessageWithPrefixToLogger(const char* prefix, const char* message); + +private: + int m_logLevel; +}; + +//================================================================================================== +// +//================================================================================================== +class RiaStdOutLogger : public RiuMessageLoggerBase +{ +public: + void writeMessageToLogger(const std::string& str) override; +}; diff --git a/ApplicationCode/Application/Tools/RiaOffshoreSphericalCoords.h b/ApplicationCode/Application/Tools/RiaOffshoreSphericalCoords.h index f89cdbba75..fd8c624278 100644 --- a/ApplicationCode/Application/Tools/RiaOffshoreSphericalCoords.h +++ b/ApplicationCode/Application/Tools/RiaOffshoreSphericalCoords.h @@ -1,20 +1,21 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018- Statoil ASA -// +// Copyright (C) 2018- Equinor ASA +// // ResInsight 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 3 of the License, or // (at your option) any later version. -// +// // ResInsight 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 at +// +// See the GNU General Public License at // for more details. // ///////////////////////////////////////////////////////////////////////////////// + #pragma once #include diff --git a/ApplicationCode/Application/Tools/RiaOptionItemFactory.cpp b/ApplicationCode/Application/Tools/RiaOptionItemFactory.cpp index c594610921..c8b275cc04 100644 --- a/ApplicationCode/Application/Tools/RiaOptionItemFactory.cpp +++ b/ApplicationCode/Application/Tools/RiaOptionItemFactory.cpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018 Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by diff --git a/ApplicationCode/Application/Tools/RiaOptionItemFactory.h b/ApplicationCode/Application/Tools/RiaOptionItemFactory.h index e2ab8b01ca..29c83fac87 100644 --- a/ApplicationCode/Application/Tools/RiaOptionItemFactory.h +++ b/ApplicationCode/Application/Tools/RiaOptionItemFactory.h @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018 Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by diff --git a/ApplicationCode/Application/Tools/RiaQDateTimeTools.cpp b/ApplicationCode/Application/Tools/RiaQDateTimeTools.cpp index e2a35b6daf..4c02eb49ae 100644 --- a/ApplicationCode/Application/Tools/RiaQDateTimeTools.cpp +++ b/ApplicationCode/Application/Tools/RiaQDateTimeTools.cpp @@ -338,3 +338,58 @@ QString RiaQDateTimeTools::toStringUsingApplicationLocale(const QDateTime& dt, c return defaultApplicationLocale.toString(dt, format); } + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RiaQDateTimeTools::createTimeFormatStringFromDates(const std::vector& dates) +{ + bool hasHoursAndMinutesInTimesteps = false; + bool hasSecondsInTimesteps = false; + bool hasMillisecondsInTimesteps = false; + + for (size_t i = 0; i < dates.size(); i++) + { + if (dates[i].time().msec() != 0.0) + { + hasMillisecondsInTimesteps = true; + hasSecondsInTimesteps = true; + hasHoursAndMinutesInTimesteps = true; + break; + } + else if (dates[i].time().second() != 0.0) + { + hasHoursAndMinutesInTimesteps = true; + hasSecondsInTimesteps = true; + } + else if (dates[i].time().hour() != 0.0 || dates[i].time().minute() != 0.0) + { + hasHoursAndMinutesInTimesteps = true; + } + } + + QString formatString = dateFormatString(); + if (hasHoursAndMinutesInTimesteps) + { + formatString += " - hh:mm"; + if (hasSecondsInTimesteps) + { + formatString += ":ss"; + if (hasMillisecondsInTimesteps) + { + formatString += ".zzz"; + } + } + } + + return formatString; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RiaQDateTimeTools::dateFormatString() +{ + return "dd.MMM yyyy"; +} \ No newline at end of file diff --git a/ApplicationCode/Application/Tools/RiaQDateTimeTools.h b/ApplicationCode/Application/Tools/RiaQDateTimeTools.h index 8fa4d3c99f..9dffa4de32 100644 --- a/ApplicationCode/Application/Tools/RiaQDateTimeTools.h +++ b/ApplicationCode/Application/Tools/RiaQDateTimeTools.h @@ -101,6 +101,9 @@ class RiaQDateTimeTools // settings on local machine. Required for stable regression testing. static QString toStringUsingApplicationLocale(const QDateTime& dt, const QString& format); + static QString createTimeFormatStringFromDates(const std::vector& dates); + static QString dateFormatString(); + private: static quint64 secondsInDay(); static quint64 secondsInYear(); diff --git a/ApplicationCode/Application/Tools/RiaQIconTools.cpp b/ApplicationCode/Application/Tools/RiaQIconTools.cpp deleted file mode 100644 index 6ed68f4850..0000000000 --- a/ApplicationCode/Application/Tools/RiaQIconTools.cpp +++ /dev/null @@ -1,44 +0,0 @@ -///////////////////////////////////////////////////////////////////////////////// -// -// Copyright (C) 2018 Equinor ASA -// -// ResInsight 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 3 of the License, or -// (at your option) any later version. -// -// ResInsight 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 at -// for more details. -// -///////////////////////////////////////////////////////////////////////////////// - -#include "RiaQIconTools.h" - -#include - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -QPixmap RiaQIconTools::appendPixmapUpperLeft(const QPixmap& pixmap, const QPixmap& overlayPixmap) -{ - QPixmap scaledPixmap; - { - QSize size = pixmap.size() - pixmap.size() / 4; - - scaledPixmap = overlayPixmap.scaled(size); - } - - QPixmap combinedPixmap(pixmap); - QPainter painter(&combinedPixmap); - - int x = 0; - int y = -4; - - painter.drawPixmap(x, y, scaledPixmap); - - return combinedPixmap; -} diff --git a/ApplicationCode/Application/Tools/RiaQIconTools.h b/ApplicationCode/Application/Tools/RiaQIconTools.h deleted file mode 100644 index 370921b4da..0000000000 --- a/ApplicationCode/Application/Tools/RiaQIconTools.h +++ /dev/null @@ -1,32 +0,0 @@ -///////////////////////////////////////////////////////////////////////////////// -// -// Copyright (C) 2018 Equinor ASA -// -// ResInsight 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 3 of the License, or -// (at your option) any later version. -// -// ResInsight 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 at -// for more details. -// -///////////////////////////////////////////////////////////////////////////////// - -#pragma once - -#include - -//================================================================================================== -// -// -// -//================================================================================================== -class RiaQIconTools -{ -public: - static QPixmap appendPixmapUpperLeft(const QPixmap& pixmap, const QPixmap& overlayPixmap); -}; diff --git a/ApplicationCode/Application/Tools/RiaRegressionTest.cpp b/ApplicationCode/Application/Tools/RiaRegressionTest.cpp index eb1f28f9a6..f4eb863610 100644 --- a/ApplicationCode/Application/Tools/RiaRegressionTest.cpp +++ b/ApplicationCode/Application/Tools/RiaRegressionTest.cpp @@ -60,6 +60,8 @@ RiaRegressionTest::RiaRegressionTest(void) CAF_PDM_InitField( &useOpenMPForGeometryCreation, "useOpenMPForGeometryCreation", true, "Use OpenMP For Geometry Creation", "", "", ""); + CAF_PDM_InitField(&openReportInBrowser, "openReportInBrowser", false, "Open Generated Report in Browser", "", "", ""); + CAF_PDM_InitFieldNoDefault( &testFilter, "testFilter", @@ -68,6 +70,9 @@ RiaRegressionTest::RiaRegressionTest(void) "If empty, all tests are executed.\nTo execute a subset of tests, specify folder names separated by ;", ""); testFilter.uiCapability()->setUiEditorTypeName(caf::PdmUiTextEditor::uiEditorTypeName()); + + CAF_PDM_InitField( + &appendTestsAfterTestFilter, "appendTestsAfterTestFilter", false, "Append All Tests After Test Filter", "", "", ""); } //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/Application/Tools/RiaRegressionTest.h b/ApplicationCode/Application/Tools/RiaRegressionTest.h index d9aff92eb6..f70d5f1986 100644 --- a/ApplicationCode/Application/Tools/RiaRegressionTest.h +++ b/ApplicationCode/Application/Tools/RiaRegressionTest.h @@ -41,6 +41,8 @@ class RiaRegressionTest : public caf::PdmObject caf::PdmField testFilter; caf::PdmField showInteractiveDiffImages; caf::PdmField useOpenMPForGeometryCreation; + caf::PdmField openReportInBrowser; + caf::PdmField appendTestsAfterTestFilter; protected: void defineEditorAttribute(const caf::PdmFieldHandle* field, diff --git a/ApplicationCode/Application/Tools/RiaRegressionTestRunner.cpp b/ApplicationCode/Application/Tools/RiaRegressionTestRunner.cpp index b6a18553b4..3b8e34ec07 100644 --- a/ApplicationCode/Application/Tools/RiaRegressionTestRunner.cpp +++ b/ApplicationCode/Application/Tools/RiaRegressionTestRunner.cpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018 Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -83,6 +83,7 @@ void logInfoTextWithTimeInSeconds(const QTime& time, const QString& msg) //-------------------------------------------------------------------------------------------------- RiaRegressionTestRunner::RiaRegressionTestRunner() : m_runningRegressionTests(false) + , m_appendAllTestsAfterLastItemInFilter(false) { } @@ -151,11 +152,18 @@ void RiaRegressionTestRunner::runRegressionTest() } QString htmlReportFileName = generateHtmlReport(folderList, baseFolderName, generatedFolderName, diffFolderName, testDir); - QDesktopServices::openUrl(htmlReportFileName); + + if (regressionTestConfig.openReportInBrowser()) + { + QDesktopServices::openUrl(htmlReportFileName); + } + + RiaLogging::info("--------------------------------------------------"); + RiaLogging::info(QTime::currentTime().toString() + ": Launching regression tests"); + RiaLogging::info("--------------------------------------------------"); QTime timeStamp; timeStamp.start(); - logInfoTextWithTimeInSeconds(timeStamp, "Starting regression tests\n"); for (const QFileInfo& folderFileInfo : folderList) @@ -582,6 +590,8 @@ QFileInfoList RiaRegressionTestRunner::subDirectoriesForTestExecution(const QDir return folderList; } + bool anyMatchFound = false; + QFileInfoList foldersMatchingTestFilter; QFileInfoList folderList = directory.entryInfoList(); @@ -593,9 +603,10 @@ QFileInfoList RiaRegressionTestRunner::subDirectoriesForTestExecution(const QDir for (const auto& s : m_testFilter) { QString trimmed = s.trimmed(); - if (baseName.contains(trimmed, Qt::CaseInsensitive)) + if (anyMatchFound || baseName.contains(trimmed, Qt::CaseInsensitive)) { foldersMatchingTestFilter.push_back(fi); + anyMatchFound = true; } } } @@ -614,6 +625,11 @@ void RiaRegressionTestRunner::executeRegressionTests() QString testPath = testConfig.regressionTestFolder(); QStringList testFilter = testConfig.testFilter().split(";", QString::SkipEmptyParts); + if (testConfig.appendTestsAfterTestFilter) + { + m_appendAllTestsAfterLastItemInFilter = true; + } + executeRegressionTests(testPath, testFilter); } diff --git a/ApplicationCode/Application/Tools/RiaRegressionTestRunner.h b/ApplicationCode/Application/Tools/RiaRegressionTestRunner.h index 2a843a81a7..4a5edf2817 100644 --- a/ApplicationCode/Application/Tools/RiaRegressionTestRunner.h +++ b/ApplicationCode/Application/Tools/RiaRegressionTestRunner.h @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018 Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -68,6 +68,7 @@ class RiaRegressionTestRunner private: QString m_rootPath; QStringList m_testFilter; + bool m_appendAllTestsAfterLastItemInFilter; bool m_runningRegressionTests; RiaRegressionTest m_regressionTestSettings; }; diff --git a/ApplicationCode/Application/Tools/RiaSummaryTools.cpp b/ApplicationCode/Application/Tools/RiaSummaryTools.cpp index 892df17d38..ca383cfd23 100644 --- a/ApplicationCode/Application/Tools/RiaSummaryTools.cpp +++ b/ApplicationCode/Application/Tools/RiaSummaryTools.cpp @@ -72,7 +72,7 @@ void RiaSummaryTools::notifyCalculatedCurveNameHasChanged(const QString& previou if (adr.quantityName() == previousCurveName.toStdString()) { RifEclipseSummaryAddress updatedAdr = RifEclipseSummaryAddress::calculatedAddress(currentCurveName.toStdString()); - curve->setSummaryAddressY(updatedAdr); + curve->setSummaryAddressYAndApplyInterpolation(updatedAdr); } } } diff --git a/ApplicationCode/Application/Tools/RiaTextFileCompare.cpp b/ApplicationCode/Application/Tools/RiaTextFileCompare.cpp index a418d3187f..d1192a8632 100644 --- a/ApplicationCode/Application/Tools/RiaTextFileCompare.cpp +++ b/ApplicationCode/Application/Tools/RiaTextFileCompare.cpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018 Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by diff --git a/ApplicationCode/Application/Tools/RiaTextFileCompare.h b/ApplicationCode/Application/Tools/RiaTextFileCompare.h index ef05fe3f17..0ec47ee21d 100644 --- a/ApplicationCode/Application/Tools/RiaTextFileCompare.h +++ b/ApplicationCode/Application/Tools/RiaTextFileCompare.h @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018 Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by diff --git a/ApplicationCode/Application/Tools/RiaTextStringTools.cpp b/ApplicationCode/Application/Tools/RiaTextStringTools.cpp index 1e4d56fc84..f62c354096 100644 --- a/ApplicationCode/Application/Tools/RiaTextStringTools.cpp +++ b/ApplicationCode/Application/Tools/RiaTextStringTools.cpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018 Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by diff --git a/ApplicationCode/Application/Tools/RiaTextStringTools.h b/ApplicationCode/Application/Tools/RiaTextStringTools.h index e287dc3cf0..78b75a6467 100644 --- a/ApplicationCode/Application/Tools/RiaTextStringTools.h +++ b/ApplicationCode/Application/Tools/RiaTextStringTools.h @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018 Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by diff --git a/ApplicationCode/Application/Tools/RiaWeightedGeometricMeanCalculator.cpp b/ApplicationCode/Application/Tools/RiaWeightedGeometricMeanCalculator.cpp index 075d0ac8a2..c0ee0f5afe 100644 --- a/ApplicationCode/Application/Tools/RiaWeightedGeometricMeanCalculator.cpp +++ b/ApplicationCode/Application/Tools/RiaWeightedGeometricMeanCalculator.cpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018- Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by diff --git a/ApplicationCode/Application/Tools/RiaWeightedGeometricMeanCalculator.h b/ApplicationCode/Application/Tools/RiaWeightedGeometricMeanCalculator.h index 0720a5d19a..580db22253 100644 --- a/ApplicationCode/Application/Tools/RiaWeightedGeometricMeanCalculator.h +++ b/ApplicationCode/Application/Tools/RiaWeightedGeometricMeanCalculator.h @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018- Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by diff --git a/ApplicationCode/Application/Tools/RiaWeightedHarmonicMeanCalculator.cpp b/ApplicationCode/Application/Tools/RiaWeightedHarmonicMeanCalculator.cpp index 6b5ba0d847..d6deac6144 100644 --- a/ApplicationCode/Application/Tools/RiaWeightedHarmonicMeanCalculator.cpp +++ b/ApplicationCode/Application/Tools/RiaWeightedHarmonicMeanCalculator.cpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018- Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by diff --git a/ApplicationCode/Application/Tools/RiaWeightedHarmonicMeanCalculator.h b/ApplicationCode/Application/Tools/RiaWeightedHarmonicMeanCalculator.h index 07d194f48a..cfee6b6dd5 100644 --- a/ApplicationCode/Application/Tools/RiaWeightedHarmonicMeanCalculator.h +++ b/ApplicationCode/Application/Tools/RiaWeightedHarmonicMeanCalculator.h @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018- Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by diff --git a/ApplicationCode/Application/Tools/RiaWeightedMeanCalculator.h b/ApplicationCode/Application/Tools/RiaWeightedMeanCalculator.h index 09bfae0649..bf5b1f3e93 100644 --- a/ApplicationCode/Application/Tools/RiaWeightedMeanCalculator.h +++ b/ApplicationCode/Application/Tools/RiaWeightedMeanCalculator.h @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018- Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by diff --git a/ApplicationCode/Application/Tools/RiaWeightedMeanCalculator.inl b/ApplicationCode/Application/Tools/RiaWeightedMeanCalculator.inl index d3fb4dc687..0656934fbb 100644 --- a/ApplicationCode/Application/Tools/RiaWeightedMeanCalculator.inl +++ b/ApplicationCode/Application/Tools/RiaWeightedMeanCalculator.inl @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018- Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by diff --git a/ApplicationCode/Application/Tools/WellPathTools/RiaArcCurveCalculator.cpp b/ApplicationCode/Application/Tools/WellPathTools/RiaArcCurveCalculator.cpp index 6f0c9e74b6..3d4fe14b34 100644 --- a/ApplicationCode/Application/Tools/WellPathTools/RiaArcCurveCalculator.cpp +++ b/ApplicationCode/Application/Tools/WellPathTools/RiaArcCurveCalculator.cpp @@ -1,20 +1,21 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018- Statoil ASA -// +// Copyright (C) 2018- Equinor ASA +// // ResInsight 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 3 of the License, or // (at your option) any later version. -// +// // ResInsight 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 at +// +// See the GNU General Public License at // for more details. // ///////////////////////////////////////////////////////////////////////////////// + #include "RiaArcCurveCalculator.h" #include "RiaOffshoreSphericalCoords.h" diff --git a/ApplicationCode/Application/Tools/WellPathTools/RiaArcCurveCalculator.h b/ApplicationCode/Application/Tools/WellPathTools/RiaArcCurveCalculator.h index b05a582cd0..42ec9ecc6e 100644 --- a/ApplicationCode/Application/Tools/WellPathTools/RiaArcCurveCalculator.h +++ b/ApplicationCode/Application/Tools/WellPathTools/RiaArcCurveCalculator.h @@ -1,20 +1,21 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018- Statoil ASA -// +// Copyright (C) 2018- Equinor ASA +// // ResInsight 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 3 of the License, or // (at your option) any later version. -// +// // ResInsight 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 at +// +// See the GNU General Public License at // for more details. // ///////////////////////////////////////////////////////////////////////////////// + #pragma once #include "cvfBase.h" diff --git a/ApplicationCode/Application/Tools/WellPathTools/RiaJCurveCalculator.cpp b/ApplicationCode/Application/Tools/WellPathTools/RiaJCurveCalculator.cpp index 2b8049988f..dc5bfcb6af 100644 --- a/ApplicationCode/Application/Tools/WellPathTools/RiaJCurveCalculator.cpp +++ b/ApplicationCode/Application/Tools/WellPathTools/RiaJCurveCalculator.cpp @@ -1,17 +1,17 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018- Statoil ASA -// +// Copyright (C) 2018- Equinor ASA +// // ResInsight 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 3 of the License, or // (at your option) any later version. -// +// // ResInsight 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 at +// +// See the GNU General Public License at // for more details. // ///////////////////////////////////////////////////////////////////////////////// diff --git a/ApplicationCode/Application/Tools/WellPathTools/RiaJCurveCalculator.h b/ApplicationCode/Application/Tools/WellPathTools/RiaJCurveCalculator.h index 7dbfaeeaa8..0643f29dc2 100644 --- a/ApplicationCode/Application/Tools/WellPathTools/RiaJCurveCalculator.h +++ b/ApplicationCode/Application/Tools/WellPathTools/RiaJCurveCalculator.h @@ -1,20 +1,21 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018- Statoil ASA -// +// Copyright (C) 2018- Equinor ASA +// // ResInsight 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 3 of the License, or // (at your option) any later version. -// +// // ResInsight 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 at +// +// See the GNU General Public License at // for more details. // ///////////////////////////////////////////////////////////////////////////////// + #pragma once #include "cvfBase.h" diff --git a/ApplicationCode/Application/Tools/WellPathTools/RiaLineArcWellPathCalculator.cpp b/ApplicationCode/Application/Tools/WellPathTools/RiaLineArcWellPathCalculator.cpp index d76a85206c..6bb4a09484 100644 --- a/ApplicationCode/Application/Tools/WellPathTools/RiaLineArcWellPathCalculator.cpp +++ b/ApplicationCode/Application/Tools/WellPathTools/RiaLineArcWellPathCalculator.cpp @@ -1,17 +1,17 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018- Statoil ASA -// +// Copyright (C) 2018- Equinor ASA +// // ResInsight 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 3 of the License, or // (at your option) any later version. -// +// // ResInsight 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 at +// +// See the GNU General Public License at // for more details. // ///////////////////////////////////////////////////////////////////////////////// diff --git a/ApplicationCode/Application/Tools/WellPathTools/RiaLineArcWellPathCalculator.h b/ApplicationCode/Application/Tools/WellPathTools/RiaLineArcWellPathCalculator.h index 4807fce197..0a06fe9245 100644 --- a/ApplicationCode/Application/Tools/WellPathTools/RiaLineArcWellPathCalculator.h +++ b/ApplicationCode/Application/Tools/WellPathTools/RiaLineArcWellPathCalculator.h @@ -1,20 +1,21 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018- Statoil ASA -// +// Copyright (C) 2018- Equinor ASA +// // ResInsight 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 3 of the License, or // (at your option) any later version. -// +// // ResInsight 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 at +// +// See the GNU General Public License at // for more details. // ///////////////////////////////////////////////////////////////////////////////// + #pragma once #include "cvfBase.h" diff --git a/ApplicationCode/Application/Tools/WellPathTools/RiaPolyArcLineSampler.cpp b/ApplicationCode/Application/Tools/WellPathTools/RiaPolyArcLineSampler.cpp index c83a6b0656..8e63337132 100644 --- a/ApplicationCode/Application/Tools/WellPathTools/RiaPolyArcLineSampler.cpp +++ b/ApplicationCode/Application/Tools/WellPathTools/RiaPolyArcLineSampler.cpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018- Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by diff --git a/ApplicationCode/Application/Tools/WellPathTools/RiaPolyArcLineSampler.h b/ApplicationCode/Application/Tools/WellPathTools/RiaPolyArcLineSampler.h index 0f8354dded..1d6e933f80 100644 --- a/ApplicationCode/Application/Tools/WellPathTools/RiaPolyArcLineSampler.h +++ b/ApplicationCode/Application/Tools/WellPathTools/RiaPolyArcLineSampler.h @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018- Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -15,6 +15,7 @@ // for more details. // ///////////////////////////////////////////////////////////////////////////////// + #pragma once #include "cvfBase.h" diff --git a/ApplicationCode/Application/Tools/WellPathTools/RiaSCurveCalculator.cpp b/ApplicationCode/Application/Tools/WellPathTools/RiaSCurveCalculator.cpp index 4777b432d5..83281577ec 100644 --- a/ApplicationCode/Application/Tools/WellPathTools/RiaSCurveCalculator.cpp +++ b/ApplicationCode/Application/Tools/WellPathTools/RiaSCurveCalculator.cpp @@ -1,17 +1,17 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018- Statoil ASA -// +// Copyright (C) 2018- Equinor ASA +// // ResInsight 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 3 of the License, or // (at your option) any later version. -// +// // ResInsight 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 at +// +// See the GNU General Public License at // for more details. // ///////////////////////////////////////////////////////////////////////////////// @@ -211,7 +211,6 @@ void RiaSCurveCalculator::initializeByFinding_q1q2(cvf::Vec3d p1, double azi1, d const int maxIterations = 40; const double maxError = 0.01; - const double closeError = 40*maxError; const double maxStepSize = 1.0e9; const double maxLengthToQ = 1.0e10; bool enableBackstepping = false; diff --git a/ApplicationCode/Application/Tools/WellPathTools/RiaSCurveCalculator.h b/ApplicationCode/Application/Tools/WellPathTools/RiaSCurveCalculator.h index 0b782a3f92..b859121f98 100644 --- a/ApplicationCode/Application/Tools/WellPathTools/RiaSCurveCalculator.h +++ b/ApplicationCode/Application/Tools/WellPathTools/RiaSCurveCalculator.h @@ -1,20 +1,21 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018- Statoil ASA -// +// Copyright (C) 2018- Equinor ASA +// // ResInsight 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 3 of the License, or // (at your option) any later version. -// +// // ResInsight 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 at +// +// See the GNU General Public License at // for more details. // ///////////////////////////////////////////////////////////////////////////////// + #pragma once #include "cvfBase.h" diff --git a/ApplicationCode/Application/Tools/WellPathTools/RiaWellPlanCalculator.cpp b/ApplicationCode/Application/Tools/WellPathTools/RiaWellPlanCalculator.cpp index 5436b432f9..d54625a754 100644 --- a/ApplicationCode/Application/Tools/WellPathTools/RiaWellPlanCalculator.cpp +++ b/ApplicationCode/Application/Tools/WellPathTools/RiaWellPlanCalculator.cpp @@ -1,17 +1,17 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018- Statoil ASA -// +// Copyright (C) 2018- Equinor ASA +// // ResInsight 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 3 of the License, or // (at your option) any later version. -// +// // ResInsight 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 at +// +// See the GNU General Public License at // for more details. // ///////////////////////////////////////////////////////////////////////////////// diff --git a/ApplicationCode/Application/Tools/WellPathTools/RiaWellPlanCalculator.h b/ApplicationCode/Application/Tools/WellPathTools/RiaWellPlanCalculator.h index e88d1b3fc4..b9a201851e 100644 --- a/ApplicationCode/Application/Tools/WellPathTools/RiaWellPlanCalculator.h +++ b/ApplicationCode/Application/Tools/WellPathTools/RiaWellPlanCalculator.h @@ -1,20 +1,21 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018- Statoil ASA -// +// Copyright (C) 2018- Equinor ASA +// // ResInsight 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 3 of the License, or // (at your option) any later version. -// +// // ResInsight 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 at +// +// See the GNU General Public License at // for more details. // ///////////////////////////////////////////////////////////////////////////////// + #pragma once #include "cvfBase.h" diff --git a/ApplicationCode/CMakeLists.txt b/ApplicationCode/CMakeLists.txt index 1fabac1f27..a213bb7d5d 100644 --- a/ApplicationCode/CMakeLists.txt +++ b/ApplicationCode/CMakeLists.txt @@ -2,6 +2,22 @@ cmake_minimum_required (VERSION 2.8.12) project (ApplicationCode) +# Open GL +find_package( OpenGL ) + +if (RESINSIGHT_BUILD_WITH_QT5) + find_package(Qt5 COMPONENTS Core QUIET) +endif(RESINSIGHT_BUILD_WITH_QT5) + +if (Qt5Core_FOUND) + find_package(Qt5 CONFIG REQUIRED Core Gui OpenGL Network Script Widgets) + set(QT_LIBRARIES Qt5::Core Qt5::Gui Qt5::Network Qt5::OpenGL Qt5::Script Qt5::Widgets) +else() + set (QT_COMPONENTS_REQUIRED QtCore QtGui QtMain QtOpenGl QtNetwork QtScript) + find_package(Qt4 COMPONENTS ${QT_COMPONENTS_REQUIRED} REQUIRED) + include(${QT_USE_FILE}) +endif(Qt5Core_FOUND) + # NB: The generated file is written to Cmake binary folder to avoid source tree pollution # This folder is added to include_directories CONFIGURE_FILE( ${CMAKE_SOURCE_DIR}/ApplicationCode/Adm/RiaVersionInfo.h.cmake @@ -11,7 +27,7 @@ CONFIGURE_FILE( ${CMAKE_SOURCE_DIR}/ApplicationCode/Adm/RiaVersionInfo.h.cmake if (MSVC AND (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 19.11)) # VS 2017 : Disable warnings from from gtest code, using deprecated code related to TR1 add_definitions(-D_SILENCE_TR1_NAMESPACE_DEPRECATION_WARNING) - message("Add flag to disable warings from gtest - _SILENCE_TR1_NAMESPACE_DEPRECATION_WARNING") + message(STATUS "Add flag to disable warings from gtest - _SILENCE_TR1_NAMESPACE_DEPRECATION_WARNING") endif() include_directories( @@ -29,6 +45,7 @@ include_directories( ${CMAKE_CURRENT_SOURCE_DIR}/Commands/EclipseCommands ${CMAKE_CURRENT_SOURCE_DIR}/FileInterface ${CMAKE_CURRENT_SOURCE_DIR}/SocketInterface + ${CMAKE_CURRENT_SOURCE_DIR}/Measurement ${CMAKE_CURRENT_SOURCE_DIR}/ModelVisualization ${CMAKE_CURRENT_SOURCE_DIR}/ModelVisualization/GridBox ${CMAKE_CURRENT_SOURCE_DIR}/ModelVisualization/Intersections @@ -37,8 +54,11 @@ include_directories( ${CMAKE_CURRENT_SOURCE_DIR}/CommandFileInterface/Core ${CMAKE_CURRENT_SOURCE_DIR}/ProjectDataModel + ${CMAKE_CURRENT_SOURCE_DIR}/ProjectDataModel/Annotations ${CMAKE_CURRENT_SOURCE_DIR}/ProjectDataModel/Completions ${CMAKE_CURRENT_SOURCE_DIR}/ProjectDataModel/Flow + ${CMAKE_CURRENT_SOURCE_DIR}/ProjectDataModel/GridCrossPlots + ${CMAKE_CURRENT_SOURCE_DIR}/ProjectDataModel/Measurement ${CMAKE_CURRENT_SOURCE_DIR}/ProjectDataModel/Summary ${CMAKE_CURRENT_SOURCE_DIR}/ResultStatisticsCache @@ -88,9 +108,13 @@ list( APPEND REFERENCED_CMAKE_FILES FileInterface/CMakeLists_files.cmake ProjectDataModel/CMakeLists_files.cmake + ProjectDataModel/GridCrossPlots/CMakeLists_files.cmake + ProjectDataModel/GridCrossPlots/CellFilters/CMakeLists_files.cmake ProjectDataModel/Summary/CMakeLists_files.cmake ProjectDataModel/Flow/CMakeLists_files.cmake + ProjectDataModel/Annotations/CMakeLists_files.cmake ProjectDataModel/Completions/CMakeLists_files.cmake + ProjectDataModel/Measurement/CMakeLists_files.cmake GeoMech/GeoMechVisualization/CMakeLists_files.cmake @@ -103,6 +127,7 @@ list( APPEND REFERENCED_CMAKE_FILES Commands/CMakeLists_files.cmake Commands/ApplicationCommands/CMakeLists_files.cmake + Commands/AnnotationCommands/CMakeLists_files.cmake Commands/CompletionCommands/CMakeLists_files.cmake Commands/CompletionExportCommands/CMakeLists_files.cmake Commands/CrossSectionCommands/CMakeLists_files.cmake @@ -110,9 +135,11 @@ list( APPEND REFERENCED_CMAKE_FILES Commands/EclipseCommands/EclipseWell/CMakeLists_files.cmake Commands/ExportCommands/CMakeLists_files.cmake Commands/FlowCommands/CMakeLists_files.cmake + Commands/GridCrossPlotCommands/CMakeLists_files.cmake Commands/HoloLensCommands/CMakeLists_files.cmake Commands/IntersectionBoxCommands/CMakeLists_files.cmake Commands/IntersectionViewCommands/CMakeLists_files.cmake + Commands/MeasurementCommands/CMakeLists_files.cmake Commands/OctaveScriptCommands/CMakeLists_files.cmake Commands/OperationsUsingObjReferences/CMakeLists_files.cmake Commands/SummaryPlotCommands/CMakeLists_files.cmake @@ -217,9 +244,14 @@ set ( QT_MOC_HEADERS SocketInterface/RiaSocketServer.h ) -qt4_wrap_cpp( MOC_FILES_CPP ${QT_MOC_HEADERS} ) +if (Qt5Core_FOUND) + qt5_wrap_cpp(MOC_SOURCE_FILES ${QT_MOC_HEADERS} ) + qt5_wrap_ui( FORM_FILES_CPP ${QT_UI_FILES} ) +else() + qt4_wrap_cpp(MOC_SOURCE_FILES ${QT_MOC_HEADERS} ) + qt4_wrap_ui( FORM_FILES_CPP ${QT_UI_FILES} ) +endif() -qt4_wrap_ui( FORM_FILES_CPP ${QT_UI_FILES} ) # NOTE! Resources in subfolders must append to QRC_FILES using the following statement # set( QRC_FILES @@ -234,7 +266,17 @@ set( QRC_FILES ) # Runs RCC on specified files -qt4_add_resources( QRC_FILES_CPP ${QRC_FILES} ) +if ( NOT CMAKE_AUTOMOC) + if (Qt5Core_FOUND) + qt5_add_resources( QRC_FILES_CPP + ${QRC_FILES} + ) + else() + qt4_add_resources( QRC_FILES_CPP + ${QRC_FILES} + ) + endif(Qt5Core_FOUND) +endif(NOT CMAKE_AUTOMOC) # Adding resource (RC) files for Windows if ( MSVC ) @@ -270,7 +312,7 @@ endif() set( EXE_FILES ${EXE_FILES} ${CPP_SOURCES} - ${MOC_FILES_CPP} + ${MOC_SOURCE_FILES} ${FORM_FILES_CPP} ${QRC_FILES_CPP} ${WIN_RESOURCE} @@ -278,6 +320,7 @@ set( EXE_FILES ${REFERENCED_CMAKE_FILES} ../ResInsightVersion.cmake ../.clang-format + ../.clang-tidy ) add_executable( ResInsight ${EXE_FILES} ) @@ -361,21 +404,29 @@ if(RESINSIGHT_ENABLE_COTIRE) ModelVisualization/Intersections/RivIntersectionGeometryGenerator.cpp # exclude file using Eigen - ReservoirDataModel/RigTransmissibilityCondenser.cpp - ReservoirDataModel/RigEclipseToStimPlanCellTransmissibilityCalculator.cpp ReservoirDataModel/RigCellGeometryTools.cpp + ReservoirDataModel/Completions/RigTransmissibilityCondenser.cpp + ReservoirDataModel/Completions/RigEclipseToStimPlanCellTransmissibilityCalculator.cpp + ReservoirDataModel/Completions/RigEclipseToStimPlanCalculator.cpp # exclude file using SolveSpace - Application/Tools/RiaSCurveCalculator.cpp - - # exclude test files due to cotire redefinition error report - UnitTests/RifCaseRealizationParametersReader-Test.cpp + Application/Tools/WellPathTools/RiaSCurveCalculator.cpp + + # QT 5 + qrc_cafAnimControl.cpp + qrc_ResInsight.cpp + ProjectDataModel/RimContourMapView.cpp + Commands/CompletionExportCommands/RicExportFractureCompletionsImpl.cpp ) foreach (fileToExclude ${COTIRE_EXCLUDE_FILES}) set_source_files_properties (${fileToExclude} PROPERTIES COTIRE_EXCLUDED TRUE) endforeach(fileToExclude) + foreach (cppFile ${CAF_COTIRE_START_NEW_UNITY_SOURCES}) + set_source_files_properties (${cppFile} PROPERTIES COTIRE_START_NEW_UNITY_SOURCE TRUE) + endforeach(cppFile ${CAF_COTIRE_START_NEW_UNITY_SOURCES}) + # disable precompiled headers set_target_properties(ResInsight PROPERTIES COTIRE_ENABLE_PRECOMPILED_HEADER FALSE) @@ -398,11 +449,19 @@ endif() if (MSVC) # Qt DLLs - set (QTLIBLIST QtCore QtCored QtGui QtGuid QtOpenGl QtOpenGld QtNetwork QtNetworkd QtScript QtScriptd QtScriptTools QtScriptToolsd) - foreach (qtlib ${QTLIBLIST}) - list(APPEND RI_DLL_FILENAMES ${QT_BINARY_DIR}/${qtlib}4.dll) - endforeach( qtlib ) - + if (Qt5Core_FOUND) + message(STATUS "Creating post build step for copying Qt DLLs") + foreach (qtlib ${QT_LIBRARIES}) + add_custom_command(TARGET ResInsight POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_if_different $ $ + ) + endforeach(qtlib) + else() + set (QTLIBLIST QtCore4 QtCored4 QtGui4 QtGuid4 QtOpenGl4 QtOpenGld4 QtNetwork4 QtNetworkd4 QtScript4 QtScriptd4 QtScriptTools4 QtScriptToolsd4) + foreach (qtlib ${QTLIBLIST}) + list(APPEND RI_DLL_FILENAMES ${QT_BINARY_DIR}/${qtlib}.dll) + endforeach( qtlib ) + endif() # Odb Dlls if (RESINSIGHT_USE_ODB_API) # Find all the dlls @@ -484,6 +543,56 @@ if (RESINSIGHT_PRIVATE_INSTALL) set (RESINSIGHT_FILES ${RI_DLL_FILENAMES}) + if(Qt5_FOUND AND WIN32 AND TARGET Qt5::qmake AND NOT TARGET Qt5::windeployqt) + get_target_property(_qt5_qmake_location Qt5::qmake IMPORTED_LOCATION) + + execute_process( + COMMAND "${_qt5_qmake_location}" -query QT_INSTALL_PREFIX + RESULT_VARIABLE return_code + OUTPUT_VARIABLE qt5_install_prefix + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + + set(imported_location "${qt5_install_prefix}/bin/windeployqt.exe") + + if(EXISTS ${imported_location}) + add_executable(Qt5::windeployqt IMPORTED) + + set_target_properties(Qt5::windeployqt PROPERTIES + IMPORTED_LOCATION ${imported_location} + ) + endif() + endif() + + # TODO(wjwwood): find a way to make this optional or to run without "deploying" the + # necessary dlls and stuff to the bin folder. + # see: + # https://stackoverflow.com/questions/41193584/deploy-all-qt-dependencies-when-building#41199492 + if(TARGET Qt5::windeployqt) + # execute windeployqt in a tmp directory after build + add_custom_command(TARGET ResInsight + POST_BUILD + COMMAND ${CMAKE_COMMAND} -E remove_directory "${CMAKE_CURRENT_BINARY_DIR}/windeployqt" + COMMAND set PATH=%PATH%$${qt5_install_prefix}/bin + COMMAND + Qt5::windeployqt + --no-compiler-runtime + --no-system-d3d-compiler + --no-quick-import + --no-translations + --verbose 0 + --dir "${CMAKE_CURRENT_BINARY_DIR}/windeployqt" + "$/$" + ) + + # copy deployment directory during installation + install( + DIRECTORY + "${CMAKE_CURRENT_BINARY_DIR}/windeployqt/" + DESTINATION ${RESINSIGHT_INSTALL_FOLDER} + ) + endif() + # CRT set(CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS_SKIP ON) set(CMAKE_INSTALL_OPENMP_LIBRARIES ON) @@ -541,14 +650,6 @@ elseif (${CMAKE_SYSTEM_NAME} MATCHES "Windows") set(CPACK_GENERATOR ZIP) endif() -if(RESINSIGHT_OCTAVE_PLUGIN_MKOCTFILE) - get_filename_component(RESINSIGHT_OCTAVE_DIRECTORY ${RESINSIGHT_OCTAVE_PLUGIN_MKOCTFILE} DIRECTORY) - - execute_process (COMMAND octave-config -v - WORKING_DIRECTORY ${RESINSIGHT_OCTAVE_DIRECTORY} - OUTPUT_VARIABLE OCTAVE_VERSION_STRING - OUTPUT_STRIP_TRAILING_WHITESPACE) -endif () # Handling of system name on Windows if(${CMAKE_SYSTEM_NAME} MATCHES Windows) diff --git a/ApplicationCode/CommandFileInterface/CMakeLists_files.cmake b/ApplicationCode/CommandFileInterface/CMakeLists_files.cmake index 7d9fe7cf0a..91b91819de 100644 --- a/ApplicationCode/CommandFileInterface/CMakeLists_files.cmake +++ b/ApplicationCode/CommandFileInterface/CMakeLists_files.cmake @@ -27,6 +27,7 @@ ${CMAKE_CURRENT_LIST_DIR}/RicfExportPropertyInViews.h ${CMAKE_CURRENT_LIST_DIR}/RicfExportLgrForCompletions.h ${CMAKE_CURRENT_LIST_DIR}/RicfCreateLgrForCompletions.h ${CMAKE_CURRENT_LIST_DIR}/RicfApplicationTools.h +${CMAKE_CURRENT_LIST_DIR}/RicfCreateSaturationPressurePlots.h ) set (SOURCE_GROUP_SOURCE_FILES @@ -57,6 +58,7 @@ ${CMAKE_CURRENT_LIST_DIR}/RicfExportPropertyInViews.cpp ${CMAKE_CURRENT_LIST_DIR}/RicfExportLgrForCompletions.cpp ${CMAKE_CURRENT_LIST_DIR}/RicfCreateLgrForCompletions.cpp ${CMAKE_CURRENT_LIST_DIR}/RicfApplicationTools.cpp +${CMAKE_CURRENT_LIST_DIR}/RicfCreateSaturationPressurePlots.cpp ) list(APPEND CODE_HEADER_FILES diff --git a/ApplicationCode/CommandFileInterface/RicfCreateSaturationPressurePlots.cpp b/ApplicationCode/CommandFileInterface/RicfCreateSaturationPressurePlots.cpp new file mode 100644 index 0000000000..2d2a98c323 --- /dev/null +++ b/ApplicationCode/CommandFileInterface/RicfCreateSaturationPressurePlots.cpp @@ -0,0 +1,83 @@ +#include "RicfCreateSaturationPressurePlots.h" +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2017 Statoil ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "RicfCreateSaturationPressurePlots.h" + +#include "GridCrossPlotCommands/RicCreateSaturationPressurePlotsFeature.h" + +#include "RiaApplication.h" +#include "RiaLogging.h" + +#include "RimEclipseResultCase.h" +#include "RimMainPlotCollection.h" +#include "RimProject.h" +#include "RimSaturationPressurePlotCollection.h" + +CAF_PDM_SOURCE_INIT(RicfCreateSaturationPressurePlots, "createSaturationPressurePlots"); + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RicfCreateSaturationPressurePlots::RicfCreateSaturationPressurePlots() +{ + RICF_InitField(&m_caseIds, "caseIds", std::vector(), "Case IDs", "", "", ""); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicfCreateSaturationPressurePlots::execute() +{ + std::vector caseIds = m_caseIds(); + if (caseIds.empty()) + { + RimProject* project = RiaApplication::instance()->project(); + if (project) + { + auto eclipeCases = project->eclipseCases(); + for (auto c : eclipeCases) + { + caseIds.push_back(c->caseId()); + } + } + } + + RimProject* project = RiaApplication::instance()->project(); + if (project) + { + auto eclipeCases = project->eclipseCases(); + for (auto c : eclipeCases) + { + auto eclipseResultCase = dynamic_cast(c); + if (!eclipseResultCase) continue; + + for (auto caseId : caseIds) + { + if (c->caseId == caseId) + { + RicCreateSaturationPressurePlotsFeature::createPlots(eclipseResultCase); + } + } + } + } + + RimSaturationPressurePlotCollection* collection = project->mainPlotCollection()->saturationPressurePlotCollection(); + collection->updateAllRequiredEditors(); + RiaApplication::instance()->getOrCreateAndShowMainPlotWindow(); +} diff --git a/ApplicationCode/CommandFileInterface/RicfCreateSaturationPressurePlots.h b/ApplicationCode/CommandFileInterface/RicfCreateSaturationPressurePlots.h new file mode 100644 index 0000000000..8194c52303 --- /dev/null +++ b/ApplicationCode/CommandFileInterface/RicfCreateSaturationPressurePlots.h @@ -0,0 +1,41 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2017 Statoil ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "RicfCommandObject.h" + +#include "cafPdmField.h" + +//================================================================================================== +// +// +// +//================================================================================================== +class RicfCreateSaturationPressurePlots : public RicfCommandObject +{ + CAF_PDM_HEADER_INIT; + +public: + RicfCreateSaturationPressurePlots(); + + void execute() override; + +private: + caf::PdmField< std::vector > m_caseIds; +}; \ No newline at end of file diff --git a/ApplicationCode/CommandFileInterface/RicfExportMsw.cpp b/ApplicationCode/CommandFileInterface/RicfExportMsw.cpp index 5e83e13528..d7e8f47720 100644 --- a/ApplicationCode/CommandFileInterface/RicfExportMsw.cpp +++ b/ApplicationCode/CommandFileInterface/RicfExportMsw.cpp @@ -33,7 +33,8 @@ #include "RimFishbonesCollection.h" #include "RimFishbonesMultipleSubs.h" -#include "CompletionExportCommands/RicExportFishbonesWellSegmentsFeature.h" +#include "CompletionExportCommands/RicExportCompletionDataSettingsUi.h" +#include "CompletionExportCommands/RicWellPathExportMswCompletionsImpl.h" CAF_PDM_SOURCE_INIT(RicfExportMsw, "exportMsw"); @@ -44,6 +45,11 @@ RicfExportMsw::RicfExportMsw() { RICF_InitField(&m_caseId, "caseId", -1, "Case ID", "", "", ""); RICF_InitField(&m_wellPathName, "wellPath", QString(), "Well Path Name", "", "", ""); + RICF_InitField(&m_includePerforations, "includePerforations", true, "Include Perforations", "", "", ""); + RICF_InitField(&m_includeFishbones, "includeFishbones", true, "Include Fishbones", "", "", ""); + RICF_InitField(&m_includeFractures, "includeFractures", true, "Include Fractures", "", "", ""); + RICF_InitField(&m_fileSplit, "fileSplit", RicExportCompletionDataSettingsUi::ExportSplitType(), "File Split", "", "", ""); + } //-------------------------------------------------------------------------------------------------- @@ -53,7 +59,7 @@ void RicfExportMsw::execute() { using TOOLS = RicfApplicationTools; - RicCaseAndFileExportSettingsUi exportSettings; + RicExportCompletionDataSettingsUi exportSettings; auto eclipseCase = TOOLS::caseFromId(m_caseId()); if (!eclipseCase) @@ -67,7 +73,12 @@ void RicfExportMsw::execute() { exportFolder = RiaApplication::instance()->createAbsolutePathFromProjectRelativePath("completions"); } + exportSettings.caseToApply = eclipseCase; exportSettings.folder = exportFolder; + exportSettings.includePerforations = m_includePerforations; + exportSettings.includeFishbones = m_includeFishbones; + exportSettings.includeFractures = m_includeFractures; + exportSettings.fileSplit = m_fileSplit; RimWellPath* wellPath = RiaApplication::instance()->project()->wellPathByName(m_wellPathName); if (!wellPath) @@ -76,8 +87,5 @@ void RicfExportMsw::execute() return; } - if (!wellPath->fishbonesCollection()->activeFishbonesSubs().empty()) - { - RicExportFishbonesWellSegmentsFeature::exportWellSegments(wellPath, wellPath->fishbonesCollection()->activeFishbonesSubs(), exportSettings); - } + RicWellPathExportMswCompletionsImpl::exportWellSegmentsForAllCompletions(exportSettings, { wellPath }); } diff --git a/ApplicationCode/CommandFileInterface/RicfExportMsw.h b/ApplicationCode/CommandFileInterface/RicfExportMsw.h index f807440c04..6a95cd2464 100644 --- a/ApplicationCode/CommandFileInterface/RicfExportMsw.h +++ b/ApplicationCode/CommandFileInterface/RicfExportMsw.h @@ -20,6 +20,8 @@ #include "RicfCommandObject.h" +#include "CompletionExportCommands/RicExportCompletionDataSettingsUi.h" + #include "cafPdmField.h" //================================================================================================== @@ -39,4 +41,8 @@ class RicfExportMsw : public RicfCommandObject private: caf::PdmField m_caseId; caf::PdmField m_wellPathName; + caf::PdmField m_includePerforations; + caf::PdmField m_includeFishbones; + caf::PdmField m_includeFractures; + caf::PdmField m_fileSplit; }; \ No newline at end of file diff --git a/ApplicationCode/CommandFileInterface/RicfExportProperty.cpp b/ApplicationCode/CommandFileInterface/RicfExportProperty.cpp index 1784a46e22..63a0f54f1e 100644 --- a/ApplicationCode/CommandFileInterface/RicfExportProperty.cpp +++ b/ApplicationCode/CommandFileInterface/RicfExportProperty.cpp @@ -85,8 +85,7 @@ void RicfExportProperty::execute() RigCaseCellResultsData* cellResultsData = eclipseCaseData->results(RiaDefines::MATRIX_MODEL); - size_t resultIdx = cellResultsData->findOrLoadScalarResult(m_propertyName); - if (resultIdx == cvf::UNDEFINED_SIZE_T) + if (!cellResultsData->ensureKnownResultLoaded(RigEclipseResultAddress(m_propertyName))) { RiaLogging::error(QString("exportProperty: Could not find result property : %1").arg(m_propertyName())); return; diff --git a/ApplicationCode/CommandFileInterface/RicfRunOctaveScript.cpp b/ApplicationCode/CommandFileInterface/RicfRunOctaveScript.cpp index 3b88f4e76a..f04871e673 100644 --- a/ApplicationCode/CommandFileInterface/RicfRunOctaveScript.cpp +++ b/ApplicationCode/CommandFileInterface/RicfRunOctaveScript.cpp @@ -22,6 +22,10 @@ #include "RiaApplication.h" #include "RiaLogging.h" +#include "RimCalcScript.h" +#include "RimEclipseCase.h" +#include "RimProject.h" + #include CAF_PDM_SOURCE_INIT(RicfRunOctaveScript, "runOctaveScript"); @@ -41,20 +45,31 @@ RicfRunOctaveScript::RicfRunOctaveScript() void RicfRunOctaveScript::execute() { QString octavePath = RiaApplication::instance()->octavePath(); - QFileInfo scriptFileInfo(m_path()); - QStringList processArguments; - processArguments << "--path" << scriptFileInfo.absolutePath(); - processArguments << scriptFileInfo.absoluteFilePath(); + QStringList processArguments = RimCalcScript::createCommandLineArguments(m_path()); + + std::vector caseIds = m_caseIds(); + if (caseIds.empty()) + { + RimProject* project = RiaApplication::instance()->project(); + if (project) + { + auto eclipeCases = project->eclipseCases(); + for (auto c : eclipeCases) + { + caseIds.push_back(c->caseId()); + } + } + } bool ok; - if (m_caseIds().empty()) + if (caseIds.empty()) { ok = RiaApplication::instance()->launchProcess(octavePath, processArguments); } else { - ok = RiaApplication::instance()->launchProcessForMultipleCases(octavePath, processArguments, m_caseIds()); + ok = RiaApplication::instance()->launchProcessForMultipleCases(octavePath, processArguments, caseIds); } if (!ok) { diff --git a/ApplicationCode/Commands/AnnotationCommands/CMakeLists_files.cmake b/ApplicationCode/Commands/AnnotationCommands/CMakeLists_files.cmake new file mode 100644 index 0000000000..ea01e1c157 --- /dev/null +++ b/ApplicationCode/Commands/AnnotationCommands/CMakeLists_files.cmake @@ -0,0 +1,40 @@ + +set (SOURCE_GROUP_HEADER_FILES +${CMAKE_CURRENT_LIST_DIR}/RicImportPolylinesAnnotationFeature.h +${CMAKE_CURRENT_LIST_DIR}/RicCreateTextAnnotationFeature.h +${CMAKE_CURRENT_LIST_DIR}/RicCreateTextAnnotationIn3dViewFeature.h +${CMAKE_CURRENT_LIST_DIR}/RicCreateReachCircleAnnotationFeature.h +${CMAKE_CURRENT_LIST_DIR}/RicCreateUserDefinedPolylinesAnnotationFeature.h +${CMAKE_CURRENT_LIST_DIR}/RicTextAnnotation3dEditor.h +) + +set (SOURCE_GROUP_SOURCE_FILES +${CMAKE_CURRENT_LIST_DIR}/RicImportPolylinesAnnotationFeature.cpp +${CMAKE_CURRENT_LIST_DIR}/RicCreateTextAnnotationFeature.cpp +${CMAKE_CURRENT_LIST_DIR}/RicCreateTextAnnotationIn3dViewFeature.cpp +${CMAKE_CURRENT_LIST_DIR}/RicCreateReachCircleAnnotationFeature.cpp +${CMAKE_CURRENT_LIST_DIR}/RicCreateUserDefinedPolylinesAnnotationFeature.cpp +${CMAKE_CURRENT_LIST_DIR}/RicTextAnnotation3dEditor.cpp +) + +list(APPEND CODE_HEADER_FILES +${SOURCE_GROUP_HEADER_FILES} +) + +list(APPEND CODE_SOURCE_FILES +${SOURCE_GROUP_SOURCE_FILES} +) + +set (QT_MOC_HEADERS +${QT_MOC_HEADERS} +${CMAKE_CURRENT_LIST_DIR}/RicTextAnnotation3dEditor.h +) + + +source_group( "CommandFeature\\AnnotationCommands" FILES ${SOURCE_GROUP_HEADER_FILES} ${SOURCE_GROUP_SOURCE_FILES} ${CMAKE_CURRENT_LIST_DIR}/CMakeLists_files.cmake ) + +# cotire +caf_cotire_start_unity_at_first_item(SOURCE_GROUP_SOURCE_FILES) +list(APPEND CAF_COTIRE_START_NEW_UNITY_SOURCES +${CMAKE_CURRENT_LIST_DIR}/RicCreateReachCircleAnnotationFeature.cpp +) diff --git a/ApplicationCode/Commands/AnnotationCommands/RicCreateReachCircleAnnotationFeature.cpp b/ApplicationCode/Commands/AnnotationCommands/RicCreateReachCircleAnnotationFeature.cpp new file mode 100644 index 0000000000..1457f21857 --- /dev/null +++ b/ApplicationCode/Commands/AnnotationCommands/RicCreateReachCircleAnnotationFeature.cpp @@ -0,0 +1,91 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2018- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "RicCreateReachCircleAnnotationFeature.h" + +#include "RiaApplication.h" +#include "RiaColorTables.h" + +#include "RimTextAnnotation.h" +#include "RimReachCircleAnnotation.h" +#include "RimPolylinesAnnotation.h" +#include "RimAnnotationCollection.h" +#include "RimAnnotationGroupCollection.h" +#include "RimAnnotationInViewCollection.h" +#include "RimAnnotationLineAppearance.h" +#include "RimProject.h" +#include "RimOilField.h" + +#include "RiuMainWindow.h" + +#include + +#include + + +CAF_CMD_SOURCE_INIT(RicCreateReachCircleAnnotationFeature, "RicCreateReachCircleAnnotationFeature"); + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RicCreateReachCircleAnnotationFeature::isCommandEnabled() +{ + auto selObjs = caf::selectedObjectsByTypeStrict(); + auto selGroupColl = caf::selectedObjectsByTypeStrict(); + + return selObjs.size() == 1 || (selGroupColl.size() == 1 + && selGroupColl.front()->uiCapability()->uiName() == RimAnnotationGroupCollection::REACH_CIRCLE_ANNOTATION_UI_NAME); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicCreateReachCircleAnnotationFeature::onActionTriggered(bool isChecked) +{ + auto coll = annotationCollection(); + if (coll) + { + auto newAnnotation = new RimReachCircleAnnotation(); + auto newColor = RiaColorTables::categoryPaletteColors().cycledColor3f(coll->lineBasedAnnotationsCount()); + newAnnotation->appearance()->setColor(newColor); + newAnnotation->enablePicking(true); + coll->addAnnotation(newAnnotation); + coll->updateConnectedEditors(); + RiuMainWindow::instance()->selectAsCurrentItem(newAnnotation); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicCreateReachCircleAnnotationFeature::setupActionLook(QAction* actionToSetup) +{ + actionToSetup->setIcon(QIcon(":/ReachCircle16x16.png")); + actionToSetup->setText("Create Reach Circle Annotation"); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimAnnotationCollection* RicCreateReachCircleAnnotationFeature::annotationCollection() const +{ + auto project = RiaApplication::instance()->project(); + auto oilField = project->activeOilField(); + return oilField ? oilField->annotationCollection() : nullptr; +} diff --git a/ApplicationCode/Commands/AnnotationCommands/RicCreateReachCircleAnnotationFeature.h b/ApplicationCode/Commands/AnnotationCommands/RicCreateReachCircleAnnotationFeature.h new file mode 100644 index 0000000000..0b5defacfa --- /dev/null +++ b/ApplicationCode/Commands/AnnotationCommands/RicCreateReachCircleAnnotationFeature.h @@ -0,0 +1,46 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2018- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "RiaPreferences.h" + +#include "cafCmdFeature.h" + +#include + + +class RimAnnotationCollection; + + +//================================================================================================== +/// +//================================================================================================== +class RicCreateReachCircleAnnotationFeature : public caf::CmdFeature +{ + CAF_CMD_HEADER_INIT; + +protected: + // Overrides + bool isCommandEnabled() override; + void onActionTriggered(bool isChecked) override; + void setupActionLook(QAction* actionToSetup) override; + +private: + RimAnnotationCollection* annotationCollection() const; +}; diff --git a/ApplicationCode/Commands/AnnotationCommands/RicCreateTextAnnotationFeature.cpp b/ApplicationCode/Commands/AnnotationCommands/RicCreateTextAnnotationFeature.cpp new file mode 100644 index 0000000000..ea84d3b883 --- /dev/null +++ b/ApplicationCode/Commands/AnnotationCommands/RicCreateTextAnnotationFeature.cpp @@ -0,0 +1,97 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2018- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "RicCreateTextAnnotationFeature.h" + +#include "RiaApplication.h" + +#include "RimTextAnnotation.h" +#include "RimReachCircleAnnotation.h" +#include "RimPolylinesAnnotation.h" +#include "RimAnnotationCollection.h" +#include "RimAnnotationGroupCollection.h" +#include "RimAnnotationInViewCollection.h" +#include "RimProject.h" +#include "RimOilField.h" + +#include "RiuMainWindow.h" + +#include + +#include + + +CAF_CMD_SOURCE_INIT(RicCreateTextAnnotationFeature, "RicCreateTextAnnotationFeature"); + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RicCreateTextAnnotationFeature::isCommandEnabled() +{ + auto selObjsGlobal = caf::selectedObjectsByTypeStrict(); + auto selObjs2InView = caf::selectedObjectsByTypeStrict(); + auto selGroupColl = caf::selectedObjectsByTypeStrict(); + + return selObjsGlobal.size() == 1 || selObjs2InView.size() == 1 || + (selGroupColl.size() == 1 && + selGroupColl.front()->uiCapability()->uiName() == RimAnnotationGroupCollection::TEXT_ANNOTATION_UI_NAME); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicCreateTextAnnotationFeature::onActionTriggered(bool isChecked) + +{ + auto coll = annotationCollectionBase(); + if (coll) + { + auto newAnnotation = new RimTextAnnotation(); + newAnnotation->enablePicking(true); + coll->addAnnotation(newAnnotation); + coll->updateConnectedEditors(); + RiuMainWindow::instance()->selectAsCurrentItem(newAnnotation); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicCreateTextAnnotationFeature::setupActionLook(QAction* actionToSetup) +{ + actionToSetup->setIcon(QIcon(":/TextAnnotation16x16.png")); + actionToSetup->setText("Create Text Annotation"); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimAnnotationCollectionBase* RicCreateTextAnnotationFeature::annotationCollectionBase() const +{ + auto selColls = caf::selectedObjectsByTypeStrict(); + if (selColls.size() == 1) return selColls.front(); + + RimAnnotationCollectionBase* coll = nullptr; + auto selGroupColl = caf::selectedObjectsByTypeStrict(); + if (selGroupColl.size() == 1) + { + selGroupColl.front()->firstAncestorOrThisOfType(coll); + } + + return coll; +} diff --git a/ApplicationCode/Commands/AnnotationCommands/RicCreateTextAnnotationFeature.h b/ApplicationCode/Commands/AnnotationCommands/RicCreateTextAnnotationFeature.h new file mode 100644 index 0000000000..72dc2315b3 --- /dev/null +++ b/ApplicationCode/Commands/AnnotationCommands/RicCreateTextAnnotationFeature.h @@ -0,0 +1,47 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2018- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "RiaPreferences.h" + +#include "cafCmdFeature.h" + +#include + + +class RimAnnotationCollection; +class RimAnnotationCollectionBase; +class RimAnnotationInViewCollection; + + +//================================================================================================== +/// +//================================================================================================== +class RicCreateTextAnnotationFeature : public caf::CmdFeature +{ + CAF_CMD_HEADER_INIT; + +protected: + // Overrides + bool isCommandEnabled() override; + void onActionTriggered(bool isChecked) override; + void setupActionLook(QAction* actionToSetup) override; + + RimAnnotationCollectionBase* annotationCollectionBase() const; +}; diff --git a/ApplicationCode/Commands/AnnotationCommands/RicCreateTextAnnotationIn3dViewFeature.cpp b/ApplicationCode/Commands/AnnotationCommands/RicCreateTextAnnotationIn3dViewFeature.cpp new file mode 100644 index 0000000000..1f50603800 --- /dev/null +++ b/ApplicationCode/Commands/AnnotationCommands/RicCreateTextAnnotationIn3dViewFeature.cpp @@ -0,0 +1,108 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2018- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "RicCreateTextAnnotationIn3dViewFeature.h" + +#include "RiaApplication.h" + +#include "RimAnnotationInViewCollection.h" +#include "RimEclipseContourMapView.h" +#include "RimCase.h" +#include "RimGridView.h" +#include "RimTextAnnotation.h" + +#include "RiuMainWindow.h" +#include "RiuViewer.h" + +#include "cvfBoundingBox.h" +#include "cvfCamera.h" + +#include + +#include + + +CAF_CMD_SOURCE_INIT(RicCreateTextAnnotationIn3dViewFeature, "RicCreateTextAnnotationIn3dViewFeature"); + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RicCreateTextAnnotationIn3dViewFeature::isCommandEnabled() +{ + return true; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicCreateTextAnnotationIn3dViewFeature::onActionTriggered(bool isChecked) + +{ + RimGridView* activeView = RiaApplication::instance()->activeGridView(); + RimEclipseContourMapView * contMapView = dynamic_cast(activeView); + + if ( activeView ) + { + cvf::Vec3d domainCoord = activeView->viewer()->lastPickPositionInDomainCoords(); + cvf::BoundingBox bbox = activeView->ownerCase()->activeCellsBoundingBox(); + + if (contMapView) domainCoord[2] = bbox.max().z() - bbox.extent().z() * 0.2; + + auto coll = activeView->annotationCollection(); + + if ( coll ) + { + auto newAnnotation = new RimTextAnnotation(); + newAnnotation->setAnchorPoint(domainCoord); + cvf::Vec3d labelPos = domainCoord; + + if (activeView->viewer()->mainCamera()->direction().z() <= 0) + { + labelPos.z() = bbox.max().z(); + } + else + { + labelPos.z() = bbox.min().z(); + } + + cvf::Vec3d horizontalRight = activeView->viewer()->mainCamera()->direction() ^ cvf::Vec3d::Z_AXIS; + cvf::Vec3d horizontalUp = activeView->viewer()->mainCamera()->up() - (cvf::Vec3d::Z_AXIS * (activeView->viewer()->mainCamera()->up() * cvf::Vec3d::Z_AXIS) ); + bool isOk = horizontalRight.normalize(); + if (!isOk) horizontalRight = {1.0, 0.0, 0.0}; + + double height = fabs(labelPos.z() - domainCoord.z()); + newAnnotation->setLabelPoint(labelPos + 2.0*height * (horizontalRight + horizontalUp)); + + coll->addAnnotation(newAnnotation); + coll->scheduleRedrawOfRelevantViews(); + coll->updateConnectedEditors(); + + RiuMainWindow::instance()->selectAsCurrentItem(newAnnotation); + } + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicCreateTextAnnotationIn3dViewFeature::setupActionLook(QAction* actionToSetup) +{ + actionToSetup->setIcon(QIcon(":/TextAnnotation16x16.png")); + actionToSetup->setText("Create Text Annotation"); +} + diff --git a/ApplicationCode/Commands/AnnotationCommands/RicCreateTextAnnotationIn3dViewFeature.h b/ApplicationCode/Commands/AnnotationCommands/RicCreateTextAnnotationIn3dViewFeature.h new file mode 100644 index 0000000000..0b3f4c3410 --- /dev/null +++ b/ApplicationCode/Commands/AnnotationCommands/RicCreateTextAnnotationIn3dViewFeature.h @@ -0,0 +1,36 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2018- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "cafCmdFeature.h" + +//================================================================================================== +/// +//================================================================================================== +class RicCreateTextAnnotationIn3dViewFeature : public caf::CmdFeature +{ + CAF_CMD_HEADER_INIT; + +protected: + // Overrides + bool isCommandEnabled() override; + void onActionTriggered(bool isChecked) override; + void setupActionLook(QAction* actionToSetup) override; + +}; diff --git a/ApplicationCode/Commands/AnnotationCommands/RicCreateUserDefinedPolylinesAnnotationFeature.cpp b/ApplicationCode/Commands/AnnotationCommands/RicCreateUserDefinedPolylinesAnnotationFeature.cpp new file mode 100644 index 0000000000..1ddffb53dc --- /dev/null +++ b/ApplicationCode/Commands/AnnotationCommands/RicCreateUserDefinedPolylinesAnnotationFeature.cpp @@ -0,0 +1,92 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2018- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "RicCreateUserDefinedPolylinesAnnotationFeature.h" + +#include "RiaApplication.h" +#include "RiaColorTables.h" + +#include "RimTextAnnotation.h" +#include "RimReachCircleAnnotation.h" +#include "RimUserDefinedPolylinesAnnotation.h" +#include "RimAnnotationCollection.h" +#include "RimAnnotationGroupCollection.h" +#include "RimAnnotationInViewCollection.h" +#include "RimAnnotationLineAppearance.h" +#include "RimProject.h" +#include "RimOilField.h" + +#include "RiuMainWindow.h" + +#include + +#include + + +CAF_CMD_SOURCE_INIT(RicCreateUserDefinedPolylinesAnnotationFeature, "RicCreateUserDefinedPolylinesAnnotationFeature"); + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RicCreateUserDefinedPolylinesAnnotationFeature::isCommandEnabled() +{ + auto selObjs = caf::selectedObjectsByTypeStrict(); + auto selGroupColl = caf::selectedObjectsByTypeStrict(); + + return selObjs.size() == 1 || (selGroupColl.size() == 1 && selGroupColl.front()->uiCapability()->uiName() == + RimAnnotationGroupCollection::USED_DEFINED_POLYLINE_ANNOTATION_UI_NAME); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicCreateUserDefinedPolylinesAnnotationFeature::onActionTriggered(bool isChecked) +{ + auto coll = annotationCollection(); + if (coll) + { + auto newAnnotation = new RimUserDefinedPolylinesAnnotation(); + auto newColor = RiaColorTables::categoryPaletteColors().cycledColor3f(coll->lineBasedAnnotationsCount()); + newAnnotation->appearance()->setColor(newColor); + newAnnotation->appearance()->setSphereColor(newColor); + newAnnotation->enablePicking(true); + coll->addAnnotation(newAnnotation); + coll->updateConnectedEditors(); + RiuMainWindow::instance()->selectAsCurrentItem(newAnnotation); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicCreateUserDefinedPolylinesAnnotationFeature::setupActionLook(QAction* actionToSetup) +{ + actionToSetup->setIcon(QIcon(":/Plus.png")); + actionToSetup->setText("Create User Defined Polyline Annotation"); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- + RimAnnotationCollection* RicCreateUserDefinedPolylinesAnnotationFeature::annotationCollection() const +{ + auto project = RiaApplication::instance()->project(); + auto oilField = project->activeOilField(); + return oilField ? oilField->annotationCollection() : nullptr; +} diff --git a/ApplicationCode/Commands/AnnotationCommands/RicCreateUserDefinedPolylinesAnnotationFeature.h b/ApplicationCode/Commands/AnnotationCommands/RicCreateUserDefinedPolylinesAnnotationFeature.h new file mode 100644 index 0000000000..c578d1db12 --- /dev/null +++ b/ApplicationCode/Commands/AnnotationCommands/RicCreateUserDefinedPolylinesAnnotationFeature.h @@ -0,0 +1,46 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2018- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "RiaPreferences.h" + +#include "cafCmdFeature.h" + +#include + + +class RimAnnotationCollection; + + +//================================================================================================== +/// +//================================================================================================== +class RicCreateUserDefinedPolylinesAnnotationFeature : public caf::CmdFeature +{ + CAF_CMD_HEADER_INIT; + +protected: + // Overrides + bool isCommandEnabled() override; + void onActionTriggered(bool isChecked) override; + void setupActionLook(QAction* actionToSetup) override; + +private: + RimAnnotationCollection* annotationCollection() const; +}; diff --git a/ApplicationCode/Commands/AnnotationCommands/RicDeleteAnnotationFeature.cpp b/ApplicationCode/Commands/AnnotationCommands/RicDeleteAnnotationFeature.cpp new file mode 100644 index 0000000000..15a1793305 --- /dev/null +++ b/ApplicationCode/Commands/AnnotationCommands/RicDeleteAnnotationFeature.cpp @@ -0,0 +1,94 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2018- equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "RicDeleteAnnotationFeature.h" + +#include "RiaApplication.h" + +#include "RimTextAnnotation.h" +#include "RimReachCircleAnnotation.h" +#include "RimPolylinesAnnotation.h" +#include "RimAnnotationCollection.h" +#include "RimAnnotationInViewCollection.h" +#include "RimProject.h" +#include "RimOilField.h" + +#include "RiuMainWindow.h" + +#include + +#include + + +CAF_CMD_SOURCE_INIT(RicDeleteAnnotationFeature, "RicDeleteAnnotationFeature"); + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RicDeleteAnnotationFeature::isCommandEnabled() +{ + auto textAnnots = caf::selectedObjectsByTypeStrict(); + auto lineBasedAnnots = caf::selectedObjectsByTypeStrict(); + + return !textAnnots.empty() || !lineBasedAnnots.empty(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicDeleteAnnotationFeature::onActionTriggered(bool isChecked) +{ + { + auto annotations = caf::selectedObjectsByTypeStrict(); + while(!annotations.empty()) + { + auto annotation = annotations.front(); + + RimAnnotationCollection* coll; + annotation->firstAncestorOrThisOfType(coll); + if (coll) + { + coll->addAnnotation() + } + + coll->addAnnotation(newAnnotation); + coll->updateConnectedEditors(); + RiuMainWindow::instance()->selectAsCurrentItem(newAnnotation); + } + } + + { + auto coll = annotationInViewCollection(); + if (coll) + { + auto newAnnotation = new RimTextAnnotation(); + coll->addAnnotation(newAnnotation); + coll->updateConnectedEditors(); + RiuMainWindow::instance()->selectAsCurrentItem(newAnnotation); + } + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicDeleteAnnotationFeature::setupActionLook(QAction* actionToSetup) +{ + actionToSetup->setIcon(QIcon(":/minus-sign-red.png")); + actionToSetup->setText("Delete Annotation"); +} diff --git a/ApplicationCode/Commands/AnnotationCommands/RicImportPolylinesAnnotationFeature.cpp b/ApplicationCode/Commands/AnnotationCommands/RicImportPolylinesAnnotationFeature.cpp new file mode 100644 index 0000000000..f1f659b3d4 --- /dev/null +++ b/ApplicationCode/Commands/AnnotationCommands/RicImportPolylinesAnnotationFeature.cpp @@ -0,0 +1,101 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2018- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "RicImportPolylinesAnnotationFeature.h" + +#include "RiaApplication.h" + +#include "RimOilField.h" +#include "RimProject.h" +#include "RimAnnotationCollection.h" +#include "RimAnnotationGroupCollection.h" +#include "RimPolylinesFromFileAnnotation.h" + +#include "Riu3DMainWindowTools.h" + +#include +#include + +#include + + +CAF_CMD_SOURCE_INIT(RicImportPolylinesAnnotationFeature, "RicImportPolylinesAnnotationFeature"); + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RicImportPolylinesAnnotationFeature::isCommandEnabled() +{ + auto selObjs = caf::selectedObjectsByTypeStrict(); + auto selGroupColl = caf::selectedObjectsByTypeStrict(); + + return selObjs.size() == 1 || + (selGroupColl.size() == 1 && selGroupColl.front()->uiCapability()->uiName() == + RimAnnotationGroupCollection::POLYLINE_FROM_FILE_ANNOTATION_UI_NAME); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicImportPolylinesAnnotationFeature::onActionTriggered(bool isChecked) +{ + RiaApplication* app = RiaApplication::instance(); + QString defaultDir = app->lastUsedDialogDirectory("BINARY_GRID"); + QStringList fileNames = QFileDialog::getOpenFileNames(Riu3DMainWindowTools::mainWindowWidget(), + "Import Poly Lines Annotation", + defaultDir, + "Text File (*.txt);Polylines (*.dat);All Files (*.*)"); + + if (fileNames.isEmpty()) return; + + // Remember the path to next time + app->setLastUsedDialogDirectory("BINARY_GRID", QFileInfo(fileNames.last()).absolutePath()); + + // Find or create the AnnotationsCollection + + RimProject* proj = RiaApplication::instance()->project(); + RimAnnotationCollection* annotColl = proj->activeOilField()->annotationCollection(); + + if (!annotColl) + { + annotColl = new RimAnnotationCollection; + proj->activeOilField()->annotationCollection = annotColl; + } + + // For each file, + + RimPolylinesFromFileAnnotation* lastCreatedOrUpdated = annotColl->importOrUpdatePolylinesFromFile(fileNames); + + proj->updateConnectedEditors(); + + if (lastCreatedOrUpdated) + { + Riu3DMainWindowTools::selectAsCurrentItem(lastCreatedOrUpdated); + } + + annotColl->scheduleRedrawOfRelevantViews(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicImportPolylinesAnnotationFeature::setupActionLook(QAction* actionToSetup) +{ + actionToSetup->setIcon(QIcon(":/PolylinesFromFile16x16.png")); + actionToSetup->setText("Import Poly Lines Annotation"); +} diff --git a/ApplicationCode/Commands/AnnotationCommands/RicImportPolylinesAnnotationFeature.h b/ApplicationCode/Commands/AnnotationCommands/RicImportPolylinesAnnotationFeature.h new file mode 100644 index 0000000000..b4d8f86479 --- /dev/null +++ b/ApplicationCode/Commands/AnnotationCommands/RicImportPolylinesAnnotationFeature.h @@ -0,0 +1,37 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2018- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "cafCmdFeature.h" + +//================================================================================================== +/// +//================================================================================================== +class RicImportPolylinesAnnotationFeature : public caf::CmdFeature +{ + CAF_CMD_HEADER_INIT; + +protected: + // Overrides + bool isCommandEnabled() override; + void onActionTriggered( bool isChecked ) override; + void setupActionLook( QAction* actionToSetup ) override; +}; + + diff --git a/ApplicationCode/Commands/AnnotationCommands/RicTextAnnotation3dEditor.cpp b/ApplicationCode/Commands/AnnotationCommands/RicTextAnnotation3dEditor.cpp new file mode 100644 index 0000000000..679a0d854f --- /dev/null +++ b/ApplicationCode/Commands/AnnotationCommands/RicTextAnnotation3dEditor.cpp @@ -0,0 +1,188 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2018- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "RicTextAnnotation3dEditor.h" + +#include "../WellPathCommands/PointTangentManipulator/RicPointTangentManipulator.h" + +#include "RimTextAnnotation.h" +#include "Rim3dView.h" +#include "RimCase.h" + +#include "RiuViewer.h" + +#include "cafDisplayCoordTransform.h" +#include "cafPdmUiCommandSystemProxy.h" +#include "cafSelectionManager.h" + +#include "cvfPart.h" +#include "cvfModelBasicList.h" + +CAF_PDM_UI_3D_OBJECT_EDITOR_SOURCE_INIT(RicTextAnnotation3dEditor); + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RicTextAnnotation3dEditor::RicTextAnnotation3dEditor() +{ + +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RicTextAnnotation3dEditor::~RicTextAnnotation3dEditor() +{ + RiuViewer* ownerRiuViewer = dynamic_cast(ownerViewer()); + + if (m_cvfModel.notNull() && ownerRiuViewer) + { + + // Could result in some circularities .... + ownerRiuViewer->removeStaticModel(m_cvfModel.p()); + } + + auto textAnnot = dynamic_cast(this->pdmObject()); + if (textAnnot) + { + textAnnot->m_anchorPointXyd.uiCapability()->removeFieldEditor(this); + textAnnot->m_labelPointXyd.uiCapability()->removeFieldEditor(this); + } + + delete m_labelManipulator; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicTextAnnotation3dEditor::configureAndUpdateUi(const QString& uiConfigName) +{ + RimTextAnnotation* textAnnot = dynamic_cast(this->pdmObject()); + RiuViewer* ownerRiuViewer = dynamic_cast(ownerViewer()); + + if ( !textAnnot || !textAnnot->isActive()) + { + m_cvfModel->removeAllParts(); + return; + } + + textAnnot->m_anchorPointXyd.uiCapability()->addFieldEditor(this); + textAnnot->m_labelPointXyd.uiCapability()->addFieldEditor(this); + + + if (m_labelManipulator.isNull()) + { + m_labelManipulator = new RicPointTangentManipulator(ownerRiuViewer); + m_anchorManipulator = new RicPointTangentManipulator(ownerRiuViewer); + QObject::connect(m_labelManipulator, + SIGNAL( notifyUpdate(const cvf::Vec3d& , const cvf::Vec3d& ) ), + this, + SLOT( slotLabelUpdated(const cvf::Vec3d& , const cvf::Vec3d& ) ) ); + QObject::connect(m_anchorManipulator, + SIGNAL( notifyUpdate(const cvf::Vec3d& , const cvf::Vec3d& ) ), + this, + SLOT( slotAnchorUpdated(const cvf::Vec3d& , const cvf::Vec3d& ) ) ); + + m_cvfModel = new cvf::ModelBasicList; + ownerRiuViewer->addStaticModelOnce(m_cvfModel.p()); + } + + cvf::ref dispXf; + double handleSize = 1.0; + { + dispXf = ownerRiuViewer->ownerReservoirView()->displayCoordTransform(); + Rim3dView* view = dynamic_cast(ownerRiuViewer->ownerReservoirView()); + handleSize = 0.7 * view->ownerCase()->characteristicCellSize(); + } + cvf::Vec3d labelPos(textAnnot->m_labelPointXyd()); + labelPos.z() *= -1.0; + m_labelManipulator->setOrigin(dispXf->transformToDisplayCoord( labelPos )); + m_labelManipulator->setHandleSize(handleSize); + + cvf::Vec3d anchorPos(textAnnot->m_anchorPointXyd()); + anchorPos.z() *= -1.0; + m_anchorManipulator->setOrigin(dispXf->transformToDisplayCoord( anchorPos )); + m_anchorManipulator->setHandleSize(handleSize); + + + m_cvfModel->removeAllParts(); + m_labelManipulator->appendPartsToModel(m_cvfModel.p()); + m_anchorManipulator->appendPartsToModel(m_cvfModel.p()); + + m_cvfModel->updateBoundingBoxesRecursive(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicTextAnnotation3dEditor::cleanupBeforeSettingPdmObject() +{ + RimTextAnnotation* textAnnot = dynamic_cast(this->pdmObject()); + if (textAnnot) + { + textAnnot->m_anchorPointXyd.uiCapability()->removeFieldEditor(this); + textAnnot->m_labelPointXyd.uiCapability()->removeFieldEditor(this); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicTextAnnotation3dEditor::slotLabelUpdated(const cvf::Vec3d& origin, const cvf::Vec3d& tangent) +{ + RimTextAnnotation* textAnnot = dynamic_cast(this->pdmObject()); + + if ( !textAnnot) + { + return; + } + updatePoint(textAnnot->m_labelPointXyd.uiCapability(), origin); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicTextAnnotation3dEditor::slotAnchorUpdated(const cvf::Vec3d& origin, const cvf::Vec3d& dummy) +{ + RimTextAnnotation* textAnnot = dynamic_cast(this->pdmObject()); + + if ( !textAnnot) + { + return; + } + updatePoint(textAnnot->m_anchorPointXyd.uiCapability(), origin); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicTextAnnotation3dEditor::updatePoint(caf::PdmUiFieldHandle* uiField, const cvf::Vec3d& newPos) +{ + cvf::ref dispXf; + { + RiuViewer* viewer = dynamic_cast(ownerViewer()); + dispXf = viewer->ownerReservoirView()->displayCoordTransform(); + } + + cvf::Vec3d domainPos = dispXf->transformToDomainCoord( newPos); + domainPos.z() = -domainPos.z(); + QVariant originVariant = caf::PdmValueFieldSpecialization < cvf::Vec3d >::convert(domainPos); + + caf::PdmUiCommandSystemProxy::instance()->setUiValueToField(uiField, originVariant); +} + diff --git a/ApplicationCode/Commands/AnnotationCommands/RicTextAnnotation3dEditor.h b/ApplicationCode/Commands/AnnotationCommands/RicTextAnnotation3dEditor.h new file mode 100644 index 0000000000..82dc572068 --- /dev/null +++ b/ApplicationCode/Commands/AnnotationCommands/RicTextAnnotation3dEditor.h @@ -0,0 +1,59 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2018- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "cafPdmUi3dObjectEditorHandle.h" + +class RicPointTangentManipulator; + +#include "cvfBase.h" +#include "cvfObject.h" +#include "cvfVector3.h" + +namespace cvf { +class ModelBasicList; +} + +class QString; +#include + +class RicTextAnnotation3dEditor : public caf::PdmUi3dObjectEditorHandle +{ + CAF_PDM_UI_3D_OBJECT_EDITOR_HEADER_INIT; + Q_OBJECT +public: + RicTextAnnotation3dEditor(); + ~RicTextAnnotation3dEditor() override; + +protected: + void configureAndUpdateUi(const QString& uiConfigName) override; + void cleanupBeforeSettingPdmObject() override; + +private slots: + void slotLabelUpdated(const cvf::Vec3d& origin, const cvf::Vec3d& dummy); + void slotAnchorUpdated(const cvf::Vec3d& origin, const cvf::Vec3d& dummy); +private: + void updatePoint(caf::PdmUiFieldHandle* uiField, const cvf::Vec3d& newPos); + + QPointer m_labelManipulator; + QPointer m_anchorManipulator; + cvf::ref m_cvfModel; +}; + + diff --git a/ApplicationCode/Commands/ApplicationCommands/CMakeLists_files.cmake b/ApplicationCode/Commands/ApplicationCommands/CMakeLists_files.cmake index 503c54c485..65f9e94ff4 100644 --- a/ApplicationCode/Commands/ApplicationCommands/CMakeLists_files.cmake +++ b/ApplicationCode/Commands/ApplicationCommands/CMakeLists_files.cmake @@ -51,3 +51,6 @@ ${QT_MOC_HEADERS} source_group( "CommandFeature\\Application" FILES ${SOURCE_GROUP_HEADER_FILES} ${SOURCE_GROUP_SOURCE_FILES} ${CMAKE_CURRENT_LIST_DIR}/CMakeLists_files.cmake ) + +# cotire +caf_cotire_start_unity_at_first_item(SOURCE_GROUP_SOURCE_FILES) diff --git a/ApplicationCode/Commands/ApplicationCommands/RicEditPreferencesFeature.cpp b/ApplicationCode/Commands/ApplicationCommands/RicEditPreferencesFeature.cpp index 08d5b8f875..ff94eeeda4 100644 --- a/ApplicationCode/Commands/ApplicationCommands/RicEditPreferencesFeature.cpp +++ b/ApplicationCode/Commands/ApplicationCommands/RicEditPreferencesFeature.cpp @@ -47,12 +47,16 @@ void RicEditPreferencesFeature::onActionTriggered(bool isChecked) RiaApplication* app = RiaApplication::instance(); QStringList tabNames = app->preferences()->tabNames(); + + std::unique_ptr oldPreferences = clonePreferences(app->preferences()); + RiuPropertyViewTabWidget propertyDialog(nullptr, app->preferences(), "Preferences", tabNames); + propertyDialog.setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); if (propertyDialog.exec() == QDialog::Accepted) { // Write preferences using QSettings and apply them to the application caf::PdmSettings::writeFieldsToApplicationStore(app->preferences()); - app->applyPreferences(); + app->applyPreferences(oldPreferences.get()); } else { @@ -68,3 +72,14 @@ void RicEditPreferencesFeature::setupActionLook(QAction* actionToSetup) { actionToSetup->setText("&Preferences..."); } + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::unique_ptr RicEditPreferencesFeature::clonePreferences(const RiaPreferences* preferences) +{ + caf::PdmObjectHandle* pdmClone = + preferences->xmlCapability()->copyByXmlSerialization(caf::PdmDefaultObjectFactory::instance()); + + return std::unique_ptr(dynamic_cast(pdmClone)); +} diff --git a/ApplicationCode/Commands/ApplicationCommands/RicEditPreferencesFeature.h b/ApplicationCode/Commands/ApplicationCommands/RicEditPreferencesFeature.h index 6b6fe56c02..f64804de4c 100644 --- a/ApplicationCode/Commands/ApplicationCommands/RicEditPreferencesFeature.h +++ b/ApplicationCode/Commands/ApplicationCommands/RicEditPreferencesFeature.h @@ -19,7 +19,9 @@ #pragma once #include "cafCmdFeature.h" +#include +class RiaPreferences; //================================================================================================== /// @@ -27,12 +29,14 @@ class RicEditPreferencesFeature : public caf::CmdFeature { CAF_CMD_HEADER_INIT; - + protected: // Overrides bool isCommandEnabled() override; void onActionTriggered( bool isChecked ) override; void setupActionLook( QAction* actionToSetup ) override; + + static std::unique_ptr clonePreferences(const RiaPreferences* preferences); }; diff --git a/ApplicationCode/Commands/ApplicationCommands/RicExitApplicationFeature.cpp b/ApplicationCode/Commands/ApplicationCommands/RicExitApplicationFeature.cpp index 24aaa0dd11..5233b6f6a1 100644 --- a/ApplicationCode/Commands/ApplicationCommands/RicExitApplicationFeature.cpp +++ b/ApplicationCode/Commands/ApplicationCommands/RicExitApplicationFeature.cpp @@ -19,8 +19,10 @@ #include "RicExitApplicationFeature.h" #include "RiaApplication.h" +#include "RiuMainWindow.h" #include +#include CAF_CMD_SOURCE_INIT(RicExitApplicationFeature, "RicExitApplicationFeature"); @@ -42,7 +44,13 @@ void RicExitApplicationFeature::onActionTriggered(bool isChecked) RiaApplication* app = RiaApplication::instance(); if (!app->askUserToSaveModifiedProject()) return; - app->closeAllWindows(); + // Hide all windows first to make sure they get closed properly + for (QWidget* topLevelWidget : app->topLevelWidgets()) + { + topLevelWidget->hide(); + } + // Close just the main window, it'll take care of closing the plot window + app->mainWindow()->close(); } //-------------------------------------------------------------------------------------------------- @@ -51,5 +59,5 @@ void RicExitApplicationFeature::onActionTriggered(bool isChecked) void RicExitApplicationFeature::setupActionLook(QAction* actionToSetup) { actionToSetup->setText("E&xit"); - actionToSetup->setShortcuts(QKeySequence::Quit); + actionToSetup->setShortcut(QKeySequence::Quit); } diff --git a/ApplicationCode/Commands/ApplicationCommands/RicHelpFeatures.cpp b/ApplicationCode/Commands/ApplicationCommands/RicHelpFeatures.cpp index 956c5b3df7..9d3d560719 100644 --- a/ApplicationCode/Commands/ApplicationCommands/RicHelpFeatures.cpp +++ b/ApplicationCode/Commands/ApplicationCommands/RicHelpFeatures.cpp @@ -1,25 +1,26 @@ ///////////////////////////////////////////////////////////////////////////////// // // Copyright (C) 2016- Statoil ASA -// +// // ResInsight 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 3 of the License, or // (at your option) any later version. -// +// // ResInsight 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 at +// +// See the GNU General Public License at // for more details. // ///////////////////////////////////////////////////////////////////////////////// #include "RicHelpFeatures.h" -#include "RiaBaseDefs.h" #include "RiaApplication.h" +#include "RiaBaseDefs.h" +#include "RiaVersionInfo.h" #include "RiuMainWindow.h" @@ -31,12 +32,12 @@ #include #include -CAF_CMD_SOURCE_INIT(RicHelpAboutFeature, "RicHelpAboutFeature"); -CAF_CMD_SOURCE_INIT(RicHelpCommandLineFeature, "RicHelpCommandLineFeature"); -CAF_CMD_SOURCE_INIT(RicHelpOpenUsersGuideFeature, "RicHelpOpenUsersGuideFeature"); +CAF_CMD_SOURCE_INIT(RicHelpAboutFeature, "RicHelpAboutFeature"); +CAF_CMD_SOURCE_INIT(RicHelpCommandLineFeature, "RicHelpCommandLineFeature"); +CAF_CMD_SOURCE_INIT(RicHelpOpenUsersGuideFeature, "RicHelpOpenUsersGuideFeature"); //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- bool RicHelpAboutFeature::isCommandEnabled() { @@ -44,7 +45,7 @@ bool RicHelpAboutFeature::isCommandEnabled() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RicHelpAboutFeature::onActionTriggered(bool isChecked) { @@ -76,7 +77,7 @@ void RicHelpAboutFeature::onActionTriggered(bool isChecked) { dlg.addVersionEntry(" ", "Features"); - for (auto feature : activeFeatures) + for (const auto& feature : activeFeatures) { dlg.addVersionEntry(" ", feature); } @@ -87,6 +88,7 @@ void RicHelpAboutFeature::onActionTriggered(bool isChecked) dlg.addVersionEntry(" ", QString(" Qt ") + qVersion()); dlg.addVersionEntry(" ", QString(" ") + caf::AboutDialog::versionStringForcurrentOpenGLContext()); dlg.addVersionEntry(" ", caf::Viewer::isShadersSupported() ? " Hardware OpenGL" : " Software OpenGL"); + dlg.addVersionEntry(" ", QString(" Octave ") + QString(RESINSIGHT_OCTAVE_VERSION)); if (RiaApplication::enableDevelopmentFeatures()) { @@ -110,7 +112,7 @@ void RicHelpAboutFeature::onActionTriggered(bool isChecked) render = str; } } - + dlg.addVersionEntry(" ", QString(" ") + vendor + " : " + render); } @@ -121,21 +123,15 @@ void RicHelpAboutFeature::onActionTriggered(bool isChecked) } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RicHelpAboutFeature::setupActionLook(QAction* actionToSetup) { actionToSetup->setText("&About"); } - - - - - - //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- bool RicHelpCommandLineFeature::isCommandEnabled() { @@ -143,32 +139,27 @@ bool RicHelpCommandLineFeature::isCommandEnabled() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RicHelpCommandLineFeature::onActionTriggered(bool isChecked) { this->disableModelChangeContribution(); - RiaApplication* app = RiaApplication::instance(); - QString text = app->commandLineParameterHelp(); + RiaApplication* app = RiaApplication::instance(); + QString text = app->commandLineParameterHelp(); app->showFormattedTextInMessageBox(text); } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RicHelpCommandLineFeature::setupActionLook(QAction* actionToSetup) { actionToSetup->setText("&Command Line Help"); } - - - - - //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- bool RicHelpOpenUsersGuideFeature::isCommandEnabled() { @@ -176,7 +167,7 @@ bool RicHelpOpenUsersGuideFeature::isCommandEnabled() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RicHelpOpenUsersGuideFeature::onActionTriggered(bool isChecked) { @@ -192,11 +183,10 @@ void RicHelpOpenUsersGuideFeature::onActionTriggered(bool isChecked) } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RicHelpOpenUsersGuideFeature::setupActionLook(QAction* actionToSetup) { actionToSetup->setText("&Users Guide"); + actionToSetup->setShortcut(QKeySequence::HelpContents); } - - diff --git a/ApplicationCode/Commands/ApplicationCommands/RicLaunchRegressionTestsFeature.cpp b/ApplicationCode/Commands/ApplicationCommands/RicLaunchRegressionTestsFeature.cpp index 3d405b3405..faaa6e4261 100644 --- a/ApplicationCode/Commands/ApplicationCommands/RicLaunchRegressionTestsFeature.cpp +++ b/ApplicationCode/Commands/ApplicationCommands/RicLaunchRegressionTestsFeature.cpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018 Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by diff --git a/ApplicationCode/Commands/ApplicationCommands/RicLaunchRegressionTestsFeature.h b/ApplicationCode/Commands/ApplicationCommands/RicLaunchRegressionTestsFeature.h index 9948adbb55..c097916a49 100644 --- a/ApplicationCode/Commands/ApplicationCommands/RicLaunchRegressionTestsFeature.h +++ b/ApplicationCode/Commands/ApplicationCommands/RicLaunchRegressionTestsFeature.h @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018 Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by diff --git a/ApplicationCode/Commands/ApplicationCommands/RicLaunchUnitTestsFeature.cpp b/ApplicationCode/Commands/ApplicationCommands/RicLaunchUnitTestsFeature.cpp index e7123bc7f1..e21f0a0a77 100644 --- a/ApplicationCode/Commands/ApplicationCommands/RicLaunchUnitTestsFeature.cpp +++ b/ApplicationCode/Commands/ApplicationCommands/RicLaunchUnitTestsFeature.cpp @@ -31,7 +31,11 @@ CAF_CMD_SOURCE_INIT(RicLaunchUnitTestsFeature, "RicLaunchUnitTestsFeature"); //-------------------------------------------------------------------------------------------------- bool RicLaunchUnitTestsFeature::isCommandEnabled() { +#ifdef USE_UNIT_TESTS return true; +#else + return false; +#endif } //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/Commands/ApplicationCommands/RicRunCommandFileFeature.cpp b/ApplicationCode/Commands/ApplicationCommands/RicRunCommandFileFeature.cpp index eff176dbfc..28d0b62490 100644 --- a/ApplicationCode/Commands/ApplicationCommands/RicRunCommandFileFeature.cpp +++ b/ApplicationCode/Commands/ApplicationCommands/RicRunCommandFileFeature.cpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018 Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by diff --git a/ApplicationCode/Commands/ApplicationCommands/RicRunCommandFileFeature.h b/ApplicationCode/Commands/ApplicationCommands/RicRunCommandFileFeature.h index be4ca628b1..6a325c07a7 100644 --- a/ApplicationCode/Commands/ApplicationCommands/RicRunCommandFileFeature.h +++ b/ApplicationCode/Commands/ApplicationCommands/RicRunCommandFileFeature.h @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018 Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by diff --git a/ApplicationCode/Commands/ApplicationCommands/RicShowMainWindowFeature.cpp b/ApplicationCode/Commands/ApplicationCommands/RicShowMainWindowFeature.cpp index 83b065e603..d397c3f775 100644 --- a/ApplicationCode/Commands/ApplicationCommands/RicShowMainWindowFeature.cpp +++ b/ApplicationCode/Commands/ApplicationCommands/RicShowMainWindowFeature.cpp @@ -62,5 +62,7 @@ void RicShowMainWindowFeature::onActionTriggered(bool isChecked) void RicShowMainWindowFeature::setupActionLook(QAction* actionToSetup) { actionToSetup->setText("Open 3D Window"); + actionToSetup->setToolTip("Open 3D Window (Ctrl+Shift+3)"); actionToSetup->setIcon(QIcon(":/3DWindow24x24.png")); + applyShortcutWithHintToAction(actionToSetup, QKeySequence(tr("Ctrl+Shift+3"))); } diff --git a/ApplicationCode/Commands/ApplicationCommands/RicShowMemoryCleanupDialogFeature.cpp b/ApplicationCode/Commands/ApplicationCommands/RicShowMemoryCleanupDialogFeature.cpp index 2c378f0ece..8bfe0f8e33 100644 --- a/ApplicationCode/Commands/ApplicationCommands/RicShowMemoryCleanupDialogFeature.cpp +++ b/ApplicationCode/Commands/ApplicationCommands/RicShowMemoryCleanupDialogFeature.cpp @@ -20,6 +20,10 @@ #include "RiaApplication.h" #include "RiaMemoryCleanup.h" + +#include "RigEclipseResultAddress.h" +#include "RigFemResultAddress.h" + #include "RiuMainWindow.h" #include "cafPdmUiPropertyViewDialog.h" diff --git a/ApplicationCode/Commands/ApplicationCommands/RicShowPlotDataFeature.cpp b/ApplicationCode/Commands/ApplicationCommands/RicShowPlotDataFeature.cpp index 9f947331c3..032cb6e252 100644 --- a/ApplicationCode/Commands/ApplicationCommands/RicShowPlotDataFeature.cpp +++ b/ApplicationCode/Commands/ApplicationCommands/RicShowPlotDataFeature.cpp @@ -20,6 +20,8 @@ #include "RiaApplication.h" +#include "RimGridCrossPlot.h" +#include "RimGridCrossPlotCurve.h" #include "RimProject.h" #include "RimSummaryCrossPlot.h" #include "RimSummaryPlot.h" @@ -28,6 +30,8 @@ #include "RiuPlotMainWindow.h" #include "RiuTextDialog.h" +#include "cafPdmPointer.h" +#include "cafProgressInfo.h" #include "cafSelectionManagerTools.h" #include @@ -35,6 +39,128 @@ CAF_CMD_SOURCE_INIT(RicShowPlotDataFeature, "RicShowPlotDataFeature"); +//-------------------------------------------------------------------------------------------------- +/// Private text provider class for summary plots +//-------------------------------------------------------------------------------------------------- +class RiuTabbedSummaryPlotTextProvider : public RiuTabbedTextProvider +{ +public: + RiuTabbedSummaryPlotTextProvider(RimSummaryPlot* summaryPlot) + : m_summaryPlot(summaryPlot) + { + } + + virtual bool isValid() const override + { + return m_summaryPlot.notNull(); + } + + QString description() const override + { + CVF_ASSERT(m_summaryPlot.notNull() && "Need to check that provider is valid"); + return m_summaryPlot->description(); + } + + QString tabTitle(int tabIndex) const override + { + auto allTabs = tabs(); + CVF_ASSERT(tabIndex < (int)allTabs.size()); + DateTimePeriod timePeriod = allTabs[tabIndex]; + if (timePeriod == DateTimePeriod::NONE) + { + return "No Resampling"; + } + else + { + return QString("Plot Data, %1").arg(RiaQDateTimeTools::dateTimePeriodName(timePeriod)); + } + } + + QString tabText(int tabIndex) const override + { + CVF_ASSERT(m_summaryPlot.notNull() && "Need to check that provider is valid"); + + DateTimePeriod timePeriod = indexToPeriod(tabIndex); + + if (m_summaryPlot->containsResamplableCurves()) + { + return m_summaryPlot->asciiDataForPlotExport(timePeriod); + } + else + { + return m_summaryPlot->asciiDataForPlotExport(); + } + } + + int tabCount() const override + { + return (int)tabs().size(); + } + +private: + static DateTimePeriod indexToPeriod(int tabIndex) + { + auto allTabs = tabs(); + CVF_ASSERT(tabIndex < (int)allTabs.size()); + DateTimePeriod timePeriod = allTabs[tabIndex]; + return timePeriod; + } + + static std::vector tabs() + { + std::vector dateTimePeriods = RiaQDateTimeTools::dateTimePeriods(); + dateTimePeriods.erase(std::remove(dateTimePeriods.begin(), dateTimePeriods.end(), DateTimePeriod::DECADE), + dateTimePeriods.end()); + return dateTimePeriods; + } + +private: + caf::PdmPointer m_summaryPlot; +}; + +//-------------------------------------------------------------------------------------------------- +/// Private text provider class for grid cross plots +//-------------------------------------------------------------------------------------------------- +class RiuTabbedGridCrossPlotTextProvider : public RiuTabbedTextProvider +{ +public: + RiuTabbedGridCrossPlotTextProvider(RimGridCrossPlot* crossPlot) + : m_crossPlot(crossPlot) + { + } + + virtual bool isValid() const override + { + return m_crossPlot.notNull(); + } + + virtual QString description() const override + { + CVF_ASSERT(m_crossPlot.notNull() && "Need to check that provider is valid"); + return m_crossPlot->createAutoName(); + } + + virtual QString tabTitle(int tabIndex) const override + { + CVF_ASSERT(m_crossPlot.notNull() && "Need to check that provider is valid"); + return m_crossPlot->asciiTitleForPlotExport(tabIndex); + } + + virtual QString tabText(int tabIndex) const override + { + CVF_ASSERT(m_crossPlot.notNull() && "Need to check that provider is valid"); + return m_crossPlot->asciiDataForPlotExport(tabIndex); + } + + virtual int tabCount() const override + { + CVF_ASSERT(m_crossPlot.notNull() && "Need to check that provider is valid"); + return (int)m_crossPlot->dataSets().size(); + } + +private: + caf::PdmPointer m_crossPlot; +}; //-------------------------------------------------------------------------------------------------- /// @@ -62,6 +188,9 @@ bool RicShowPlotDataFeature::isCommandEnabled() auto wellLogPlots = caf::selectedObjectsByType(); if (wellLogPlots.size() > 0) return true; + auto gridCrossPlots = caf::selectedObjectsByType(); + if (gridCrossPlots.size() > 0) return true; + return false; } @@ -72,10 +201,10 @@ void RicShowPlotDataFeature::onActionTriggered(bool isChecked) { this->disableModelChangeContribution(); - std::vector selectedSummaryPlots = caf::selectedObjectsByType(); - std::vector wellLogPlots = caf::selectedObjectsByType(); - - if (selectedSummaryPlots.size() == 0 && wellLogPlots.size() == 0) + std::vector selectedSummaryPlots = caf::selectedObjectsByType(); + std::vector wellLogPlots = caf::selectedObjectsByType(); + std::vector crossPlots = caf::selectedObjectsByType(); + if (selectedSummaryPlots.size() == 0 && wellLogPlots.size() == 0 && crossPlots.size() == 0) { CVF_ASSERT(false); @@ -87,26 +216,22 @@ void RicShowPlotDataFeature::onActionTriggered(bool isChecked) for (RimSummaryPlot* summaryPlot : selectedSummaryPlots) { - QString title = summaryPlot->description(); - - if (summaryPlot->containsResamplableCurves()) - { - RicShowPlotDataFeature::showTabbedTextWindow(title, [summaryPlot](DateTimePeriod period) { return summaryPlot->asciiDataForPlotExport(period); }); - } - else - { - QString text = summaryPlot->asciiDataForPlotExport(); - RicShowPlotDataFeature::showTextWindow(title, text); - } + auto textProvider = new RiuTabbedSummaryPlotTextProvider(summaryPlot); + RicShowPlotDataFeature::showTabbedTextWindow(textProvider); } for (RimWellLogPlot* wellLogPlot : wellLogPlots) { QString title = wellLogPlot->description(); QString text = wellLogPlot->asciiDataForPlotExport(); - RicShowPlotDataFeature::showTextWindow(title, text); } + + for (RimGridCrossPlot* crossPlot : crossPlots) + { + auto textProvider = new RiuTabbedGridCrossPlotTextProvider(crossPlot); + RicShowPlotDataFeature::showTabbedTextWindow(textProvider); + } } //-------------------------------------------------------------------------------------------------- @@ -118,25 +243,19 @@ void RicShowPlotDataFeature::setupActionLook(QAction* actionToSetup) actionToSetup->setIcon(QIcon(":/PlotWindow24x24.png")); } - //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RicShowPlotDataFeature::showTabbedTextWindow(const QString& title, std::function textProvider) +void RicShowPlotDataFeature::showTabbedTextWindow(RiuTabbedTextProvider* textProvider) { RiuPlotMainWindow* plotwindow = RiaApplication::instance()->mainPlotWindow(); CVF_ASSERT(plotwindow); - RiuShowTabbedPlotDataDialog* textWiget = new RiuShowTabbedPlotDataDialog(); - textWiget->setMinimumSize(800, 600); - - textWiget->setWindowTitle(title); - textWiget->setDescription(title); - textWiget->setTextProvider(textProvider); - - textWiget->show(); - - plotwindow->addToTemporaryWidgets(textWiget); + RiuTabbedTextDialog* textWidget = new RiuTabbedTextDialog(textProvider); + textWidget->setMinimumSize(800, 600); + plotwindow->addToTemporaryWidgets(textWidget); + textWidget->show(); + textWidget->redrawText(); } //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/Commands/ApplicationCommands/RicShowPlotDataFeature.h b/ApplicationCode/Commands/ApplicationCommands/RicShowPlotDataFeature.h index 27284bcdfd..a36fde06f8 100644 --- a/ApplicationCode/Commands/ApplicationCommands/RicShowPlotDataFeature.h +++ b/ApplicationCode/Commands/ApplicationCommands/RicShowPlotDataFeature.h @@ -24,6 +24,8 @@ #include +class RiuTabbedTextProvider; + //================================================================================================== /// //================================================================================================== @@ -38,7 +40,7 @@ class RicShowPlotDataFeature : public caf::CmdFeature void setupActionLook( QAction* actionToSetup ) override; public: - static void showTabbedTextWindow(const QString& title, std::function textProvider); + static void showTabbedTextWindow(RiuTabbedTextProvider* textProvider); static void showTextWindow(const QString& title, const QString& text); }; diff --git a/ApplicationCode/Commands/ApplicationCommands/RicShowPlotWindowFeature.cpp b/ApplicationCode/Commands/ApplicationCommands/RicShowPlotWindowFeature.cpp index 62085d6b09..92f6ca31f8 100644 --- a/ApplicationCode/Commands/ApplicationCommands/RicShowPlotWindowFeature.cpp +++ b/ApplicationCode/Commands/ApplicationCommands/RicShowPlotWindowFeature.cpp @@ -48,5 +48,7 @@ void RicShowPlotWindowFeature::onActionTriggered(bool isChecked) void RicShowPlotWindowFeature::setupActionLook(QAction* actionToSetup) { actionToSetup->setText("Open Plot Window"); + actionToSetup->setToolTip("Open Plot Window (Ctrl+Shift+P)"); actionToSetup->setIcon(QIcon(":/PlotWindow24x24.png")); + applyShortcutWithHintToAction(actionToSetup, QKeySequence(tr("Ctrl+Shift+P"))); } diff --git a/ApplicationCode/Commands/ApplicationCommands/RicTileWindowsFeature.cpp b/ApplicationCode/Commands/ApplicationCommands/RicTileWindowsFeature.cpp index ea57db2541..fb105f5fb1 100644 --- a/ApplicationCode/Commands/ApplicationCommands/RicTileWindowsFeature.cpp +++ b/ApplicationCode/Commands/ApplicationCommands/RicTileWindowsFeature.cpp @@ -52,7 +52,14 @@ void RicTileWindowsFeature::onActionTriggered(bool isChecked) RiuMainWindow* mainWindow = RiuMainWindow::instance(); if (mainWindow) { - mainWindow->tileWindows(); + if (!mainWindow->subWindowsAreTiled()) + { + mainWindow->tileSubWindows(); + } + else + { + mainWindow->clearWindowTiling(); + } } } @@ -63,10 +70,23 @@ void RicTileWindowsFeature::setupActionLook(QAction* actionToSetup) { actionToSetup->setText("Tile Windows"); actionToSetup->setIcon(QIcon(":/TileWindows24x24.png")); + actionToSetup->setCheckable(true); } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RicTileWindowsFeature::isCommandChecked() +{ + if (RiaApplication::instance()->mainWindow()) + { + return RiaApplication::instance()->mainWindow()->subWindowsAreTiled(); + } + return false; +} + CAF_CMD_SOURCE_INIT(RicTilePlotWindowsFeature, "RicTilePlotWindowsFeature"); //-------------------------------------------------------------------------------------------------- @@ -91,7 +111,14 @@ void RicTilePlotWindowsFeature::onActionTriggered(bool isChecked) RiuPlotMainWindow* mainPlotWindow = RiaApplication::instance()->mainPlotWindow(); if (mainPlotWindow) { - mainPlotWindow->tileWindows(); + if (!mainPlotWindow->subWindowsAreTiled()) + { + mainPlotWindow->tileSubWindows(); + } + else + { + mainPlotWindow->clearWindowTiling(); + } } } @@ -102,4 +129,17 @@ void RicTilePlotWindowsFeature::setupActionLook(QAction* actionToSetup) { actionToSetup->setText("Tile Windows"); actionToSetup->setIcon(QIcon(":/TileWindows24x24.png")); + actionToSetup->setCheckable(true); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RicTilePlotWindowsFeature::isCommandChecked() +{ + if (RiaApplication::instance()->mainPlotWindow()) + { + return RiaApplication::instance()->mainPlotWindow()->subWindowsAreTiled(); + } + return false; } diff --git a/ApplicationCode/Commands/ApplicationCommands/RicTileWindowsFeature.h b/ApplicationCode/Commands/ApplicationCommands/RicTileWindowsFeature.h index b698ed32ad..f159635929 100644 --- a/ApplicationCode/Commands/ApplicationCommands/RicTileWindowsFeature.h +++ b/ApplicationCode/Commands/ApplicationCommands/RicTileWindowsFeature.h @@ -34,6 +34,8 @@ class RicTileWindowsFeature : public caf::CmdFeature bool isCommandEnabled() override; void onActionTriggered( bool isChecked ) override; void setupActionLook( QAction* actionToSetup ) override; + bool isCommandChecked() override; + }; //================================================================================================== @@ -48,5 +50,6 @@ class RicTilePlotWindowsFeature : public caf::CmdFeature bool isCommandEnabled() override; void onActionTriggered(bool isChecked) override; void setupActionLook(QAction* actionToSetup) override; + bool isCommandChecked() override; }; diff --git a/ApplicationCode/Commands/CMakeLists_files.cmake b/ApplicationCode/Commands/CMakeLists_files.cmake index 51078ac36c..bbabfd08b5 100644 --- a/ApplicationCode/Commands/CMakeLists_files.cmake +++ b/ApplicationCode/Commands/CMakeLists_files.cmake @@ -42,12 +42,15 @@ ${CMAKE_CURRENT_LIST_DIR}/RicImportSummaryCaseFeature.h ${CMAKE_CURRENT_LIST_DIR}/RicImportSummaryCasesFeature.h ${CMAKE_CURRENT_LIST_DIR}/RicImportObservedDataFeature.h ${CMAKE_CURRENT_LIST_DIR}/RicImportObservedDataInMenuFeature.h +${CMAKE_CURRENT_LIST_DIR}/RicImportGeneralDataFeature.h ${CMAKE_CURRENT_LIST_DIR}/RicExportFeatureImpl.h ${CMAKE_CURRENT_LIST_DIR}/RicSelectOrCreateViewFeatureImpl.h ${CMAKE_CURRENT_LIST_DIR}/RicPickEventHandler.h +${CMAKE_CURRENT_LIST_DIR}/Ric3dViewPickEventHandler.h ${CMAKE_CURRENT_LIST_DIR}/RicContourMapPickEventHandler.h +${CMAKE_CURRENT_LIST_DIR}/RicVec3dPickEventHandler.h # General delete of any object in a child array field ${CMAKE_CURRENT_LIST_DIR}/RicDeleteItemExec.h @@ -119,11 +122,14 @@ ${CMAKE_CURRENT_LIST_DIR}/RicImportSummaryCaseFeature.cpp ${CMAKE_CURRENT_LIST_DIR}/RicImportSummaryCasesFeature.cpp ${CMAKE_CURRENT_LIST_DIR}/RicImportObservedDataFeature.cpp ${CMAKE_CURRENT_LIST_DIR}/RicImportObservedDataInMenuFeature.cpp +${CMAKE_CURRENT_LIST_DIR}/RicImportGeneralDataFeature.cpp ${CMAKE_CURRENT_LIST_DIR}/RicExportFeatureImpl.cpp ${CMAKE_CURRENT_LIST_DIR}/RicSelectOrCreateViewFeatureImpl.cpp +${CMAKE_CURRENT_LIST_DIR}/Ric3dViewPickEventHandler.cpp ${CMAKE_CURRENT_LIST_DIR}/RicContourMapPickEventHandler.cpp +${CMAKE_CURRENT_LIST_DIR}/RicVec3dPickEventHandler.cpp # General delete of any object in a child array field ${CMAKE_CURRENT_LIST_DIR}/RicDeleteItemExec.cpp diff --git a/ApplicationCode/Commands/CompletionCommands/CMakeLists_files.cmake b/ApplicationCode/Commands/CompletionCommands/CMakeLists_files.cmake index 066c63754f..a2cf995e2f 100644 --- a/ApplicationCode/Commands/CompletionCommands/CMakeLists_files.cmake +++ b/ApplicationCode/Commands/CompletionCommands/CMakeLists_files.cmake @@ -7,6 +7,9 @@ ${CMAKE_CURRENT_LIST_DIR}/RicNewFishbonesSubsFeature.h ${CMAKE_CURRENT_LIST_DIR}/RicNewPerforationIntervalFeature.h ${CMAKE_CURRENT_LIST_DIR}/RicNewPerforationIntervalAtMeasuredDepthFeature.h ${CMAKE_CURRENT_LIST_DIR}/RicNewValveFeature.h +${CMAKE_CURRENT_LIST_DIR}/RicNewValveTemplateFeature.h +${CMAKE_CURRENT_LIST_DIR}/RicNewValveAtMeasuredDepthFeature.h +${CMAKE_CURRENT_LIST_DIR}/RicDeleteValveTemplateFeature.h ${CMAKE_CURRENT_LIST_DIR}/RicWellPathImportCompletionsFileFeature.h ${CMAKE_CURRENT_LIST_DIR}/RicWellPathImportPerforationIntervalsFeature.h ) @@ -19,6 +22,9 @@ ${CMAKE_CURRENT_LIST_DIR}/RicNewFishbonesSubsFeature.cpp ${CMAKE_CURRENT_LIST_DIR}/RicNewPerforationIntervalFeature.cpp ${CMAKE_CURRENT_LIST_DIR}/RicNewPerforationIntervalAtMeasuredDepthFeature.cpp ${CMAKE_CURRENT_LIST_DIR}/RicNewValveFeature.cpp +${CMAKE_CURRENT_LIST_DIR}/RicNewValveTemplateFeature.cpp +${CMAKE_CURRENT_LIST_DIR}/RicNewValveAtMeasuredDepthFeature.cpp +${CMAKE_CURRENT_LIST_DIR}/RicDeleteValveTemplateFeature.cpp ${CMAKE_CURRENT_LIST_DIR}/RicWellPathImportCompletionsFileFeature.cpp ${CMAKE_CURRENT_LIST_DIR}/RicWellPathImportPerforationIntervalsFeature.cpp ) @@ -33,3 +39,6 @@ ${SOURCE_GROUP_SOURCE_FILES} ) source_group( "CommandFeature\\Completion" FILES ${SOURCE_GROUP_HEADER_FILES} ${SOURCE_GROUP_SOURCE_FILES} ${CMAKE_CURRENT_LIST_DIR}/CMakeLists_files.cmake ) + +# cotire +caf_cotire_start_unity_at_first_item(SOURCE_GROUP_SOURCE_FILES) diff --git a/ApplicationCode/Commands/CompletionCommands/RicDeleteValveTemplateFeature.cpp b/ApplicationCode/Commands/CompletionCommands/RicDeleteValveTemplateFeature.cpp new file mode 100644 index 0000000000..11cd4f6aa6 --- /dev/null +++ b/ApplicationCode/Commands/CompletionCommands/RicDeleteValveTemplateFeature.cpp @@ -0,0 +1,83 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2019- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// +#include "RicDeleteValveTemplateFeature.h" + +#include "RimProject.h" +#include "RimValveTemplate.h" +#include "RimValveTemplateCollection.h" +#include "RimWellPathValve.h" + +#include "cafSelectionManager.h" + +#include + +CAF_CMD_SOURCE_INIT(RicDeleteValveTemplateFeature, "RicDeleteValveTemplateFeature"); + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RicDeleteValveTemplateFeature::isCommandEnabled() +{ + if (caf::SelectionManager::instance()->selectedItemOfType()) + { + return true; + } + return false; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicDeleteValveTemplateFeature::onActionTriggered(bool isChecked) +{ + RimValveTemplate* valveTemplate = caf::SelectionManager::instance()->selectedItemOfType(); + + if (valveTemplate) + { + RimProject* project = nullptr; + valveTemplate->firstAncestorOrThisOfTypeAsserted(project); + std::vector valves; + project->descendantsIncludingThisOfType(valves); + for (RimWellPathValve* valve : valves) + { + if (valve->valveTemplate() == valveTemplate) + { + valve->setValveTemplate(nullptr); + valve->updateAllRequiredEditors(); + } + } + + RimValveTemplateCollection* collection = nullptr; + valveTemplate->firstAncestorOrThisOfTypeAsserted(collection); + collection->removeAndDeleteValveTemplate(valveTemplate); + collection->updateAllRequiredEditors(); + + project->scheduleCreateDisplayModelAndRedrawAllViews(); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicDeleteValveTemplateFeature::setupActionLook(QAction* actionToSetup) +{ + actionToSetup->setText("Delete Valve Template"); + actionToSetup->setIcon(QIcon(":/Erase.png")); + applyShortcutWithHintToAction(actionToSetup, QKeySequence::Delete); +} + diff --git a/ApplicationCode/Commands/CompletionCommands/RicDeleteValveTemplateFeature.h b/ApplicationCode/Commands/CompletionCommands/RicDeleteValveTemplateFeature.h new file mode 100644 index 0000000000..caed93c6d5 --- /dev/null +++ b/ApplicationCode/Commands/CompletionCommands/RicDeleteValveTemplateFeature.h @@ -0,0 +1,35 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2019- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "cafCmdFeature.h" + +//================================================================================================== +/// +//================================================================================================== +class RicDeleteValveTemplateFeature : public caf::CmdFeature +{ + CAF_CMD_HEADER_INIT; + +protected: + // Overrides + bool isCommandEnabled() override; + void onActionTriggered(bool isChecked) override; + void setupActionLook(QAction* actionToSetup) override; +}; diff --git a/ApplicationCode/Commands/CompletionCommands/RicNewFishbonesSubsAtMeasuredDepthFeature.cpp b/ApplicationCode/Commands/CompletionCommands/RicNewFishbonesSubsAtMeasuredDepthFeature.cpp index 218993877b..f25c7fde41 100644 --- a/ApplicationCode/Commands/CompletionCommands/RicNewFishbonesSubsAtMeasuredDepthFeature.cpp +++ b/ApplicationCode/Commands/CompletionCommands/RicNewFishbonesSubsAtMeasuredDepthFeature.cpp @@ -27,7 +27,7 @@ #include "RimWellPath.h" #include "Riu3DMainWindowTools.h" -#include "RiuSelectionManager.h" +#include "Riu3dSelectionManager.h" #include "cafSelectionManager.h" @@ -70,8 +70,8 @@ void RicNewFishbonesSubsAtMeasuredDepthFeature::onActionTriggered(bool isChecked //-------------------------------------------------------------------------------------------------- RiuWellPathSelectionItem* RicNewFishbonesSubsAtMeasuredDepthFeature::wellPathSelectionItem() { - RiuSelectionManager* riuSelManager = RiuSelectionManager::instance(); - RiuSelectionItem* selItem = riuSelManager->selectedItem(RiuSelectionManager::RUI_TEMPORARY); + Riu3dSelectionManager* riuSelManager = Riu3dSelectionManager::instance(); + RiuSelectionItem* selItem = riuSelManager->selectedItem(Riu3dSelectionManager::RUI_TEMPORARY); RiuWellPathSelectionItem* wellPathItem = dynamic_cast(selItem); @@ -84,7 +84,7 @@ RiuWellPathSelectionItem* RicNewFishbonesSubsAtMeasuredDepthFeature::wellPathSel void RicNewFishbonesSubsAtMeasuredDepthFeature::setupActionLook(QAction* actionToSetup) { actionToSetup->setIcon(QIcon(":/FishBoneGroup16x16.png")); - actionToSetup->setText("New Fishbones"); + actionToSetup->setText("Create Fishbones at this Depth"); } //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/Commands/CompletionCommands/RicNewFishbonesSubsFeature.cpp b/ApplicationCode/Commands/CompletionCommands/RicNewFishbonesSubsFeature.cpp index ef7007617e..36119f3609 100644 --- a/ApplicationCode/Commands/CompletionCommands/RicNewFishbonesSubsFeature.cpp +++ b/ApplicationCode/Commands/CompletionCommands/RicNewFishbonesSubsFeature.cpp @@ -30,6 +30,7 @@ #include "RimFishbonesMultipleSubs.h" #include "Rim3dView.h" #include "RimWellPathCollection.h" +#include "RimWellPathCompletions.h" #include "RiuMainWindow.h" @@ -94,9 +95,13 @@ void RicNewFishbonesSubsFeature::onActionTriggered(bool isChecked) //-------------------------------------------------------------------------------------------------- RimFishbonesCollection* RicNewFishbonesSubsFeature::selectedFishbonesCollection() { + std::vector allSelectedItems; + caf::SelectionManager::instance()->selectedItems(allSelectedItems); + if (allSelectedItems.size() != 1u) return nullptr; + RimFishbonesCollection* objToFind = nullptr; - caf::PdmUiItem* pdmUiItem = caf::SelectionManager::instance()->selectedItem(); + caf::PdmUiItem* pdmUiItem = allSelectedItems.front(); caf::PdmObjectHandle* objHandle = dynamic_cast(pdmUiItem); if (objHandle) @@ -112,6 +117,11 @@ RimFishbonesCollection* RicNewFishbonesSubsFeature::selectedFishbonesCollection( { return wellPaths[0]->fishbonesCollection(); } + RimWellPathCompletions* completions = caf::SelectionManager::instance()->selectedItemOfType(); + if (completions) + { + return completions->fishbonesCollection(); + } } return objToFind; @@ -123,7 +133,7 @@ RimFishbonesCollection* RicNewFishbonesSubsFeature::selectedFishbonesCollection( void RicNewFishbonesSubsFeature::setupActionLook(QAction* actionToSetup) { actionToSetup->setIcon(QIcon(":/FishBoneGroup16x16.png")); - actionToSetup->setText("New Fishbones"); + actionToSetup->setText("Create Fishbones"); } //-------------------------------------------------------------------------------------------------- @@ -189,6 +199,7 @@ void RicNewFishbonesSubsFeature::askUserToSetUsefulScaling(RimFishbonesCollectio { activeView->setScaleZAndUpdate(1.0); activeView->scheduleCreateDisplayModelAndRedraw(); + activeView->updateZScaleLabel(); RiuMainWindow::instance()->updateScaleValue(); } diff --git a/ApplicationCode/Commands/CompletionCommands/RicNewPerforationIntervalAtMeasuredDepthFeature.cpp b/ApplicationCode/Commands/CompletionCommands/RicNewPerforationIntervalAtMeasuredDepthFeature.cpp index eb61d16f4b..0ed62e44dc 100644 --- a/ApplicationCode/Commands/CompletionCommands/RicNewPerforationIntervalAtMeasuredDepthFeature.cpp +++ b/ApplicationCode/Commands/CompletionCommands/RicNewPerforationIntervalAtMeasuredDepthFeature.cpp @@ -28,7 +28,7 @@ #include "RimWellPathCollection.h" #include "Riu3DMainWindowTools.h" -#include "RiuSelectionManager.h" +#include "Riu3dSelectionManager.h" #include "cafSelectionManager.h" @@ -70,8 +70,8 @@ void RicNewPerforationIntervalAtMeasuredDepthFeature::onActionTriggered(bool isC //-------------------------------------------------------------------------------------------------- RiuWellPathSelectionItem* RicNewPerforationIntervalAtMeasuredDepthFeature::wellPathSelectionItem() { - RiuSelectionManager* riuSelManager = RiuSelectionManager::instance(); - RiuSelectionItem* selItem = riuSelManager->selectedItem(RiuSelectionManager::RUI_TEMPORARY); + Riu3dSelectionManager* riuSelManager = Riu3dSelectionManager::instance(); + RiuSelectionItem* selItem = riuSelManager->selectedItem(Riu3dSelectionManager::RUI_TEMPORARY); RiuWellPathSelectionItem* wellPathItem = dynamic_cast(selItem); @@ -83,8 +83,8 @@ RiuWellPathSelectionItem* RicNewPerforationIntervalAtMeasuredDepthFeature::wellP //-------------------------------------------------------------------------------------------------- void RicNewPerforationIntervalAtMeasuredDepthFeature::setupActionLook(QAction* actionToSetup) { - //actionToSetup->setIcon(QIcon(":/FractureSymbol16x16.png")); - actionToSetup->setText("New Perforation Interval"); + actionToSetup->setIcon(QIcon(":/PerforationIntervals16x16.png")); + actionToSetup->setText("Create Perforation Interval at this Depth"); } //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/Commands/CompletionCommands/RicNewPerforationIntervalFeature.cpp b/ApplicationCode/Commands/CompletionCommands/RicNewPerforationIntervalFeature.cpp index 6a66b7a196..df153caca5 100644 --- a/ApplicationCode/Commands/CompletionCommands/RicNewPerforationIntervalFeature.cpp +++ b/ApplicationCode/Commands/CompletionCommands/RicNewPerforationIntervalFeature.cpp @@ -26,6 +26,7 @@ #include "RimPerforationInterval.h" #include "RimPerforationCollection.h" #include "RimWellPathCollection.h" +#include "RimWellPathCompletions.h" #include "cafSelectionManager.h" @@ -75,33 +76,36 @@ void RicNewPerforationIntervalFeature::onActionTriggered(bool isChecked) void RicNewPerforationIntervalFeature::setupActionLook(QAction* actionToSetup) { actionToSetup->setIcon(QIcon(":/PerforationInterval16x16.png")); - actionToSetup->setText("New Perforation Interval"); + actionToSetup->setText("Create Perforation Interval"); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- RimPerforationCollection* RicNewPerforationIntervalFeature::selectedPerforationCollection() -{ - RimPerforationCollection* objToFind = nullptr; - - caf::PdmUiItem* pdmUiItem = caf::SelectionManager::instance()->selectedItem(); +{ + std::vector selectedItems; + caf::SelectionManager::instance()->selectedItems(selectedItems); + if (selectedItems.size() != 1u) return nullptr; + + caf::PdmUiItem* pdmUiItem = selectedItems.front(); + RimPerforationCollection* perforationCollection = nullptr; caf::PdmObjectHandle* objHandle = dynamic_cast(pdmUiItem); if (objHandle) { - objHandle->firstAncestorOrThisOfType(objToFind); - } - - if (objToFind == nullptr) - { - std::vector wellPaths; - caf::SelectionManager::instance()->objectsByType(&wellPaths); - if (!wellPaths.empty()) - { - return wellPaths[0]->perforationIntervalCollection(); - } + objHandle->firstAncestorOrThisOfType(perforationCollection); + + if (perforationCollection) + return perforationCollection; + + RimWellPath* wellPath = dynamic_cast(objHandle); + if (wellPath) + return wellPath->perforationIntervalCollection(); + + RimWellPathCompletions* completions = caf::SelectionManager::instance()->selectedItemOfType(); + if (completions) + return completions->perforationCollection(); } - - return objToFind; + return nullptr; } diff --git a/ApplicationCode/Commands/CompletionCommands/RicNewValveAtMeasuredDepthFeature.cpp b/ApplicationCode/Commands/CompletionCommands/RicNewValveAtMeasuredDepthFeature.cpp new file mode 100644 index 0000000000..df96c1130d --- /dev/null +++ b/ApplicationCode/Commands/CompletionCommands/RicNewValveAtMeasuredDepthFeature.cpp @@ -0,0 +1,114 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2019- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// +#include "RicNewValveAtMeasuredDepthFeature.h" + +#include "WellPathCommands/RicWellPathsUnitSystemSettingsImpl.h" + +#include "RimFishbonesMultipleSubs.h" +#include "RimPerforationCollection.h" +#include "RimPerforationInterval.h" +#include "RimProject.h" +#include "RimWellPath.h" +#include "RimWellPathCollection.h" +#include "RimWellPathValve.h" + +#include "Riu3DMainWindowTools.h" +#include "Riu3dSelectionManager.h" + +#include "cafSelectionManager.h" + +#include + +CAF_CMD_SOURCE_INIT(RicNewValveAtMeasuredDepthFeature, "RicNewValveAtMeasuredDepthFeature"); + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicNewValveAtMeasuredDepthFeature::onActionTriggered(bool isChecked) +{ + RiuWellPathSelectionItem* wellPathSelItem = wellPathSelectionItem(); + CVF_ASSERT(wellPathSelItem); + + RimWellPath* wellPath = wellPathSelItem->m_wellpath; + CVF_ASSERT(wellPath); + + if (!RicWellPathsUnitSystemSettingsImpl::ensureHasUnitSystem(wellPath)) return; + + RimPerforationInterval* perfInterval = dynamic_cast(wellPathSelItem->m_wellPathComponent); + double measuredDepth = wellPathSelItem->m_measuredDepth; + + RimWellPathValve* valve = new RimWellPathValve; + + std::vector existingValves = perfInterval->valves(); + valve->setName(QString("Valve #%1").arg(existingValves.size() + 1)); + + RimProject* project; + perfInterval->firstAncestorOrThisOfTypeAsserted(project); + + std::vector allValveTemplates = project->allValveTemplates(); + if (!allValveTemplates.empty()) + { + valve->setValveTemplate(allValveTemplates.front()); + } + perfInterval->addValve(valve); + valve->setMeasuredDepthAndCount(measuredDepth, perfInterval->endMD() - measuredDepth, 1); + + RimWellPathCollection* wellPathCollection = nullptr; + wellPath->firstAncestorOrThisOfTypeAsserted(wellPathCollection); + + wellPathCollection->uiCapability()->updateConnectedEditors(); + wellPathCollection->scheduleRedrawAffectedViews(); + + Riu3DMainWindowTools::selectAsCurrentItem(valve); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicNewValveAtMeasuredDepthFeature::setupActionLook(QAction* actionToSetup) +{ + actionToSetup->setIcon(QIcon(":/ICDValve16x16.png")); + actionToSetup->setText("Create Valve at this Depth"); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RicNewValveAtMeasuredDepthFeature::isCommandEnabled() +{ + if (wellPathSelectionItem() && dynamic_cast(wellPathSelectionItem()->m_wellPathComponent)) + { + return true; + } + + return false; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RiuWellPathSelectionItem* RicNewValveAtMeasuredDepthFeature::wellPathSelectionItem() +{ + Riu3dSelectionManager* riuSelManager = Riu3dSelectionManager::instance(); + RiuSelectionItem* selItem = riuSelManager->selectedItem(Riu3dSelectionManager::RUI_TEMPORARY); + + RiuWellPathSelectionItem* wellPathItem = dynamic_cast(selItem); + + return wellPathItem; +} + diff --git a/ApplicationCode/Commands/CompletionCommands/RicNewValveAtMeasuredDepthFeature.h b/ApplicationCode/Commands/CompletionCommands/RicNewValveAtMeasuredDepthFeature.h new file mode 100644 index 0000000000..4736324b40 --- /dev/null +++ b/ApplicationCode/Commands/CompletionCommands/RicNewValveAtMeasuredDepthFeature.h @@ -0,0 +1,42 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2019- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + + +#include "cafCmdFeature.h" + +class RiuWellPathSelectionItem; + +//================================================================================================== +/// +//================================================================================================== +class RicNewValveAtMeasuredDepthFeature : public caf::CmdFeature +{ + CAF_CMD_HEADER_INIT; + +protected: + void onActionTriggered(bool isChecked) override; + void setupActionLook(QAction* actionToSetup) override; + bool isCommandEnabled() override; + +private: + static RiuWellPathSelectionItem* wellPathSelectionItem(); +}; + + diff --git a/ApplicationCode/Commands/CompletionCommands/RicNewValveFeature.cpp b/ApplicationCode/Commands/CompletionCommands/RicNewValveFeature.cpp index 6dbf2e4c53..078a9f68ad 100644 --- a/ApplicationCode/Commands/CompletionCommands/RicNewValveFeature.cpp +++ b/ApplicationCode/Commands/CompletionCommands/RicNewValveFeature.cpp @@ -3,6 +3,7 @@ #include "RiaApplication.h" #include "RimPerforationInterval.h" +#include "RimProject.h" #include "RimWellPathValve.h" #include "RimWellPathCollection.h" @@ -17,8 +18,12 @@ CAF_CMD_SOURCE_INIT(RicNewValveFeature, "RicNewValveFeature"); //-------------------------------------------------------------------------------------------------- bool RicNewValveFeature::isCommandEnabled() { - const RimPerforationInterval* perfInterval = caf::SelectionManager::instance()->selectedItemOfType(); - return perfInterval != nullptr && RiaApplication::enableDevelopmentFeatures(); + std::vector allSelectedItems; + caf::SelectionManager::instance()->selectedItems(allSelectedItems); + if (allSelectedItems.size() != 1u) return false; + + const RimPerforationInterval* perfInterval = dynamic_cast(allSelectedItems.front()); + return perfInterval != nullptr; } //-------------------------------------------------------------------------------------------------- @@ -30,6 +35,19 @@ void RicNewValveFeature::onActionTriggered(bool isChecked) if (perfInterval) { RimWellPathValve* valve = new RimWellPathValve; + + RimProject* project = nullptr; + perfInterval->firstAncestorOrThisOfTypeAsserted(project); + + std::vector existingValves = perfInterval->valves(); + valve->setName(QString("Valve #%1").arg(existingValves.size() + 1)); + + std::vector allValveTemplates = project->allValveTemplates(); + if (!allValveTemplates.empty()) + { + valve->setValveTemplate(allValveTemplates.front()); + } + perfInterval->addValve(valve); valve->setMeasuredDepthAndCount(perfInterval->startMD(), perfInterval->endMD() - perfInterval->startMD(), 1); @@ -51,5 +69,5 @@ void RicNewValveFeature::onActionTriggered(bool isChecked) void RicNewValveFeature::setupActionLook(QAction* actionToSetup) { actionToSetup->setIcon(QIcon(":/ICDValve16x16.png")); - actionToSetup->setText("New Valve"); + actionToSetup->setText("Create Valve"); } diff --git a/ApplicationCode/Commands/CompletionCommands/RicNewValveTemplateFeature.cpp b/ApplicationCode/Commands/CompletionCommands/RicNewValveTemplateFeature.cpp new file mode 100644 index 0000000000..aea3fa3cde --- /dev/null +++ b/ApplicationCode/Commands/CompletionCommands/RicNewValveTemplateFeature.cpp @@ -0,0 +1,133 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2016- Statoil ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "RicNewValveTemplateFeature.h" + +#include "RiaApplication.h" + +#include "RimEclipseView.h" +#include "RimValveTemplate.h" +#include "RimValveTemplateCollection.h" +#include "RimOilField.h" +#include "RimProject.h" +#include "RimWellPathValve.h" + +#include "Riu3DMainWindowTools.h" + +#include "cafSelectionManager.h" + +#include "cvfAssert.h" + +#include + +CAF_CMD_SOURCE_INIT(RicNewValveTemplateFeature, "RicNewValveTemplateFeature"); + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicNewValveTemplateFeature::selectValveTemplateAndUpdate(RimValveTemplate* valveTemplate) +{ + valveTemplate->loadDataAndUpdate(); + + RimValveTemplateCollection* templateCollection = nullptr; + valveTemplate->firstAncestorOrThisOfType(templateCollection); + if (templateCollection) + { + templateCollection->updateConnectedEditors(); + } + + RimProject* project = RiaApplication::instance()->project(); + + std::vector views; + project->allVisibleViews(views); + + for (Rim3dView* view : views) + { + if (dynamic_cast(view)) + { + view->updateConnectedEditors(); + } + } + + Riu3DMainWindowTools::selectAsCurrentItem(valveTemplate); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicNewValveTemplateFeature::createNewValveTemplateForValveAndUpdate(RimWellPathValve* valve) +{ + RimValveTemplate* valveTemplate = createNewValveTemplate(); + valve->setValveTemplate(valveTemplate); + selectValveTemplateAndUpdate(valveTemplate); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimValveTemplate* RicNewValveTemplateFeature::createNewValveTemplate() +{ + RimProject* project = RiaApplication::instance()->project(); + CVF_ASSERT(project); + + RimOilField* oilfield = project->activeOilField(); + if (oilfield == nullptr) return nullptr; + + RimValveTemplateCollection* valveTemplateColl = oilfield->valveTemplateCollection(); + + if (valveTemplateColl) + { + RimValveTemplate* valveTemplate = new RimValveTemplate(); + QString userLabel = QString("Valve Template #%1").arg(valveTemplateColl->valveTemplates().size() + 1); + valveTemplate->setUserLabel(userLabel); + valveTemplateColl->addValveTemplate(valveTemplate); + valveTemplate->setUnitSystem(valveTemplateColl->defaultUnitSystemType()); + valveTemplate->setDefaultValuesFromUnits(); + return valveTemplate; + } + return nullptr; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicNewValveTemplateFeature::onActionTriggered(bool isChecked) +{ + RimValveTemplate* valveTemplate = createNewValveTemplate(); + if (valveTemplate) + { + selectValveTemplateAndUpdate(valveTemplate); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicNewValveTemplateFeature::setupActionLook(QAction* actionToSetup) +{ + actionToSetup->setIcon(QIcon(":/ICDValve16x16.png")); + actionToSetup->setText("New Valve Template"); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RicNewValveTemplateFeature::isCommandEnabled() +{ + return true; +} diff --git a/ApplicationCode/Commands/CompletionCommands/RicNewValveTemplateFeature.h b/ApplicationCode/Commands/CompletionCommands/RicNewValveTemplateFeature.h new file mode 100644 index 0000000000..fa2aa61480 --- /dev/null +++ b/ApplicationCode/Commands/CompletionCommands/RicNewValveTemplateFeature.h @@ -0,0 +1,44 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2018- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "cafCmdFeature.h" + +#include + +class RimValveTemplate; +class RimValveTemplateCollection; +class RimWellPathValve; + +//================================================================================================== +/// +//================================================================================================== +class RicNewValveTemplateFeature : public caf::CmdFeature +{ + CAF_CMD_HEADER_INIT; + +public: + static void selectValveTemplateAndUpdate(RimValveTemplate* valveTemplate); + static void createNewValveTemplateForValveAndUpdate(RimWellPathValve* valve); +protected: + static RimValveTemplate* createNewValveTemplate(); + void onActionTriggered(bool isChecked) override; + void setupActionLook(QAction* actionToSetup) override; + bool isCommandEnabled() override; +}; diff --git a/ApplicationCode/Commands/CompletionExportCommands/CMakeLists_files.cmake b/ApplicationCode/Commands/CompletionExportCommands/CMakeLists_files.cmake index 8fb0094b74..a481bb6bcc 100644 --- a/ApplicationCode/Commands/CompletionExportCommands/CMakeLists_files.cmake +++ b/ApplicationCode/Commands/CompletionExportCommands/CMakeLists_files.cmake @@ -3,14 +3,19 @@ set (SOURCE_GROUP_HEADER_FILES ${CMAKE_CURRENT_LIST_DIR}/RicExportCompletionDataSettingsUi.h ${CMAKE_CURRENT_LIST_DIR}/RicWellPathExportCompletionDataFeature.h ${CMAKE_CURRENT_LIST_DIR}/RicWellPathExportCompletionDataFeatureImpl.h +${CMAKE_CURRENT_LIST_DIR}/RicWellPathExportMswCompletionsImpl.h +${CMAKE_CURRENT_LIST_DIR}/RicWellPathExportCompletionsFileTools.h ${CMAKE_CURRENT_LIST_DIR}/RicFishbonesTransmissibilityCalculationFeatureImp.h -${CMAKE_CURRENT_LIST_DIR}/RicExportFishbonesWellSegmentsFeature.h -${CMAKE_CURRENT_LIST_DIR}/RicExportFracturesWellSegmentsFeature.h +${CMAKE_CURRENT_LIST_DIR}/RicExportCompletionsWellSegmentsFeature.h ${CMAKE_CURRENT_LIST_DIR}/RicCaseAndFileExportSettingsUi.h ${CMAKE_CURRENT_LIST_DIR}/RicExportFractureCompletionsImpl.h ${CMAKE_CURRENT_LIST_DIR}/RicExportCompletionsForVisibleWellPathsFeature.h ${CMAKE_CURRENT_LIST_DIR}/RicExportCompletionsForVisibleSimWellsFeature.h -${CMAKE_CURRENT_LIST_DIR}/RicMultiSegmentWellExportInfo.h +${CMAKE_CURRENT_LIST_DIR}/RicMswCompletions.h +${CMAKE_CURRENT_LIST_DIR}/RicMswExportInfo.h +${CMAKE_CURRENT_LIST_DIR}/RicMswSegment.h +${CMAKE_CURRENT_LIST_DIR}/RicMswSubSegment.h +${CMAKE_CURRENT_LIST_DIR}/RicMswValveAccumulators.h ${CMAKE_CURRENT_LIST_DIR}/RicWellPathFractureTextReportFeatureImpl.h ${CMAKE_CURRENT_LIST_DIR}/RicWellPathFractureReportItem.h ${CMAKE_CURRENT_LIST_DIR}/RicExportCompletionsForTemporaryLgrsFeature.h @@ -21,14 +26,19 @@ set (SOURCE_GROUP_SOURCE_FILES ${CMAKE_CURRENT_LIST_DIR}/RicExportCompletionDataSettingsUi.cpp ${CMAKE_CURRENT_LIST_DIR}/RicWellPathExportCompletionDataFeature.cpp ${CMAKE_CURRENT_LIST_DIR}/RicWellPathExportCompletionDataFeatureImpl.cpp +${CMAKE_CURRENT_LIST_DIR}/RicWellPathExportMswCompletionsImpl.cpp +${CMAKE_CURRENT_LIST_DIR}/RicWellPathExportCompletionsFileTools.cpp ${CMAKE_CURRENT_LIST_DIR}/RicFishbonesTransmissibilityCalculationFeatureImp.cpp -${CMAKE_CURRENT_LIST_DIR}/RicExportFishbonesWellSegmentsFeature.cpp -${CMAKE_CURRENT_LIST_DIR}/RicExportFracturesWellSegmentsFeature.cpp +${CMAKE_CURRENT_LIST_DIR}/RicExportCompletionsWellSegmentsFeature.cpp ${CMAKE_CURRENT_LIST_DIR}/RicCaseAndFileExportSettingsUi.cpp ${CMAKE_CURRENT_LIST_DIR}/RicExportFractureCompletionsImpl.cpp ${CMAKE_CURRENT_LIST_DIR}/RicExportCompletionsForVisibleWellPathsFeature.cpp ${CMAKE_CURRENT_LIST_DIR}/RicExportCompletionsForVisibleSimWellsFeature.cpp -${CMAKE_CURRENT_LIST_DIR}/RicMultiSegmentWellExportInfo.cpp +${CMAKE_CURRENT_LIST_DIR}/RicMswCompletions.cpp +${CMAKE_CURRENT_LIST_DIR}/RicMswExportInfo.cpp +${CMAKE_CURRENT_LIST_DIR}/RicMswSegment.cpp +${CMAKE_CURRENT_LIST_DIR}/RicMswSubSegment.cpp +${CMAKE_CURRENT_LIST_DIR}/RicMswValveAccumulators.cpp ${CMAKE_CURRENT_LIST_DIR}/RicWellPathFractureTextReportFeatureImpl.cpp ${CMAKE_CURRENT_LIST_DIR}/RicWellPathFractureReportItem.cpp ${CMAKE_CURRENT_LIST_DIR}/RicExportCompletionsForTemporaryLgrsFeature.cpp diff --git a/ApplicationCode/Commands/CompletionExportCommands/RicExportCompletionDataSettingsUi.cpp b/ApplicationCode/Commands/CompletionExportCommands/RicExportCompletionDataSettingsUi.cpp index bd5fab7391..d047c5f332 100644 --- a/ApplicationCode/Commands/CompletionExportCommands/RicExportCompletionDataSettingsUi.cpp +++ b/ApplicationCode/Commands/CompletionExportCommands/RicExportCompletionDataSettingsUi.cpp @@ -113,6 +113,14 @@ RicExportCompletionDataSettingsUi::RicExportCompletionDataSettingsUi() m_fishbonesEnabled = true; } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicExportCompletionDataSettingsUi::enableIncludeMsw() +{ + includeMsw = true; +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/Commands/CompletionExportCommands/RicExportCompletionDataSettingsUi.h b/ApplicationCode/Commands/CompletionExportCommands/RicExportCompletionDataSettingsUi.h index 9ddedbc6af..f9c72863d6 100644 --- a/ApplicationCode/Commands/CompletionExportCommands/RicExportCompletionDataSettingsUi.h +++ b/ApplicationCode/Commands/CompletionExportCommands/RicExportCompletionDataSettingsUi.h @@ -78,6 +78,7 @@ class RicExportCompletionDataSettingsUi : public RicCaseAndFileExportSettingsUi caf::PdmField includeFractures; + void enableIncludeMsw(); void showForSimWells(); void showForWellPath(); diff --git a/ApplicationCode/Commands/CompletionExportCommands/RicExportCompletionsWellSegmentsFeature.cpp b/ApplicationCode/Commands/CompletionExportCommands/RicExportCompletionsWellSegmentsFeature.cpp new file mode 100644 index 0000000000..6e4e622354 --- /dev/null +++ b/ApplicationCode/Commands/CompletionExportCommands/RicExportCompletionsWellSegmentsFeature.cpp @@ -0,0 +1,140 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2017 Statoil ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "RicExportCompletionsWellSegmentsFeature.h" + +#include "RiaApplication.h" +#include "RiaLogging.h" + +#include "RifEclipseDataTableFormatter.h" + +#include "RicExportFeatureImpl.h" +#include "RicMswExportInfo.h" +#include "RicWellPathExportCompletionDataFeatureImpl.h" +#include "RicWellPathExportMswCompletionsImpl.h" +#include "RicWellPathExportCompletionsFileTools.h" + +#include "RimProject.h" +#include "RimFishboneWellPathCollection.h" +#include "RimFishbonesCollection.h" +#include "RimFishbonesMultipleSubs.h" +#include "RimPerforationCollection.h" +#include "RimWellPath.h" +#include "RimWellPathFractureCollection.h" +#include "RimEclipseCase.h" + +#include "RigMainGrid.h" +#include "RigEclipseCaseData.h" +#include "RigWellPath.h" + +#include "Riu3DMainWindowTools.h" + +#include "cafSelectionManager.h" +#include "cafPdmUiPropertyViewDialog.h" +#include "cafUtils.h" + +#include "cvfMath.h" + +#include +#include + + +CAF_CMD_SOURCE_INIT(RicExportCompletionsWellSegmentsFeature, "RicExportCompletionsWellSegmentsFeature"); + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicExportCompletionsWellSegmentsFeature::onActionTriggered(bool isChecked) +{ + RimWellPath* wellPath = caf::SelectionManager::instance()->selectedItemAncestorOfType(); + CVF_ASSERT(wellPath); + + RimFishbonesCollection* fishbonesCollection = + caf::SelectionManager::instance()->selectedItemAncestorOfType(); + RimWellPathFractureCollection* fractureCollection = + caf::SelectionManager::instance()->selectedItemAncestorOfType(); + RimPerforationCollection* perforationCollection = + caf::SelectionManager::instance()->selectedItemAncestorOfType(); + + CVF_ASSERT(fishbonesCollection || fractureCollection || perforationCollection); + + RiaApplication* app = RiaApplication::instance(); + + QString defaultDir = RiaApplication::instance()->lastUsedDialogDirectoryWithFallbackToProjectFolder("COMPLETIONS"); + + RicCaseAndFileExportSettingsUi exportSettings; + std::vector cases; + app->project()->allCases(cases); + for (auto c : cases) + { + RimEclipseCase* eclipseCase = dynamic_cast(c); + if (eclipseCase != nullptr) + { + exportSettings.caseToApply = eclipseCase; + break; + } + } + + exportSettings.folder = defaultDir; + + caf::PdmUiPropertyViewDialog propertyDialog(Riu3DMainWindowTools::mainWindowWidget(), &exportSettings, "Export Well Segments", ""); + RicExportFeatureImpl::configureForExport(propertyDialog.dialogButtonBox()); + + if (propertyDialog.exec() == QDialog::Accepted) + { + RiaApplication::instance()->setLastUsedDialogDirectory("COMPLETIONS", QFileInfo(exportSettings.folder).absolutePath()); + RicExportCompletionDataSettingsUi completionExportSettings; + completionExportSettings.caseToApply.setValue(exportSettings.caseToApply); + completionExportSettings.folder.setValue(exportSettings.folder); + + completionExportSettings.includeFishbones = fishbonesCollection != nullptr && !fishbonesCollection->activeFishbonesSubs().empty(); + completionExportSettings.includeFractures = fractureCollection != nullptr && !fractureCollection->activeFractures().empty(); + completionExportSettings.includePerforations = perforationCollection != nullptr && !perforationCollection->activePerforations().empty(); + + RicWellPathExportMswCompletionsImpl::exportWellSegmentsForAllCompletions(completionExportSettings, { wellPath }); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicExportCompletionsWellSegmentsFeature::setupActionLook(QAction* actionToSetup) +{ + actionToSetup->setText("Export Well Segments"); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RicExportCompletionsWellSegmentsFeature::isCommandEnabled() +{ + if (caf::SelectionManager::instance()->selectedItemAncestorOfType()) + { + return true; + } + else if (caf::SelectionManager::instance()->selectedItemAncestorOfType()) + { + return true; + } + else if (caf::SelectionManager::instance()->selectedItemAncestorOfType()) + { + return true; + } + + return false; +} diff --git a/ApplicationCode/Commands/CompletionExportCommands/RicExportCompletionsWellSegmentsFeature.h b/ApplicationCode/Commands/CompletionExportCommands/RicExportCompletionsWellSegmentsFeature.h new file mode 100644 index 0000000000..7e4f477001 --- /dev/null +++ b/ApplicationCode/Commands/CompletionExportCommands/RicExportCompletionsWellSegmentsFeature.h @@ -0,0 +1,43 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2017 Statoil ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "RicCaseAndFileExportSettingsUi.h" + +#include "cafCmdFeature.h" + +class RimFishbonesCollection; +class RimFishbonesMultipleSubs; +class RimWellPath; + + + +//================================================================================================== +/// +//================================================================================================== +class RicExportCompletionsWellSegmentsFeature : public caf::CmdFeature +{ + CAF_CMD_HEADER_INIT; + +protected: + void onActionTriggered(bool isChecked) override; + void setupActionLook(QAction* actionToSetup) override; + bool isCommandEnabled() override; + +}; diff --git a/ApplicationCode/Commands/CompletionExportCommands/RicExportFishbonesWellSegmentsFeature.cpp b/ApplicationCode/Commands/CompletionExportCommands/RicExportFishbonesWellSegmentsFeature.cpp deleted file mode 100644 index fc5e8aeca2..0000000000 --- a/ApplicationCode/Commands/CompletionExportCommands/RicExportFishbonesWellSegmentsFeature.cpp +++ /dev/null @@ -1,160 +0,0 @@ -///////////////////////////////////////////////////////////////////////////////// -// -// Copyright (C) 2017 Statoil ASA -// -// ResInsight 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 3 of the License, or -// (at your option) any later version. -// -// ResInsight 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 at -// for more details. -// -///////////////////////////////////////////////////////////////////////////////// - -#include "RicExportFishbonesWellSegmentsFeature.h" - -#include "RiaApplication.h" -#include "RiaLogging.h" - -#include "RifEclipseDataTableFormatter.h" - -#include "RicExportFeatureImpl.h" -#include "RicMultiSegmentWellExportInfo.h" -#include "RicWellPathExportCompletionDataFeatureImpl.h" - -#include "RimProject.h" -#include "RimFishboneWellPathCollection.h" -#include "RimFishbonesCollection.h" -#include "RimFishbonesMultipleSubs.h" -#include "RimWellPath.h" -#include "RimEclipseCase.h" - -#include "RigMainGrid.h" -#include "RigEclipseCaseData.h" -#include "RigWellPath.h" - -#include "Riu3DMainWindowTools.h" - -#include "cafSelectionManager.h" -#include "cafPdmUiPropertyViewDialog.h" -#include "cafUtils.h" - -#include "cvfMath.h" - -#include -#include - - -CAF_CMD_SOURCE_INIT(RicExportFishbonesWellSegmentsFeature, "RicExportFishbonesWellSegmentsFeature"); - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RicExportFishbonesWellSegmentsFeature::onActionTriggered(bool isChecked) -{ - RimFishbonesCollection* fishbonesCollection = caf::SelectionManager::instance()->selectedItemAncestorOfType(); - RimWellPath* wellPath = caf::SelectionManager::instance()->selectedItemAncestorOfType(); - CVF_ASSERT(fishbonesCollection); - CVF_ASSERT(wellPath); - - RiaApplication* app = RiaApplication::instance(); - - QString defaultDir = RiaApplication::instance()->lastUsedDialogDirectoryWithFallbackToProjectFolder("COMPLETIONS"); - - RicCaseAndFileExportSettingsUi exportSettings; - std::vector cases; - app->project()->allCases(cases); - for (auto c : cases) - { - RimEclipseCase* eclipseCase = dynamic_cast(c); - if (eclipseCase != nullptr) - { - exportSettings.caseToApply = eclipseCase; - break; - } - } - - exportSettings.folder = defaultDir; - - caf::PdmUiPropertyViewDialog propertyDialog(Riu3DMainWindowTools::mainWindowWidget(), &exportSettings, "Export Well Segments", ""); - RicExportFeatureImpl::configureForExport(&propertyDialog); - - if (propertyDialog.exec() == QDialog::Accepted) - { - RiaApplication::instance()->setLastUsedDialogDirectory("COMPLETIONS", QFileInfo(exportSettings.folder).absolutePath()); - - if (!fishbonesCollection->activeFishbonesSubs().empty()) - { - exportWellSegments(wellPath, fishbonesCollection->activeFishbonesSubs(), exportSettings); - } - } -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RicExportFishbonesWellSegmentsFeature::setupActionLook(QAction* actionToSetup) -{ - actionToSetup->setText("Export Well Segments"); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -bool RicExportFishbonesWellSegmentsFeature::isCommandEnabled() -{ - if (caf::SelectionManager::instance()->selectedItemAncestorOfType()) - { - return true; - } - - return false; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RicExportFishbonesWellSegmentsFeature::exportWellSegments(const RimWellPath* wellPath, const std::vector& fishbonesSubs, const RicCaseAndFileExportSettingsUi& settings) -{ - if (fishbonesSubs.empty()) return; - - if (settings.caseToApply() == nullptr) - { - RiaLogging::error("Export Well Segments: Cannot export completions data without specified eclipse case"); - return; - } - - QString fileName = QString("%1-Welsegs").arg(settings.caseToApply()->caseUserDescription()); - fileName = caf::Utils::makeValidFileBasename(fileName); - - QDir exportFolder(settings.folder()); - if (!exportFolder.exists()) - { - bool createdPath = exportFolder.mkpath("."); - if (createdPath) - RiaLogging::info("Created export folder " + settings.folder()); - else - RiaLogging::error("Selected output folder does not exist, and could not be created."); - } - - QString filePath = exportFolder.filePath(fileName); - QFile exportFile(filePath); - if (!exportFile.open(QIODevice::WriteOnly | QIODevice::Text)) - { - RiaLogging::error(QString("Export Well Segments: Could not open the file: %1").arg(filePath)); - return; - } - - RicMswExportInfo exportInfo = RicWellPathExportCompletionDataFeatureImpl::generateFishbonesMswExportInfo(settings.caseToApply, wellPath, fishbonesSubs, true); - - QTextStream stream(&exportFile); - RifEclipseDataTableFormatter formatter(stream); - RicWellPathExportCompletionDataFeatureImpl::generateWelsegsTable (formatter, exportInfo); - RicWellPathExportCompletionDataFeatureImpl::generateCompsegTables(formatter, exportInfo); - RicWellPathExportCompletionDataFeatureImpl::generateWsegvalvTable(formatter, exportInfo); -} diff --git a/ApplicationCode/Commands/CompletionExportCommands/RicExportFishbonesWellSegmentsFeature.h b/ApplicationCode/Commands/CompletionExportCommands/RicExportFishbonesWellSegmentsFeature.h deleted file mode 100644 index a8ba80aa1c..0000000000 --- a/ApplicationCode/Commands/CompletionExportCommands/RicExportFishbonesWellSegmentsFeature.h +++ /dev/null @@ -1,47 +0,0 @@ -///////////////////////////////////////////////////////////////////////////////// -// -// Copyright (C) 2017 Statoil ASA -// -// ResInsight 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 3 of the License, or -// (at your option) any later version. -// -// ResInsight 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 at -// for more details. -// -///////////////////////////////////////////////////////////////////////////////// - -#pragma once - -#include "RicCaseAndFileExportSettingsUi.h" - -#include "cafCmdFeature.h" - -class RimFishbonesCollection; -class RimFishbonesMultipleSubs; -class RimWellPath; - - - -//================================================================================================== -/// -//================================================================================================== -class RicExportFishbonesWellSegmentsFeature : public caf::CmdFeature -{ - CAF_CMD_HEADER_INIT; - -protected: - void onActionTriggered(bool isChecked) override; - void setupActionLook(QAction* actionToSetup) override; - bool isCommandEnabled() override; - -public: - static void exportWellSegments(const RimWellPath* wellPath, - const std::vector& fishbonesSubs, - const RicCaseAndFileExportSettingsUi& settings); -}; diff --git a/ApplicationCode/Commands/CompletionExportCommands/RicExportFractureCompletionsImpl.cpp b/ApplicationCode/Commands/CompletionExportCommands/RicExportFractureCompletionsImpl.cpp index 04c91e4103..269eec1081 100644 --- a/ApplicationCode/Commands/CompletionExportCommands/RicExportFractureCompletionsImpl.cpp +++ b/ApplicationCode/Commands/CompletionExportCommands/RicExportFractureCompletionsImpl.cpp @@ -134,7 +134,7 @@ std::vector //-------------------------------------------------------------------------------------------------- std::vector RicExportFractureCompletionsImpl::generateCompdatValues(RimEclipseCase* caseToApply, - const QString& wellPathName, + const QString& wellNameForExport, const RigWellPath* wellPathGeometry, const std::vector& fractures, std::vector* fractureDataReportItems, @@ -187,11 +187,11 @@ std::vector if (pdParams.performScaling) { RigCaseCellResultsData* results = caseToApply->results(RiaDefines::MATRIX_MODEL); - results->findOrLoadScalarResult(RiaDefines::DYNAMIC_NATIVE, "PRESSURE"); + results->ensureKnownResultLoaded(RigEclipseResultAddress(RiaDefines::DYNAMIC_NATIVE, "PRESSURE")); } return generateCompdatValuesConst(caseToApply, - wellPathName, + wellNameForExport, wellPathGeometry, fractures, fractureDataReportItems, @@ -204,7 +204,7 @@ std::vector //-------------------------------------------------------------------------------------------------- std::vector RicExportFractureCompletionsImpl::generateCompdatValuesConst( const RimEclipseCase* caseToApply, - const QString& wellPathName, + const QString& wellNameForExport, const RigWellPath* wellPathGeometry, const std::vector& fractures, std::vector* fractureDataReportItems, @@ -221,9 +221,8 @@ std::vector RicExportFractureCompletionsImpl::generateCompdat double cDarcyInCorrectUnit = RiaEclipseUnitTools::darcysConstant(caseToApply->eclipseCaseData()->unitsType()); const RigMainGrid* mainGrid = caseToApply->eclipseCaseData()->mainGrid(); - const RigCaseCellResultsData* results = caseToApply->results(RiaDefines::MATRIX_MODEL); - size_t pressureResultIndex = results->findScalarResultIndex(RiaDefines::DYNAMIC_NATIVE, "PRESSURE"); - const RigActiveCellInfo* actCellInfo = caseToApply->eclipseCaseData()->activeCellInfo(RiaDefines::MATRIX_MODEL); + const RigCaseCellResultsData* results = caseToApply->results(RiaDefines::MATRIX_MODEL); + const RigActiveCellInfo* actCellInfo = caseToApply->eclipseCaseData()->activeCellInfo(RiaDefines::MATRIX_MODEL); bool performPressureDepletionScaling = pdParams.performScaling; @@ -238,7 +237,7 @@ std::vector RicExportFractureCompletionsImpl::generateCompdat double currentWBHPFromSummary = 0.0; // Find well pressures (WBHP) from summary case. getWellPressuresAndInitialProductionTimeStepFromSummaryData(caseToApply, - wellPathName, + wellNameForExport, pdParams.pressureScalingTimeStep, &initialWellProductionTimeStep, &initialWBHPFromSummary, @@ -262,7 +261,7 @@ std::vector RicExportFractureCompletionsImpl::generateCompdat const std::vector* currentMatrixPressures = nullptr; if (performPressureDepletionScaling) { - pressureResultVector = &results->cellScalarResults(pressureResultIndex); + pressureResultVector = &results->cellScalarResults(RigEclipseResultAddress(RiaDefines::DYNAMIC_NATIVE, "PRESSURE")); CVF_ASSERT(!pressureResultVector->empty()); if (pdParams.pressureScalingTimeStep < static_cast(pressureResultVector->size())) @@ -332,14 +331,12 @@ std::vector RicExportFractureCompletionsImpl::generateCompdat RigTransmissibilityCondenser scaledCondenser = transCondenser; // 1. Scale matrix to fracture transmissibilities by matrix to fracture pressure std::map originalLumpedMatrixToFractureTrans = scaledCondenser.scaleMatrixToFracTransByMatrixWellDP( - actCellInfo, - currentWellPressure, - *currentMatrixPressures, &minPressureDrop, &maxPressureDrop); + actCellInfo, currentWellPressure, *currentMatrixPressures, &minPressureDrop, &maxPressureDrop); // 2: Calculate new external transmissibilities scaledCondenser.calculateCondensedTransmissibilities(); { // 3: H�gst�l correction. - + // a. Calculate new effective fracture to well transmissiblities std::map fictitiousFractureToWellTransmissibilities = scaledCondenser.calculateFicticiousFractureToWellTransmissibilities(); @@ -350,19 +347,23 @@ std::vector RicExportFractureCompletionsImpl::generateCompdat matrixToWellTrans = effectiveMatrixToWellTrans; } } - + std::vector allCompletionsForOneFracture = - generateCompdatValuesForFracture(matrixToWellTrans, wellPathName, caseToApply, fracture, fracTemplate); + generateCompdatValuesForFracture(matrixToWellTrans, wellNameForExport, caseToApply, fracture, fracTemplate); if (fractureDataReportItems) { RicWellPathFractureReportItem reportItem( - wellPathName, fracture->name(), fracTemplate->name(), fracture->fractureMD()); + wellNameForExport, fracture->name(), fracTemplate->name(), fracture->fractureMD()); reportItem.setUnitSystem(fracTemplate->fractureTemplateUnit()); - reportItem.setPressureDepletionParameters(performPressureDepletionScaling, + reportItem.setPressureDepletionParameters( + performPressureDepletionScaling, caseToApply->timeStepStrings()[pdParams.pressureScalingTimeStep], caf::AppEnum::uiTextFromIndex(pdParams.wbhpSource), - pdParams.userWBHP, currentWellPressure, minPressureDrop, maxPressureDrop); + pdParams.userWBHP, + currentWellPressure, + minPressureDrop, + maxPressureDrop); RicExportFractureCompletionsImpl::calculateAndSetReportItemData( allCompletionsForOneFracture, eclToFractureCalc, reportItem); @@ -646,7 +647,7 @@ std::map //-------------------------------------------------------------------------------------------------- std::vector RicExportFractureCompletionsImpl::generateCompdatValuesForFracture( const std::map& matrixToWellTransmissibilites, - const QString& wellPathName, + const QString& wellNameForExport, const RimEclipseCase* caseToApply, const RimFracture* fracture, const RimFractureTemplate* fracTemplate) @@ -657,7 +658,7 @@ std::vector RicExportFractureCompletionsImpl::generateCompdat size_t globalCellIndex = matrixToWellTransmissibility.first; double trans = matrixToWellTransmissibility.second; RigCompletionData compDat( - wellPathName, RigCompletionDataGridCell(globalCellIndex, caseToApply->mainGrid()), fracture->fractureMD()); + wellNameForExport, RigCompletionDataGridCell(globalCellIndex, caseToApply->mainGrid()), fracture->fractureMD()); double diameter = 2.0 * fracture->wellRadius(); compDat.setFromFracture(trans, fracTemplate->skinFactor(), diameter); diff --git a/ApplicationCode/Commands/CompletionExportCommands/RicExportFractureCompletionsImpl.h b/ApplicationCode/Commands/CompletionExportCommands/RicExportFractureCompletionsImpl.h index 643222f059..06c670e8a0 100644 --- a/ApplicationCode/Commands/CompletionExportCommands/RicExportFractureCompletionsImpl.h +++ b/ApplicationCode/Commands/CompletionExportCommands/RicExportFractureCompletionsImpl.h @@ -84,7 +84,7 @@ class RicExportFractureCompletionsImpl PressureDepletionParameters pdParams = PressureDepletionParameters()); static std::vector generateCompdatValues(RimEclipseCase* caseToApply, - const QString& wellPathName, + const QString& wellNameForExport, const RigWellPath* wellPathGeometry, const std::vector& fractures, std::vector* fractureDataReportItems, diff --git a/ApplicationCode/Commands/CompletionExportCommands/RicExportFracturesWellSegmentsFeature.cpp b/ApplicationCode/Commands/CompletionExportCommands/RicExportFracturesWellSegmentsFeature.cpp deleted file mode 100644 index d1b87bd49d..0000000000 --- a/ApplicationCode/Commands/CompletionExportCommands/RicExportFracturesWellSegmentsFeature.cpp +++ /dev/null @@ -1,168 +0,0 @@ -///////////////////////////////////////////////////////////////////////////////// -// -// Copyright (C) 2017 Statoil ASA -// -// ResInsight 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 3 of the License, or -// (at your option) any later version. -// -// ResInsight 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 at -// for more details. -// -///////////////////////////////////////////////////////////////////////////////// - -#include "RicExportFracturesWellSegmentsFeature.h" - -#include "RiaApplication.h" -#include "RiaLogging.h" - -#include "RicCaseAndFileExportSettingsUi.h" -#include "RicExportFeatureImpl.h" -#include "RicMultiSegmentWellExportInfo.h" -#include "RicWellPathExportCompletionDataFeatureImpl.h" - -#include "RimProject.h" -#include "RimWellPath.h" -#include "RimWellPathFracture.h" -#include "RimWellPathFractureCollection.h" - -#include "RifEclipseDataTableFormatter.h" - -#include "Riu3DMainWindowTools.h" - -#include "cafSelectionManager.h" -#include "cafPdmUiPropertyViewDialog.h" -#include "cafUtils.h" - -#include -#include - - -CAF_CMD_SOURCE_INIT(RicExportFracturesWellSegmentsFeature, "RicExportFracturesWellSegmentsFeature"); - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RicExportFracturesWellSegmentsFeature::exportWellSegments(const RimWellPath* wellPath, const std::vector& fractures, const RicCaseAndFileExportSettingsUi& settings) -{ - if (settings.caseToApply() == nullptr) - { - RiaLogging::error("Export Fracture Well Segments: Cannot export completions data without specified eclipse case"); - return; - } - - QString fileName = QString("%1-Fracture-Welsegs").arg(settings.caseToApply()->caseUserDescription()); - fileName = caf::Utils::makeValidFileBasename(fileName); - - QDir exportFolder(settings.folder()); - if (!exportFolder.exists()) - { - bool createdPath = exportFolder.mkpath("."); - if (createdPath) - RiaLogging::info("Export Fracture Well Segments: Created export folder " + settings.folder()); - else - RiaLogging::error("Export Fracture Well Segments: Selected output folder does not exist, and could not be created."); - } - - QString filePath = exportFolder.filePath(fileName); - QFile exportFile(filePath); - if (!exportFile.open(QIODevice::WriteOnly | QIODevice::Text)) - { - RiaLogging::error(QString("Export Fracture Well Segments: Could not open the file: %1").arg(filePath)); - return; - } - - RicMswExportInfo exportInfo = RicWellPathExportCompletionDataFeatureImpl::generateFracturesMswExportInfo(settings.caseToApply, wellPath, fractures); - - QTextStream stream(&exportFile); - RifEclipseDataTableFormatter formatter(stream); - RicWellPathExportCompletionDataFeatureImpl::generateWelsegsTable(formatter, exportInfo); - RicWellPathExportCompletionDataFeatureImpl::generateCompsegTables(formatter, exportInfo); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RicExportFracturesWellSegmentsFeature::onActionTriggered(bool isChecked) -{ - RimWellPath* wellPath = caf::SelectionManager::instance()->selectedItemAncestorOfType(); - RimWellPathFracture* fracture = caf::SelectionManager::instance()->selectedItemAncestorOfType(); - RimWellPathFractureCollection* collection = caf::SelectionManager::instance()->selectedItemAncestorOfType(); - - CVF_ASSERT(wellPath); - CVF_ASSERT(collection); - - RiaApplication* app = RiaApplication::instance(); - - QString defaultDir = RiaApplication::instance()->lastUsedDialogDirectoryWithFallbackToProjectFolder("COMPLETIONS"); - - RicCaseAndFileExportSettingsUi exportSettings; - std::vector cases; - app->project()->allCases(cases); - for (auto c : cases) - { - RimEclipseCase* eclipseCase = dynamic_cast(c); - if (eclipseCase != nullptr) - { - exportSettings.caseToApply = eclipseCase; - break; - } - } - - exportSettings.folder = defaultDir; - - caf::PdmUiPropertyViewDialog propertyDialog(Riu3DMainWindowTools::mainWindowWidget(), &exportSettings, "Export Fractures as Multi Segment Wells", ""); - RicExportFeatureImpl::configureForExport(&propertyDialog); - - if (propertyDialog.exec() == QDialog::Accepted) - { - RiaApplication::instance()->setLastUsedDialogDirectory("COMPLETIONS", QFileInfo(exportSettings.folder).absolutePath()); - std::vector fractures; - if (fracture) - { - fractures.push_back(fracture); - } - else - { - for (RimWellPathFracture* activeFracture : collection->activeFractures()) - { - fractures.push_back(activeFracture); - } - } - - exportWellSegments(wellPath, fractures, exportSettings); - } -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RicExportFracturesWellSegmentsFeature::setupActionLook(QAction* actionToSetup) -{ - if (caf::SelectionManager::instance()->selectedItemOfType()) - { - actionToSetup->setText("Export Fracture as Multi Segment Well"); - } - else - { - actionToSetup->setText("Export Fractures as Multi Segment Well"); - } -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -bool RicExportFracturesWellSegmentsFeature::isCommandEnabled() -{ - if (RiaApplication::enableDevelopmentFeatures() && caf::SelectionManager::instance()->selectedItemAncestorOfType()) - { - return true; - } - - return false; -} diff --git a/ApplicationCode/Commands/CompletionExportCommands/RicExportFracturesWellSegmentsFeature.h b/ApplicationCode/Commands/CompletionExportCommands/RicExportFracturesWellSegmentsFeature.h deleted file mode 100644 index aac083976f..0000000000 --- a/ApplicationCode/Commands/CompletionExportCommands/RicExportFracturesWellSegmentsFeature.h +++ /dev/null @@ -1,43 +0,0 @@ -///////////////////////////////////////////////////////////////////////////////// -// -// Copyright (C) 2017 Statoil ASA -// -// ResInsight 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 3 of the License, or -// (at your option) any later version. -// -// ResInsight 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 at -// for more details. -// -///////////////////////////////////////////////////////////////////////////////// - -#pragma once - -#include "RicCaseAndFileExportSettingsUi.h" - -#include "cafCmdFeature.h" - -class RimWellPath; -class RimWellPathFracture; -class RimWellPathFractureCollection; - -//================================================================================================== -/// -//================================================================================================== -class RicExportFracturesWellSegmentsFeature : public caf::CmdFeature -{ - CAF_CMD_HEADER_INIT; - -public: - static void exportWellSegments(const RimWellPath* wellPath, const std::vector& fractures, const RicCaseAndFileExportSettingsUi& settings); - -protected: - void onActionTriggered(bool isChecked) override; - void setupActionLook(QAction* actionToSetup) override; - bool isCommandEnabled() override; -}; diff --git a/ApplicationCode/Commands/CompletionExportCommands/RicFishbonesTransmissibilityCalculationFeatureImp.cpp b/ApplicationCode/Commands/CompletionExportCommands/RicFishbonesTransmissibilityCalculationFeatureImp.cpp index 378d19cc8b..acfe77e79d 100644 --- a/ApplicationCode/Commands/CompletionExportCommands/RicFishbonesTransmissibilityCalculationFeatureImp.cpp +++ b/ApplicationCode/Commands/CompletionExportCommands/RicFishbonesTransmissibilityCalculationFeatureImp.cpp @@ -19,7 +19,9 @@ #include "RicFishbonesTransmissibilityCalculationFeatureImp.h" #include "RicExportCompletionDataSettingsUi.h" +#include "RicMswExportInfo.h" #include "RicWellPathExportCompletionDataFeatureImpl.h" +#include "RicWellPathExportMswCompletionsImpl.h" #include "RigActiveCellInfo.h" #include "RigCompletionData.h" @@ -187,31 +189,31 @@ void RicFishbonesTransmissibilityCalculationFeatureImp::findFishboneLateralsWell // Generate data const RigEclipseCaseData* caseData = settings.caseToApply()->eclipseCaseData(); RicMswExportInfo exportInfo = - RicWellPathExportCompletionDataFeatureImpl::generateFishbonesMswExportInfo(settings.caseToApply(), wellPath, false); + RicWellPathExportMswCompletionsImpl::generateFishbonesMswExportInfo(settings.caseToApply(), wellPath, false); RiaEclipseUnitTools::UnitSystem unitSystem = caseData->unitsType(); bool isMainBore = false; - for (const RicMswSegment& location : exportInfo.wellSegmentLocations()) + for (std::shared_ptr location : exportInfo.wellSegmentLocations()) { - for (const RicMswCompletion& completion : location.completions()) + for (std::shared_ptr completion : location->completions()) { - for (const RicMswSubSegment& segment : completion.subSegments()) + for (std::shared_ptr segment : completion->subSegments()) { - for (const RicMswSubSegmentCellIntersection& intersection : segment.intersections()) + for (std::shared_ptr intersection : segment->intersections()) { - double diameter = location.holeDiameter(); + double diameter = location->holeDiameter(); QString completionMetaData = - (location.label() + QString(": Sub: %1 Lateral: %2").arg(location.subIndex()).arg(completion.index())); + (location->label() + QString(": Sub: %1 Lateral: %2").arg(location->subIndex()).arg(completion->index())); WellBorePartForTransCalc wellBorePart = WellBorePartForTransCalc( - intersection.lengthsInCell(), diameter / 2.0, location.skinFactor(), isMainBore, completionMetaData); + intersection->lengthsInCell(), diameter / 2.0, location->skinFactor(), isMainBore, completionMetaData); - wellBorePart.intersectionWithWellMeasuredDepth = location.endMD(); - wellBorePart.lateralIndex = completion.index(); - wellBorePart.setSourcePdmObject(location.sourcePdmObject()); + wellBorePart.intersectionWithWellMeasuredDepth = location->endMD(); + wellBorePart.lateralIndex = completion->index(); + wellBorePart.setSourcePdmObject(location->sourcePdmObject()); - wellBorePartsInCells[intersection.globalCellIndex()].push_back(wellBorePart); + wellBorePartsInCells[intersection->globalCellIndex()].push_back(wellBorePart); } } } diff --git a/ApplicationCode/Commands/CompletionExportCommands/RicMswCompletions.cpp b/ApplicationCode/Commands/CompletionExportCommands/RicMswCompletions.cpp new file mode 100644 index 0000000000..5bd2020855 --- /dev/null +++ b/ApplicationCode/Commands/CompletionExportCommands/RicMswCompletions.cpp @@ -0,0 +1,327 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2018 Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "RicMswCompletions.h" + +#include "RicMswSubSegment.h" + +#include "RimWellPathValve.h" +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RicMswCompletion::RicMswCompletion(const QString& label, + size_t index /* = cvf::UNDEFINED_SIZE_T */, + int branchNumber /*= 0*/) + : m_label(label) + , m_index(index) + , m_branchNumber(branchNumber) +{ +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +const QString& RicMswCompletion::label() const +{ + return m_label; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +size_t RicMswCompletion::index() const +{ + return m_index; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +int RicMswCompletion::branchNumber() const +{ + return m_branchNumber; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicMswCompletion::setBranchNumber(int branchNumber) +{ + m_branchNumber = branchNumber; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicMswCompletion::addSubSegment(std::shared_ptr subSegment) +{ + m_subSegments.push_back(subSegment); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector>& RicMswCompletion::subSegments() +{ + return m_subSegments; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +const std::vector>& RicMswCompletion::subSegments() const +{ + return m_subSegments; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicMswCompletion::setLabel(const QString& label) +{ + m_label = label; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RicMswFracture::RicMswFracture(const QString& label, + size_t index /*= cvf::UNDEFINED_SIZE_T*/, + int branchNumber /*= cvf::UNDEFINED_INT*/) + : RicMswCompletion(label, index, branchNumber) +{ +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RigCompletionData::CompletionType RicMswFracture::completionType() const +{ + return RigCompletionData::FRACTURE; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RicMswPerforation::RicMswPerforation(const QString& label, + size_t index /*= cvf::UNDEFINED_SIZE_T*/, + int branchNumber /*= cvf::UNDEFINED_INT*/) + : RicMswCompletion(label, index, branchNumber) +{ +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RigCompletionData::CompletionType RicMswPerforation::completionType() const +{ + return RigCompletionData::PERFORATION; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RicMswValve::RicMswValve(const QString& label, + const RimWellPathValve* wellPathValve) + : RicMswCompletion(label) + , m_wellPathValve(wellPathValve) +{ +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +const RimWellPathValve* RicMswValve::wellPathValve() const +{ + return m_wellPathValve; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RicMswWsegValve::RicMswWsegValve(const QString& label, const RimWellPathValve* wellPathValve) + : RicMswValve(label, wellPathValve) + , m_flowCoefficient(0.0) + , m_area(0.0) +{ +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +double RicMswWsegValve::flowCoefficient() const +{ + return m_flowCoefficient; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +double RicMswWsegValve::area() const +{ + return m_area; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicMswWsegValve::setFlowCoefficient(double icdFlowCoefficient) +{ + m_flowCoefficient = icdFlowCoefficient; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicMswWsegValve::setArea(double icdArea) +{ + m_area = icdArea; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RicMswFishbonesICD::RicMswFishbonesICD(const QString& label, const RimWellPathValve* wellPathValve) + : RicMswWsegValve(label, wellPathValve) +{ +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RigCompletionData::CompletionType RicMswFishbonesICD::completionType() const +{ + return RigCompletionData::FISHBONES_ICD; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RicMswPerforationICD::RicMswPerforationICD(const QString& label, + const RimWellPathValve* wellPathValve) + : RicMswWsegValve(label, wellPathValve) +{ +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RigCompletionData::CompletionType RicMswPerforationICD::completionType() const +{ + return RigCompletionData::PERFORATION_ICD; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RicMswPerforationICV::RicMswPerforationICV(const QString& label, + const RimWellPathValve* wellPathValve) + : RicMswWsegValve(label, wellPathValve) +{ +} + +//------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RigCompletionData::CompletionType RicMswPerforationICV::completionType() const +{ + return RigCompletionData::PERFORATION_ICV; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RicMswPerforationAICD::RicMswPerforationAICD(const QString& label, const RimWellPathValve* wellPathValve) + : RicMswValve(label, wellPathValve) + , m_valid(false) + , m_deviceOpen(false) + , m_length(0.0) +{ +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RigCompletionData::CompletionType RicMswPerforationAICD::completionType() const +{ + return RigCompletionData::PERFORATION_AICD; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RicMswPerforationAICD::isValid() const +{ + return m_valid; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicMswPerforationAICD::setIsValid(bool valid) +{ + m_valid = valid; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RicMswPerforationAICD::isOpen() const +{ + return m_deviceOpen; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicMswPerforationAICD::setIsOpen(bool deviceOpen) +{ + m_deviceOpen = deviceOpen; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +double RicMswPerforationAICD::length() const +{ + return m_length; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicMswPerforationAICD::setLength(double length) +{ + m_length = length; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +const std::array& RicMswPerforationAICD::values() const +{ + return m_parameters; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::array& RicMswPerforationAICD::values() +{ + return m_parameters; +} diff --git a/ApplicationCode/Commands/CompletionExportCommands/RicMswCompletions.h b/ApplicationCode/Commands/CompletionExportCommands/RicMswCompletions.h new file mode 100644 index 0000000000..364f34f17a --- /dev/null +++ b/ApplicationCode/Commands/CompletionExportCommands/RicMswCompletions.h @@ -0,0 +1,181 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2018 Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// +#pragma once + +#include "RicMswSubSegment.h" + +#include "RigCompletionData.h" + +#include "RimWellPathAicdParameters.h" + +#include "cvfBase.h" +#include "cvfMath.h" + +#include +#include + +class RimWellPathValve; + +//================================================================================================== +/// +//================================================================================================== +class RicMswCompletion +{ +public: + RicMswCompletion(const QString& label, size_t index = cvf::UNDEFINED_SIZE_T, int branchNumber = cvf::UNDEFINED_INT); + + virtual RigCompletionData::CompletionType completionType() const = 0; + + const QString& label() const; + size_t index() const; + int branchNumber() const; + void setBranchNumber(int branchNumber); + + void addSubSegment(std::shared_ptr subSegment); + + std::vector>& subSegments(); + const std::vector>& subSegments() const; + + void setLabel(const QString& label); + +private: + QString m_label; + size_t m_index; + int m_branchNumber; + + std::vector> m_subSegments; +}; + +class RicMswFishbones : public RicMswCompletion +{ +public: + RicMswFishbones(const QString& label, size_t index = cvf::UNDEFINED_SIZE_T, int branchNumber = cvf::UNDEFINED_INT) + : RicMswCompletion(label, index, branchNumber) + {} + + RigCompletionData::CompletionType completionType() const override { return RigCompletionData::FISHBONES; } +}; + +//================================================================================================== +/// +//================================================================================================== +class RicMswFracture : public RicMswCompletion +{ +public: + RicMswFracture(const QString& label, size_t index = cvf::UNDEFINED_SIZE_T, int branchNumber = cvf::UNDEFINED_INT); + RigCompletionData::CompletionType completionType() const override; +}; + +//================================================================================================== +/// +//================================================================================================== +class RicMswPerforation : public RicMswCompletion +{ +public: + RicMswPerforation(const QString& label, size_t index = cvf::UNDEFINED_SIZE_T, int branchNumber = cvf::UNDEFINED_INT); + RigCompletionData::CompletionType completionType() const override; +}; + +//================================================================================================== +/// +//================================================================================================== +class RicMswValve : public RicMswCompletion +{ +public: + RicMswValve(const QString& label, const RimWellPathValve* wellPathValve); + + virtual ~RicMswValve() {} + + const RimWellPathValve* wellPathValve() const; + +private: + const RimWellPathValve* m_wellPathValve; +}; + +//================================================================================================== +/// +//================================================================================================== +class RicMswWsegValve : public RicMswValve +{ +public: + RicMswWsegValve(const QString& label, const RimWellPathValve* wellPathValve); + + double flowCoefficient() const; + double area() const; + void setFlowCoefficient(double icdFlowCoefficient); + void setArea(double icdArea); +private: + double m_flowCoefficient; + double m_area; +}; + +//================================================================================================== +/// +//================================================================================================== +class RicMswFishbonesICD : public RicMswWsegValve +{ +public: + RicMswFishbonesICD(const QString& label, const RimWellPathValve* wellPathValve); + RigCompletionData::CompletionType completionType() const override; +}; + +//================================================================================================== +/// +//================================================================================================== +class RicMswPerforationICD : public RicMswWsegValve +{ +public: + RicMswPerforationICD(const QString& label, const RimWellPathValve* wellPathValve); + RigCompletionData::CompletionType completionType() const override; +}; + +//================================================================================================== +/// +//================================================================================================== +class RicMswPerforationICV : public RicMswWsegValve +{ +public: + RicMswPerforationICV(const QString& label, const RimWellPathValve* wellPathValve); + RigCompletionData::CompletionType completionType() const override; +}; + +//================================================================================================== +/// +//================================================================================================== +class RicMswPerforationAICD : public RicMswValve +{ +public: + RicMswPerforationAICD(const QString& label, const RimWellPathValve* wellPathValve); + RigCompletionData::CompletionType completionType() const override; + + bool isValid() const; + void setIsValid(bool valid); + bool isOpen() const; + void setIsOpen(bool deviceOpen); + double length() const; + void setLength(double length); + + const std::array& values() const; + std::array& values(); + +private: + bool m_valid; + bool m_deviceOpen; + std::array m_parameters; + double m_length; +}; diff --git a/ApplicationCode/Commands/CompletionExportCommands/RicMswExportInfo.cpp b/ApplicationCode/Commands/CompletionExportCommands/RicMswExportInfo.cpp new file mode 100644 index 0000000000..f481217242 --- /dev/null +++ b/ApplicationCode/Commands/CompletionExportCommands/RicMswExportInfo.cpp @@ -0,0 +1,200 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2018 Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "RicMswExportInfo.h" + +#include "RicMswSegment.h" + +#include "RimMswCompletionParameters.h" +#include "RimWellPath.h" + +#include "RigWellPath.h" + +#include +#include + + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RicMswExportInfo::RicMswExportInfo(const RimWellPath* wellPath, + RiaEclipseUnitTools::UnitSystem unitSystem, + double initialMD, + const QString& lengthAndDepthText, + const QString& pressureDropText) + : m_wellPath(wellPath) + , m_initialMD(initialMD) + , m_unitSystem(unitSystem) + , m_topWellBoreVolume(RicMswExportInfo::defaultDoubleValue()) + , m_linerDiameter(RimMswCompletionParameters::defaultLinerDiameter(unitSystem)) + , m_roughnessFactor(RimMswCompletionParameters::defaultRoughnessFactor(unitSystem)) + , m_lengthAndDepthText(lengthAndDepthText) + , m_pressureDropText(pressureDropText) + , m_hasSubGridIntersections(false) +{ +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicMswExportInfo::setLinerDiameter(double linerDiameter) +{ + m_linerDiameter = linerDiameter; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicMswExportInfo::setRoughnessFactor(double roughnessFactor) +{ + m_roughnessFactor = roughnessFactor; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicMswExportInfo::setHasSubGridIntersections(bool subGridIntersections) +{ + m_hasSubGridIntersections = subGridIntersections; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicMswExportInfo::addWellSegment(std::shared_ptr location) +{ + m_wellSegmentLocations.push_back(location); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicMswExportInfo::sortLocations() +{ + std::sort(m_wellSegmentLocations.begin(), + m_wellSegmentLocations.end(), + [](std::shared_ptr lhs, std::shared_ptr rhs) + { + return *lhs < *rhs; + }); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +const RimWellPath* RicMswExportInfo::wellPath() const +{ + return m_wellPath; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +double RicMswExportInfo::initialMD() const +{ + return m_initialMD; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +double RicMswExportInfo::initialTVD() const +{ + return -m_wellPath->wellPathGeometry()->interpolatedPointAlongWellPath(m_initialMD).z(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RiaEclipseUnitTools::UnitSystem RicMswExportInfo::unitSystem() const +{ + return m_unitSystem; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +double RicMswExportInfo::topWellBoreVolume() const +{ + return m_topWellBoreVolume; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +double RicMswExportInfo::linerDiameter() const +{ + return m_linerDiameter; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +double RicMswExportInfo::roughnessFactor() const +{ + return m_roughnessFactor; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RicMswExportInfo::lengthAndDepthText() const +{ + return m_lengthAndDepthText; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RicMswExportInfo::pressureDropText() const +{ + return m_pressureDropText; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RicMswExportInfo::hasSubGridIntersections() const +{ + return m_hasSubGridIntersections; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +double RicMswExportInfo::defaultDoubleValue() +{ + return std::numeric_limits::infinity(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +const std::vector>& RicMswExportInfo::wellSegmentLocations() const +{ + return m_wellSegmentLocations; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector>& RicMswExportInfo::wellSegmentLocations() +{ + return m_wellSegmentLocations; +} diff --git a/ApplicationCode/Commands/CompletionExportCommands/RicMswExportInfo.h b/ApplicationCode/Commands/CompletionExportCommands/RicMswExportInfo.h new file mode 100644 index 0000000000..634b9f535b --- /dev/null +++ b/ApplicationCode/Commands/CompletionExportCommands/RicMswExportInfo.h @@ -0,0 +1,79 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2018 Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "RiaEclipseUnitTools.h" + +#include "RicMswSegment.h" + +#include + +#include + +class RimWellPath; +class RimFishbonesMultipleSubs; + +//================================================================================================== +/// +//================================================================================================== +class RicMswExportInfo +{ +public: + RicMswExportInfo(const RimWellPath* wellPath, + RiaEclipseUnitTools::UnitSystem unitSystem, + double initialMD, + const QString& lengthAndDepthText, + const QString& pressureDropText); + + void setLinerDiameter(double linerDiameter); + void setRoughnessFactor(double roughnessFactor); + void setHasSubGridIntersections(bool subGridIntersections); + + void addWellSegment(std::shared_ptr location); + void sortLocations(); + + const RimWellPath* wellPath() const; + RiaEclipseUnitTools::UnitSystem unitSystem() const; + double initialMD() const; + double initialTVD() const; + double topWellBoreVolume() const; + double linerDiameter() const; + double roughnessFactor() const; + QString lengthAndDepthText() const; + QString pressureDropText() const; + bool hasSubGridIntersections() const; + static double defaultDoubleValue(); + + const std::vector>& wellSegmentLocations() const; + std::vector>& wellSegmentLocations(); + +private: + const RimWellPath* m_wellPath; + RiaEclipseUnitTools::UnitSystem m_unitSystem; + double m_initialMD; + double m_topWellBoreVolume; + double m_linerDiameter; + double m_roughnessFactor; + QString m_lengthAndDepthText; + QString m_pressureDropText; + bool m_hasSubGridIntersections; + + std::vector> m_wellSegmentLocations; +}; + diff --git a/ApplicationCode/Commands/CompletionExportCommands/RicMswSegment.cpp b/ApplicationCode/Commands/CompletionExportCommands/RicMswSegment.cpp new file mode 100644 index 0000000000..a9054af9aa --- /dev/null +++ b/ApplicationCode/Commands/CompletionExportCommands/RicMswSegment.cpp @@ -0,0 +1,264 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2018 Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "RicMswSegment.h" + +#include "RicMswExportInfo.h" + +#include +#include + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RicMswSegment::RicMswSegment(const QString& label, + double startMD, + double endMD, + double startTVD, + double endTVD, + size_t subIndex, + int segmentNumber /*= -1*/) + : m_label(label) + , m_startMD(startMD) + , m_endMD(endMD) + , m_startTVD(startTVD) + , m_endTVD(endTVD) + , m_effectiveDiameter(0.15) + , m_holeDiameter(RicMswExportInfo::defaultDoubleValue()) + , m_openHoleRoughnessFactor(5.0e-5) + , m_skinFactor(RicMswExportInfo::defaultDoubleValue()) + , m_subIndex(subIndex) + , m_segmentNumber(segmentNumber) +{ +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RicMswSegment::label() const +{ + return m_label; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +double RicMswSegment::startMD() const +{ + return m_startMD; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +double RicMswSegment::endMD() const +{ + return m_endMD; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +double RicMswSegment::deltaMD() const +{ + return m_endMD - m_startMD; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +double RicMswSegment::startTVD() const +{ + return m_startTVD; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +double RicMswSegment::endTVD() const +{ + return m_endTVD; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +double RicMswSegment::deltaTVD() const +{ + return m_endTVD - m_startTVD; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +double RicMswSegment::effectiveDiameter() const +{ + return m_effectiveDiameter; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +double RicMswSegment::holeDiameter() const +{ + return m_holeDiameter; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +double RicMswSegment::openHoleRoughnessFactor() const +{ + return m_openHoleRoughnessFactor; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +double RicMswSegment::skinFactor() const +{ + return m_skinFactor; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +size_t RicMswSegment::subIndex() const +{ + return m_subIndex; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +int RicMswSegment::segmentNumber() const +{ + return m_segmentNumber; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +const std::vector>& RicMswSegment::completions() const +{ + return m_completions; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector>& RicMswSegment::completions() +{ + return m_completions; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicMswSegment::setLabel(const QString& label) +{ + m_label = label; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicMswSegment::setEffectiveDiameter(double effectiveDiameter) +{ + m_effectiveDiameter = effectiveDiameter; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicMswSegment::setHoleDiameter(double holeDiameter) +{ + m_holeDiameter = holeDiameter; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicMswSegment::setOpenHoleRoughnessFactor(double roughnessFactor) +{ + m_openHoleRoughnessFactor = roughnessFactor; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicMswSegment::setSkinFactor(double skinFactor) +{ + m_skinFactor = skinFactor; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicMswSegment::setSegmentNumber(int segmentNumber) +{ + m_segmentNumber = segmentNumber; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicMswSegment::addCompletion(std::shared_ptr completion) +{ + m_completions.push_back(completion); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicMswSegment::removeCompletion(std::shared_ptr completion) +{ + for (auto it = m_completions.begin(); it != m_completions.end(); ++it) + { + if ((*it) == completion) + { + m_completions.erase(it); + break; + } + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicMswSegment::setSourcePdmObject(const caf::PdmObject* object) +{ + m_sourcePdmObject = const_cast(object); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +const caf::PdmObject* RicMswSegment::sourcePdmObject() const +{ + return m_sourcePdmObject; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RicMswSegment::operator<(const RicMswSegment& rhs) const +{ + return startMD() < rhs.startMD(); +} + diff --git a/ApplicationCode/Commands/CompletionExportCommands/RicMswSegment.h b/ApplicationCode/Commands/CompletionExportCommands/RicMswSegment.h new file mode 100644 index 0000000000..280b978cd8 --- /dev/null +++ b/ApplicationCode/Commands/CompletionExportCommands/RicMswSegment.h @@ -0,0 +1,92 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2018 Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// +#pragma once + +#include "RicMswCompletions.h" + +#include + +#include + +//================================================================================================== +/// +//================================================================================================== +class RicMswSegment +{ +public: + RicMswSegment(const QString& label, + double startMD, + double endMD, + double startTVD, + double endTVD, + size_t subIndex = cvf::UNDEFINED_SIZE_T, + int segmentNumber = -1); + + QString label() const; + + double startMD() const; + double endMD() const; + double deltaMD() const; + double startTVD() const; + double endTVD() const; + double deltaTVD() const; + + double effectiveDiameter() const; + double holeDiameter() const; + double openHoleRoughnessFactor() const; + double skinFactor() const; + + size_t subIndex() const; + int segmentNumber() const; + + const std::vector>& completions() const; + std::vector>& completions(); + + void setLabel(const QString& label); + void setEffectiveDiameter(double effectiveDiameter); + void setHoleDiameter(double holeDiameter); + void setOpenHoleRoughnessFactor(double roughnessFactor); + void setSkinFactor(double skinFactor); + void setSegmentNumber(int segmentNumber); + void addCompletion(std::shared_ptr completion); + void removeCompletion(std::shared_ptr completion); + + void setSourcePdmObject(const caf::PdmObject* object); + const caf::PdmObject* sourcePdmObject() const; + + bool operator<(const RicMswSegment& rhs) const; + +private: + QString m_label; + double m_startMD; + double m_endMD; + double m_startTVD; + double m_endTVD; + double m_effectiveDiameter; + double m_holeDiameter; + double m_openHoleRoughnessFactor; + double m_skinFactor; + + size_t m_subIndex; + int m_segmentNumber; + + std::vector> m_completions; + + caf::PdmPointer m_sourcePdmObject; +}; + diff --git a/ApplicationCode/Commands/CompletionExportCommands/RicMswSubSegment.cpp b/ApplicationCode/Commands/CompletionExportCommands/RicMswSubSegment.cpp new file mode 100644 index 0000000000..df88849394 --- /dev/null +++ b/ApplicationCode/Commands/CompletionExportCommands/RicMswSubSegment.cpp @@ -0,0 +1,184 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2018 Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "RicMswSubSegment.h" + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RicMswSubSegmentCellIntersection::RicMswSubSegmentCellIntersection(const QString& gridName, + size_t globalCellIndex, + const cvf::Vec3st& gridLocalCellIJK, + const cvf::Vec3d& lengthsInCell) + : m_gridName(gridName) + , m_globalCellIndex(globalCellIndex) + , m_gridLocalCellIJK(gridLocalCellIJK) + , m_lengthsInCell(lengthsInCell) +{ +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +const QString& RicMswSubSegmentCellIntersection::gridName() const +{ + return m_gridName; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +size_t RicMswSubSegmentCellIntersection::globalCellIndex() const +{ + return m_globalCellIndex; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +cvf::Vec3st RicMswSubSegmentCellIntersection::gridLocalCellIJK() const +{ + return m_gridLocalCellIJK; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +const cvf::Vec3d& RicMswSubSegmentCellIntersection::lengthsInCell() const +{ + return m_lengthsInCell; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RicMswSubSegment::RicMswSubSegment(double startMD, double endMD, double startTVD, double endTVD) + : m_startMD(startMD) + , m_endMD(endMD) + , m_startTVD(startTVD) + , m_endTVD(endTVD) + , m_segmentNumber(-1) + , m_attachedSegmentNumber(-1) +{ +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +double RicMswSubSegment::startMD() const +{ + return m_startMD; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +double RicMswSubSegment::endMD() const +{ + return m_endMD; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +double RicMswSubSegment::deltaMD() const +{ + return m_endMD - m_startMD; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +double RicMswSubSegment::startTVD() const +{ + return m_startTVD; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +double RicMswSubSegment::endTVD() const +{ + return m_endTVD; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +double RicMswSubSegment::deltaTVD() const +{ + return m_endTVD - m_startTVD; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +int RicMswSubSegment::segmentNumber() const +{ + return m_segmentNumber; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +int RicMswSubSegment::attachedSegmentNumber() const +{ + return m_attachedSegmentNumber; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicMswSubSegment::setSegmentNumber(int segmentNumber) +{ + m_segmentNumber = segmentNumber; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicMswSubSegment::setAttachedSegmentNumber(int attachedSegmentNumber) +{ + m_attachedSegmentNumber = attachedSegmentNumber; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicMswSubSegment::addIntersection(std::shared_ptr intersection) +{ + m_intersections.push_back(intersection); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +const std::vector>& RicMswSubSegment::intersections() const +{ + return m_intersections; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector>& RicMswSubSegment::intersections() +{ + return m_intersections; +} + + diff --git a/ApplicationCode/Commands/CompletionExportCommands/RicMswSubSegment.h b/ApplicationCode/Commands/CompletionExportCommands/RicMswSubSegment.h new file mode 100644 index 0000000000..6957ca2f6b --- /dev/null +++ b/ApplicationCode/Commands/CompletionExportCommands/RicMswSubSegment.h @@ -0,0 +1,88 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2018 Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// +#pragma once + +#include "cvfBase.h" +#include "cvfVector3.h" + +#include +#include +#include + +//================================================================================================== +/// +//================================================================================================== +class RicMswSubSegmentCellIntersection +{ +public: + RicMswSubSegmentCellIntersection(const QString& gridName, // Pass in empty string for main grid + size_t globalCellIndex, + const cvf::Vec3st& gridLocalCellIJK, + const cvf::Vec3d& lengthsInCell); + const QString& gridName() const; + size_t globalCellIndex() const; + cvf::Vec3st gridLocalCellIJK() const; + const cvf::Vec3d& lengthsInCell() const; +private: + QString m_gridName; + size_t m_globalCellIndex; + cvf::Vec3st m_gridLocalCellIJK; + cvf::Vec3d m_lengthsInCell; +}; + +//================================================================================================== +/// +//================================================================================================== +class RicMswSubSegment +{ +public: + RicMswSubSegment(double startMD, + double endMD, + double startTVD, + double endTVD); + + double startMD() const; + double endMD() const; + double deltaMD() const; + double startTVD() const; + double endTVD() const; + double deltaTVD() const; + + int segmentNumber() const; + int attachedSegmentNumber() const; + + void setSegmentNumber(int segmentNumber); + void setAttachedSegmentNumber(int attachedSegmentNumber); + void addIntersection(std::shared_ptr intersection); + + const std::vector>& intersections() const; + std::vector>& intersections(); + + +private: + double m_startMD; + double m_endMD; + double m_startTVD; + double m_endTVD; + int m_segmentNumber; + int m_attachedSegmentNumber; + + std::vector> m_intersections; +}; + + diff --git a/ApplicationCode/Commands/CompletionExportCommands/RicMswValveAccumulators.cpp b/ApplicationCode/Commands/CompletionExportCommands/RicMswValveAccumulators.cpp new file mode 100644 index 0000000000..58cebc4145 --- /dev/null +++ b/ApplicationCode/Commands/CompletionExportCommands/RicMswValveAccumulators.cpp @@ -0,0 +1,145 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2018 Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// +#include "RicMswValveAccumulators.h" + +#include "RiaStatisticsTools.h" + +#include "RicMswCompletions.h" + +#include "RimPerforationInterval.h" +#include "RimWellPathValve.h" + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RicMswICDAccumulator::RicMswICDAccumulator(RiaEclipseUnitTools::UnitSystem unitSystem) + : RicMswValveAccumulator(unitSystem) + , m_areaSum(0.0) +{ +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RicMswICDAccumulator::accumulateValveParameters(const RimWellPathValve* wellPathValve, size_t subValve, double contributionFraction) +{ + CVF_ASSERT(wellPathValve); + if (wellPathValve->componentType() == RiaDefines::ICV || wellPathValve->componentType() == RiaDefines::ICD) + { + double icdOrificeRadius = wellPathValve->orificeDiameter(m_unitSystem) / 2; + double icdArea = icdOrificeRadius * icdOrificeRadius * cvf::PI_D; + + m_areaSum += icdArea * contributionFraction; + m_coefficientCalculator.addValueAndWeight(wellPathValve->flowCoefficient(), icdArea * contributionFraction); + return true; + } + return false; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicMswICDAccumulator::applyToSuperValve(std::shared_ptr valve) +{ + std::shared_ptr icd = std::dynamic_pointer_cast(valve); + CVF_ASSERT(icd); + icd->setArea(m_areaSum); + if (m_coefficientCalculator.validAggregatedWeight()) + { + icd->setFlowCoefficient(m_coefficientCalculator.weightedMean()); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RicMswAICDAccumulator::RicMswAICDAccumulator(RiaEclipseUnitTools::UnitSystem unitSystem) + : RicMswValveAccumulator(unitSystem), m_valid(false), m_deviceOpen(false), m_accumulatedLength(0.0) +{ +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RicMswAICDAccumulator::accumulateValveParameters(const RimWellPathValve* wellPathValve, size_t subValve, double contributionFraction) +{ + CVF_ASSERT(wellPathValve); + if (wellPathValve->componentType() == RiaDefines::AICD) + { + const RimWellPathAicdParameters* params = wellPathValve->aicdParameters(); + if (params->isValid()) + { + m_valid = true; + m_deviceOpen = m_deviceOpen || params->isOpen(); + if (params->isOpen()) + { + std::array values = params->doubleValues(); + for (size_t i = 0; i < (size_t)AICD_NUM_PARAMS; ++i) + { + if (RiaStatisticsTools::isValidNumber(values[i])) + { + m_meanCalculators[i].addValueAndWeight(values[i], contributionFraction); + } + } + std::pair valveSegment = wellPathValve->valveSegments()[subValve]; + double valveSegmentLength = std::fabs(valveSegment.second - valveSegment.first); + const RimPerforationInterval* perfInterval = nullptr; + wellPathValve->firstAncestorOrThisOfTypeAsserted(perfInterval); + double perfIntervalLength = std::fabs(perfInterval->endMD() - perfInterval->startMD()); + double lengthFraction = 1.0; + if (perfIntervalLength > 1.0e-8) + { + lengthFraction = valveSegmentLength / perfIntervalLength; + } + m_accumulatedLength += lengthFraction * contributionFraction; + } + } + return true; + } + return false; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicMswAICDAccumulator::applyToSuperValve(std::shared_ptr valve) +{ + std::shared_ptr aicd = std::dynamic_pointer_cast(valve); + + if (aicd) + { + std::array values; + + for (size_t i = 0; i < (size_t) AICD_NUM_PARAMS; ++i) + { + if (m_meanCalculators[i].validAggregatedWeight()) + { + values[i] = m_meanCalculators[i].weightedMean(); + } + else + { + values[i] = std::numeric_limits::infinity(); + } + } + aicd->setIsValid(m_valid); + aicd->setIsOpen(m_deviceOpen); + aicd->setLength(m_accumulatedLength); + + aicd->values() = values; + } +} diff --git a/ApplicationCode/Commands/CompletionExportCommands/RicMswValveAccumulators.h b/ApplicationCode/Commands/CompletionExportCommands/RicMswValveAccumulators.h new file mode 100644 index 0000000000..0d448ee7ac --- /dev/null +++ b/ApplicationCode/Commands/CompletionExportCommands/RicMswValveAccumulators.h @@ -0,0 +1,74 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2018 Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// +#pragma once + +#include "RiaEclipseUnitTools.h" +#include "RiaWeightedMeanCalculator.h" +#include "RimWellPathAicdParameters.h" + +#include +#include + +class RimWellPathValve; +class RicMswValve; + +//================================================================================================== +/// +//================================================================================================== +class RicMswValveAccumulator +{ +public: + RicMswValveAccumulator(RiaEclipseUnitTools::UnitSystem unitSystem) : m_unitSystem(unitSystem) {} + virtual bool accumulateValveParameters(const RimWellPathValve* wellPathValve, size_t subValve, double contributionFraction) = 0; + virtual void applyToSuperValve(std::shared_ptr valve) = 0; + +protected: + RiaEclipseUnitTools::UnitSystem m_unitSystem; +}; + +//================================================================================================== +/// +//================================================================================================== +class RicMswICDAccumulator : public RicMswValveAccumulator +{ +public: + RicMswICDAccumulator(RiaEclipseUnitTools::UnitSystem unitSystem); + bool accumulateValveParameters(const RimWellPathValve* wellPathValve, size_t subValve, double contributionFraction) override; + void applyToSuperValve(std::shared_ptr valve) override; + +private: + RiaWeightedMeanCalculator m_coefficientCalculator; + double m_areaSum; +}; + +//================================================================================================== +/// +//================================================================================================== +class RicMswAICDAccumulator : public RicMswValveAccumulator +{ +public: + RicMswAICDAccumulator(RiaEclipseUnitTools::UnitSystem unitSystem); + bool accumulateValveParameters(const RimWellPathValve* wellPathValve, size_t subValve, double contributionFraction) override; + void applyToSuperValve(std::shared_ptr valve) override; + +private: + bool m_valid; + bool m_deviceOpen; + std::array, AICD_NUM_PARAMS> m_meanCalculators; + double m_accumulatedLength; +}; \ No newline at end of file diff --git a/ApplicationCode/Commands/CompletionExportCommands/RicMultiSegmentWellExportInfo.cpp b/ApplicationCode/Commands/CompletionExportCommands/RicMultiSegmentWellExportInfo.cpp deleted file mode 100644 index 6439d49e80..0000000000 --- a/ApplicationCode/Commands/CompletionExportCommands/RicMultiSegmentWellExportInfo.cpp +++ /dev/null @@ -1,656 +0,0 @@ -#include "RicMultiSegmentWellExportInfo.h" - -#include "RimMswCompletionParameters.h" -#include "RimWellPath.h" - -#include "RigWellPath.h" - -#include -#include - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -RicMswSubSegmentCellIntersection::RicMswSubSegmentCellIntersection(const QString& gridName, - size_t globalCellIndex, - const cvf::Vec3st& gridLocalCellIJK, - const cvf::Vec3d& lengthsInCell) - : m_gridName(gridName) - , m_globalCellIndex(globalCellIndex) - , m_gridLocalCellIJK(gridLocalCellIJK) - , m_lengthsInCell(lengthsInCell) -{ -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -const QString& RicMswSubSegmentCellIntersection::gridName() const -{ - return m_gridName; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -size_t RicMswSubSegmentCellIntersection::globalCellIndex() const -{ - return m_globalCellIndex; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -cvf::Vec3st RicMswSubSegmentCellIntersection::gridLocalCellIJK() const -{ - return m_gridLocalCellIJK; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -const cvf::Vec3d& RicMswSubSegmentCellIntersection::lengthsInCell() const -{ - return m_lengthsInCell; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -RicMswSubSegment::RicMswSubSegment(double startMD, double deltaMD, double startTVD, double deltaTVD) - : m_startMD(startMD) - , m_deltaMD(deltaMD) - , m_startTVD(startTVD) - , m_deltaTVD(deltaTVD) - , m_segmentNumber(-1) - , m_attachedSegmentNumber(-1) -{ -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -double RicMswSubSegment::startMD() const -{ - return m_startMD; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -double RicMswSubSegment::deltaMD() const -{ - return m_deltaMD; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -double RicMswSubSegment::startTVD() const -{ - return m_startTVD; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -double RicMswSubSegment::deltaTVD() const -{ - return m_deltaTVD; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -int RicMswSubSegment::segmentNumber() const -{ - return m_segmentNumber; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -int RicMswSubSegment::attachedSegmentNumber() const -{ - return m_attachedSegmentNumber; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RicMswSubSegment::setSegmentNumber(int segmentNumber) -{ - m_segmentNumber = segmentNumber; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RicMswSubSegment::setAttachedSegmentNumber(int attachedSegmentNumber) -{ - m_attachedSegmentNumber = attachedSegmentNumber; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RicMswSubSegment::addIntersection(const RicMswSubSegmentCellIntersection& intersection) -{ - m_intersections.push_back(intersection); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -const std::vector& RicMswSubSegment::intersections() const -{ - return m_intersections; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -std::vector& RicMswSubSegment::intersections() -{ - return m_intersections; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -RicMswCompletion::RicMswCompletion(RigCompletionData::CompletionType completionType, - const QString& label, - size_t index /* = cvf::UNDEFINED_SIZE_T */, - int branchNumber /*= 0*/) - : m_completionType(completionType) - , m_label(label) - , m_index(index) - , m_branchNumber(branchNumber) -{ -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -RigCompletionData::CompletionType RicMswCompletion::completionType() const -{ - return m_completionType; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -const QString& RicMswCompletion::label() const -{ - return m_label; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -size_t RicMswCompletion::index() const -{ - return m_index; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -int RicMswCompletion::branchNumber() const -{ - return m_branchNumber; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RicMswCompletion::setBranchNumber(int branchNumber) -{ - m_branchNumber = branchNumber; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RicMswCompletion::addSubSegment(const RicMswSubSegment& subSegment) -{ - m_subSegments.push_back(subSegment); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -std::vector& RicMswCompletion::subSegments() -{ - return m_subSegments; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -const std::vector& RicMswCompletion::subSegments() const -{ - return m_subSegments; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -RicMswSegment::RicMswSegment(const QString& label, - double startMD, - double endMD, - double startTVD, - double endTVD, - size_t subIndex, - int segmentNumber /*= -1*/) - : m_label(label) - , m_startMD(startMD) - , m_endMD(endMD) - , m_startTVD(startTVD) - , m_endTVD(endTVD) - , m_effectiveDiameter(0.15) - , m_holeDiameter(RicMswExportInfo::defaultDoubleValue()) - , m_openHoleRoughnessFactor(5.0e-5) - , m_skinFactor(RicMswExportInfo::defaultDoubleValue()) - , m_icdFlowCoefficient(RicMswExportInfo::defaultDoubleValue()) - , m_icdArea(RicMswExportInfo::defaultDoubleValue()) - , m_subIndex(subIndex) - , m_segmentNumber(segmentNumber) -{ -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -QString RicMswSegment::label() const -{ - return m_label; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -double RicMswSegment::startMD() const -{ - return m_startMD; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -double RicMswSegment::endMD() const -{ - return m_endMD; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -double RicMswSegment::deltaMD() const -{ - return m_endMD - m_startMD; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -double RicMswSegment::startTVD() const -{ - return m_startTVD; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -double RicMswSegment::endTVD() const -{ - return m_endTVD; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -double RicMswSegment::deltaTVD() const -{ - return m_endTVD - m_startTVD; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -double RicMswSegment::effectiveDiameter() const -{ - return m_effectiveDiameter; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -double RicMswSegment::holeDiameter() const -{ - return m_holeDiameter; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -double RicMswSegment::openHoleRoughnessFactor() const -{ - return m_openHoleRoughnessFactor; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -double RicMswSegment::skinFactor() const -{ - return m_skinFactor; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -double RicMswSegment::icdFlowCoefficient() const -{ - return m_icdFlowCoefficient; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -double RicMswSegment::icdArea() const -{ - return m_icdArea; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -size_t RicMswSegment::subIndex() const -{ - return m_subIndex; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -int RicMswSegment::segmentNumber() const -{ - return m_segmentNumber; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -const std::vector& RicMswSegment::completions() const -{ - return m_completions; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -std::vector& RicMswSegment::completions() -{ - return m_completions; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RicMswSegment::setEffectiveDiameter(double effectiveDiameter) -{ - m_effectiveDiameter = effectiveDiameter; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RicMswSegment::setHoleDiameter(double holeDiameter) -{ - m_holeDiameter = holeDiameter; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RicMswSegment::setOpenHoleRoughnessFactor(double roughnessFactor) -{ - m_openHoleRoughnessFactor = roughnessFactor; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RicMswSegment::setSkinFactor(double skinFactor) -{ - m_skinFactor = skinFactor; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RicMswSegment::setIcdFlowCoefficient(double icdFlowCoefficient) -{ - m_icdFlowCoefficient = icdFlowCoefficient; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RicMswSegment::setIcdArea(double icdArea) -{ - m_icdArea = icdArea; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RicMswSegment::setSegmentNumber(int segmentNumber) -{ - m_segmentNumber = segmentNumber; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RicMswSegment::addCompletion(const RicMswCompletion& completion) -{ - m_completions.push_back(completion); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RicMswSegment::setSourcePdmObject(const caf::PdmObject* object) -{ - m_sourcePdmObject = const_cast(object); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -const caf::PdmObject* RicMswSegment::sourcePdmObject() const -{ - return m_sourcePdmObject; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -bool RicMswSegment::operator<(const RicMswSegment& rhs) const -{ - return startMD() < rhs.startMD(); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -RicMswExportInfo::RicMswExportInfo(const RimWellPath* wellPath, - RiaEclipseUnitTools::UnitSystem unitSystem, - double initialMD, - const QString& lengthAndDepthText, - const QString& pressureDropText) - : m_wellPath(wellPath) - , m_initialMD(initialMD) - , m_unitSystem(unitSystem) - , m_topWellBoreVolume(RicMswExportInfo::defaultDoubleValue()) - , m_linerDiameter(RimMswCompletionParameters::defaultLinerDiameter(unitSystem)) - , m_roughnessFactor(RimMswCompletionParameters::defaultRoughnessFactor(unitSystem)) - , m_lengthAndDepthText(lengthAndDepthText) - , m_pressureDropText(pressureDropText) - , m_hasSubGridIntersections(false) -{ -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RicMswExportInfo::setTopWellBoreVolume(double topWellBoreVolume) -{ - m_topWellBoreVolume = topWellBoreVolume; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RicMswExportInfo::setLinerDiameter(double linerDiameter) -{ - m_linerDiameter = linerDiameter; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RicMswExportInfo::setRoughnessFactor(double roughnessFactor) -{ - m_roughnessFactor = roughnessFactor; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RicMswExportInfo::setHasSubGridIntersections(bool subGridIntersections) -{ - m_hasSubGridIntersections = subGridIntersections; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RicMswExportInfo::addWellSegmentLocation(const RicMswSegment& location) -{ - m_wellSegmentLocations.push_back(location); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RicMswExportInfo::sortLocations() -{ - std::sort(m_wellSegmentLocations.begin(), m_wellSegmentLocations.end()); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -const RimWellPath* RicMswExportInfo::wellPath() const -{ - return m_wellPath; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -double RicMswExportInfo::initialMD() const -{ - return m_initialMD; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -double RicMswExportInfo::initialTVD() const -{ - return -m_wellPath->wellPathGeometry()->interpolatedPointAlongWellPath(m_initialMD).z(); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -RiaEclipseUnitTools::UnitSystem RicMswExportInfo::unitSystem() const -{ - return m_unitSystem; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -double RicMswExportInfo::topWellBoreVolume() const -{ - return m_topWellBoreVolume; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -double RicMswExportInfo::linerDiameter() const -{ - return m_linerDiameter; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -double RicMswExportInfo::roughnessFactor() const -{ - return m_roughnessFactor; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -QString RicMswExportInfo::lengthAndDepthText() const -{ - return m_lengthAndDepthText; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -QString RicMswExportInfo::pressureDropText() const -{ - return m_pressureDropText; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -bool RicMswExportInfo::hasSubGridIntersections() const -{ - return m_hasSubGridIntersections; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -double RicMswExportInfo::defaultDoubleValue() -{ - return std::numeric_limits::infinity(); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -const std::vector& RicMswExportInfo::wellSegmentLocations() const -{ - return m_wellSegmentLocations; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -std::vector& RicMswExportInfo::wellSegmentLocations() -{ - return m_wellSegmentLocations; -} diff --git a/ApplicationCode/Commands/CompletionExportCommands/RicMultiSegmentWellExportInfo.h b/ApplicationCode/Commands/CompletionExportCommands/RicMultiSegmentWellExportInfo.h deleted file mode 100644 index aded04da13..0000000000 --- a/ApplicationCode/Commands/CompletionExportCommands/RicMultiSegmentWellExportInfo.h +++ /dev/null @@ -1,235 +0,0 @@ -///////////////////////////////////////////////////////////////////////////////// -// -// Copyright (C) 2018 Equinor ASA -// -// ResInsight 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 3 of the License, or -// (at your option) any later version. -// -// ResInsight 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 at -// for more details. -// -///////////////////////////////////////////////////////////////////////////////// - -#pragma once - -#include "RiaEclipseUnitTools.h" -#include "RigCompletionData.h" - -#include "cvfBase.h" -#include "cvfMath.h" -#include "cvfVector3.h" - -#include - -class RimWellPath; -class RimFishbonesMultipleSubs; - -//================================================================================================== -/// -//================================================================================================== -class RicMswSubSegmentCellIntersection -{ -public: - RicMswSubSegmentCellIntersection(const QString& gridName, // Pass in empty string for main grid - size_t globalCellIndex, - const cvf::Vec3st& gridLocalCellIJK, - const cvf::Vec3d& lengthsInCell); - const QString& gridName() const; - size_t globalCellIndex() const; - cvf::Vec3st gridLocalCellIJK() const; - const cvf::Vec3d& lengthsInCell() const; -private: - QString m_gridName; - size_t m_globalCellIndex; - cvf::Vec3st m_gridLocalCellIJK; - cvf::Vec3d m_lengthsInCell; -}; - -//================================================================================================== -/// -//================================================================================================== -class RicMswSubSegment -{ -public: - RicMswSubSegment(double startMD, - double deltaMD, - double startTVD, - double deltaTVD); - - double startMD() const; - double deltaMD() const; - double startTVD() const; - double deltaTVD() const; - - int segmentNumber() const; - int attachedSegmentNumber() const; - - void setSegmentNumber(int segmentNumber); - void setAttachedSegmentNumber(int attachedSegmentNumber); - void addIntersection(const RicMswSubSegmentCellIntersection& intersection); - - const std::vector& intersections() const; - std::vector& intersections(); - - -private: - double m_startMD; - double m_deltaMD; - double m_startTVD; - double m_deltaTVD; - int m_segmentNumber; - int m_attachedSegmentNumber; - - std::vector m_intersections; -}; - -//================================================================================================== -/// -//================================================================================================== -class RicMswCompletion -{ -public: - RicMswCompletion(RigCompletionData::CompletionType completionType, const QString& label, size_t index = cvf::UNDEFINED_SIZE_T, int branchNumber = cvf::UNDEFINED_INT); - - RigCompletionData::CompletionType completionType() const; - const QString& label() const; - size_t index() const; - int branchNumber() const; - void setBranchNumber(int branchNumber); - - void addSubSegment(const RicMswSubSegment& subSegment); - - std::vector& subSegments(); - const std::vector& subSegments() const; - -private: - RigCompletionData::CompletionType m_completionType; - QString m_label; - size_t m_index; - int m_branchNumber; - std::vector m_subSegments; -}; - -//================================================================================================== -/// -//================================================================================================== -class RicMswSegment -{ -public: - RicMswSegment(const QString& label, - double startMD, - double endMD, - double startTVD, - double endTVD, - size_t subIndex = cvf::UNDEFINED_SIZE_T, - int segmentNumber = -1); - - QString label() const; - - double startMD() const; - double endMD() const; - double deltaMD() const; - double startTVD() const; - double endTVD() const; - double deltaTVD() const; - - double effectiveDiameter() const; - double holeDiameter() const; - double openHoleRoughnessFactor() const; - double skinFactor() const; - double icdFlowCoefficient() const; - double icdArea() const; - - size_t subIndex() const; - int segmentNumber() const; - - const std::vector& completions() const; - std::vector& completions(); - - void setEffectiveDiameter(double effectiveDiameter); - void setHoleDiameter(double holeDiameter); - void setOpenHoleRoughnessFactor(double roughnessFactor); - void setSkinFactor(double skinFactor); - void setIcdFlowCoefficient(double icdFlowCoefficient); - void setIcdArea(double icdArea); - void setSegmentNumber(int segmentNumber); - void addCompletion(const RicMswCompletion& completion); - - void setSourcePdmObject(const caf::PdmObject* object); - const caf::PdmObject* sourcePdmObject() const; - - bool operator<(const RicMswSegment& rhs) const; - -private: - QString m_label; - double m_startMD; - double m_endMD; - double m_startTVD; - double m_endTVD; - double m_effectiveDiameter; - double m_holeDiameter; - double m_linerDiameter; - double m_openHoleRoughnessFactor; - double m_skinFactor; - double m_icdFlowCoefficient; - double m_icdArea; - - size_t m_subIndex; - int m_segmentNumber; - - std::vector m_completions; - - caf::PdmPointer m_sourcePdmObject; -}; - -class RicMswExportInfo -{ -public: - RicMswExportInfo(const RimWellPath* wellPath, - RiaEclipseUnitTools::UnitSystem unitSystem, - double initialMD, - const QString& lengthAndDepthText, - const QString& pressureDropText); - - void setTopWellBoreVolume(double topWellBoreVolume); - void setLinerDiameter(double linerDiameter); - void setRoughnessFactor(double roughnessFactor); - void setHasSubGridIntersections(bool subGridIntersections); - - void addWellSegmentLocation(const RicMswSegment& location); - void sortLocations(); - - const RimWellPath* wellPath() const; - RiaEclipseUnitTools::UnitSystem unitSystem() const; - double initialMD() const; - double initialTVD() const; - double topWellBoreVolume() const; - double linerDiameter() const; - double roughnessFactor() const; - QString lengthAndDepthText() const; - QString pressureDropText() const; - bool hasSubGridIntersections() const; - static double defaultDoubleValue(); - - const std::vector& wellSegmentLocations() const; - std::vector& wellSegmentLocations(); - -private: - const RimWellPath* m_wellPath; - RiaEclipseUnitTools::UnitSystem m_unitSystem; - double m_initialMD; - double m_topWellBoreVolume; - double m_linerDiameter; - double m_roughnessFactor; - QString m_lengthAndDepthText; - QString m_pressureDropText; - bool m_hasSubGridIntersections; - std::vector m_wellSegmentLocations; -}; - diff --git a/ApplicationCode/Commands/CompletionExportCommands/RicWellPathExportCompletionDataFeature.cpp b/ApplicationCode/Commands/CompletionExportCommands/RicWellPathExportCompletionDataFeature.cpp index 11d975fbfa..d9d09ecfc2 100644 --- a/ApplicationCode/Commands/CompletionExportCommands/RicWellPathExportCompletionDataFeature.cpp +++ b/ApplicationCode/Commands/CompletionExportCommands/RicWellPathExportCompletionDataFeature.cpp @@ -21,8 +21,8 @@ #include "RiaApplication.h" -#include "RicExportFeatureImpl.h" #include "ExportCommands/RicExportLgrFeature.h" +#include "RicExportFeatureImpl.h" #include "RimDialogData.h" #include "RimFishbonesMultipleSubs.h" @@ -33,7 +33,9 @@ #include "RimSimWellInViewCollection.h" #include "RimWellPath.h" #include "RimWellPathCollection.h" +#include "RimWellPathCompletions.h" #include "RimWellPathFracture.h" +#include "RimWellPathValve.h" #include "Riu3DMainWindowTools.h" @@ -122,6 +124,17 @@ void RicWellPathExportCompletionDataFeature::prepareExportSettingsAndExportCompl if (!wellPathPerforations.empty()) { exportSettings->showPerforationsInUi(true); + + std::vector perforationValves; + for (const auto& perf : wellPathPerforations) + { + perf->descendantsIncludingThisOfType(perforationValves); + } + + if (!perforationValves.empty()) + { + exportSettings->enableIncludeMsw(); + } } else { @@ -129,7 +142,7 @@ void RicWellPathExportCompletionDataFeature::prepareExportSettingsAndExportCompl } caf::PdmUiPropertyViewDialog propertyDialog(Riu3DMainWindowTools::mainWindowWidget(), exportSettings, dialogTitle, ""); - RicExportFeatureImpl::configureForExport(&propertyDialog); + RicExportFeatureImpl::configureForExport(propertyDialog.dialogButtonBox()); if (propertyDialog.exec() == QDialog::Accepted) { @@ -173,9 +186,16 @@ void RicWellPathExportCompletionDataFeature::onActionTriggered(bool isChecked) //-------------------------------------------------------------------------------------------------- void RicWellPathExportCompletionDataFeature::setupActionLook(QAction* actionToSetup) { - actionToSetup->setText("Export Completion Data for Selected Well Paths"); + std::vector selected = selectedWellPaths(); + if (selected.size() == 1u) + { + actionToSetup->setText("Export Completion Data for Current Well Path"); + } + else + { + actionToSetup->setText("Export Completion Data for Selected Well Paths"); + } actionToSetup->setIcon(QIcon(":/ExportCompletionsSymbol16x16.png")); - } //-------------------------------------------------------------------------------------------------- @@ -189,5 +209,17 @@ std::vector RicWellPathExportCompletionDataFeature::selectedWellPa std::set uniqueWellPaths(wellPaths.begin(), wellPaths.end()); wellPaths.assign(uniqueWellPaths.begin(), uniqueWellPaths.end()); + if (wellPaths.empty()) + { + RimWellPathCompletions* completions = + caf::SelectionManager::instance()->selectedItemAncestorOfType(); + if (completions) + { + RimWellPath* wellPath = nullptr; + completions->firstAncestorOrThisOfTypeAsserted(wellPath); + wellPaths.push_back(wellPath); + } + } + return wellPaths; } diff --git a/ApplicationCode/Commands/CompletionExportCommands/RicWellPathExportCompletionDataFeatureImpl.cpp b/ApplicationCode/Commands/CompletionExportCommands/RicWellPathExportCompletionDataFeatureImpl.cpp index 7e0081b18c..d342de6797 100644 --- a/ApplicationCode/Commands/CompletionExportCommands/RicWellPathExportCompletionDataFeatureImpl.cpp +++ b/ApplicationCode/Commands/CompletionExportCommands/RicWellPathExportCompletionDataFeatureImpl.cpp @@ -23,6 +23,7 @@ #include "RiaFractureDefines.h" #include "RiaLogging.h" #include "RiaPreferences.h" +#include "RiaWeightedMeanCalculator.h" #include "../ExportCommands/RicExportLgrFeature.h" #include "RicExportCompletionDataSettingsUi.h" @@ -31,6 +32,7 @@ #include "RicFishbonesTransmissibilityCalculationFeatureImp.h" #include "RicWellPathFractureReportItem.h" #include "RicWellPathFractureTextReportFeatureImpl.h" +#include "RicWellPathExportMswCompletionsImpl.h" #include "RifEclipseDataTableFormatter.h" @@ -61,6 +63,7 @@ #include "RimWellPathCompletions.h" #include "RimWellPathFracture.h" #include "RimWellPathFractureCollection.h" +#include "RimWellPathValve.h" #include "RiuMainWindow.h" @@ -72,55 +75,10 @@ #include "cvfPlane.h" #include +#include +#include +#include "RicWellPathExportCompletionsFileTools.h" -//-------------------------------------------------------------------------------------------------- -/// Internal definitions -//-------------------------------------------------------------------------------------------------- -class SubSegmentIntersectionInfo -{ -public: - SubSegmentIntersectionInfo(size_t globCellIndex, - double startTVD, - double endTVD, - double startMD, - double endMD, - cvf::Vec3d lengthsInCell) - : globCellIndex(globCellIndex) - , startTVD(startTVD) - , endTVD(endTVD) - , startMD(startMD) - , endMD(endMD) - , intersectionLengthsInCellCS(lengthsInCell) - { - } - - size_t globCellIndex; - double startTVD; - double endTVD; - double startMD; - double endMD; - cvf::Vec3d intersectionLengthsInCellCS; -}; - -const RimWellPath* findWellPathFromExportName(const QString& wellNameForExport); -std::vector - spiltIntersectionSegmentsToMaxLength(const RigWellPath* pathGeometry, - const std::vector& intersections, - double maxSegmentLength); -int numberOfSplittedSegments(double startMd, double endMd, double maxSegmentLength); - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -class OpenFileException -{ -public: - OpenFileException(const QString& message) - : message(message) - { - } - QString message; -}; //-------------------------------------------------------------------------------------------------- /// @@ -345,7 +303,7 @@ void RicWellPathExportCompletionDataFeatureImpl::exportCompletions(const std::ve } } - QString fileName = QString("%1_unifiedCompletions_%2").arg(wellPath->name()).arg(eclipseCaseName); + QString fileName = QString("%1_UnifiedCompletions_%2").arg(wellPath->name()).arg(eclipseCaseName); sortAndExportCompletionsToFile(exportSettings.caseToApply, exportSettings.folder, fileName, @@ -454,77 +412,7 @@ void RicWellPathExportCompletionDataFeatureImpl::exportCompletions(const std::ve if (exportSettings.includeMsw) { - if (exportSettings.includeFractures()) - { - bool anyActiveFractures = false; - - for (const auto& wellPath : wellPaths) - { - if (!wellPath->fractureCollection()->activeFractures().empty()) - { - anyActiveFractures = true; - } - } - - if (anyActiveFractures) - { - QString fileName = QString("%1-Fracture-Welsegs").arg(exportSettings.caseToApply->caseUserDescription()); - QFilePtr exportFile = openFileForExport(exportSettings.folder, fileName); - - for (const auto wellPath : wellPaths) - { - auto fractures = wellPath->fractureCollection()->activeFractures(); - if (!fractures.empty()) - { - exportWellSegments(exportSettings.caseToApply, exportFile, wellPath, fractures); - } - } - exportFile->close(); - } - } - - if (exportSettings.includeFishbones()) - { - bool anyFishbones = false; - - for (const auto& wellPath : wellPaths) - { - if (!wellPath->fishbonesCollection()->activeFishbonesSubs().empty()) - { - anyFishbones = true; - } - } - - if (anyFishbones) - { - QString fileName = QString("%1-Fishbone-Welsegs").arg(exportSettings.caseToApply->caseUserDescription()); - QFilePtr exportFile = openFileForExport(exportSettings.folder, fileName); - - for (const auto wellPath : wellPaths) - { - auto fishbones = wellPath->fishbonesCollection()->activeFishbonesSubs(); - if (!fishbones.empty()) - { - exportWellSegments(exportSettings.caseToApply, exportFile, wellPath, fishbones); - } - } - - exportFile->close(); - } - } - - if (exportSettings.includePerforations()) - { - QString fileName = QString("%1-Perforation-Welsegs").arg(exportSettings.caseToApply->caseUserDescription()); - QFilePtr exportFile = openFileForExport(exportSettings.folder, fileName); - - for (const auto wellPath : wellPaths) - { - auto perforations = wellPath->perforationIntervalCollection()->perforations(); - exportWellSegments(exportSettings, exportFile, wellPath, perforations); - } - exportFile->close(); - } + RicWellPathExportMswCompletionsImpl::exportWellSegmentsForAllCompletions(exportSettings, wellPaths); } } @@ -591,398 +479,6 @@ std::vector return completionsPerEclipseCell; } -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RicWellPathExportCompletionDataFeatureImpl::generateWelsegsTable(RifEclipseDataTableFormatter& formatter, - const RicMswExportInfo& exportInfo) -{ - formatter.keyword("WELSEGS"); - - double startMD = exportInfo.initialMD(); - double startTVD = exportInfo.initialTVD(); - - { - std::vector header = { - RifEclipseOutputTableColumn("Name"), - RifEclipseOutputTableColumn("Dep 1"), - RifEclipseOutputTableColumn("Tlen 1"), - RifEclipseOutputTableColumn("Vol 1"), - RifEclipseOutputTableColumn("Len&Dep"), - RifEclipseOutputTableColumn("PresDrop"), - }; - formatter.header(header); - - formatter.add(exportInfo.wellPath()->name()); - formatter.add(startTVD); - formatter.add(startMD); - formatter.addValueOrDefaultMarker(exportInfo.topWellBoreVolume(), RicMswExportInfo::defaultDoubleValue()); - formatter.add(exportInfo.lengthAndDepthText()); - formatter.add(QString("'%1'").arg(exportInfo.pressureDropText())); - - formatter.rowCompleted(); - } - - { - std::vector header = { - RifEclipseOutputTableColumn("First Seg"), - RifEclipseOutputTableColumn("Last Seg"), - RifEclipseOutputTableColumn("Branch Num"), - RifEclipseOutputTableColumn("Outlet Seg"), - RifEclipseOutputTableColumn("Length"), - RifEclipseOutputTableColumn("Depth Change"), - RifEclipseOutputTableColumn("Diam"), - RifEclipseOutputTableColumn("Rough"), - }; - formatter.header(header); - } - - { - double prevMD = exportInfo.initialMD(); - double prevTVD = exportInfo.initialTVD(); - formatter.comment("Main Stem Segments"); - for (const RicMswSegment& location : exportInfo.wellSegmentLocations()) - { - double depth = 0; - double length = 0; - - if (exportInfo.lengthAndDepthText() == QString("INC")) - { - depth = location.endTVD() - prevTVD; - length = location.endMD() - prevMD; - } - else - { - depth = location.endTVD(); - length = location.endMD(); - } - - if (location.subIndex() != cvf::UNDEFINED_SIZE_T) - { - QString comment = location.label() + QString(", sub %1").arg(location.subIndex()); - formatter.comment(comment); - } - - formatter.add(location.segmentNumber()).add(location.segmentNumber()); - formatter.add(1); // All segments on main stem are branch 1 - formatter.add(location.segmentNumber() - 1); // All main stem segments are connected to the segment below them - formatter.add(length); - formatter.add(depth); - formatter.add(exportInfo.linerDiameter()); - formatter.add(exportInfo.roughnessFactor()); - formatter.rowCompleted(); - prevMD = location.endMD(); - prevTVD = location.endTVD(); - } - } - - { - generateWelsegsSegments(formatter, exportInfo, {RigCompletionData::ICD, RigCompletionData::FISHBONES}); - generateWelsegsSegments(formatter, exportInfo, {RigCompletionData::FRACTURE}); - } - - formatter.tableCompleted(); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RicWellPathExportCompletionDataFeatureImpl::generateWelsegsSegments( - RifEclipseDataTableFormatter& formatter, - const RicMswExportInfo& exportInfo, - const std::set& exportCompletionTypes) -{ - bool generatedHeader = false; - for (const RicMswSegment& segment : exportInfo.wellSegmentLocations()) - { - for (const RicMswCompletion& completion : segment.completions()) - { - if (exportCompletionTypes.count(completion.completionType())) - { - if (!generatedHeader) - { - generateWelsegsCompletionCommentHeader(formatter, completion.completionType()); - generatedHeader = true; - } - - if (completion.completionType() == RigCompletionData::ICD) // Found ICD - { - formatter.comment(completion.label()); - formatter.add(completion.subSegments().front().segmentNumber()); - formatter.add(completion.subSegments().front().segmentNumber()); - formatter.add(completion.branchNumber()); - formatter.add(segment.segmentNumber()); - formatter.add(0.1); // ICDs have 0.1 length - formatter.add(0); // Depth change - formatter.add(exportInfo.linerDiameter()); - formatter.add(exportInfo.roughnessFactor()); - formatter.rowCompleted(); - } - else - { - if (completion.completionType() == RigCompletionData::FISHBONES) - { - formatter.comment(QString("%1 : Sub index %2 - %3") - .arg(segment.label()) - .arg(segment.subIndex()) - .arg(completion.label())); - } - else if (completion.completionType() == RigCompletionData::FRACTURE) - { - formatter.comment(QString("%1 connected to %2").arg(completion.label()).arg(segment.label())); - } - - for (const RicMswSubSegment& subSegment : completion.subSegments()) - { - double depth = 0; - double length = 0; - - if (exportInfo.lengthAndDepthText() == QString("INC")) - { - depth = subSegment.deltaTVD(); - length = subSegment.deltaMD(); - } - else - { - depth = subSegment.startTVD() + subSegment.deltaTVD(); - length = subSegment.startMD() + subSegment.deltaMD(); - } - double diameter = segment.effectiveDiameter(); - formatter.add(subSegment.segmentNumber()); - formatter.add(subSegment.segmentNumber()); - formatter.add(completion.branchNumber()); - formatter.add(subSegment.attachedSegmentNumber()); - formatter.add(length); - formatter.add(depth); - formatter.add(diameter); - formatter.add(segment.openHoleRoughnessFactor()); - formatter.rowCompleted(); - } - } - } - } - } -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RicWellPathExportCompletionDataFeatureImpl::generateWelsegsCompletionCommentHeader( - RifEclipseDataTableFormatter& formatter, - RigCompletionData::CompletionType completionType) -{ - if (completionType == RigCompletionData::CT_UNDEFINED) - { - formatter.comment("Main stem"); - } - else if (completionType == RigCompletionData::ICD) - { - formatter.comment("Fishbone Laterals"); - formatter.comment("Diam: MSW - Tubing Radius"); - formatter.comment("Rough: MSW - Open Hole Roughness Factor"); - } - else if (completionType == RigCompletionData::FRACTURE) - { - formatter.comment("Fracture Segments"); - formatter.comment("Diam: MSW - Default Dummy"); - formatter.comment("Rough: MSW - Default Dummy"); - } -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RicWellPathExportCompletionDataFeatureImpl::generateCompsegTables(RifEclipseDataTableFormatter& formatter, - const RicMswExportInfo& exportInfo) -{ - /* - * TODO: Creating the regular perforation COMPSEGS table should come in here, before the others - * should take precedence by appearing later in the output. See #3230. - */ - - { - std::set fishbonesTypes = {RigCompletionData::ICD, RigCompletionData::FISHBONES}; - generateCompsegTable(formatter, exportInfo, false, fishbonesTypes); - if (exportInfo.hasSubGridIntersections()) - { - generateCompsegTable(formatter, exportInfo, true, fishbonesTypes); - } - } - - { - std::set fractureTypes = {RigCompletionData::FRACTURE}; - generateCompsegTable(formatter, exportInfo, false, fractureTypes); - if (exportInfo.hasSubGridIntersections()) - { - generateCompsegTable(formatter, exportInfo, true, fractureTypes); - } - } - - { - std::set completionTypes = {RigCompletionData::PERFORATION}; - generateCompsegTable(formatter, exportInfo, false, completionTypes); - if (exportInfo.hasSubGridIntersections()) - { - generateCompsegTable(formatter, exportInfo, true, completionTypes); - } - } -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RicWellPathExportCompletionDataFeatureImpl::generateCompsegTable( - RifEclipseDataTableFormatter& formatter, - const RicMswExportInfo& exportInfo, - bool exportSubGridIntersections, - const std::set& exportCompletionTypes) -{ - bool generatedHeader = false; - - for (const RicMswSegment& location : exportInfo.wellSegmentLocations()) - { - double startMD = location.startMD(); - - for (const RicMswCompletion& completion : location.completions()) - { - if (exportCompletionTypes.count(completion.completionType())) - { - if (!generatedHeader) - { - generateCompsegHeader(formatter, exportInfo, completion.completionType(), exportSubGridIntersections); - generatedHeader = true; - } - - for (const RicMswSubSegment& segment : completion.subSegments()) - { - if (completion.completionType() == RigCompletionData::ICD) - { - startMD = segment.startMD(); - } - - for (const RicMswSubSegmentCellIntersection& intersection : segment.intersections()) - { - bool isSubGridIntersection = !intersection.gridName().isEmpty(); - if (isSubGridIntersection == exportSubGridIntersections) - { - if (exportSubGridIntersections) - { - formatter.add(intersection.gridName()); - } - cvf::Vec3st ijk = intersection.gridLocalCellIJK(); - formatter.addOneBasedCellIndex(ijk.x()).addOneBasedCellIndex(ijk.y()).addOneBasedCellIndex(ijk.z()); - formatter.add(completion.branchNumber()); - - double startLength = segment.startMD(); - if (exportInfo.lengthAndDepthText() == QString("INC") && - completion.completionType() != RigCompletionData::PERFORATION) - { - startLength -= startMD; - } - formatter.add(startLength); - formatter.add(startLength + segment.deltaMD()); - - formatter.rowCompleted(); - } - } - } - } - } - } - if (generatedHeader) - { - formatter.tableCompleted(); - } -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RicWellPathExportCompletionDataFeatureImpl::generateCompsegHeader(RifEclipseDataTableFormatter& formatter, - const RicMswExportInfo& exportInfo, - RigCompletionData::CompletionType completionType, - bool exportSubGridIntersections) -{ - if (exportSubGridIntersections) - { - formatter.keyword("COMPSEGL"); - } - else - { - formatter.keyword("COMPSEGS"); - } - - if (completionType == RigCompletionData::ICD) - { - formatter.comment("Fishbones"); - } - else if (completionType == RigCompletionData::FRACTURE) - { - formatter.comment("Fractures"); - } - - { - std::vector header = {RifEclipseOutputTableColumn("Name")}; - formatter.header(header); - formatter.add(exportInfo.wellPath()->name()); - formatter.rowCompleted(); - } - - { - std::vector allHeaders; - if (exportSubGridIntersections) - { - allHeaders.push_back(RifEclipseOutputTableColumn("Grid")); - } - - std::vector commonHeaders = {RifEclipseOutputTableColumn("I"), - RifEclipseOutputTableColumn("J"), - RifEclipseOutputTableColumn("K"), - RifEclipseOutputTableColumn("Branch no"), - RifEclipseOutputTableColumn("Start Length"), - RifEclipseOutputTableColumn("End Length"), - RifEclipseOutputTableColumn("Dir Pen"), - RifEclipseOutputTableColumn("End Range"), - RifEclipseOutputTableColumn("Connection Depth")}; - allHeaders.insert(allHeaders.end(), commonHeaders.begin(), commonHeaders.end()); - formatter.header(allHeaders); - } -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RicWellPathExportCompletionDataFeatureImpl::generateWsegvalvTable(RifEclipseDataTableFormatter& formatter, - const RicMswExportInfo& exportInfo) -{ - { - formatter.keyword("WSEGVALV"); - std::vector header = { - RifEclipseOutputTableColumn("Well Name"), - RifEclipseOutputTableColumn("Seg No"), - RifEclipseOutputTableColumn("Cv"), - RifEclipseOutputTableColumn("Ac"), - }; - formatter.header(header); - } - for (const RicMswSegment& location : exportInfo.wellSegmentLocations()) - { - for (const RicMswCompletion& completion : location.completions()) - { - if (completion.completionType() == RigCompletionData::ICD) - { - CVF_ASSERT(completion.subSegments().size() == 1u); - formatter.add(exportInfo.wellPath()->name()); - formatter.add(completion.subSegments().front().segmentNumber()); - formatter.add(location.icdFlowCoefficient()); - formatter.add(location.icdArea()); - formatter.rowCompleted(); - } - } - } - formatter.tableCompleted(); -} - //================================================================================================== /// //================================================================================================== @@ -1100,47 +596,6 @@ RigCompletionData return resultCompletion; } -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -QFilePtr RicWellPathExportCompletionDataFeatureImpl::openFileForExport(const QString& fullFileName) -{ - std::pair folderAndFileName = RiaFilePathTools::toFolderAndFileName(fullFileName); - return openFileForExport(folderAndFileName.first, folderAndFileName.second); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -QFilePtr RicWellPathExportCompletionDataFeatureImpl::openFileForExport(const QString& folderName, const QString& fileName) -{ - QDir exportFolder = QDir(folderName); - if (!exportFolder.exists()) - { - bool createdPath = exportFolder.mkpath("."); - if (createdPath) - RiaLogging::info("Created export folder " + folderName); - else - { - auto errorMessage = QString("Selected output folder does not exist, and could not be created."); - RiaLogging::error(errorMessage); - throw OpenFileException(errorMessage); - } - } - - QString validFileName = caf::Utils::makeValidFileBasename(fileName); - - QString filePath = exportFolder.filePath(validFileName); - QFilePtr exportFile(new QFile(filePath)); - if (!exportFile->open(QIODevice::WriteOnly | QIODevice::Text)) - { - auto errorMessage = QString("Export Completions Data: Could not open the file: %1").arg(filePath); - RiaLogging::error(errorMessage); - throw OpenFileException(errorMessage); - } - return exportFile; -} - //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -1250,14 +705,21 @@ void RicWellPathExportCompletionDataFeatureImpl::exportWelspecsToFile(RimEclipse QTextStream stream(exportFile.get()); RifEclipseDataTableFormatter formatter(stream); - formatter.setColumnSpacing(3); + formatter.setColumnSpacing(2); std::vector header = {RifEclipseOutputTableColumn("Well"), RifEclipseOutputTableColumn("Grp"), RifEclipseOutputTableColumn("I"), RifEclipseOutputTableColumn("J"), RifEclipseOutputTableColumn("RefDepth"), - RifEclipseOutputTableColumn("WellType")}; + RifEclipseOutputTableColumn("Type"), + RifEclipseOutputTableColumn("DrainRad"), + RifEclipseOutputTableColumn("GasInEq"), + RifEclipseOutputTableColumn("AutoShut"), + RifEclipseOutputTableColumn("XFlow"), + RifEclipseOutputTableColumn("FluidPVT"), + RifEclipseOutputTableColumn("HydSDens"), + RifEclipseOutputTableColumn("FluidInPlReg")}; formatter.keyword("WELSPECS"); formatter.header(header); @@ -1267,7 +729,7 @@ void RicWellPathExportCompletionDataFeatureImpl::exportWelspecsToFile(RimEclipse // Build list of unique RimWellPath for (const auto& completion : completions) { - const auto wellPath = findWellPathFromExportName(completion.wellName()); + const auto wellPath = RicWellPathExportCompletionsFileTools::findWellPathFromExportName(completion.wellName()); if (wellPath) { wellPathSet.insert(wellPath); @@ -1277,15 +739,22 @@ void RicWellPathExportCompletionDataFeatureImpl::exportWelspecsToFile(RimEclipse // Export for (const auto wellPath : wellPathSet) { - auto rimCcompletions = wellPath->completions(); + auto rimCompletions = wellPath->completions(); auto ijIntersection = wellPathUpperGridIntersectionIJ(gridCase, wellPath); - formatter.add(rimCcompletions->wellNameForExport()) - .add(rimCcompletions->wellGroupNameForExport()) + formatter.add(rimCompletions->wellNameForExport()) + .add(rimCompletions->wellGroupNameForExport()) .addOneBasedCellIndex(ijIntersection.second.x()) .addOneBasedCellIndex(ijIntersection.second.y()) - .add(rimCcompletions->referenceDepthForExport()) - .add(rimCcompletions->wellTypeNameForExport()) + .add(rimCompletions->referenceDepthForExport()) + .add(rimCompletions->wellTypeNameForExport()) + .add(rimCompletions->drainageRadiusForExport()) + .add(rimCompletions->gasInflowEquationForExport()) + .add(rimCompletions->automaticWellShutInForExport()) + .add(rimCompletions->allowWellCrossFlowForExport()) + .add(rimCompletions->wellBoreFluidPVTForExport()) + .add(rimCompletions->hydrostaticDensityForExport()) + .add(rimCompletions->fluidInPlaceRegionForExport()) .rowCompleted(); } @@ -1303,7 +772,7 @@ void RicWellPathExportCompletionDataFeatureImpl::exportWelspeclToFile( QTextStream stream(exportFile.get()); RifEclipseDataTableFormatter formatter(stream); - formatter.setColumnSpacing(3); + formatter.setColumnSpacing(2); std::vector header = {RifEclipseOutputTableColumn("Well"), RifEclipseOutputTableColumn("Grp"), @@ -1311,7 +780,14 @@ void RicWellPathExportCompletionDataFeatureImpl::exportWelspeclToFile( RifEclipseOutputTableColumn("I"), RifEclipseOutputTableColumn("J"), RifEclipseOutputTableColumn("RefDepth"), - RifEclipseOutputTableColumn("WellType")}; + RifEclipseOutputTableColumn("Type"), + RifEclipseOutputTableColumn("DrainRad"), + RifEclipseOutputTableColumn("GasInEq"), + RifEclipseOutputTableColumn("AutoShut"), + RifEclipseOutputTableColumn("XFlow"), + RifEclipseOutputTableColumn("FluidPVT"), + RifEclipseOutputTableColumn("HydSDens"), + RifEclipseOutputTableColumn("FluidInPlReg")}; formatter.keyword("WELSPECL"); formatter.header(header); @@ -1322,7 +798,7 @@ void RicWellPathExportCompletionDataFeatureImpl::exportWelspeclToFile( { for (const auto& completion : completionsForLgr.second) { - const auto wellPath = findWellPathFromExportName(completion.wellName()); + const auto wellPath = RicWellPathExportCompletionsFileTools::findWellPathFromExportName(completion.wellName()); auto item = wellPathToLgrNameMap.find(wellPath); wellPathToLgrNameMap[wellPath].insert(completionsForLgr.first); } @@ -1362,6 +838,13 @@ void RicWellPathExportCompletionDataFeatureImpl::exportWelspeclToFile( .addOneBasedCellIndex(ijIntersection.y()) .add(rimCompletions->referenceDepthForExport()) .add(rimCompletions->wellTypeNameForExport()) + .add(rimCompletions->drainageRadiusForExport()) + .add(rimCompletions->gasInflowEquationForExport()) + .add(rimCompletions->automaticWellShutInForExport()) + .add(rimCompletions->allowWellCrossFlowForExport()) + .add(rimCompletions->wellBoreFluidPVTForExport()) + .add(rimCompletions->hydrostaticDensityForExport()) + .add(rimCompletions->fluidInPlaceRegionForExport()) .rowCompleted(); } } @@ -1387,7 +870,7 @@ void RicWellPathExportCompletionDataFeatureImpl::sortAndExportCompletionsToFile( { try { - QFilePtr exportFile = openFileForExport(folderName, fileName); + std::shared_ptr exportFile = RicWellPathExportCompletionsFileTools::openFileForExport(folderName, fileName); std::map> completionsForGrid; completionsForGrid.insert(std::pair>("", completionsForMainGrid)); @@ -1396,7 +879,7 @@ void RicWellPathExportCompletionDataFeatureImpl::sortAndExportCompletionsToFile( exportWelspecsToFile(eclipseCase, exportFile, completionsForMainGrid); exportCompdatAndWpimultTables(eclipseCase, exportFile, completionsForGrid, exportType); } - catch (OpenFileException) + catch (RicWellPathExportCompletionsFileTools::OpenFileException) { } } @@ -1406,13 +889,13 @@ void RicWellPathExportCompletionDataFeatureImpl::sortAndExportCompletionsToFile( try { QString lgrFileName = fileName + "_LGR"; - QFilePtr exportFile = openFileForExport(folderName, lgrFileName); + std::shared_ptr exportFile = RicWellPathExportCompletionsFileTools::openFileForExport(folderName, lgrFileName); exportWellPathFractureReport(eclipseCase, exportFile, wellPathFractureReportItems); exportWelspeclToFile(eclipseCase, exportFile, completionsForSubGrids); exportCompdatAndWpimultTables(eclipseCase, exportFile, completionsForSubGrids, exportType); } - catch (OpenFileException) + catch (RicWellPathExportCompletionsFileTools::OpenFileException) { } } @@ -1744,536 +1227,6 @@ std::vector RicWellPathExportCompletionDataFeatureImpl::gener return completionData; } -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -RicMswExportInfo RicWellPathExportCompletionDataFeatureImpl::generateFishbonesMswExportInfo(const RimEclipseCase* caseToApply, - const RimWellPath* wellPath, - bool enableSegmentSplitting) -{ - std::vector fishbonesSubs = wellPath->fishbonesCollection()->activeFishbonesSubs(); - - return generateFishbonesMswExportInfo(caseToApply, wellPath, fishbonesSubs, enableSegmentSplitting); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -RicMswExportInfo RicWellPathExportCompletionDataFeatureImpl::generateFishbonesMswExportInfo( - const RimEclipseCase* caseToApply, - const RimWellPath* wellPath, - const std::vector& fishbonesSubs, - bool enableSegmentSplitting) -{ - RiaEclipseUnitTools::UnitSystem unitSystem = caseToApply->eclipseCaseData()->unitsType(); - - RicMswExportInfo exportInfo(wellPath, - unitSystem, - wellPath->fishbonesCollection()->startMD(), - wellPath->fishbonesCollection()->mswParameters()->lengthAndDepth().text(), - wellPath->fishbonesCollection()->mswParameters()->pressureDrop().text()); - exportInfo.setLinerDiameter(wellPath->fishbonesCollection()->mswParameters()->linerDiameter(unitSystem)); - exportInfo.setRoughnessFactor(wellPath->fishbonesCollection()->mswParameters()->roughnessFactor(unitSystem)); - - double maxSegmentLength = enableSegmentSplitting ? wellPath->fishbonesCollection()->mswParameters()->maxSegmentLength() - : std::numeric_limits::infinity(); - bool foundSubGridIntersections = false; - double subStartMD = wellPath->fishbonesCollection()->startMD(); - for (RimFishbonesMultipleSubs* subs : fishbonesSubs) - { - for (auto& sub : subs->installedLateralIndices()) - { - double subEndMD = subs->measuredDepth(sub.subIndex); - double subEndTVD = -wellPath->wellPathGeometry()->interpolatedPointAlongWellPath(subEndMD).z(); - int subSegCount = numberOfSplittedSegments(subStartMD, subEndMD, maxSegmentLength); - double subSegLen = (subEndMD - subStartMD) / subSegCount; - - double startMd = subStartMD; - double startTvd = -wellPath->wellPathGeometry()->interpolatedPointAlongWellPath(startMd).z(); - for (int ssi = 0; ssi < subSegCount; ssi++) - { - double endMd = startMd + subSegLen; - double endTvd = -wellPath->wellPathGeometry()->interpolatedPointAlongWellPath(endMd).z(); - - RicMswSegment location = RicMswSegment(subs->generatedName(), startMd, endMd, startTvd, endTvd, sub.subIndex); - location.setEffectiveDiameter(subs->effectiveDiameter(unitSystem)); - location.setHoleDiameter(subs->holeDiameter(unitSystem)); - location.setOpenHoleRoughnessFactor(subs->openHoleRoughnessFactor(unitSystem)); - location.setSkinFactor(subs->skinFactor()); - location.setIcdFlowCoefficient(subs->icdFlowCoefficient()); - double icdOrificeRadius = subs->icdOrificeDiameter(unitSystem) / 2; - location.setIcdArea(icdOrificeRadius * icdOrificeRadius * cvf::PI_D * subs->icdCount()); - location.setSourcePdmObject(subs); - - if (ssi == 0) - { - // Add completion for ICD - RicMswCompletion icdCompletion(RigCompletionData::ICD, QString("ICD")); - RicMswSubSegment icdSegment(subEndMD, 0.1, subEndTVD, 0.0); - icdCompletion.addSubSegment(icdSegment); - location.addCompletion(icdCompletion); - - for (size_t lateralIndex : sub.lateralIndices) - { - QString label = QString("Lateral %1").arg(lateralIndex); - location.addCompletion(RicMswCompletion(RigCompletionData::FISHBONES, label, lateralIndex)); - } - assignFishbonesLateralIntersections( - caseToApply, subs, &location, &foundSubGridIntersections, maxSegmentLength); - } - - exportInfo.addWellSegmentLocation(location); - - startMd = endMd; - startTvd = endTvd; - } - - subStartMD = subEndMD; - } - } - exportInfo.setHasSubGridIntersections(foundSubGridIntersections); - exportInfo.sortLocations(); - - assignBranchAndSegmentNumbers(caseToApply, &exportInfo); - - return exportInfo; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -RicMswExportInfo RicWellPathExportCompletionDataFeatureImpl::generateFracturesMswExportInfo(RimEclipseCase* caseToApply, - const RimWellPath* wellPath) -{ - std::vector fractures = wellPath->fractureCollection()->activeFractures(); - - return generateFracturesMswExportInfo(caseToApply, wellPath, fractures); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -RicMswExportInfo - RicWellPathExportCompletionDataFeatureImpl::generateFracturesMswExportInfo(RimEclipseCase* caseToApply, - const RimWellPath* wellPath, - const std::vector& fractures) -{ - const RigMainGrid* grid = caseToApply->eclipseCaseData()->mainGrid(); - const RigActiveCellInfo* activeCellInfo = caseToApply->eclipseCaseData()->activeCellInfo(RiaDefines::MATRIX_MODEL); - RiaEclipseUnitTools::UnitSystem unitSystem = caseToApply->eclipseCaseData()->unitsType(); - - const RigWellPath* wellPathGeometry = wellPath->wellPathGeometry(); - const std::vector& coords = wellPathGeometry->wellPathPoints(); - const std::vector& mds = wellPathGeometry->measureDepths(); - CVF_ASSERT(!coords.empty() && !mds.empty()); - - std::vector intersections = - RigWellPathIntersectionTools::findCellIntersectionInfosAlongPath(caseToApply->eclipseCaseData(), coords, mds); - - double maxSegmentLength = wellPath->fractureCollection()->mswParameters()->maxSegmentLength(); - std::vector subSegIntersections = - spiltIntersectionSegmentsToMaxLength(wellPathGeometry, intersections, maxSegmentLength); - - double initialMD = 0.0; - if (wellPath->fractureCollection()->referenceMDType() == RimWellPathFractureCollection::MANUAL_REFERENCE_MD) - { - initialMD = wellPath->fractureCollection()->manualReferenceMD(); - } - else - { - for (WellPathCellIntersectionInfo intersection : intersections) - { - if (activeCellInfo->isActive(intersection.globCellIndex)) - { - initialMD = intersection.startMD; - break; - } - } - } - - RicMswExportInfo exportInfo(wellPath, - unitSystem, - initialMD, - wellPath->fractureCollection()->mswParameters()->lengthAndDepth().text(), - wellPath->fractureCollection()->mswParameters()->pressureDrop().text()); - - exportInfo.setLinerDiameter(wellPath->fractureCollection()->mswParameters()->linerDiameter(unitSystem)); - exportInfo.setRoughnessFactor(wellPath->fractureCollection()->mswParameters()->roughnessFactor(unitSystem)); - - bool foundSubGridIntersections = false; - - // Main bore - int mainBoreSegment = 1; - for (const auto& cellIntInfo : subSegIntersections) - { - double startTVD = cellIntInfo.startTVD; - double endTVD = cellIntInfo.endTVD; - - size_t localGridIdx = 0u; - const RigGridBase* localGrid = grid->gridAndGridLocalIdxFromGlobalCellIdx(cellIntInfo.globCellIndex, &localGridIdx); - QString gridName; - if (localGrid != grid) - { - gridName = QString::fromStdString(localGrid->gridName()); - foundSubGridIntersections = true; - } - - size_t i = 0u, j = 0u, k = 0u; - localGrid->ijkFromCellIndex(localGridIdx, &i, &j, &k); - QString label = QString("Main stem segment %1").arg(++mainBoreSegment); - RicMswSegment location(label, cellIntInfo.startMD, cellIntInfo.endMD, startTVD, endTVD); - - // Check if fractures are to be assigned to current main bore segment - for (RimWellPathFracture* fracture : fractures) - { - double fractureStartMD = fracture->fractureMD(); - if (fracture->fractureTemplate()->orientationType() == RimFractureTemplate::ALONG_WELL_PATH) - { - double perforationLength = fracture->fractureTemplate()->perforationLength(); - fractureStartMD -= 0.5 * perforationLength; - } - - if (cvf::Math::valueInRange(fractureStartMD, cellIntInfo.startMD, cellIntInfo.endMD)) - { - std::vector completionData = - RicExportFractureCompletionsImpl::generateCompdatValues(caseToApply, - wellPath->completions()->wellNameForExport(), - wellPath->wellPathGeometry(), - {fracture}, - nullptr, - nullptr); - - assignFractureIntersections(caseToApply, fracture, completionData, &location, &foundSubGridIntersections); - } - } - - exportInfo.addWellSegmentLocation(location); - } - exportInfo.setHasSubGridIntersections(foundSubGridIntersections); - exportInfo.sortLocations(); - assignBranchAndSegmentNumbers(caseToApply, &exportInfo); - - return exportInfo; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -RicMswExportInfo RicWellPathExportCompletionDataFeatureImpl::generatePerforationsMswExportInfo( - const RicExportCompletionDataSettingsUi& exportSettings, - const RimWellPath* wellPath, - const std::vector& perforationIntervals) -{ - const RimEclipseCase* caseToApply = exportSettings.caseToApply; - const RigMainGrid* grid = caseToApply->eclipseCaseData()->mainGrid(); - const RigActiveCellInfo* activeCellInfo = caseToApply->eclipseCaseData()->activeCellInfo(RiaDefines::MATRIX_MODEL); - RiaEclipseUnitTools::UnitSystem unitSystem = caseToApply->eclipseCaseData()->unitsType(); - - const RigWellPath* wellPathGeometry = wellPath->wellPathGeometry(); - const std::vector& coords = wellPathGeometry->wellPathPoints(); - const std::vector& mds = wellPathGeometry->measureDepths(); - CVF_ASSERT(!coords.empty() && !mds.empty()); - - std::vector intersections = - RigWellPathIntersectionTools::findCellIntersectionInfosAlongPath(caseToApply->eclipseCaseData(), coords, mds); - - double maxSegmentLength = wellPath->perforationIntervalCollection()->mswParameters()->maxSegmentLength(); - std::vector subSegIntersections = - spiltIntersectionSegmentsToMaxLength(wellPathGeometry, intersections, maxSegmentLength); - - double initialMD = 0.0; - for (WellPathCellIntersectionInfo intersection : intersections) - { - if (activeCellInfo->isActive(intersection.globCellIndex)) - { - initialMD = intersection.startMD; - break; - } - } - - RicMswExportInfo exportInfo(wellPath, - unitSystem, - initialMD, - wellPath->perforationIntervalCollection()->mswParameters()->lengthAndDepth().text(), - wellPath->perforationIntervalCollection()->mswParameters()->pressureDrop().text()); - - exportInfo.setLinerDiameter(wellPath->perforationIntervalCollection()->mswParameters()->linerDiameter(unitSystem)); - exportInfo.setRoughnessFactor(wellPath->perforationIntervalCollection()->mswParameters()->roughnessFactor(unitSystem)); - - bool foundSubGridIntersections = false; - - // Main bore - int mainBoreSegment = 1; - for (const auto& cellIntInfo : subSegIntersections) - { - double startTVD = cellIntInfo.startTVD; - double endTVD = cellIntInfo.endTVD; - - size_t localGridIdx = 0u; - const RigGridBase* localGrid = grid->gridAndGridLocalIdxFromGlobalCellIdx(cellIntInfo.globCellIndex, &localGridIdx); - QString gridName; - if (localGrid != grid) - { - gridName = QString::fromStdString(localGrid->gridName()); - foundSubGridIntersections = true; - } - - size_t i = 0u, j = 0u, k = 0u; - localGrid->ijkFromCellIndex(localGridIdx, &i, &j, &k); - QString label = QString("Main stem segment %1").arg(++mainBoreSegment); - RicMswSegment location(label, cellIntInfo.startMD, cellIntInfo.endMD, startTVD, endTVD); - - // Check if fractures are to be assigned to current main bore segment - for (const RimPerforationInterval* interval : perforationIntervals) - { - double intervalStartMD = interval->startMD(); - double intervalEndMD = interval->endMD(); - - if (cellIntInfo.endMD > intervalStartMD && cellIntInfo.startMD < intervalEndMD) - { - std::vector completionData = - generatePerforationsCompdatValues(wellPath, {interval}, exportSettings); - assignPerforationIntervalIntersections( - caseToApply, interval, completionData, &location, &cellIntInfo, &foundSubGridIntersections); - } - } - - exportInfo.addWellSegmentLocation(location); - } - exportInfo.setHasSubGridIntersections(foundSubGridIntersections); - exportInfo.sortLocations(); - assignBranchAndSegmentNumbers(caseToApply, &exportInfo); - - return exportInfo; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RicWellPathExportCompletionDataFeatureImpl::assignFishbonesLateralIntersections( - const RimEclipseCase* caseToApply, - const RimFishbonesMultipleSubs* fishbonesSubs, - RicMswSegment* location, - bool* foundSubGridIntersections, - double maxSegmentLength) -{ - CVF_ASSERT(foundSubGridIntersections != nullptr); - - const RigMainGrid* grid = caseToApply->eclipseCaseData()->mainGrid(); - - for (RicMswCompletion& completion : location->completions()) - { - if (completion.completionType() != RigCompletionData::FISHBONES) - { - continue; - } - - std::vector> lateralCoordMDPairs = - fishbonesSubs->coordsAndMDForLateral(location->subIndex(), completion.index()); - - if (lateralCoordMDPairs.empty()) - { - continue; - } - - std::vector lateralCoords; - std::vector lateralMDs; - - lateralCoords.reserve(lateralCoordMDPairs.size()); - lateralMDs.reserve(lateralCoordMDPairs.size()); - - for (auto& coordMD : lateralCoordMDPairs) - { - lateralCoords.push_back(coordMD.first); - lateralMDs.push_back(coordMD.second); - } - - std::vector intersections = - RigWellPathIntersectionTools::findCellIntersectionInfosAlongPath( - caseToApply->eclipseCaseData(), lateralCoords, lateralMDs); - - RigWellPath pathGeometry; - pathGeometry.m_wellPathPoints = lateralCoords; - pathGeometry.m_measuredDepths = lateralMDs; - std::vector subSegIntersections = - spiltIntersectionSegmentsToMaxLength(&pathGeometry, intersections, maxSegmentLength); - - double previousExitMD = lateralMDs.front(); - double previousExitTVD = -lateralCoords.front().z(); - - for (const auto& cellIntInfo : subSegIntersections) - { - size_t localGridIdx = 0u; - const RigGridBase* localGrid = grid->gridAndGridLocalIdxFromGlobalCellIdx(cellIntInfo.globCellIndex, &localGridIdx); - QString gridName; - if (localGrid != grid) - { - gridName = QString::fromStdString(localGrid->gridName()); - *foundSubGridIntersections = true; - } - - size_t i = 0u, j = 0u, k = 0u; - localGrid->ijkFromCellIndex(localGridIdx, &i, &j, &k); - RicMswSubSegment subSegment( - previousExitMD, cellIntInfo.endMD - previousExitMD, previousExitTVD, cellIntInfo.endTVD - previousExitTVD); - - RicMswSubSegmentCellIntersection intersection( - gridName, cellIntInfo.globCellIndex, cvf::Vec3st(i, j, k), cellIntInfo.intersectionLengthsInCellCS); - subSegment.addIntersection(intersection); - completion.addSubSegment(subSegment); - - previousExitMD = cellIntInfo.endMD; - previousExitTVD = cellIntInfo.endTVD; - } - } -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RicWellPathExportCompletionDataFeatureImpl::assignFractureIntersections(const RimEclipseCase* caseToApply, - const RimWellPathFracture* fracture, - const std::vector& completionData, - RicMswSegment* location, - bool* foundSubGridIntersections) -{ - CVF_ASSERT(foundSubGridIntersections != nullptr); - - RicMswCompletion fractureCompletion(RigCompletionData::FRACTURE, fracture->name()); - double position = fracture->fractureMD(); - double width = fracture->fractureTemplate()->computeFractureWidth(fracture); - - if (fracture->fractureTemplate()->orientationType() == RimFractureTemplate::ALONG_WELL_PATH) - { - double perforationLength = fracture->fractureTemplate()->perforationLength(); - position -= 0.5 * perforationLength; - width = perforationLength; - } - - RicMswSubSegment subSegment(position, width, 0.0, 0.0); - for (const RigCompletionData& compIntersection : completionData) - { - const RigCompletionDataGridCell& cell = compIntersection.completionDataGridCell(); - cvf::Vec3st localIJK(cell.localCellIndexI(), cell.localCellIndexJ(), cell.localCellIndexK()); - - RicMswSubSegmentCellIntersection intersection(cell.lgrName(), cell.globalCellIndex(), localIJK, cvf::Vec3d::ZERO); - subSegment.addIntersection(intersection); - } - fractureCompletion.addSubSegment(subSegment); - location->addCompletion(fractureCompletion); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RicWellPathExportCompletionDataFeatureImpl::assignPerforationIntervalIntersections( - const RimEclipseCase* caseToApply, - const RimPerforationInterval* interval, - const std::vector& completionData, - RicMswSegment* location, - const SubSegmentIntersectionInfo* cellIntInfo, - bool* foundSubGridIntersections) -{ - CVF_ASSERT(foundSubGridIntersections != nullptr); - - RicMswCompletion intervalCompletion(RigCompletionData::PERFORATION, interval->name()); - double startMd = std::max(location->startMD(), interval->startMD()); - double endMd = std::min(location->endMD(), interval->endMD()); - RicMswSubSegment subSegment(startMd, endMd - startMd, 0.0, 0.0); - - size_t currCellId = cellIntInfo->globCellIndex; - - for (const RigCompletionData& compIntersection : completionData) - { - const RigCompletionDataGridCell& cell = compIntersection.completionDataGridCell(); - - if (cell.globalCellIndex() != currCellId) continue; - - cvf::Vec3st localIJK(cell.localCellIndexI(), cell.localCellIndexJ(), cell.localCellIndexK()); - - RicMswSubSegmentCellIntersection intersection( - cell.lgrName(), cell.globalCellIndex(), localIJK, cellIntInfo->intersectionLengthsInCellCS); - subSegment.addIntersection(intersection); - } - intervalCompletion.addSubSegment(subSegment); - location->addCompletion(intervalCompletion); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RicWellPathExportCompletionDataFeatureImpl::assignBranchAndSegmentNumbers(const RimEclipseCase* caseToApply, - RicMswSegment* location, - int* branchNum, - int* segmentNum) -{ - int icdSegmentNumber = cvf::UNDEFINED_INT; - for (RicMswCompletion& completion : location->completions()) - { - if (completion.completionType() == RigCompletionData::PERFORATION) - { - completion.setBranchNumber(1); - } - else if (completion.completionType() != RigCompletionData::ICD) - { - ++(*branchNum); - completion.setBranchNumber(*branchNum); - } - - int attachedSegmentNumber = location->segmentNumber(); - if (icdSegmentNumber != cvf::UNDEFINED_INT) - { - attachedSegmentNumber = icdSegmentNumber; - } - - for (auto& subSegment : completion.subSegments()) - { - if (completion.completionType() == RigCompletionData::ICD) - { - subSegment.setSegmentNumber(location->segmentNumber() + 1); - icdSegmentNumber = subSegment.segmentNumber(); - } - else - { - ++(*segmentNum); - subSegment.setSegmentNumber(*segmentNum); - } - subSegment.setAttachedSegmentNumber(attachedSegmentNumber); - attachedSegmentNumber = *segmentNum; - } - } -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RicWellPathExportCompletionDataFeatureImpl::assignBranchAndSegmentNumbers(const RimEclipseCase* caseToApply, - RicMswExportInfo* exportInfo) -{ - int segmentNumber = 1; - int branchNumber = 1; - - // First loop over the locations so that each segment on the main stem is an incremental number - for (RicMswSegment& location : exportInfo->wellSegmentLocations()) - { - location.setSegmentNumber(++segmentNumber); - for (RicMswCompletion& completion : location.completions()) - { - if (completion.completionType() == RigCompletionData::ICD) - { - ++segmentNumber; // Skip a segment number because we need one for the ICD - completion.setBranchNumber(++branchNumber); - } - } - } - - // Then assign branch and segment numbers to each completion sub segment - for (RicMswSegment& location : exportInfo->wellSegmentLocations()) - { - assignBranchAndSegmentNumbers(caseToApply, &location, &branchNumber, &segmentNumber); - } -} - //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -2305,15 +1258,15 @@ CellDirection RicWellPathExportCompletionDataFeatureImpl::calculateCellMainDirec { RigEclipseCaseData* eclipseCaseData = eclipseCase->eclipseCaseData(); - eclipseCase->results(RiaDefines::MATRIX_MODEL)->findOrLoadScalarResult(RiaDefines::STATIC_NATIVE, "DX"); + eclipseCase->results(RiaDefines::MATRIX_MODEL)->ensureKnownResultLoaded(RigEclipseResultAddress(RiaDefines::STATIC_NATIVE, "DX")); cvf::ref dxAccessObject = - RigResultAccessorFactory::createFromUiResultName(eclipseCaseData, 0, RiaDefines::MATRIX_MODEL, 0, "DX"); - eclipseCase->results(RiaDefines::MATRIX_MODEL)->findOrLoadScalarResult(RiaDefines::STATIC_NATIVE, "DY"); + RigResultAccessorFactory::createFromResultAddress(eclipseCaseData, 0, RiaDefines::MATRIX_MODEL, 0, RigEclipseResultAddress(RiaDefines::STATIC_NATIVE, "DX")); + eclipseCase->results(RiaDefines::MATRIX_MODEL)->ensureKnownResultLoaded(RigEclipseResultAddress(RiaDefines::STATIC_NATIVE, "DY")); cvf::ref dyAccessObject = - RigResultAccessorFactory::createFromUiResultName(eclipseCaseData, 0, RiaDefines::MATRIX_MODEL, 0, "DY"); - eclipseCase->results(RiaDefines::MATRIX_MODEL)->findOrLoadScalarResult(RiaDefines::STATIC_NATIVE, "DZ"); + RigResultAccessorFactory::createFromResultAddress(eclipseCaseData, 0, RiaDefines::MATRIX_MODEL, 0, RigEclipseResultAddress(RiaDefines::STATIC_NATIVE, "DY")); + eclipseCase->results(RiaDefines::MATRIX_MODEL)->ensureKnownResultLoaded(RigEclipseResultAddress(RiaDefines::STATIC_NATIVE, "DZ")); cvf::ref dzAccessObject = - RigResultAccessorFactory::createFromUiResultName(eclipseCaseData, 0, RiaDefines::MATRIX_MODEL, 0, "DZ"); + RigResultAccessorFactory::createFromResultAddress(eclipseCaseData, 0, RiaDefines::MATRIX_MODEL, 0, RigEclipseResultAddress(RiaDefines::STATIC_NATIVE, "DZ")); double xLengthFraction = fabs(lengthsInCell.x() / dxAccessObject->cellScalarGlobIdx(globalCellIndex)); double yLengthFraction = fabs(lengthsInCell.y() / dyAccessObject->cellScalarGlobIdx(globalCellIndex)); @@ -2349,25 +1302,25 @@ TransmissibilityData { RigEclipseCaseData* eclipseCaseData = eclipseCase->eclipseCaseData(); - eclipseCase->results(RiaDefines::MATRIX_MODEL)->findOrLoadScalarResult(RiaDefines::STATIC_NATIVE, "DX"); + eclipseCase->results(RiaDefines::MATRIX_MODEL)->ensureKnownResultLoaded(RigEclipseResultAddress(RiaDefines::STATIC_NATIVE, "DX")); cvf::ref dxAccessObject = - RigResultAccessorFactory::createFromUiResultName(eclipseCaseData, 0, RiaDefines::MATRIX_MODEL, 0, "DX"); - eclipseCase->results(RiaDefines::MATRIX_MODEL)->findOrLoadScalarResult(RiaDefines::STATIC_NATIVE, "DY"); + RigResultAccessorFactory::createFromResultAddress(eclipseCaseData, 0, RiaDefines::MATRIX_MODEL, 0, RigEclipseResultAddress(RiaDefines::STATIC_NATIVE, "DX")); + eclipseCase->results(RiaDefines::MATRIX_MODEL)->ensureKnownResultLoaded(RigEclipseResultAddress(RiaDefines::STATIC_NATIVE, "DY")); cvf::ref dyAccessObject = - RigResultAccessorFactory::createFromUiResultName(eclipseCaseData, 0, RiaDefines::MATRIX_MODEL, 0, "DY"); - eclipseCase->results(RiaDefines::MATRIX_MODEL)->findOrLoadScalarResult(RiaDefines::STATIC_NATIVE, "DZ"); + RigResultAccessorFactory::createFromResultAddress(eclipseCaseData, 0, RiaDefines::MATRIX_MODEL, 0,RigEclipseResultAddress(RiaDefines::STATIC_NATIVE, "DY")); + eclipseCase->results(RiaDefines::MATRIX_MODEL)->ensureKnownResultLoaded(RigEclipseResultAddress(RiaDefines::STATIC_NATIVE, "DZ")); cvf::ref dzAccessObject = - RigResultAccessorFactory::createFromUiResultName(eclipseCaseData, 0, RiaDefines::MATRIX_MODEL, 0, "DZ"); + RigResultAccessorFactory::createFromResultAddress(eclipseCaseData, 0, RiaDefines::MATRIX_MODEL, 0, RigEclipseResultAddress(RiaDefines::STATIC_NATIVE, "DZ")); - eclipseCase->results(RiaDefines::MATRIX_MODEL)->findOrLoadScalarResult(RiaDefines::STATIC_NATIVE, "PERMX"); + eclipseCase->results(RiaDefines::MATRIX_MODEL)->ensureKnownResultLoaded(RigEclipseResultAddress(RiaDefines::STATIC_NATIVE, "PERMX")); cvf::ref permxAccessObject = - RigResultAccessorFactory::createFromUiResultName(eclipseCaseData, 0, RiaDefines::MATRIX_MODEL, 0, "PERMX"); - eclipseCase->results(RiaDefines::MATRIX_MODEL)->findOrLoadScalarResult(RiaDefines::STATIC_NATIVE, "PERMY"); + RigResultAccessorFactory::createFromResultAddress(eclipseCaseData, 0, RiaDefines::MATRIX_MODEL, 0, RigEclipseResultAddress(RiaDefines::STATIC_NATIVE, "PERMX")); + eclipseCase->results(RiaDefines::MATRIX_MODEL)->ensureKnownResultLoaded(RigEclipseResultAddress(RiaDefines::STATIC_NATIVE, "PERMY")); cvf::ref permyAccessObject = - RigResultAccessorFactory::createFromUiResultName(eclipseCaseData, 0, RiaDefines::MATRIX_MODEL, 0, "PERMY"); - eclipseCase->results(RiaDefines::MATRIX_MODEL)->findOrLoadScalarResult(RiaDefines::STATIC_NATIVE, "PERMZ"); + RigResultAccessorFactory::createFromResultAddress(eclipseCaseData, 0, RiaDefines::MATRIX_MODEL, 0, RigEclipseResultAddress(RiaDefines::STATIC_NATIVE, "PERMY")); + eclipseCase->results(RiaDefines::MATRIX_MODEL)->ensureKnownResultLoaded(RigEclipseResultAddress(RiaDefines::STATIC_NATIVE, "PERMZ")); cvf::ref permzAccessObject = - RigResultAccessorFactory::createFromUiResultName(eclipseCaseData, 0, RiaDefines::MATRIX_MODEL, 0, "PERMZ"); + RigResultAccessorFactory::createFromResultAddress(eclipseCaseData, 0, RiaDefines::MATRIX_MODEL, 0, RigEclipseResultAddress(RiaDefines::STATIC_NATIVE, "PERMZ")); if (dxAccessObject.isNull() || dyAccessObject.isNull() || dzAccessObject.isNull() || permxAccessObject.isNull() || permyAccessObject.isNull() || permzAccessObject.isNull()) @@ -2378,10 +1331,10 @@ TransmissibilityData double ntg = 1.0; { // Trigger loading from file - eclipseCase->results(RiaDefines::MATRIX_MODEL)->findOrLoadScalarResult(RiaDefines::STATIC_NATIVE, "NTG"); + eclipseCase->results(RiaDefines::MATRIX_MODEL)->ensureKnownResultLoaded(RigEclipseResultAddress(RiaDefines::STATIC_NATIVE, "NTG")); cvf::ref ntgAccessObject = - RigResultAccessorFactory::createFromUiResultName(eclipseCaseData, 0, RiaDefines::MATRIX_MODEL, 0, "NTG"); + RigResultAccessorFactory::createFromResultAddress(eclipseCaseData, 0, RiaDefines::MATRIX_MODEL, 0, RigEclipseResultAddress(RiaDefines::STATIC_NATIVE, "NTG")); if (ntgAccessObject.notNull()) { @@ -2445,9 +1398,9 @@ double RicWellPathExportCompletionDataFeatureImpl::calculateDFactor(RimEclipseCa double porosity = 0.0; { - eclipseCase->results(RiaDefines::MATRIX_MODEL)->findOrLoadScalarResult(RiaDefines::STATIC_NATIVE, "PORO"); + eclipseCase->results(RiaDefines::MATRIX_MODEL)->ensureKnownResultLoaded(RigEclipseResultAddress(RiaDefines::STATIC_NATIVE, "PORO")); cvf::ref poroAccessObject = - RigResultAccessorFactory::createFromUiResultName(eclipseCaseData, 0, RiaDefines::MATRIX_MODEL, 0, "PORO"); + RigResultAccessorFactory::createFromResultAddress(eclipseCaseData, 0, RiaDefines::MATRIX_MODEL, 0, RigEclipseResultAddress(RiaDefines::STATIC_NATIVE, "PORO")); if (poroAccessObject.notNull()) { @@ -2483,32 +1436,31 @@ double RicWellPathExportCompletionDataFeatureImpl::calculateTransmissibilityAsEc { RigEclipseCaseData* eclipseCaseData = eclipseCase->eclipseCaseData(); - eclipseCase->results(RiaDefines::MATRIX_MODEL)->findOrLoadScalarResult(RiaDefines::STATIC_NATIVE, "DX"); + eclipseCase->results(RiaDefines::MATRIX_MODEL)->ensureKnownResultLoaded(RigEclipseResultAddress(RiaDefines::STATIC_NATIVE, "DX")); cvf::ref dxAccessObject = - RigResultAccessorFactory::createFromUiResultName(eclipseCaseData, 0, RiaDefines::MATRIX_MODEL, 0, "DX"); - eclipseCase->results(RiaDefines::MATRIX_MODEL)->findOrLoadScalarResult(RiaDefines::STATIC_NATIVE, "DY"); + RigResultAccessorFactory::createFromResultAddress(eclipseCaseData, 0, RiaDefines::MATRIX_MODEL, 0, RigEclipseResultAddress(RiaDefines::STATIC_NATIVE, "DX")); + eclipseCase->results(RiaDefines::MATRIX_MODEL)->ensureKnownResultLoaded(RigEclipseResultAddress(RiaDefines::STATIC_NATIVE, "DY")); cvf::ref dyAccessObject = - RigResultAccessorFactory::createFromUiResultName(eclipseCaseData, 0, RiaDefines::MATRIX_MODEL, 0, "DY"); - eclipseCase->results(RiaDefines::MATRIX_MODEL)->findOrLoadScalarResult(RiaDefines::STATIC_NATIVE, "DZ"); + RigResultAccessorFactory::createFromResultAddress(eclipseCaseData, 0, RiaDefines::MATRIX_MODEL, 0, RigEclipseResultAddress(RiaDefines::STATIC_NATIVE, "DY")); + eclipseCase->results(RiaDefines::MATRIX_MODEL)->ensureKnownResultLoaded(RigEclipseResultAddress(RiaDefines::STATIC_NATIVE, "DZ")); cvf::ref dzAccessObject = - RigResultAccessorFactory::createFromUiResultName(eclipseCaseData, 0, RiaDefines::MATRIX_MODEL, 0, "DZ"); + RigResultAccessorFactory::createFromResultAddress(eclipseCaseData, 0, RiaDefines::MATRIX_MODEL, 0, RigEclipseResultAddress(RiaDefines::STATIC_NATIVE, "DZ")); - eclipseCase->results(RiaDefines::MATRIX_MODEL)->findOrLoadScalarResult(RiaDefines::STATIC_NATIVE, "PERMX"); + eclipseCase->results(RiaDefines::MATRIX_MODEL)->ensureKnownResultLoaded(RigEclipseResultAddress(RiaDefines::STATIC_NATIVE, "PERMX")); cvf::ref permxAccessObject = - RigResultAccessorFactory::createFromUiResultName(eclipseCaseData, 0, RiaDefines::MATRIX_MODEL, 0, "PERMX"); - eclipseCase->results(RiaDefines::MATRIX_MODEL)->findOrLoadScalarResult(RiaDefines::STATIC_NATIVE, "PERMY"); + RigResultAccessorFactory::createFromResultAddress(eclipseCaseData, 0, RiaDefines::MATRIX_MODEL, 0, RigEclipseResultAddress(RiaDefines::STATIC_NATIVE, "PERMX")); + eclipseCase->results(RiaDefines::MATRIX_MODEL)->ensureKnownResultLoaded(RigEclipseResultAddress(RiaDefines::STATIC_NATIVE, "PERMY")); cvf::ref permyAccessObject = - RigResultAccessorFactory::createFromUiResultName(eclipseCaseData, 0, RiaDefines::MATRIX_MODEL, 0, "PERMY"); - eclipseCase->results(RiaDefines::MATRIX_MODEL)->findOrLoadScalarResult(RiaDefines::STATIC_NATIVE, "PERMZ"); + RigResultAccessorFactory::createFromResultAddress(eclipseCaseData, 0, RiaDefines::MATRIX_MODEL, 0, RigEclipseResultAddress(RiaDefines::STATIC_NATIVE, "PERMY")); + eclipseCase->results(RiaDefines::MATRIX_MODEL)->ensureKnownResultLoaded(RigEclipseResultAddress(RiaDefines::STATIC_NATIVE, "PERMZ")); cvf::ref permzAccessObject = - RigResultAccessorFactory::createFromUiResultName(eclipseCaseData, 0, RiaDefines::MATRIX_MODEL, 0, "PERMZ"); + RigResultAccessorFactory::createFromResultAddress(eclipseCaseData, 0, RiaDefines::MATRIX_MODEL, 0, RigEclipseResultAddress(RiaDefines::STATIC_NATIVE, "PERMZ")); double ntg = 1.0; - size_t ntgResIdx = eclipseCase->results(RiaDefines::MATRIX_MODEL)->findOrLoadScalarResult(RiaDefines::STATIC_NATIVE, "NTG"); - if (ntgResIdx != cvf::UNDEFINED_SIZE_T) + if (eclipseCase->results(RiaDefines::MATRIX_MODEL)->ensureKnownResultLoaded(RigEclipseResultAddress(RiaDefines::STATIC_NATIVE, "NTG"))) { cvf::ref ntgAccessObject = - RigResultAccessorFactory::createFromUiResultName(eclipseCaseData, 0, RiaDefines::MATRIX_MODEL, 0, "NTG"); + RigResultAccessorFactory::createFromResultAddress(eclipseCaseData, 0, RiaDefines::MATRIX_MODEL, 0, RigEclipseResultAddress(RiaDefines::STATIC_NATIVE, "NTG")); ntg = ntgAccessObject->cellScalarGlobIdx(globalCellIndex); } @@ -2586,94 +1538,6 @@ std::pair return std::make_pair(cvf::UNDEFINED_DOUBLE, cvf::Vec2i()); } -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RicWellPathExportCompletionDataFeatureImpl::exportWellSegments(RimEclipseCase* eclipseCase, - QFilePtr exportFile, - const RimWellPath* wellPath, - const std::vector& fractures) -{ - if (eclipseCase == nullptr) - { - RiaLogging::error("Export Fracture Well Segments: Cannot export completions data without specified eclipse case"); - return; - } - - RicMswExportInfo exportInfo = - RicWellPathExportCompletionDataFeatureImpl::generateFracturesMswExportInfo(eclipseCase, wellPath, fractures); - - QTextStream stream(exportFile.get()); - RifEclipseDataTableFormatter formatter(stream); - RicWellPathExportCompletionDataFeatureImpl::generateWelsegsTable(formatter, exportInfo); - RicWellPathExportCompletionDataFeatureImpl::generateCompsegTables(formatter, exportInfo); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RicWellPathExportCompletionDataFeatureImpl::exportWellSegments(RimEclipseCase* eclipseCase, - QFilePtr exportFile, - const RimWellPath* wellPath, - const std::vector& fishbonesSubs) -{ - if (eclipseCase == nullptr) - { - RiaLogging::error("Export Well Segments: Cannot export completions data without specified eclipse case"); - return; - } - - RicMswExportInfo exportInfo = - RicWellPathExportCompletionDataFeatureImpl::generateFishbonesMswExportInfo(eclipseCase, wellPath, fishbonesSubs, true); - - QTextStream stream(exportFile.get()); - RifEclipseDataTableFormatter formatter(stream); - RicWellPathExportCompletionDataFeatureImpl::generateWelsegsTable(formatter, exportInfo); - RicWellPathExportCompletionDataFeatureImpl::generateCompsegTables(formatter, exportInfo); - RicWellPathExportCompletionDataFeatureImpl::generateWsegvalvTable(formatter, exportInfo); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RicWellPathExportCompletionDataFeatureImpl::exportWellSegments( - const RicExportCompletionDataSettingsUi& exportSettings, - QFilePtr exportFile, - const RimWellPath* wellPath, - const std::vector& perforationIntervals) -{ - if (exportSettings.caseToApply == nullptr) - { - RiaLogging::error("Export Well Segments: Cannot export completions data without specified eclipse case"); - return; - } - - RicMswExportInfo exportInfo = RicWellPathExportCompletionDataFeatureImpl::generatePerforationsMswExportInfo( - exportSettings, wellPath, perforationIntervals); - - QTextStream stream(exportFile.get()); - RifEclipseDataTableFormatter formatter(stream); - RicWellPathExportCompletionDataFeatureImpl::generateWelsegsTable(formatter, exportInfo); - RicWellPathExportCompletionDataFeatureImpl::generateCompsegTables(formatter, exportInfo); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RicWellPathExportCompletionDataFeatureImpl::exportCarfinForTemporaryLgrs(const RimEclipseCase* sourceCase, - const QString& folder) -{ - if (!sourceCase || !sourceCase->mainGrid()) return; - - const auto mainGrid = sourceCase->mainGrid(); - const auto& lgrInfosForWells = RicExportLgrFeature::createLgrInfoListForTemporaryLgrs(mainGrid); - - for (const auto& lgrInfoForWell : lgrInfosForWells) - { - RicExportLgrFeature::exportLgrs(folder, lgrInfoForWell.first, lgrInfoForWell.second); - } -} - //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -2691,81 +1555,19 @@ bool RicWellPathExportCompletionDataFeatureImpl::isCompletionWellPathEqual(const return (parentWellPath == wellPath); } -//-------------------------------------------------------------------------------------------------- -/// Internal function -//-------------------------------------------------------------------------------------------------- -const RimWellPath* findWellPathFromExportName(const QString& wellNameForExport) -{ - auto allWellPaths = RiaApplication::instance()->project()->allWellPaths(); - - for (const auto wellPath : allWellPaths) - { - if (wellPath->completions()->wellNameForExport() == wellNameForExport) return wellPath; - } - return nullptr; -} - //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -std::vector - spiltIntersectionSegmentsToMaxLength(const RigWellPath* pathGeometry, - const std::vector& intersections, - double maxSegmentLength) +void RicWellPathExportCompletionDataFeatureImpl::exportCarfinForTemporaryLgrs(const RimEclipseCase* sourceCase, + const QString& folder) { - std::vector out; + if (!sourceCase || !sourceCase->mainGrid()) return; - if (!pathGeometry) return out; + const auto mainGrid = sourceCase->mainGrid(); + const auto& lgrInfosForWells = RicExportLgrFeature::createLgrInfoListForTemporaryLgrs(mainGrid); - for (size_t i = 0; i < intersections.size(); i++) + for (const auto& lgrInfoForWell : lgrInfosForWells) { - const auto& intersection = intersections[i]; - double segLen = intersection.endMD - intersection.startMD; - int segCount = (int)std::trunc(segLen / maxSegmentLength) + 1; - - // Calc effective max length - double effectiveMaxSegLen = segLen / segCount; - - if (segCount == 1) - { - out.push_back(SubSegmentIntersectionInfo(intersection.globCellIndex, - -intersection.startPoint.z(), - -intersection.endPoint.z(), - intersection.startMD, - intersection.endMD, - intersection.intersectionLengthsInCellCS)); - } - else - { - double currStartMd = intersection.startMD; - double currEndMd = currStartMd; - double lastTvd = -intersection.startPoint.z(); - - for (int segIndex = 0; segIndex < segCount; segIndex++) - { - bool lasti = segIndex == (segCount - 1); - currEndMd = currStartMd + effectiveMaxSegLen; - - cvf::Vec3d segEndPoint = pathGeometry->interpolatedPointAlongWellPath(currEndMd); - out.push_back(SubSegmentIntersectionInfo(intersection.globCellIndex, - lastTvd, - lasti ? -intersection.endPoint.z() : -segEndPoint.z(), - currStartMd, - lasti ? intersection.endMD : currEndMd, - intersection.intersectionLengthsInCellCS / segCount)); - - currStartMd = currEndMd; - lastTvd = -segEndPoint.z(); - } - } + RicExportLgrFeature::exportLgrs(folder, lgrInfoForWell.first, lgrInfoForWell.second); } - return out; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -int numberOfSplittedSegments(double startMd, double endMd, double maxSegmentLength) -{ - return (int)(std::trunc((endMd - startMd) / maxSegmentLength) + 1); -} +} \ No newline at end of file diff --git a/ApplicationCode/Commands/CompletionExportCommands/RicWellPathExportCompletionDataFeatureImpl.h b/ApplicationCode/Commands/CompletionExportCommands/RicWellPathExportCompletionDataFeatureImpl.h index ca64c86b02..cd3f190357 100644 --- a/ApplicationCode/Commands/CompletionExportCommands/RicWellPathExportCompletionDataFeatureImpl.h +++ b/ApplicationCode/Commands/CompletionExportCommands/RicWellPathExportCompletionDataFeatureImpl.h @@ -21,7 +21,6 @@ #include "RigCompletionData.h" #include "RicExportCompletionDataSettingsUi.h" -#include "RicMultiSegmentWellExportInfo.h" #include "RicWellPathFractureReportItem.h" #include @@ -33,6 +32,7 @@ #include #include +class RicMswCompletion; class RigCell; class RigEclipseCaseData; class RigMainGrid; @@ -41,6 +41,7 @@ class RimFishbonesMultipleSubs; class RimSimWellInView; class RimPerforationInterval; class RimWellPath; +class RimWellPathValve; class RimWellPathFracture; class RimNonDarcyPerforationParameters; class RifEclipseDataTableFormatter; @@ -112,25 +113,6 @@ class RicWellPathExportCompletionDataFeatureImpl { public: - static RicMswExportInfo generateFishbonesMswExportInfo(const RimEclipseCase* caseToApply, - const RimWellPath* wellPath, - bool enableSegmentSplitting); - - static RicMswExportInfo generateFishbonesMswExportInfo(const RimEclipseCase* caseToApply, - const RimWellPath* wellPath, - const std::vector& fishbonesSubs, - bool enableSegmentSplitting); - - static RicMswExportInfo generateFracturesMswExportInfo(RimEclipseCase* caseToApply, - const RimWellPath* wellPath); - - static RicMswExportInfo generateFracturesMswExportInfo(RimEclipseCase* caseToApply, - const RimWellPath* wellPath, - const std::vector& fractures); - - static RicMswExportInfo generatePerforationsMswExportInfo(const RicExportCompletionDataSettingsUi& exportSettings, - const RimWellPath* wellPath, - const std::vector& perforationIntervals); static CellDirection calculateCellMainDirection(RimEclipseCase* eclipseCase, size_t globalCellIndex, @@ -164,28 +146,12 @@ class RicWellPathExportCompletionDataFeatureImpl RimEclipseCase* eclipseCase, size_t timeStepIndex); - static void generateWelsegsTable(RifEclipseDataTableFormatter& formatter, - const RicMswExportInfo& exportInfo); - - static void generateWelsegsSegments(RifEclipseDataTableFormatter &formatter, - const RicMswExportInfo &exportInfo, - const std::set& exportCompletionTypes); - static void generateWelsegsCompletionCommentHeader(RifEclipseDataTableFormatter &formatter, - RigCompletionData::CompletionType completionType); - static void generateCompsegTables(RifEclipseDataTableFormatter& formatter, - const RicMswExportInfo& exportInfo); - static void generateCompsegTable(RifEclipseDataTableFormatter& formatter, - const RicMswExportInfo& exportInfo, - bool exportSubGridIntersections, - const std::set& exportCompletionTypes); - static void generateCompsegHeader(RifEclipseDataTableFormatter& formatter, - const RicMswExportInfo& exportInfo, - RigCompletionData::CompletionType completionType, - bool exportSubGridIntersections); - static void generateWsegvalvTable(RifEclipseDataTableFormatter& formatter, - const RicMswExportInfo& exportInfo); + static std::vector generatePerforationsCompdatValues(const RimWellPath* wellPath, + const std::vector& intervals, + const RicExportCompletionDataSettingsUi& settings); private: + static double calculateTransmissibilityAsEclipseDoes(RimEclipseCase* eclipseCase, double skinFactor, double wellRadius, @@ -195,11 +161,6 @@ class RicWellPathExportCompletionDataFeatureImpl static RigCompletionData combineEclipseCellCompletions(const std::vector& completions, const RicExportCompletionDataSettingsUi& settings); - static QFilePtr openFileForExport(const QString& fullFileName); - - static QFilePtr openFileForExport(const QString& folderName, - const QString& fileName); - static std::vector mainGridCompletions(std::vector& allCompletions); static std::map> subGridsCompletions(std::vector& allCompletions); @@ -236,36 +197,6 @@ class RicWellPathExportCompletionDataFeatureImpl const QString& gridName, const std::vector& completionData); - static std::vector generatePerforationsCompdatValues(const RimWellPath* wellPath, - const std::vector& intervals, - const RicExportCompletionDataSettingsUi& settings); - - static void assignFishbonesLateralIntersections(const RimEclipseCase* caseToApply, - const RimFishbonesMultipleSubs* fishbonesSubs, - RicMswSegment* location, - bool* foundSubGridIntersections, - double maxSegmentLength); - - static void assignFractureIntersections(const RimEclipseCase* caseToApply, - const RimWellPathFracture* fracture, - const std::vector& completionData, - RicMswSegment* location, - bool* foundSubGridIntersections); - - static void assignPerforationIntervalIntersections(const RimEclipseCase* caseToApply, - const RimPerforationInterval* interval, - const std::vector& completionData, - RicMswSegment* location, - const SubSegmentIntersectionInfo* cellIntInfo, - bool* foundSubGridIntersections); - - static void assignBranchAndSegmentNumbers(const RimEclipseCase* caseToApply, - RicMswSegment* location, - int* branchNum, - int* segmentNum); - static void assignBranchAndSegmentNumbers(const RimEclipseCase* caseToApply, - RicMswExportInfo* exportInfo); - static void appendCompletionData(std::map>* completionData, const std::vector& data); @@ -273,22 +204,7 @@ class RicWellPathExportCompletionDataFeatureImpl const RimWellPath* wellPath, const QString& gridName = ""); - static void exportWellSegments(RimEclipseCase* eclipseCase, - QFilePtr exportFile, - const RimWellPath* wellPath, - const std::vector& fractures); - - static void exportWellSegments(RimEclipseCase* eclipseCase, - QFilePtr exportFile, - const RimWellPath* wellPath, - const std::vector& fishbonesSubs); - - static void exportWellSegments(const RicExportCompletionDataSettingsUi& exportSettings, - QFilePtr exportFile, - const RimWellPath* wellPath, - const std::vector& perforationIntervals); - static void exportCarfinForTemporaryLgrs(const RimEclipseCase* sourceCase, const QString& folder); - static bool isCompletionWellPathEqual(const RigCompletionData& completion, const RimWellPath* wellPath); + static bool isCompletionWellPathEqual(const RigCompletionData& completion, const RimWellPath* wellPath); }; diff --git a/ApplicationCode/Commands/CompletionExportCommands/RicWellPathExportCompletionsFileTools.cpp b/ApplicationCode/Commands/CompletionExportCommands/RicWellPathExportCompletionsFileTools.cpp new file mode 100644 index 0000000000..2942646edc --- /dev/null +++ b/ApplicationCode/Commands/CompletionExportCommands/RicWellPathExportCompletionsFileTools.cpp @@ -0,0 +1,95 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2018 Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "RicWellPathExportCompletionsFileTools.h" + +#include "RiaApplication.h" +#include "RiaFilePathTools.h" +#include "RiaLogging.h" + +#include "RimProject.h" +#include "RimWellPath.h" +#include "RimWellPathCompletions.h" + +#include "cafUtils.h" + +#include + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RicWellPathExportCompletionsFileTools::OpenFileException::OpenFileException(const QString& message) + : message(message) +{ +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::shared_ptr RicWellPathExportCompletionsFileTools::openFileForExport(const QString& fullFileName) +{ + std::pair folderAndFileName = RiaFilePathTools::toFolderAndFileName(fullFileName); + return openFileForExport(folderAndFileName.first, folderAndFileName.second); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::shared_ptr RicWellPathExportCompletionsFileTools::openFileForExport(const QString& folderName, const QString& fileName) +{ + QString validFileName = caf::Utils::makeValidFileBasename(fileName); + + QDir exportFolder = QDir(folderName); + if (!exportFolder.exists()) + { + bool createdPath = exportFolder.mkpath("."); + if (createdPath) + RiaLogging::info("Created export folder " + folderName); + else + { + auto errorMessage = QString("Selected output folder does not exist, and could not be created."); + RiaLogging::error(errorMessage); + throw OpenFileException(errorMessage); + } + } + + QString filePath = exportFolder.filePath(validFileName); + std::shared_ptr exportFile(new QFile(filePath)); + if (!exportFile->open(QIODevice::WriteOnly | QIODevice::Text)) + { + auto errorMessage = QString("Export Completions Data: Could not open the file: %1").arg(filePath); + RiaLogging::error(errorMessage); + throw OpenFileException(errorMessage); + } + return exportFile; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +const RimWellPath* RicWellPathExportCompletionsFileTools::findWellPathFromExportName(const QString& wellNameForExport) +{ + auto allWellPaths = RiaApplication::instance()->project()->allWellPaths(); + + for (const auto wellPath : allWellPaths) + { + if (wellPath->completions()->wellNameForExport() == wellNameForExport) return wellPath; + } + return nullptr; +} + diff --git a/ApplicationCode/Commands/CompletionExportCommands/RicWellPathExportCompletionsFileTools.h b/ApplicationCode/Commands/CompletionExportCommands/RicWellPathExportCompletionsFileTools.h new file mode 100644 index 0000000000..51495516a0 --- /dev/null +++ b/ApplicationCode/Commands/CompletionExportCommands/RicWellPathExportCompletionsFileTools.h @@ -0,0 +1,42 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2018 Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include +#include + +#include + +class RimWellPath; + +class RicWellPathExportCompletionsFileTools +{ +public: + class OpenFileException + { + public: + OpenFileException(const QString& message); + QString message; + }; + + static std::shared_ptr openFileForExport(const QString& folderName, const QString& fileName); + static std::shared_ptr openFileForExport(const QString& fullFileName); + static const RimWellPath* findWellPathFromExportName(const QString& wellNameForExport); + +}; \ No newline at end of file diff --git a/ApplicationCode/Commands/CompletionExportCommands/RicWellPathExportMswCompletionsImpl.cpp b/ApplicationCode/Commands/CompletionExportCommands/RicWellPathExportMswCompletionsImpl.cpp new file mode 100644 index 0000000000..945e62ec7f --- /dev/null +++ b/ApplicationCode/Commands/CompletionExportCommands/RicWellPathExportMswCompletionsImpl.cpp @@ -0,0 +1,1785 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2018 Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "RicWellPathExportMswCompletionsImpl.h" + +#include "RiaLogging.h" +#include "RiaWeightedMeanCalculator.h" + +#include "RicExportCompletionDataSettingsUi.h" +#include "RicExportFractureCompletionsImpl.h" +#include "RicMswExportInfo.h" +#include "RicMswValveAccumulators.h" +#include "RicWellPathExportCompletionsFileTools.h" + +#include "RifEclipseDataTableFormatter.h" + +#include "RigActiveCellInfo.h" +#include "RigEclipseCaseData.h" +#include "RigGridBase.h" +#include "RigMainGrid.h" +#include "RigWellLogExtractor.h" +#include "RigWellPath.h" +#include "RigWellPathIntersectionTools.h" + +#include "RimEclipseCase.h" +#include "RimFishbonesCollection.h" +#include "RimFishbonesMultipleSubs.h" +#include "RimFractureTemplate.h" +#include "RimPerforationCollection.h" +#include "RimPerforationInterval.h" +#include "RimWellPath.h" +#include "RimWellPathCompletions.h" +#include "RimWellPathFracture.h" +#include "RimWellPathFractureCollection.h" +#include "RimWellPathValve.h" + +#include + +#include + +//-------------------------------------------------------------------------------------------------- +/// Internal definitions +//-------------------------------------------------------------------------------------------------- +class SubSegmentIntersectionInfo +{ +public: + SubSegmentIntersectionInfo(size_t globCellIndex, + double startTVD, + double endTVD, + double startMD, + double endMD, + cvf::Vec3d lengthsInCell); + static std::vector + spiltIntersectionSegmentsToMaxLength(const RigWellPath* pathGeometry, + const std::vector& intersections, + double maxSegmentLength); + static int numberOfSplittedSegments(double startMd, double endMd, double maxSegmentLength); + + size_t globCellIndex; + double startTVD; + double endTVD; + double startMD; + double endMD; + cvf::Vec3d intersectionLengthsInCellCS; +}; + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicWellPathExportMswCompletionsImpl::exportWellSegmentsForAllCompletions( + const RicExportCompletionDataSettingsUi& exportSettings, + const std::vector& wellPaths) +{ + std::shared_ptr unifiedExportFile; + if (exportSettings.fileSplit() == RicExportCompletionDataSettingsUi::UNIFIED_FILE) + { + QString unifiedFileName = QString("UnifiedCompletions_MSW_%1").arg(exportSettings.caseToApply->caseUserDescription()); + unifiedExportFile = RicWellPathExportCompletionsFileTools::openFileForExport(exportSettings.folder, unifiedFileName); + } + + for (const auto& wellPath : wellPaths) + { + std::shared_ptr unifiedWellPathFile; + + bool exportFractures = exportSettings.includeFractures() && !wellPath->fractureCollection()->activeFractures().empty(); + bool exportPerforations = + exportSettings.includePerforations() && !wellPath->perforationIntervalCollection()->activePerforations().empty(); + bool exportFishbones = + exportSettings.includeFishbones() && !wellPath->fishbonesCollection()->activeFishbonesSubs().empty(); + bool exportAnyCompletion = exportFractures || exportPerforations || exportFishbones; + if (exportAnyCompletion && exportSettings.fileSplit() == RicExportCompletionDataSettingsUi::SPLIT_ON_WELL && + !unifiedWellPathFile) + { + QString wellFileName = + QString("%1_UnifiedCompletions_MSW_%2") + .arg(wellPath->name(), exportSettings.caseToApply->caseUserDescription()); + unifiedWellPathFile = RicWellPathExportCompletionsFileTools::openFileForExport(exportSettings.folder, wellFileName); + } + + if (exportFractures) + { + std::shared_ptr fractureExportFile; + if (unifiedExportFile) + fractureExportFile = unifiedExportFile; + else if (unifiedWellPathFile) + fractureExportFile = unifiedWellPathFile; + else + { + QString fileName = + QString("%1_Fracture_MSW_%2") + .arg(wellPath->name(), exportSettings.caseToApply->caseUserDescription()); + fractureExportFile = RicWellPathExportCompletionsFileTools::openFileForExport(exportSettings.folder, fileName); + } + exportWellSegmentsForFractures( + exportSettings.caseToApply, fractureExportFile, wellPath, wellPath->fractureCollection()->activeFractures()); + } + + if (exportPerforations) + { + std::shared_ptr perforationsExportFile; + if (unifiedExportFile) + perforationsExportFile = unifiedExportFile; + else if (unifiedWellPathFile) + perforationsExportFile = unifiedWellPathFile; + else + { + QString fileName = + QString("%1_Perforation_MSW_%2") + .arg(wellPath->name(), exportSettings.caseToApply->caseUserDescription()); + perforationsExportFile = + RicWellPathExportCompletionsFileTools::openFileForExport(exportSettings.folder, fileName); + } + exportWellSegmentsForPerforations(exportSettings.caseToApply, + perforationsExportFile, + wellPath, + exportSettings.timeStep, + wellPath->perforationIntervalCollection()->activePerforations()); + } + + if (exportFishbones) + { + std::shared_ptr fishbonesExportFile; + if (unifiedExportFile) + fishbonesExportFile = unifiedExportFile; + else if (unifiedWellPathFile) + fishbonesExportFile = unifiedWellPathFile; + else + { + QString fileName = + QString("%1_Fishbones_MSW_%2") + .arg(wellPath->name(), exportSettings.caseToApply->caseUserDescription()); + fishbonesExportFile = RicWellPathExportCompletionsFileTools::openFileForExport(exportSettings.folder, fileName); + } + exportWellSegmentsForFishbones(exportSettings.caseToApply, + fishbonesExportFile, + wellPath, + wellPath->fishbonesCollection()->activeFishbonesSubs()); + } + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicWellPathExportMswCompletionsImpl::exportWellSegmentsForFractures(RimEclipseCase* eclipseCase, + std::shared_ptr exportFile, + const RimWellPath* wellPath, + const std::vector& fractures) +{ + if (eclipseCase == nullptr) + { + RiaLogging::error("Export Fracture Well Segments: Cannot export completions data without specified eclipse case"); + return; + } + + RicMswExportInfo exportInfo = generateFracturesMswExportInfo(eclipseCase, wellPath, fractures); + + QTextStream stream(exportFile.get()); + RifEclipseDataTableFormatter formatter(stream); + generateWelsegsTable(formatter, exportInfo); + generateCompsegTables(formatter, exportInfo); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicWellPathExportMswCompletionsImpl::exportWellSegmentsForFishbones( + RimEclipseCase* eclipseCase, + std::shared_ptr exportFile, + const RimWellPath* wellPath, + const std::vector& fishbonesSubs) +{ + if (eclipseCase == nullptr) + { + RiaLogging::error("Export Well Segments: Cannot export completions data without specified eclipse case"); + return; + } + + RicMswExportInfo exportInfo = generateFishbonesMswExportInfo(eclipseCase, wellPath, fishbonesSubs, true); + + QTextStream stream(exportFile.get()); + RifEclipseDataTableFormatter formatter(stream); + + generateWelsegsTable(formatter, exportInfo); + generateCompsegTables(formatter, exportInfo); + generateWsegvalvTable(formatter, exportInfo); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicWellPathExportMswCompletionsImpl::exportWellSegmentsForPerforations( + RimEclipseCase* eclipseCase, + std::shared_ptr exportFile, + const RimWellPath* wellPath, + int timeStep, + const std::vector& perforationIntervals) +{ + if (eclipseCase == nullptr) + { + RiaLogging::error("Export Well Segments: Cannot export completions data without specified eclipse case"); + return; + } + + RicMswExportInfo exportInfo = generatePerforationsMswExportInfo(eclipseCase, wellPath, timeStep, perforationIntervals); + + QTextStream stream(exportFile.get()); + RifEclipseDataTableFormatter formatter(stream); + + generateWelsegsTable(formatter, exportInfo); + generateCompsegTables(formatter, exportInfo); + generateWsegvalvTable(formatter, exportInfo); + generateWsegAicdTable(formatter, exportInfo); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicWellPathExportMswCompletionsImpl::generateWelsegsTable(RifEclipseDataTableFormatter& formatter, + const RicMswExportInfo& exportInfo) +{ + formatter.keyword("WELSEGS"); + + double startMD = exportInfo.initialMD(); + double startTVD = exportInfo.initialTVD(); + + { + std::vector header = { + RifEclipseOutputTableColumn("Name"), + RifEclipseOutputTableColumn("Dep 1"), + RifEclipseOutputTableColumn("Tlen 1"), + RifEclipseOutputTableColumn("Vol 1"), + RifEclipseOutputTableColumn("Len&Dep"), + RifEclipseOutputTableColumn("PresDrop"), + }; + formatter.header(header); + + formatter.add(exportInfo.wellPath()->completions()->wellNameForExport()); + formatter.add(startTVD); + formatter.add(startMD); + formatter.addValueOrDefaultMarker(exportInfo.topWellBoreVolume(), RicMswExportInfo::defaultDoubleValue()); + formatter.add(exportInfo.lengthAndDepthText()); + formatter.add(QString("'%1'").arg(exportInfo.pressureDropText())); + + formatter.rowCompleted(); + } + + { + std::vector header = { + RifEclipseOutputTableColumn("First Seg"), + RifEclipseOutputTableColumn("Last Seg"), + RifEclipseOutputTableColumn("Branch Num"), + RifEclipseOutputTableColumn("Outlet Seg"), + RifEclipseOutputTableColumn("Length"), + RifEclipseOutputTableColumn("Depth Change"), + RifEclipseOutputTableColumn("Diam"), + RifEclipseOutputTableColumn("Rough"), + }; + formatter.header(header); + } + + { + double prevMD = exportInfo.initialMD(); + double prevTVD = exportInfo.initialTVD(); + formatter.comment("Main Stem Segments"); + for (std::shared_ptr location : exportInfo.wellSegmentLocations()) + { + double depth = 0; + double length = 0; + + if (exportInfo.lengthAndDepthText() == QString("INC")) + { + depth = location->endTVD() - prevTVD; + length = location->endMD() - prevMD; + } + else + { + depth = location->endTVD(); + length = location->endMD(); + } + + if (location->subIndex() != cvf::UNDEFINED_SIZE_T) + { + QString comment = location->label() + QString(", sub %1").arg(location->subIndex()); + formatter.comment(comment); + } + + formatter.add(location->segmentNumber()).add(location->segmentNumber()); + formatter.add(1); // All segments on main stem are branch 1 + formatter.add(location->segmentNumber() - 1); // All main stem segments are connected to the segment below them + formatter.add(length); + formatter.add(depth); + formatter.add(exportInfo.linerDiameter()); + formatter.add(exportInfo.roughnessFactor()); + formatter.rowCompleted(); + prevMD = location->endMD(); + prevTVD = location->endTVD(); + } + } + + { + generateWelsegsSegments(formatter, exportInfo, {RigCompletionData::FISHBONES_ICD, RigCompletionData::FISHBONES}); + generateWelsegsSegments(formatter, exportInfo, {RigCompletionData::FRACTURE}); + generateWelsegsSegments( + formatter, + exportInfo, + {RigCompletionData::PERFORATION_ICD, RigCompletionData::PERFORATION_ICV, RigCompletionData::PERFORATION_AICD}); + } + + formatter.tableCompleted(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicWellPathExportMswCompletionsImpl::generateWelsegsSegments( + RifEclipseDataTableFormatter& formatter, + const RicMswExportInfo& exportInfo, + const std::set& exportCompletionTypes) +{ + bool generatedHeader = false; + for (std::shared_ptr segment : exportInfo.wellSegmentLocations()) + { + for (std::shared_ptr completion : segment->completions()) + { + if (exportCompletionTypes.count(completion->completionType())) + { + if (!generatedHeader) + { + generateWelsegsCompletionCommentHeader(formatter, completion->completionType()); + generatedHeader = true; + } + + if (RigCompletionData::isValve(completion->completionType())) + { + if (!completion->subSegments().empty()) + { + formatter.comment(completion->label()); + + formatter.add(completion->subSegments().front()->segmentNumber()); + formatter.add(completion->subSegments().front()->segmentNumber()); + formatter.add(completion->branchNumber()); + formatter.add(segment->segmentNumber()); + formatter.add(0.1); // ICDs have 0.1 length + formatter.add(0); // Depth change + formatter.add(exportInfo.linerDiameter()); + formatter.add(exportInfo.roughnessFactor()); + formatter.rowCompleted(); + } + } + else + { + if (completion->completionType() == RigCompletionData::FISHBONES) + { + formatter.comment(QString("%1 : Sub index %2 - %3") + .arg(segment->label()) + .arg(segment->subIndex()) + .arg(completion->label())); + } + else if (completion->completionType() == RigCompletionData::FRACTURE) + { + formatter.comment(QString("%1 connected to %2").arg(completion->label()).arg(segment->label())); + } + + for (std::shared_ptr subSegment : completion->subSegments()) + { + double depth = 0; + double length = 0; + + if (exportInfo.lengthAndDepthText() == QString("INC")) + { + depth = subSegment->deltaTVD(); + length = subSegment->deltaMD(); + } + else + { + depth = subSegment->endTVD(); + length = subSegment->endMD(); + } + double diameter = segment->effectiveDiameter(); + formatter.add(subSegment->segmentNumber()); + formatter.add(subSegment->segmentNumber()); + formatter.add(completion->branchNumber()); + formatter.add(subSegment->attachedSegmentNumber()); + formatter.add(length); + formatter.add(depth); + formatter.add(diameter); + formatter.add(segment->openHoleRoughnessFactor()); + formatter.rowCompleted(); + } + } + } + } + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicWellPathExportMswCompletionsImpl::generateWelsegsCompletionCommentHeader(RifEclipseDataTableFormatter& formatter, + RigCompletionData::CompletionType completionType) +{ + if (completionType == RigCompletionData::CT_UNDEFINED) + { + formatter.comment("Main stem"); + } + else if (completionType == RigCompletionData::FISHBONES_ICD) + { + formatter.comment("Fishbone Laterals"); + formatter.comment("Diam: MSW - Tubing Radius"); + formatter.comment("Rough: MSW - Open Hole Roughness Factor"); + } + else if (RigCompletionData::isPerforationValve(completionType)) + { + formatter.comment("Perforation Valve Segments"); + formatter.comment("Diam: MSW - Tubing Radius"); + formatter.comment("Rough: MSW - Open Hole Roughness Factor"); + } + else if (completionType == RigCompletionData::FRACTURE) + { + formatter.comment("Fracture Segments"); + formatter.comment("Diam: MSW - Default Dummy"); + formatter.comment("Rough: MSW - Default Dummy"); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicWellPathExportMswCompletionsImpl::generateCompsegTables(RifEclipseDataTableFormatter& formatter, + const RicMswExportInfo& exportInfo) +{ + /* + * TODO: Creating the regular perforation COMPSEGS table should come in here, before the others + * should take precedence by appearing later in the output. See #3230. + */ + + { + std::set fishbonesTypes = {RigCompletionData::FISHBONES_ICD, + RigCompletionData::FISHBONES}; + generateCompsegTable(formatter, exportInfo, false, fishbonesTypes); + if (exportInfo.hasSubGridIntersections()) + { + generateCompsegTable(formatter, exportInfo, true, fishbonesTypes); + } + } + + { + std::set fractureTypes = {RigCompletionData::FRACTURE}; + generateCompsegTable(formatter, exportInfo, false, fractureTypes); + if (exportInfo.hasSubGridIntersections()) + { + generateCompsegTable(formatter, exportInfo, true, fractureTypes); + } + } + + { + std::set perforationTypes = {RigCompletionData::PERFORATION, + RigCompletionData::PERFORATION_ICD, + RigCompletionData::PERFORATION_ICV, + RigCompletionData::PERFORATION_AICD}; + generateCompsegTable(formatter, exportInfo, false, perforationTypes); + if (exportInfo.hasSubGridIntersections()) + { + generateCompsegTable(formatter, exportInfo, true, perforationTypes); + } + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicWellPathExportMswCompletionsImpl::generateCompsegTable( + RifEclipseDataTableFormatter& formatter, + const RicMswExportInfo& exportInfo, + bool exportSubGridIntersections, + const std::set& exportCompletionTypes) +{ + bool generatedHeader = false; + + for (std::shared_ptr location : exportInfo.wellSegmentLocations()) + { + double startMD = location->startMD(); + + for (std::shared_ptr completion : location->completions()) + { + if (!completion->subSegments().empty() && exportCompletionTypes.count(completion->completionType())) + { + if (!generatedHeader) + { + generateCompsegHeader(formatter, exportInfo, completion->completionType(), exportSubGridIntersections); + generatedHeader = true; + } + + for (const std::shared_ptr& subSegment : completion->subSegments()) + { + if (completion->completionType() == RigCompletionData::FISHBONES_ICD) + { + startMD = subSegment->startMD(); + } + + for (const std::shared_ptr& intersection : subSegment->intersections()) + { + bool isSubGridIntersection = !intersection->gridName().isEmpty(); + if (isSubGridIntersection == exportSubGridIntersections) + { + if (exportSubGridIntersections) + { + formatter.add(intersection->gridName()); + } + cvf::Vec3st ijk = intersection->gridLocalCellIJK(); + formatter.addOneBasedCellIndex(ijk.x()).addOneBasedCellIndex(ijk.y()).addOneBasedCellIndex(ijk.z()); + formatter.add(completion->branchNumber()); + + double startLength = subSegment->startMD(); + if (exportInfo.lengthAndDepthText() == QString("INC") && completion->branchNumber() != 1) + { + startLength -= startMD; + } + formatter.add(startLength); + formatter.add(startLength + subSegment->deltaMD()); + + formatter.rowCompleted(); + } + } + } + } + } + } + if (generatedHeader) + { + formatter.tableCompleted(); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicWellPathExportMswCompletionsImpl::generateCompsegHeader(RifEclipseDataTableFormatter& formatter, + const RicMswExportInfo& exportInfo, + RigCompletionData::CompletionType completionType, + bool exportSubGridIntersections) +{ + if (exportSubGridIntersections) + { + formatter.keyword("COMPSEGL"); + } + else + { + formatter.keyword("COMPSEGS"); + } + + if (completionType == RigCompletionData::FISHBONES_ICD) + { + formatter.comment("Fishbones"); + } + else if (completionType == RigCompletionData::FRACTURE) + { + formatter.comment("Fractures"); + } + + { + std::vector header = {RifEclipseOutputTableColumn("Name")}; + formatter.header(header); + formatter.add(exportInfo.wellPath()->completions()->wellNameForExport()); + formatter.rowCompleted(); + } + + { + std::vector allHeaders; + if (exportSubGridIntersections) + { + allHeaders.push_back(RifEclipseOutputTableColumn("Grid")); + } + + std::vector commonHeaders = {RifEclipseOutputTableColumn("I"), + RifEclipseOutputTableColumn("J"), + RifEclipseOutputTableColumn("K"), + RifEclipseOutputTableColumn("Branch no"), + RifEclipseOutputTableColumn("Start Length"), + RifEclipseOutputTableColumn("End Length"), + RifEclipseOutputTableColumn("Dir Pen"), + RifEclipseOutputTableColumn("End Range"), + RifEclipseOutputTableColumn("Connection Depth")}; + allHeaders.insert(allHeaders.end(), commonHeaders.begin(), commonHeaders.end()); + formatter.header(allHeaders); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicWellPathExportMswCompletionsImpl::generateWsegvalvTable(RifEclipseDataTableFormatter& formatter, + const RicMswExportInfo& exportInfo) +{ + bool foundValve = false; + + for (std::shared_ptr location : exportInfo.wellSegmentLocations()) + { + for (std::shared_ptr completion : location->completions()) + { + if (RigCompletionData::isWsegValveTypes(completion->completionType())) + { + if (!foundValve) + { + formatter.keyword("WSEGVALV"); + std::vector header = { + RifEclipseOutputTableColumn("Well Name"), + RifEclipseOutputTableColumn("Seg No"), + RifEclipseOutputTableColumn("Cv"), + RifEclipseOutputTableColumn("Ac"), + }; + formatter.header(header); + + foundValve = true; + } + + std::shared_ptr icd = std::static_pointer_cast(completion); + if (!icd->subSegments().empty()) + { + CVF_ASSERT(icd->subSegments().size() == 1u); + if (icd->completionType() == RigCompletionData::PERFORATION_ICD || + icd->completionType() == RigCompletionData::PERFORATION_ICV) + { + formatter.comment(icd->label()); + } + formatter.add(exportInfo.wellPath()->completions()->wellNameForExport()); + formatter.add(icd->subSegments().front()->segmentNumber()); + formatter.add(icd->flowCoefficient()); + formatter.add(QString("%1").arg(icd->area(), 8, 'g', 4)); + formatter.rowCompleted(); + } + } + } + } + if (foundValve) + { + formatter.tableCompleted(); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicWellPathExportMswCompletionsImpl::generateWsegAicdTable(RifEclipseDataTableFormatter& formatter, + const RicMswExportInfo& exportInfo) +{ + RifEclipseDataTableFormatter tighterFormatter(formatter); + tighterFormatter.setColumnSpacing(1); + tighterFormatter.setTableRowPrependText(" "); + + bool foundValve = false; + + for (std::shared_ptr location : exportInfo.wellSegmentLocations()) + { + for (std::shared_ptr completion : location->completions()) + { + if (completion->completionType() == RigCompletionData::PERFORATION_AICD) + { + std::shared_ptr aicd = std::static_pointer_cast(completion); + if (!aicd->isValid()) + { + RiaLogging::error( + QString("Export AICD Valve (%1): Valve is invalid. At least one required template parameter is not set.") + .arg(aicd->label())); + } + + if (!foundValve) + { + std::vector columnDescriptions = { + "Well Name", + "Segment Number", + "Segment Number", + "Strength of AICD", + "Length of AICD", + "Density of Calibration Fluid", + "Viscosity of Calibration Fluid", + "Critical water in liquid fraction for emulsions viscosity model", + "Emulsion viscosity transition region", + "Max ratio of emulsion viscosity to continuous phase viscosity", + "Flow scaling factor method", + "Maximum flowrate for AICD device", + "Volume flow rate exponent, x", + "Viscosity function exponent, y", + "Device OPEN/SHUT", + "Exponent of the oil flowing fraction in the density mixture calculation", + "Exponent of the water flowing fraction in the density mixture calculation", + "Exponent of the gas flowing fraction in the density mixture calculation", + "Exponent of the oil flowing fraction in the density viscosity calculation", + "Exponent of the water flowing fraction in the density viscosity calculation", + "Exponent of the gas flowing fraction in the density viscosity calculation"}; + + tighterFormatter.keyword("WSEGAICD"); + tighterFormatter.comment("Column Overview:"); + for (size_t i = 0; i < columnDescriptions.size(); ++i) + { + tighterFormatter.comment(QString("%1: %2").arg(i + 1, 2, 10, QChar('0')).arg(columnDescriptions[i])); + } + + std::vector header; + for (size_t i = 1; i <= 21; ++i) + { + QString cName = QString("%1").arg(i, 2, 10, QChar('0')); + RifEclipseOutputTableColumn col( + cName, RifEclipseOutputTableDoubleFormatting(RifEclipseOutputTableDoubleFormat::RIF_CONSISE), RIGHT); + header.push_back(col); + } + tighterFormatter.header(header); + + foundValve = true; + } + if (!aicd->subSegments().empty()) + { + CVF_ASSERT(aicd->subSegments().size() == 1u); + tighterFormatter.comment(aicd->label()); + tighterFormatter.add(exportInfo.wellPath()->completions()->wellNameForExport()); // 1 + tighterFormatter.add(aicd->subSegments().front()->segmentNumber()); + tighterFormatter.add(aicd->subSegments().front()->segmentNumber()); + + std::array values = aicd->values(); + tighterFormatter.add(values[AICD_STRENGTH]); + tighterFormatter.add(aicd->length()); // 5 + tighterFormatter.add(values[AICD_DENSITY_CALIB_FLUID]); + tighterFormatter.add(values[AICD_VISCOSITY_CALIB_FLUID]); + tighterFormatter.addValueOrDefaultMarker(values[AICD_CRITICAL_WATER_IN_LIQUID_FRAC], + RicMswExportInfo::defaultDoubleValue()); + tighterFormatter.addValueOrDefaultMarker(values[AICD_EMULSION_VISC_TRANS_REGION], + RicMswExportInfo::defaultDoubleValue()); + tighterFormatter.addValueOrDefaultMarker(values[AICD_MAX_RATIO_EMULSION_VISC], + RicMswExportInfo::defaultDoubleValue()); // 10 + tighterFormatter.add(1); + tighterFormatter.addValueOrDefaultMarker(values[AICD_MAX_FLOW_RATE], RicMswExportInfo::defaultDoubleValue()); + tighterFormatter.add(values[AICD_VOL_FLOW_EXP]); + tighterFormatter.add(values[AICD_VISOSITY_FUNC_EXP]); + tighterFormatter.add(aicd->isOpen() ? "OPEN" : "SHUT"); // 15 + tighterFormatter.addValueOrDefaultMarker(values[AICD_EXP_OIL_FRAC_DENSITY], RicMswExportInfo::defaultDoubleValue()); + tighterFormatter.addValueOrDefaultMarker(values[AICD_EXP_WATER_FRAC_DENSITY], + RicMswExportInfo::defaultDoubleValue()); + tighterFormatter.addValueOrDefaultMarker(values[AICD_EXP_GAS_FRAC_DENSITY], RicMswExportInfo::defaultDoubleValue()); + tighterFormatter.addValueOrDefaultMarker(values[AICD_EXP_OIL_FRAC_VISCOSITY], + RicMswExportInfo::defaultDoubleValue()); + tighterFormatter.addValueOrDefaultMarker(values[AICD_EXP_WATER_FRAC_VISCOSITY], + RicMswExportInfo::defaultDoubleValue()); // 20 + tighterFormatter.addValueOrDefaultMarker(values[AICD_EXP_GAS_FRAC_VISCOSITY], + RicMswExportInfo::defaultDoubleValue()); + tighterFormatter.rowCompleted(); + } + } + } + } + if (foundValve) + { + tighterFormatter.tableCompleted(); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RicMswExportInfo RicWellPathExportMswCompletionsImpl::generateFishbonesMswExportInfo(const RimEclipseCase* caseToApply, + const RimWellPath* wellPath, + bool enableSegmentSplitting) +{ + std::vector fishbonesSubs = wellPath->fishbonesCollection()->activeFishbonesSubs(); + + return generateFishbonesMswExportInfo(caseToApply, wellPath, fishbonesSubs, enableSegmentSplitting); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RicMswExportInfo RicWellPathExportMswCompletionsImpl::generateFishbonesMswExportInfo( + const RimEclipseCase* caseToApply, + const RimWellPath* wellPath, + const std::vector& fishbonesSubs, + bool enableSegmentSplitting) +{ + RiaEclipseUnitTools::UnitSystem unitSystem = caseToApply->eclipseCaseData()->unitsType(); + + RicMswExportInfo exportInfo(wellPath, + unitSystem, + wellPath->fishbonesCollection()->startMD(), + wellPath->fishbonesCollection()->mswParameters()->lengthAndDepth().text(), + wellPath->fishbonesCollection()->mswParameters()->pressureDrop().text()); + exportInfo.setLinerDiameter(wellPath->fishbonesCollection()->mswParameters()->linerDiameter(unitSystem)); + exportInfo.setRoughnessFactor(wellPath->fishbonesCollection()->mswParameters()->roughnessFactor(unitSystem)); + + double maxSegmentLength = enableSegmentSplitting ? wellPath->fishbonesCollection()->mswParameters()->maxSegmentLength() + : std::numeric_limits::infinity(); + bool foundSubGridIntersections = false; + double subStartMD = wellPath->fishbonesCollection()->startMD(); + for (RimFishbonesMultipleSubs* subs : fishbonesSubs) + { + for (auto& sub : subs->installedLateralIndices()) + { + double subEndMD = subs->measuredDepth(sub.subIndex); + double subEndTVD = -wellPath->wellPathGeometry()->interpolatedPointAlongWellPath(subEndMD).z(); + int subSegCount = SubSegmentIntersectionInfo::numberOfSplittedSegments(subStartMD, subEndMD, maxSegmentLength); + double subSegLen = (subEndMD - subStartMD) / subSegCount; + + double startMd = subStartMD; + double startTvd = -wellPath->wellPathGeometry()->interpolatedPointAlongWellPath(startMd).z(); + for (int ssi = 0; ssi < subSegCount; ssi++) + { + double endMd = startMd + subSegLen; + double endTvd = -wellPath->wellPathGeometry()->interpolatedPointAlongWellPath(endMd).z(); + + std::shared_ptr location( + new RicMswSegment(subs->generatedName(), startMd, endMd, startTvd, endTvd, sub.subIndex)); + location->setEffectiveDiameter(subs->effectiveDiameter(unitSystem)); + location->setHoleDiameter(subs->holeDiameter(unitSystem)); + location->setOpenHoleRoughnessFactor(subs->openHoleRoughnessFactor(unitSystem)); + location->setSkinFactor(subs->skinFactor()); + location->setSourcePdmObject(subs); + + if (ssi == 0) + { + // Add completion for ICD + std::shared_ptr icdCompletion(new RicMswFishbonesICD(QString("ICD"), nullptr)); + std::shared_ptr icdSegment( + new RicMswSubSegment(subEndMD, subEndMD + 0.1, subEndTVD, subEndTVD)); + icdCompletion->setFlowCoefficient(subs->icdFlowCoefficient()); + double icdOrificeRadius = subs->icdOrificeDiameter(unitSystem) / 2; + icdCompletion->setArea(icdOrificeRadius * icdOrificeRadius * cvf::PI_D * subs->icdCount()); + + icdCompletion->addSubSegment(icdSegment); + location->addCompletion(icdCompletion); + + for (size_t lateralIndex : sub.lateralIndices) + { + QString label = QString("Lateral %1").arg(lateralIndex); + location->addCompletion(std::make_shared(label, lateralIndex)); + } + assignFishbonesLateralIntersections( + caseToApply, subs, location, &foundSubGridIntersections, maxSegmentLength); + } + + exportInfo.addWellSegment(location); + + startMd = endMd; + startTvd = endTvd; + } + + subStartMD = subEndMD; + } + } + exportInfo.setHasSubGridIntersections(foundSubGridIntersections); + exportInfo.sortLocations(); + + assignBranchAndSegmentNumbers(caseToApply, &exportInfo); + + return exportInfo; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RicMswExportInfo RicWellPathExportMswCompletionsImpl::generateFracturesMswExportInfo(RimEclipseCase* caseToApply, + const RimWellPath* wellPath) +{ + std::vector fractures = wellPath->fractureCollection()->activeFractures(); + + return generateFracturesMswExportInfo(caseToApply, wellPath, fractures); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RicMswExportInfo + RicWellPathExportMswCompletionsImpl::generateFracturesMswExportInfo(RimEclipseCase* caseToApply, + const RimWellPath* wellPath, + const std::vector& fractures) +{ + const RigMainGrid* grid = caseToApply->eclipseCaseData()->mainGrid(); + const RigActiveCellInfo* activeCellInfo = caseToApply->eclipseCaseData()->activeCellInfo(RiaDefines::MATRIX_MODEL); + RiaEclipseUnitTools::UnitSystem unitSystem = caseToApply->eclipseCaseData()->unitsType(); + + const RigWellPath* wellPathGeometry = wellPath->wellPathGeometry(); + const std::vector& coords = wellPathGeometry->wellPathPoints(); + const std::vector& mds = wellPathGeometry->measureDepths(); + CVF_ASSERT(!coords.empty() && !mds.empty()); + + std::vector intersections = + RigWellPathIntersectionTools::findCellIntersectionInfosAlongPath(caseToApply->eclipseCaseData(), coords, mds); + + double maxSegmentLength = wellPath->fractureCollection()->mswParameters()->maxSegmentLength(); + std::vector subSegIntersections = + SubSegmentIntersectionInfo::spiltIntersectionSegmentsToMaxLength(wellPathGeometry, intersections, maxSegmentLength); + + double initialMD = 0.0; + if (wellPath->fractureCollection()->mswParameters()->referenceMDType() == RimMswCompletionParameters::MANUAL_REFERENCE_MD) + { + initialMD = wellPath->fractureCollection()->mswParameters()->manualReferenceMD(); + } + else + { + for (WellPathCellIntersectionInfo intersection : intersections) + { + if (activeCellInfo->isActive(intersection.globCellIndex)) + { + initialMD = intersection.startMD; + break; + } + } + } + + RicMswExportInfo exportInfo(wellPath, + unitSystem, + initialMD, + wellPath->fractureCollection()->mswParameters()->lengthAndDepth().text(), + wellPath->fractureCollection()->mswParameters()->pressureDrop().text()); + + exportInfo.setLinerDiameter(wellPath->fractureCollection()->mswParameters()->linerDiameter(unitSystem)); + exportInfo.setRoughnessFactor(wellPath->fractureCollection()->mswParameters()->roughnessFactor(unitSystem)); + + bool foundSubGridIntersections = false; + + // Main bore + int mainBoreSegment = 1; + for (const auto& cellIntInfo : subSegIntersections) + { + double startTVD = cellIntInfo.startTVD; + double endTVD = cellIntInfo.endTVD; + + size_t localGridIdx = 0u; + const RigGridBase* localGrid = grid->gridAndGridLocalIdxFromGlobalCellIdx(cellIntInfo.globCellIndex, &localGridIdx); + QString gridName; + if (localGrid != grid) + { + gridName = QString::fromStdString(localGrid->gridName()); + foundSubGridIntersections = true; + } + + size_t i = 0u, j = 0u, k = 0u; + localGrid->ijkFromCellIndex(localGridIdx, &i, &j, &k); + QString label = QString("Main stem segment %1").arg(++mainBoreSegment); + std::shared_ptr location( + new RicMswSegment(label, cellIntInfo.startMD, cellIntInfo.endMD, startTVD, endTVD)); + + // Check if fractures are to be assigned to current main bore segment + for (RimWellPathFracture* fracture : fractures) + { + double fractureStartMD = fracture->fractureMD(); + if (fracture->fractureTemplate()->orientationType() == RimFractureTemplate::ALONG_WELL_PATH) + { + double perforationLength = fracture->fractureTemplate()->perforationLength(); + fractureStartMD -= 0.5 * perforationLength; + } + + if (cvf::Math::valueInRange(fractureStartMD, cellIntInfo.startMD, cellIntInfo.endMD)) + { + std::vector completionData = + RicExportFractureCompletionsImpl::generateCompdatValues(caseToApply, + wellPath->completions()->wellNameForExport(), + wellPath->wellPathGeometry(), + {fracture}, + nullptr, + nullptr); + + assignFractureIntersections(caseToApply, fracture, completionData, location, &foundSubGridIntersections); + } + } + + exportInfo.addWellSegment(location); + } + exportInfo.setHasSubGridIntersections(foundSubGridIntersections); + exportInfo.sortLocations(); + assignBranchAndSegmentNumbers(caseToApply, &exportInfo); + + return exportInfo; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RicMswExportInfo RicWellPathExportMswCompletionsImpl::generatePerforationsMswExportInfo( + RimEclipseCase* eclipseCase, + const RimWellPath* wellPath, + int timeStep, + const std::vector& perforationIntervals) +{ + const RigActiveCellInfo* activeCellInfo = eclipseCase->eclipseCaseData()->activeCellInfo(RiaDefines::MATRIX_MODEL); + RiaEclipseUnitTools::UnitSystem unitSystem = eclipseCase->eclipseCaseData()->unitsType(); + + const RigWellPath* wellPathGeometry = wellPath->wellPathGeometry(); + const std::vector& coords = wellPathGeometry->wellPathPoints(); + const std::vector& mds = wellPathGeometry->measureDepths(); + CVF_ASSERT(!coords.empty() && !mds.empty()); + + std::vector intersections = + RigWellPathIntersectionTools::findCellIntersectionInfosAlongPath(eclipseCase->eclipseCaseData(), coords, mds); + + double maxSegmentLength = wellPath->perforationIntervalCollection()->mswParameters()->maxSegmentLength(); + std::vector subSegIntersections = + SubSegmentIntersectionInfo::spiltIntersectionSegmentsToMaxLength(wellPathGeometry, intersections, maxSegmentLength); + + double initialMD = 0.0; + if (wellPath->perforationIntervalCollection()->mswParameters()->referenceMDType() == RimMswCompletionParameters::MANUAL_REFERENCE_MD) + { + initialMD = wellPath->perforationIntervalCollection()->mswParameters()->manualReferenceMD(); + } + else + { + for (WellPathCellIntersectionInfo intersection : intersections) + { + if (activeCellInfo->isActive(intersection.globCellIndex)) + { + initialMD = intersection.startMD; + break; + } + } + } + + RicMswExportInfo exportInfo(wellPath, + unitSystem, + initialMD, + wellPath->perforationIntervalCollection()->mswParameters()->lengthAndDepth().text(), + wellPath->perforationIntervalCollection()->mswParameters()->pressureDrop().text()); + + exportInfo.setLinerDiameter(wellPath->perforationIntervalCollection()->mswParameters()->linerDiameter(unitSystem)); + exportInfo.setRoughnessFactor(wellPath->perforationIntervalCollection()->mswParameters()->roughnessFactor(unitSystem)); + + bool foundSubGridIntersections = false; + + MainBoreSegments mainBoreSegments = createMainBoreSegmentsForPerforations( + subSegIntersections, perforationIntervals, wellPath, timeStep, eclipseCase, &foundSubGridIntersections); + + createValveCompletions(mainBoreSegments, perforationIntervals, unitSystem); + assignValveContributionsToSuperICDsOrAICDs(mainBoreSegments, perforationIntervals, unitSystem); + moveIntersectionsToICVs(mainBoreSegments, perforationIntervals, unitSystem); + moveIntersectionsToSuperICDsOrAICDs(mainBoreSegments); + + for (std::shared_ptr segment : mainBoreSegments) + { + exportInfo.addWellSegment(segment); + } + + exportInfo.setHasSubGridIntersections(foundSubGridIntersections); + exportInfo.sortLocations(); + assignBranchAndSegmentNumbers(eclipseCase, &exportInfo); + + return exportInfo; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RicWellPathExportMswCompletionsImpl::MainBoreSegments RicWellPathExportMswCompletionsImpl::createMainBoreSegmentsForPerforations( + const std::vector& subSegIntersections, + const std::vector& perforationIntervals, + const RimWellPath* wellPath, + int timeStep, + RimEclipseCase* eclipseCase, + bool* foundSubGridIntersections) +{ + MainBoreSegments mainBoreSegments; + + for (const auto& cellIntInfo : subSegIntersections) + { + if (std::fabs(cellIntInfo.endMD - cellIntInfo.startMD) > 1.0e-8) + { + QString label = QString("Main stem segment %1").arg(mainBoreSegments.size() + 2); + std::shared_ptr segment( + new RicMswSegment(label, cellIntInfo.startMD, cellIntInfo.endMD, cellIntInfo.startTVD, cellIntInfo.endTVD)); + + for (const RimPerforationInterval* interval : perforationIntervals) + { + double overlapStart = std::max(interval->startMD(), segment->startMD()); + double overlapEnd = std::min(interval->endMD(), segment->endMD()); + double overlap = std::max(0.0, overlapEnd - overlapStart); + if (overlap > 0.0) + { + std::shared_ptr intervalCompletion(new RicMswPerforation(interval->name())); + std::vector completionData = + generatePerforationIntersections(wellPath, interval, timeStep, eclipseCase); + assignPerforationIntersections( + completionData, intervalCompletion, cellIntInfo, overlapStart, overlapEnd, foundSubGridIntersections); + segment->addCompletion(intervalCompletion); + } + } + mainBoreSegments.push_back(segment); + } + } + return mainBoreSegments; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicWellPathExportMswCompletionsImpl::createValveCompletions( + std::vector>& mainBoreSegments, + const std::vector& perforationIntervals, + RiaEclipseUnitTools::UnitSystem unitSystem) +{ + for (size_t nMainSegment = 0u; nMainSegment < mainBoreSegments.size(); ++nMainSegment) + { + std::shared_ptr segment = mainBoreSegments[nMainSegment]; + + std::shared_ptr ICV; + std::shared_ptr superICD; + std::shared_ptr superAICD; + + double totalICDOverlap = 0.0; + double totalAICDOverlap = 0.0; + + for (const RimPerforationInterval* interval : perforationIntervals) + { + if (!interval->isChecked()) continue; + + std::vector perforationValves; + interval->descendantsIncludingThisOfType(perforationValves); + + for (const RimWellPathValve* valve : perforationValves) + { + if (!valve->isChecked()) continue; + + for (size_t nSubValve = 0u; nSubValve < valve->valveLocations().size(); ++nSubValve) + { + double valveMD = valve->valveLocations()[nSubValve]; + + std::pair valveSegment = valve->valveSegments()[nSubValve]; + double overlapStart = std::max(valveSegment.first, segment->startMD()); + double overlapEnd = std::min(valveSegment.second, segment->endMD()); + double overlap = std::max(0.0, overlapEnd - overlapStart); + + if (segment->startMD() <= valveMD && valveMD < segment->endMD()) + { + if (valve->componentType() == RiaDefines::AICD) + { + QString valveLabel = QString("%1 #%2").arg("Combined Valve for segment").arg(nMainSegment + 2); + std::shared_ptr subSegment(new RicMswSubSegment(valveMD, valveMD + 0.1, 0.0, 0.0)); + + superAICD = std::make_shared(valveLabel, valve); + superAICD->addSubSegment(subSegment); + } + else if (valve->componentType() == RiaDefines::ICD) + { + QString valveLabel = QString("%1 #%2").arg("Combined Valve for segment").arg(nMainSegment + 2); + std::shared_ptr subSegment(new RicMswSubSegment(valveMD, valveMD + 0.1, 0.0, 0.0)); + + superICD = std::make_shared(valveLabel, valve); + superICD->addSubSegment(subSegment); + } + else if (valve->componentType() == RiaDefines::ICV) + { + QString valveLabel = QString("ICV %1 at segment #%2").arg(valve->name()).arg(nMainSegment + 2); + std::shared_ptr subSegment(new RicMswSubSegment(valveMD, valveMD + 0.1, 0.0, 0.0)); + + ICV = std::make_shared(valveLabel, valve); + ICV->addSubSegment(subSegment); + ICV->setFlowCoefficient(valve->flowCoefficient()); + double orificeRadius = valve->orificeDiameter(unitSystem) / 2; + ICV->setArea(orificeRadius * orificeRadius * cvf::PI_D); + } + } + else if (overlap > 0.0 && (valve->componentType() == RiaDefines::ICD && !superICD)) + { + QString valveLabel = QString("%1 #%2").arg("Combined Valve for segment").arg(nMainSegment + 2); + std::shared_ptr subSegment( + new RicMswSubSegment(overlapStart, overlapStart + 0.1, 0.0, 0.0)); + superICD = std::make_shared(valveLabel, valve); + superICD->addSubSegment(subSegment); + } + else if (overlap > 0.0 && (valve->componentType() == RiaDefines::AICD && !superAICD)) + { + QString valveLabel = QString("%1 #%2").arg("Combined Valve for segment").arg(nMainSegment + 2); + std::shared_ptr subSegment( + new RicMswSubSegment(overlapStart, overlapStart + 0.1, 0.0, 0.0)); + superAICD = std::make_shared(valveLabel, valve); + superAICD->addSubSegment(subSegment); + } + + if (valve->componentType() == RiaDefines::AICD) + { + totalAICDOverlap += overlap; + } + else if (valve->componentType() == RiaDefines::ICD) + { + totalICDOverlap += overlap; + } + } + } + } + + if (ICV) + { + segment->addCompletion(ICV); + } + else + { + if (totalICDOverlap > 0.0 || totalAICDOverlap > 0.0) + { + if (totalAICDOverlap > totalICDOverlap) + { + segment->addCompletion(superAICD); + } + else + { + segment->addCompletion(superICD); + } + } + } + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicWellPathExportMswCompletionsImpl::assignValveContributionsToSuperICDsOrAICDs( + const std::vector>& mainBoreSegments, + const std::vector& perforationIntervals, + RiaEclipseUnitTools::UnitSystem unitSystem) +{ + ValveContributionMap assignedRegularValves; + for (std::shared_ptr segment : mainBoreSegments) + { + std::shared_ptr superValve; + for (auto completion : segment->completions()) + { + std::shared_ptr valve = std::dynamic_pointer_cast(completion); + if (valve) + { + superValve = valve; + break; + } + } + + std::shared_ptr accumulator; + if (std::dynamic_pointer_cast(superValve)) + { + accumulator = std::make_shared(unitSystem); + } + else if (std::dynamic_pointer_cast(superValve)) + { + accumulator = std::make_shared(unitSystem); + } + + if (!accumulator) continue; + + for (const RimPerforationInterval* interval : perforationIntervals) + { + if (!interval->isChecked()) continue; + + std::vector perforationValves; + interval->descendantsIncludingThisOfType(perforationValves); + + for (const RimWellPathValve* valve : perforationValves) + { + if (!valve->isChecked()) continue; + + for (size_t nSubValve = 0u; nSubValve < valve->valveSegments().size(); ++nSubValve) + { + std::pair valveSegment = valve->valveSegments()[nSubValve]; + double valveSegmentLength = valveSegment.second - valveSegment.first; + double overlapStart = std::max(valveSegment.first, segment->startMD()); + double overlapEnd = std::min(valveSegment.second, segment->endMD()); + double overlap = std::max(0.0, overlapEnd - overlapStart); + + if (overlap > 0.0 && accumulator) + { + if (accumulator->accumulateValveParameters(valve, nSubValve, overlap / valveSegmentLength)) + { + assignedRegularValves[superValve].insert(std::make_pair(valve, nSubValve)); + } + } + } + } + } + if (superValve && accumulator) + { + accumulator->applyToSuperValve(superValve); + } + } + + for (auto regularValvePair : assignedRegularValves) + { + if (!regularValvePair.second.empty()) + { + QStringList valveLabels; + for (std::pair regularValve : regularValvePair.second) + { + QString valveLabel = QString("%1 #%2").arg(regularValve.first->name()).arg(regularValve.second + 1); + valveLabels.push_back(valveLabel); + } + QString valveContribLabel = QString(" with contribution from: %1").arg(valveLabels.join(", ")); + regularValvePair.first->setLabel(regularValvePair.first->label() + valveContribLabel); + } + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicWellPathExportMswCompletionsImpl::moveIntersectionsToICVs( + const std::vector>& mainBoreSegments, + const std::vector& perforationIntervals, + RiaEclipseUnitTools::UnitSystem unitSystem) +{ + std::map> icvCompletionMap; + + for (std::shared_ptr segment : mainBoreSegments) + { + for (auto completion : segment->completions()) + { + std::shared_ptr icv = std::dynamic_pointer_cast(completion); + if (icv) + { + icvCompletionMap[icv->wellPathValve()] = icv; + } + } + } + + for (std::shared_ptr segment : mainBoreSegments) + { + std::vector> perforations; + for (auto completionPtr : segment->completions()) + { + if (completionPtr->completionType() == RigCompletionData::PERFORATION) + { + perforations.push_back(completionPtr); + } + } + + for (const RimPerforationInterval* interval : perforationIntervals) + { + if (!interval->isChecked()) continue; + + std::vector perforationValves; + interval->descendantsIncludingThisOfType(perforationValves); + + for (const RimWellPathValve* valve : perforationValves) + { + if (!valve->isChecked()) continue; + if (valve->componentType() != RiaDefines::ICV) continue; + + auto icvIt = icvCompletionMap.find(valve); + if (icvIt == icvCompletionMap.end()) continue; + + std::shared_ptr icvCompletion = icvIt->second; + CVF_ASSERT(icvCompletion); + + std::pair valveSegment = valve->valveSegments().front(); + double overlapStart = std::max(valveSegment.first, segment->startMD()); + double overlapEnd = std::min(valveSegment.second, segment->endMD()); + double overlap = std::max(0.0, overlapEnd - overlapStart); + + if (overlap > 0.0) + { + CVF_ASSERT(icvCompletion->subSegments().size() == 1u); + for (auto perforationPtr : perforations) + { + for (auto subSegmentPtr : perforationPtr->subSegments()) + { + for (auto intersectionPtr : subSegmentPtr->intersections()) + { + icvCompletion->subSegments()[0]->addIntersection(intersectionPtr); + } + } + segment->removeCompletion(perforationPtr); + } + } + } + } + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicWellPathExportMswCompletionsImpl::moveIntersectionsToSuperICDsOrAICDs(MainBoreSegments mainBoreSegments) +{ + for (auto segmentPtr : mainBoreSegments) + { + std::shared_ptr superValve; + std::vector> perforations; + for (auto completionPtr : segmentPtr->completions()) + { + if (RigCompletionData::isPerforationValve(completionPtr->completionType())) + { + superValve = completionPtr; + } + else + { + CVF_ASSERT(completionPtr->completionType() == RigCompletionData::PERFORATION); + perforations.push_back(completionPtr); + } + } + + if (superValve == nullptr) continue; + + CVF_ASSERT(superValve->subSegments().size() == 1u); + segmentPtr->completions().clear(); + segmentPtr->addCompletion(superValve); + for (auto perforationPtr : perforations) + { + for (auto subSegmentPtr : perforationPtr->subSegments()) + { + for (auto intersectionPtr : subSegmentPtr->intersections()) + { + superValve->subSegments()[0]->addIntersection(intersectionPtr); + } + } + } + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicWellPathExportMswCompletionsImpl::assignFishbonesLateralIntersections(const RimEclipseCase* caseToApply, + const RimFishbonesMultipleSubs* fishbonesSubs, + std::shared_ptr location, + bool* foundSubGridIntersections, + double maxSegmentLength) +{ + CVF_ASSERT(foundSubGridIntersections != nullptr); + + const RigMainGrid* grid = caseToApply->eclipseCaseData()->mainGrid(); + + for (std::shared_ptr completion : location->completions()) + { + if (completion->completionType() != RigCompletionData::FISHBONES) + { + continue; + } + + std::vector> lateralCoordMDPairs = + fishbonesSubs->coordsAndMDForLateral(location->subIndex(), completion->index()); + + if (lateralCoordMDPairs.empty()) + { + continue; + } + + std::vector lateralCoords; + std::vector lateralMDs; + + lateralCoords.reserve(lateralCoordMDPairs.size()); + lateralMDs.reserve(lateralCoordMDPairs.size()); + + for (auto& coordMD : lateralCoordMDPairs) + { + lateralCoords.push_back(coordMD.first); + lateralMDs.push_back(coordMD.second); + } + + std::vector intersections = + RigWellPathIntersectionTools::findCellIntersectionInfosAlongPath( + caseToApply->eclipseCaseData(), lateralCoords, lateralMDs); + + RigWellPath pathGeometry; + pathGeometry.m_wellPathPoints = lateralCoords; + pathGeometry.m_measuredDepths = lateralMDs; + std::vector subSegIntersections = + SubSegmentIntersectionInfo::spiltIntersectionSegmentsToMaxLength(&pathGeometry, intersections, maxSegmentLength); + + double previousExitMD = lateralMDs.front(); + double previousExitTVD = -lateralCoords.front().z(); + + for (const auto& cellIntInfo : subSegIntersections) + { + size_t localGridIdx = 0u; + const RigGridBase* localGrid = grid->gridAndGridLocalIdxFromGlobalCellIdx(cellIntInfo.globCellIndex, &localGridIdx); + QString gridName; + if (localGrid != grid) + { + gridName = QString::fromStdString(localGrid->gridName()); + *foundSubGridIntersections = true; + } + + size_t i = 0u, j = 0u, k = 0u; + localGrid->ijkFromCellIndex(localGridIdx, &i, &j, &k); + std::shared_ptr subSegment( + new RicMswSubSegment(previousExitMD, cellIntInfo.endMD, previousExitTVD, cellIntInfo.endTVD)); + + std::shared_ptr intersection(new RicMswSubSegmentCellIntersection( + gridName, cellIntInfo.globCellIndex, cvf::Vec3st(i, j, k), cellIntInfo.intersectionLengthsInCellCS)); + subSegment->addIntersection(intersection); + completion->addSubSegment(subSegment); + + previousExitMD = cellIntInfo.endMD; + previousExitTVD = cellIntInfo.endTVD; + } + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicWellPathExportMswCompletionsImpl::assignFractureIntersections(const RimEclipseCase* caseToApply, + const RimWellPathFracture* fracture, + const std::vector& completionData, + std::shared_ptr location, + bool* foundSubGridIntersections) +{ + CVF_ASSERT(foundSubGridIntersections != nullptr); + + std::shared_ptr fractureCompletion(new RicMswFracture(fracture->name())); + double position = fracture->fractureMD(); + double width = fracture->fractureTemplate()->computeFractureWidth(fracture); + + if (fracture->fractureTemplate()->orientationType() == RimFractureTemplate::ALONG_WELL_PATH) + { + double perforationLength = fracture->fractureTemplate()->perforationLength(); + position -= 0.5 * perforationLength; + width = perforationLength; + } + + std::shared_ptr subSegment(new RicMswSubSegment(position, position + width, 0.0, 0.0)); + for (const RigCompletionData& compIntersection : completionData) + { + const RigCompletionDataGridCell& cell = compIntersection.completionDataGridCell(); + cvf::Vec3st localIJK(cell.localCellIndexI(), cell.localCellIndexJ(), cell.localCellIndexK()); + + std::shared_ptr intersection( + new RicMswSubSegmentCellIntersection(cell.lgrName(), cell.globalCellIndex(), localIJK, cvf::Vec3d::ZERO)); + subSegment->addIntersection(intersection); + } + fractureCompletion->addSubSegment(subSegment); + location->addCompletion(fractureCompletion); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector + RicWellPathExportMswCompletionsImpl::generatePerforationIntersections(const RimWellPath* wellPath, + const RimPerforationInterval* perforationInterval, + int timeStep, + RimEclipseCase* eclipseCase) +{ + std::vector completionData; + const RigActiveCellInfo* activeCellInfo = eclipseCase->eclipseCaseData()->activeCellInfo(RiaDefines::MATRIX_MODEL); + + if (wellPath->perforationIntervalCollection()->isChecked() && perforationInterval->isChecked() && + perforationInterval->isActiveOnDate(eclipseCase->timeStepDates()[timeStep])) + { + std::pair, std::vector> perforationPointsAndMD = + wellPath->wellPathGeometry()->clippedPointSubset(perforationInterval->startMD(), perforationInterval->endMD()); + + std::vector intersectedCells = + RigWellPathIntersectionTools::findCellIntersectionInfosAlongPath( + eclipseCase->eclipseCaseData(), perforationPointsAndMD.first, perforationPointsAndMD.second); + + for (auto& cell : intersectedCells) + { + bool cellIsActive = activeCellInfo->isActive(cell.globCellIndex); + if (!cellIsActive) continue; + + RigCompletionData completion(wellPath->completions()->wellNameForExport(), + RigCompletionDataGridCell(cell.globCellIndex, eclipseCase->mainGrid()), + cell.startMD); + + completion.setSourcePdmObject(perforationInterval); + completionData.push_back(completion); + } + } + + return completionData; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicWellPathExportMswCompletionsImpl::assignPerforationIntersections(const std::vector& completionData, + std::shared_ptr perforationCompletion, + const SubSegmentIntersectionInfo& cellIntInfo, + double overlapStart, + double overlapEnd, + bool* foundSubGridIntersections) +{ + size_t currCellId = cellIntInfo.globCellIndex; + + std::shared_ptr subSegment( + new RicMswSubSegment(overlapStart, overlapEnd, cellIntInfo.startTVD, cellIntInfo.endTVD)); + for (const RigCompletionData& compIntersection : completionData) + { + const RigCompletionDataGridCell& cell = compIntersection.completionDataGridCell(); + if (!cell.isMainGridCell()) + { + *foundSubGridIntersections = true; + } + + if (cell.globalCellIndex() != currCellId) continue; + + cvf::Vec3st localIJK(cell.localCellIndexI(), cell.localCellIndexJ(), cell.localCellIndexK()); + + std::shared_ptr intersection(new RicMswSubSegmentCellIntersection( + cell.lgrName(), cell.globalCellIndex(), localIJK, cellIntInfo.intersectionLengthsInCellCS)); + subSegment->addIntersection(intersection); + } + perforationCompletion->addSubSegment(subSegment); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicWellPathExportMswCompletionsImpl::assignBranchAndSegmentNumbers(const RimEclipseCase* caseToApply, + std::shared_ptr location, + int* branchNum, + int* segmentNum) +{ + int icdSegmentNumber = cvf::UNDEFINED_INT; + for (std::shared_ptr completion : location->completions()) + { + if (completion->completionType() == RigCompletionData::PERFORATION) + { + completion->setBranchNumber(1); + } + else if (completion->completionType() != RigCompletionData::FISHBONES_ICD) + { + ++(*branchNum); + completion->setBranchNumber(*branchNum); + } + + int attachedSegmentNumber = location->segmentNumber(); + if (icdSegmentNumber != cvf::UNDEFINED_INT) + { + attachedSegmentNumber = icdSegmentNumber; + } + + for (auto subSegment : completion->subSegments()) + { + if (completion->completionType() == RigCompletionData::FISHBONES_ICD) + { + subSegment->setSegmentNumber(location->segmentNumber() + 1); + icdSegmentNumber = subSegment->segmentNumber(); + } + else if (completion->completionType() != RigCompletionData::PERFORATION) + { + ++(*segmentNum); + subSegment->setSegmentNumber(*segmentNum); + } + subSegment->setAttachedSegmentNumber(attachedSegmentNumber); + attachedSegmentNumber = *segmentNum; + } + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicWellPathExportMswCompletionsImpl::assignBranchAndSegmentNumbers(const RimEclipseCase* caseToApply, + RicMswExportInfo* exportInfo) +{ + int segmentNumber = 1; + int branchNumber = 1; + + // First loop over the locations so that each segment on the main stem is an incremental number + for (auto location : exportInfo->wellSegmentLocations()) + { + location->setSegmentNumber(++segmentNumber); + for (auto completion : location->completions()) + { + if (completion->completionType() == RigCompletionData::FISHBONES_ICD) + { + ++segmentNumber; // Skip a segment number because we need one for the ICD + if (completion->completionType() == RigCompletionData::FISHBONES_ICD) + { + completion->setBranchNumber(++branchNumber); + } + } + } + } + + // Then assign branch and segment numbers to each completion sub segment + for (auto location : exportInfo->wellSegmentLocations()) + { + assignBranchAndSegmentNumbers(caseToApply, location, &branchNumber, &segmentNumber); + } +} + +SubSegmentIntersectionInfo::SubSegmentIntersectionInfo(size_t globCellIndex, + double startTVD, + double endTVD, + double startMD, + double endMD, + cvf::Vec3d lengthsInCell) + : globCellIndex(globCellIndex) + , startTVD(startTVD) + , endTVD(endTVD) + , startMD(startMD) + , endMD(endMD) + , intersectionLengthsInCellCS(lengthsInCell) +{ +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector SubSegmentIntersectionInfo::spiltIntersectionSegmentsToMaxLength( + const RigWellPath* pathGeometry, + const std::vector& intersections, + double maxSegmentLength) +{ + std::vector out; + + if (!pathGeometry) return out; + + for (const auto& intersection : intersections) + { + double segLen = intersection.endMD - intersection.startMD; + int segCount = (int)std::trunc(segLen / maxSegmentLength) + 1; + + // Calc effective max length + double effectiveMaxSegLen = segLen / segCount; + + if (segCount == 1) + { + out.emplace_back(intersection.globCellIndex, + -intersection.startPoint.z(), + -intersection.endPoint.z(), + intersection.startMD, + intersection.endMD, + intersection.intersectionLengthsInCellCS); + } + else + { + double currStartMd = intersection.startMD; + double currEndMd = currStartMd; + double lastTvd = -intersection.startPoint.z(); + + for (int segIndex = 0; segIndex < segCount; segIndex++) + { + bool lasti = segIndex == (segCount - 1); + currEndMd = currStartMd + effectiveMaxSegLen; + + cvf::Vec3d segEndPoint = pathGeometry->interpolatedPointAlongWellPath(currEndMd); + out.emplace_back(intersection.globCellIndex, + lastTvd, + lasti ? -intersection.endPoint.z() : -segEndPoint.z(), + currStartMd, + lasti ? intersection.endMD : currEndMd, + intersection.intersectionLengthsInCellCS / segCount); + + currStartMd = currEndMd; + lastTvd = -segEndPoint.z(); + } + } + } + return out; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +int SubSegmentIntersectionInfo::numberOfSplittedSegments(double startMd, double endMd, double maxSegmentLength) +{ + return (int)(std::trunc((endMd - startMd) / maxSegmentLength) + 1); +} diff --git a/ApplicationCode/Commands/CompletionExportCommands/RicWellPathExportMswCompletionsImpl.h b/ApplicationCode/Commands/CompletionExportCommands/RicWellPathExportMswCompletionsImpl.h new file mode 100644 index 0000000000..437e3a7efe --- /dev/null +++ b/ApplicationCode/Commands/CompletionExportCommands/RicWellPathExportMswCompletionsImpl.h @@ -0,0 +1,154 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2018 Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// +#pragma once + +#include "RicMswExportInfo.h" +#include "RigCompletionData.h" + +class RicExportCompletionDataSettingsUi; +class RifEclipseDataTableFormatter; +class RimEclipseCase; +class RimFishbonesMultipleSubs; +class RimPerforationInterval; +class RimWellPath; +class RimWellPathValve; +class RimWellPathFracture; +class SubSegmentIntersectionInfo; + +class QFile; + +class RicWellPathExportMswCompletionsImpl +{ +public: + static void exportWellSegmentsForAllCompletions(const RicExportCompletionDataSettingsUi& exportSettings, + const std::vector& wellPaths); + + static void exportWellSegmentsForFractures(RimEclipseCase* eclipseCase, + std::shared_ptr exportFile, + const RimWellPath* wellPath, + const std::vector& fractures); + + static void exportWellSegmentsForFishbones(RimEclipseCase* eclipseCase, + std::shared_ptr exportFile, + const RimWellPath* wellPath, + const std::vector& fishbonesSubs); + + static void exportWellSegmentsForPerforations(RimEclipseCase* eclipseCase, + std::shared_ptr exportFile, + const RimWellPath* wellPath, + int timeStep, + const std::vector& perforationIntervals); + + static RicMswExportInfo generateFishbonesMswExportInfo(const RimEclipseCase* caseToApply, + const RimWellPath* wellPath, + bool enableSegmentSplitting); + +private: + static RicMswExportInfo generateFishbonesMswExportInfo(const RimEclipseCase* caseToApply, + const RimWellPath* wellPath, + const std::vector& fishbonesSubs, + bool enableSegmentSplitting); + + static RicMswExportInfo generateFracturesMswExportInfo(RimEclipseCase* caseToApply, const RimWellPath* wellPath); + + static RicMswExportInfo generateFracturesMswExportInfo(RimEclipseCase* caseToApply, + const RimWellPath* wellPath, + const std::vector& fractures); + + static RicMswExportInfo + generatePerforationsMswExportInfo(RimEclipseCase* eclipseCase, + const RimWellPath* wellPath, + int timeStep, + const std::vector& perforationIntervals); + + static void generateWelsegsTable(RifEclipseDataTableFormatter& formatter, const RicMswExportInfo& exportInfo); + + static void generateWelsegsSegments(RifEclipseDataTableFormatter& formatter, + const RicMswExportInfo& exportInfo, + const std::set& exportCompletionTypes); + static void generateWelsegsCompletionCommentHeader(RifEclipseDataTableFormatter& formatter, + RigCompletionData::CompletionType completionType); + static void generateCompsegTables(RifEclipseDataTableFormatter& formatter, const RicMswExportInfo& exportInfo); + static void generateCompsegTable(RifEclipseDataTableFormatter& formatter, + const RicMswExportInfo& exportInfo, + bool exportSubGridIntersections, + const std::set& exportCompletionTypes); + static void generateCompsegHeader(RifEclipseDataTableFormatter& formatter, + const RicMswExportInfo& exportInfo, + RigCompletionData::CompletionType completionType, + bool exportSubGridIntersections); + static void generateWsegvalvTable(RifEclipseDataTableFormatter& formatter, const RicMswExportInfo& exportInfo); + static void generateWsegAicdTable(RifEclipseDataTableFormatter& formatter, const RicMswExportInfo& exportInfo); + +private: + typedef std::vector> MainBoreSegments; + typedef std::map, std::set>> + ValveContributionMap; + + static MainBoreSegments createMainBoreSegmentsForPerforations(const std::vector& subSegIntersections, + const std::vector& perforationIntervals, + const RimWellPath* wellPath, + int timeStep, + RimEclipseCase* eclipseCase, + bool* foundSubGridIntersections); + + static void createValveCompletions(std::vector>& mainBoreSegments, + const std::vector& perforationIntervals, + RiaEclipseUnitTools::UnitSystem unitSystem); + + static void assignValveContributionsToSuperICDsOrAICDs(const std::vector>& mainBoreSegments, + const std::vector& perforationIntervals, + RiaEclipseUnitTools::UnitSystem unitSystem); + + static void moveIntersectionsToICVs(const std::vector>& mainBoreSegments, + const std::vector& perforationIntervals, + RiaEclipseUnitTools::UnitSystem unitSystem); + + static void moveIntersectionsToSuperICDsOrAICDs(MainBoreSegments mainBoreSegments); + + static void assignFishbonesLateralIntersections(const RimEclipseCase* caseToApply, + const RimFishbonesMultipleSubs* fishbonesSubs, + std::shared_ptr location, + bool* foundSubGridIntersections, + double maxSegmentLength); + + static void assignFractureIntersections(const RimEclipseCase* caseToApply, + const RimWellPathFracture* fracture, + const std::vector& completionData, + std::shared_ptr location, + bool* foundSubGridIntersections); + + static std::vector generatePerforationIntersections(const RimWellPath* wellPath, + const RimPerforationInterval* perforationInterval, + int timeStep, + RimEclipseCase* eclipseCase); + + static void assignPerforationIntersections(const std::vector& completionData, + std::shared_ptr perforationCompletion, + const SubSegmentIntersectionInfo& cellIntInfo, + double overlapStart, + double overlapEnd, + bool* foundSubGridIntersections); + + static void assignBranchAndSegmentNumbers(const RimEclipseCase* caseToApply, + std::shared_ptr location, + int* branchNum, + int* segmentNum); + static void assignBranchAndSegmentNumbers(const RimEclipseCase* caseToApply, RicMswExportInfo* exportInfo); + +}; \ No newline at end of file diff --git a/ApplicationCode/Commands/CompletionExportCommands/RicWellPathFractureReportItem.cpp b/ApplicationCode/Commands/CompletionExportCommands/RicWellPathFractureReportItem.cpp index 70022f4a93..1df5ff4c98 100644 --- a/ApplicationCode/Commands/CompletionExportCommands/RicWellPathFractureReportItem.cpp +++ b/ApplicationCode/Commands/CompletionExportCommands/RicWellPathFractureReportItem.cpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018 Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by diff --git a/ApplicationCode/Commands/CompletionExportCommands/RicWellPathFractureReportItem.h b/ApplicationCode/Commands/CompletionExportCommands/RicWellPathFractureReportItem.h index e9a6dc6910..97ecc4b783 100644 --- a/ApplicationCode/Commands/CompletionExportCommands/RicWellPathFractureReportItem.h +++ b/ApplicationCode/Commands/CompletionExportCommands/RicWellPathFractureReportItem.h @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018 Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -28,7 +28,7 @@ class RicWellPathFractureReportItem { public: - RicWellPathFractureReportItem(const QString& wellPathName, const QString& fractureName, const QString& fractureTemplateName, double measuredDepth); + RicWellPathFractureReportItem(const QString& wellPathNameForExport, const QString& fractureName, const QString& fractureTemplateName, double measuredDepth); void setData(double trans, size_t connCount, double area); void setWidthAndConductivity(double width, double conductivity); diff --git a/ApplicationCode/Commands/CompletionExportCommands/RicWellPathFractureTextReportFeatureImpl.cpp b/ApplicationCode/Commands/CompletionExportCommands/RicWellPathFractureTextReportFeatureImpl.cpp index a9b38bce1b..e6fbd2a489 100644 --- a/ApplicationCode/Commands/CompletionExportCommands/RicWellPathFractureTextReportFeatureImpl.cpp +++ b/ApplicationCode/Commands/CompletionExportCommands/RicWellPathFractureTextReportFeatureImpl.cpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018 Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by diff --git a/ApplicationCode/Commands/CompletionExportCommands/RicWellPathFractureTextReportFeatureImpl.h b/ApplicationCode/Commands/CompletionExportCommands/RicWellPathFractureTextReportFeatureImpl.h index 6b768e3027..affd9b41a5 100644 --- a/ApplicationCode/Commands/CompletionExportCommands/RicWellPathFractureTextReportFeatureImpl.h +++ b/ApplicationCode/Commands/CompletionExportCommands/RicWellPathFractureTextReportFeatureImpl.h @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018 Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by diff --git a/ApplicationCode/Commands/CrossSectionCommands/RicAppendIntersectionFeature.cpp b/ApplicationCode/Commands/CrossSectionCommands/RicAppendIntersectionFeature.cpp index 9d6f30a044..a8bf8bbc1e 100644 --- a/ApplicationCode/Commands/CrossSectionCommands/RicAppendIntersectionFeature.cpp +++ b/ApplicationCode/Commands/CrossSectionCommands/RicAppendIntersectionFeature.cpp @@ -107,9 +107,6 @@ void RicAppendIntersectionFeatureCmd::redo() RimGridView* view = nullptr; m_intersectionCollection->firstAncestorOrThisOfTypeAsserted(view); - //Enable display of grid cells, to be able to show generated property filter - view->showGridCells(false); - RimGeoMechView* geoMechView = nullptr; geoMechView = dynamic_cast(view); if (geoMechView) diff --git a/ApplicationCode/Commands/CrossSectionCommands/RicNewAzimuthDipIntersectionFeature.cpp b/ApplicationCode/Commands/CrossSectionCommands/RicNewAzimuthDipIntersectionFeature.cpp index 946c26fdae..4e8013eb6e 100644 --- a/ApplicationCode/Commands/CrossSectionCommands/RicNewAzimuthDipIntersectionFeature.cpp +++ b/ApplicationCode/Commands/CrossSectionCommands/RicNewAzimuthDipIntersectionFeature.cpp @@ -26,7 +26,7 @@ #include "RimGridView.h" #include "Riu3DMainWindowTools.h" -#include "RiuSelectionManager.h" +#include "Riu3dSelectionManager.h" #include "RiuViewer.h" #include "cafCmdExecCommandManager.h" @@ -124,7 +124,7 @@ void RicNewAzimuthDipIntersectionFeatureCmd::redo() m_intersectionCollection->appendIntersectionAndUpdate(intersection); - RiuSelectionManager::instance()->deleteAllItems(); + Riu3dSelectionManager::instance()->deleteAllItems(); Riu3DMainWindowTools::selectAsCurrentItem(intersection); } diff --git a/ApplicationCode/Commands/CrossSectionCommands/RicNewAzimuthDipIntersectionFeature.h b/ApplicationCode/Commands/CrossSectionCommands/RicNewAzimuthDipIntersectionFeature.h index 78d380cc4c..4b3a08ad57 100644 --- a/ApplicationCode/Commands/CrossSectionCommands/RicNewAzimuthDipIntersectionFeature.h +++ b/ApplicationCode/Commands/CrossSectionCommands/RicNewAzimuthDipIntersectionFeature.h @@ -18,9 +18,8 @@ #pragma once -#include "RicPickEventHandler.h" - #include "cafCmdExecuteCommand.h" +#include "cafCmdFeature.h" #include "cafPdmPointer.h" class RimIntersectionCollection; diff --git a/ApplicationCode/Commands/CrossSectionCommands/RicNewPolylineIntersectionFeature.cpp b/ApplicationCode/Commands/CrossSectionCommands/RicNewPolylineIntersectionFeature.cpp index 35c6ebfa72..1a61e94d53 100644 --- a/ApplicationCode/Commands/CrossSectionCommands/RicNewPolylineIntersectionFeature.cpp +++ b/ApplicationCode/Commands/CrossSectionCommands/RicNewPolylineIntersectionFeature.cpp @@ -27,7 +27,7 @@ #include "RimGridView.h" #include "Riu3DMainWindowTools.h" -#include "RiuSelectionManager.h" +#include "Riu3dSelectionManager.h" #include "RiuViewer.h" #include "cafCmdExecCommandManager.h" @@ -114,7 +114,7 @@ void RicNewPolylineIntersectionFeatureCmd::redo() m_intersectionCollection->appendIntersectionAndUpdate(intersection); - RiuSelectionManager::instance()->deleteAllItems(); + Riu3dSelectionManager::instance()->deleteAllItems(); Riu3DMainWindowTools::selectAsCurrentItem(intersection); } diff --git a/ApplicationCode/Commands/CrossSectionCommands/RicNewPolylineIntersectionFeature.h b/ApplicationCode/Commands/CrossSectionCommands/RicNewPolylineIntersectionFeature.h index 4a6591e579..9f80c0d7e4 100644 --- a/ApplicationCode/Commands/CrossSectionCommands/RicNewPolylineIntersectionFeature.h +++ b/ApplicationCode/Commands/CrossSectionCommands/RicNewPolylineIntersectionFeature.h @@ -19,9 +19,8 @@ #pragma once -#include "RicPickEventHandler.h" - #include "cafCmdExecuteCommand.h" +#include "cafCmdFeature.h" #include "cafPdmPointer.h" class RimIntersectionCollection; diff --git a/ApplicationCode/Commands/CrossSectionCommands/RicNewWellPathIntersectionFeature.cpp b/ApplicationCode/Commands/CrossSectionCommands/RicNewWellPathIntersectionFeature.cpp index b885afe50b..e429a0cd1c 100644 --- a/ApplicationCode/Commands/CrossSectionCommands/RicNewWellPathIntersectionFeature.cpp +++ b/ApplicationCode/Commands/CrossSectionCommands/RicNewWellPathIntersectionFeature.cpp @@ -75,7 +75,7 @@ void RicNewWellPathIntersectionFeature::onActionTriggered(bool isChecked) void RicNewWellPathIntersectionFeature::setupActionLook(QAction* actionToSetup) { actionToSetup->setIcon(QIcon(":/CrossSection16x16.png")); - actionToSetup->setText("New Intersection"); + actionToSetup->setText("Create Intersection"); } //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/Commands/EclipseCommands/RicApplyPropertyFilterAsCellResultFeature.cpp b/ApplicationCode/Commands/EclipseCommands/RicApplyPropertyFilterAsCellResultFeature.cpp index a9ab8dff7c..94dfd34763 100644 --- a/ApplicationCode/Commands/EclipseCommands/RicApplyPropertyFilterAsCellResultFeature.cpp +++ b/ApplicationCode/Commands/EclipseCommands/RicApplyPropertyFilterAsCellResultFeature.cpp @@ -18,6 +18,8 @@ #include "RicApplyPropertyFilterAsCellResultFeature.h" +#include "RigFemResultAddress.h" + #include "RimEclipseCellColors.h" #include "RimEclipsePropertyFilter.h" #include "RimEclipseView.h" diff --git a/ApplicationCode/Commands/EclipseCommands/RicEclipsePropertyFilterFeatureImpl.cpp b/ApplicationCode/Commands/EclipseCommands/RicEclipsePropertyFilterFeatureImpl.cpp index 1a63a39bc9..9c6a3b5ebd 100644 --- a/ApplicationCode/Commands/EclipseCommands/RicEclipsePropertyFilterFeatureImpl.cpp +++ b/ApplicationCode/Commands/EclipseCommands/RicEclipsePropertyFilterFeatureImpl.cpp @@ -118,10 +118,10 @@ void RicEclipsePropertyFilterFeatureImpl::setDefaults(RimEclipsePropertyFilter* RimEclipseView* reservoirView = nullptr; propertyFilter->firstAncestorOrThisOfTypeAsserted(reservoirView); - propertyFilter->resultDefinition->setEclipseCase(reservoirView->eclipseCase()); - propertyFilter->resultDefinition->simpleCopy(reservoirView->cellResult()); + propertyFilter->resultDefinition()->setEclipseCase(reservoirView->eclipseCase()); + propertyFilter->resultDefinition()->simpleCopy(reservoirView->cellResult()); - propertyFilter->resultDefinition->loadResult(); + propertyFilter->resultDefinition()->loadResult(); propertyFilter->setToDefaultValues(); propertyFilter->updateFilterName(); propertyFilter->m_useCategorySelection = true; diff --git a/ApplicationCode/Commands/EclipseCommands/RicImportEclipseCaseFeature.cpp b/ApplicationCode/Commands/EclipseCommands/RicImportEclipseCaseFeature.cpp index 5a21716256..6e38739c41 100644 --- a/ApplicationCode/Commands/EclipseCommands/RicImportEclipseCaseFeature.cpp +++ b/ApplicationCode/Commands/EclipseCommands/RicImportEclipseCaseFeature.cpp @@ -19,8 +19,6 @@ #include "RicImportEclipseCaseFeature.h" -#include "RiaImportEclipseCaseTools.h" - #include "RiaApplication.h" #include "RimEclipseCaseCollection.h" @@ -51,16 +49,13 @@ void RicImportEclipseCaseFeature::onActionTriggered(bool isChecked) QString defaultDir = app->lastUsedDialogDirectory("BINARY_GRID"); QStringList fileNames = QFileDialog::getOpenFileNames(Riu3DMainWindowTools::mainWindowWidget(), "Import Eclipse File", defaultDir, "Eclipse Grid Files (*.GRID *.EGRID)"); - if (fileNames.size()) defaultDir = QFileInfo(fileNames.last()).absolutePath(); - app->setLastUsedDialogDirectory("BINARY_GRID", defaultDir); - QStringList newCaseFiles; - RiaImportEclipseCaseTools::openEclipseCasesFromFile(fileNames, &newCaseFiles); + if (fileNames.isEmpty()) return; + + defaultDir = QFileInfo(fileNames.last()).absolutePath(); + app->setLastUsedDialogDirectory("BINARY_GRID", defaultDir); - for (const auto newCaseFile : newCaseFiles) - { - RiaApplication::instance()->addToRecentFiles(newCaseFile); - } + openEclipseCaseFromFileNames(fileNames); } //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/Commands/EclipseCommands/RicImportEclipseCaseFeature.h b/ApplicationCode/Commands/EclipseCommands/RicImportEclipseCaseFeature.h index 3eed62c52c..e4674333c0 100644 --- a/ApplicationCode/Commands/EclipseCommands/RicImportEclipseCaseFeature.h +++ b/ApplicationCode/Commands/EclipseCommands/RicImportEclipseCaseFeature.h @@ -19,6 +19,8 @@ #pragma once +#include "RicImportGeneralDataFeature.h" + #include "cafCmdFeature.h" #include @@ -26,7 +28,7 @@ //================================================================================================== /// //================================================================================================== -class RicImportEclipseCaseFeature : public caf::CmdFeature +class RicImportEclipseCaseFeature : public RicImportGeneralDataFeature { CAF_CMD_HEADER_INIT; diff --git a/ApplicationCode/Commands/EclipseCommands/RicImportInputEclipseCaseFeature.cpp b/ApplicationCode/Commands/EclipseCommands/RicImportInputEclipseCaseFeature.cpp index f7e16bc27c..a1d245d721 100644 --- a/ApplicationCode/Commands/EclipseCommands/RicImportInputEclipseCaseFeature.cpp +++ b/ApplicationCode/Commands/EclipseCommands/RicImportInputEclipseCaseFeature.cpp @@ -39,53 +39,6 @@ CAF_CMD_SOURCE_INIT(RicImportInputEclipseCaseFeature, "RicImportInputEclipseCaseFeature"); -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -bool RicImportInputEclipseCaseFeature::openInputEclipseCaseFromFileNames(const QStringList& fileNames) -{ - RimEclipseInputCase* rimInputReservoir = new RimEclipseInputCase(); - - RiaApplication* app = RiaApplication::instance(); - RimProject* project = app->project(); - - project->assignCaseIdToCase(rimInputReservoir); - - bool gridImportSuccess = rimInputReservoir->openDataFileSet(fileNames); - if (!gridImportSuccess) - { - RiaLogging::error("Failed to import grid"); - return false; - } - - RimEclipseCaseCollection* analysisModels = project->activeOilField() ? project->activeOilField()->analysisModels() : nullptr; - if (analysisModels == nullptr) return false; - - analysisModels->cases.push_back(rimInputReservoir); - - RimEclipseView* riv = rimInputReservoir->createAndAddReservoirView(); - - riv->cellResult()->setResultType(RiaDefines::INPUT_PROPERTY); - - riv->loadDataAndUpdate(); - - if (!riv->cellResult()->hasResult()) - { - riv->cellResult()->setResultVariable(RiaDefines::undefinedResultName()); - } - - analysisModels->updateConnectedEditors(); - - Riu3DMainWindowTools::selectAsCurrentItem(riv->cellResult()); - - if (fileNames.size() == 1) - { - app->addToRecentFiles(fileNames[0]); - } - - return true; -} - //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -99,16 +52,7 @@ bool RicImportInputEclipseCaseFeature::isCommandEnabled() //-------------------------------------------------------------------------------------------------- void RicImportInputEclipseCaseFeature::onActionTriggered(bool isChecked) { - RiaApplication* app = RiaApplication::instance(); - QString defaultDir = app->lastUsedDialogDirectory("INPUT_FILES"); - QStringList fileNames = QFileDialog::getOpenFileNames(Riu3DMainWindowTools::mainWindowWidget(), "Import Eclipse Input Files", defaultDir, "Eclipse Input Files and Input Properties Eclipse Input Files (*.GRDECL);;All Files (*.*)"); - - if (fileNames.isEmpty()) return; - - // Remember the path to next time - app->setLastUsedDialogDirectory("INPUT_FILES", QFileInfo(fileNames.last()).absolutePath()); - - RicImportInputEclipseCaseFeature::openInputEclipseCaseFromFileNames(fileNames); + RicImportGeneralDataFeature::openFileDialog(RiaDefines::ECLIPSE_INPUT_FILE); } //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/Commands/EclipseCommands/RicImportInputEclipseCaseFeature.h b/ApplicationCode/Commands/EclipseCommands/RicImportInputEclipseCaseFeature.h index 8fd8f46cff..710fafb0d1 100644 --- a/ApplicationCode/Commands/EclipseCommands/RicImportInputEclipseCaseFeature.h +++ b/ApplicationCode/Commands/EclipseCommands/RicImportInputEclipseCaseFeature.h @@ -19,6 +19,8 @@ #pragma once +#include "RicImportGeneralDataFeature.h" + #include "cafCmdFeature.h" #include @@ -28,14 +30,10 @@ class QStringList; //================================================================================================== /// //================================================================================================== -class RicImportInputEclipseCaseFeature : public caf::CmdFeature +class RicImportInputEclipseCaseFeature : public RicImportGeneralDataFeature { CAF_CMD_HEADER_INIT; -public: - static bool openInputEclipseCaseFromFileNames(const QStringList& fileNames); - - protected: // Overrides bool isCommandEnabled() override; diff --git a/ApplicationCode/Commands/ExportCommands/CMakeLists_files.cmake b/ApplicationCode/Commands/ExportCommands/CMakeLists_files.cmake index b044e3b81c..19dac388e3 100644 --- a/ApplicationCode/Commands/ExportCommands/CMakeLists_files.cmake +++ b/ApplicationCode/Commands/ExportCommands/CMakeLists_files.cmake @@ -3,7 +3,7 @@ ${CMAKE_CURRENT_LIST_DIR}/RicCellRangeUi.h ${CMAKE_CURRENT_LIST_DIR}/RicExportCarfin.h ${CMAKE_CURRENT_LIST_DIR}/RicExportCarfinUi.h ${CMAKE_CURRENT_LIST_DIR}/RicExportFaultsFeature.h -${CMAKE_CURRENT_LIST_DIR}/RicExportMultipleSnapshotsFeature.h +${CMAKE_CURRENT_LIST_DIR}/RicAdvancedSnapshotExportFeature.h ${CMAKE_CURRENT_LIST_DIR}/RicExportToLasFileFeature.h ${CMAKE_CURRENT_LIST_DIR}/RicExportToLasFileResampleUi.h ${CMAKE_CURRENT_LIST_DIR}/RicSaveEclipseInputPropertyFeature.h @@ -11,6 +11,8 @@ ${CMAKE_CURRENT_LIST_DIR}/RicSaveEclipseInputVisibleCellsFeature.h ${CMAKE_CURRENT_LIST_DIR}/RicSaveEclipseInputVisibleCellsUi.h ${CMAKE_CURRENT_LIST_DIR}/RicSaveEclipseResultAsInputPropertyExec.h ${CMAKE_CURRENT_LIST_DIR}/RicSaveEclipseResultAsInputPropertyFeature.h +${CMAKE_CURRENT_LIST_DIR}/RicExportEclipseSectorModelFeature.h +${CMAKE_CURRENT_LIST_DIR}/RicExportEclipseSectorModelUi.h ${CMAKE_CURRENT_LIST_DIR}/RicSnapshotAllPlotsToFileFeature.h ${CMAKE_CURRENT_LIST_DIR}/RicSnapshotAllViewsToFileFeature.h ${CMAKE_CURRENT_LIST_DIR}/RicSnapshotFilenameGenerator.h @@ -30,12 +32,14 @@ ${CMAKE_CURRENT_LIST_DIR}/RicCellRangeUi.cpp ${CMAKE_CURRENT_LIST_DIR}/RicExportCarfin.cpp ${CMAKE_CURRENT_LIST_DIR}/RicExportCarfinUi.cpp ${CMAKE_CURRENT_LIST_DIR}/RicExportFaultsFeature.cpp -${CMAKE_CURRENT_LIST_DIR}/RicExportMultipleSnapshotsFeature.cpp +${CMAKE_CURRENT_LIST_DIR}/RicAdvancedSnapshotExportFeature.cpp ${CMAKE_CURRENT_LIST_DIR}/RicExportToLasFileFeature.cpp ${CMAKE_CURRENT_LIST_DIR}/RicExportToLasFileResampleUi.cpp ${CMAKE_CURRENT_LIST_DIR}/RicSaveEclipseInputPropertyFeature.cpp ${CMAKE_CURRENT_LIST_DIR}/RicSaveEclipseInputVisibleCellsFeature.cpp ${CMAKE_CURRENT_LIST_DIR}/RicSaveEclipseInputVisibleCellsUi.cpp +${CMAKE_CURRENT_LIST_DIR}/RicExportEclipseSectorModelFeature.cpp +${CMAKE_CURRENT_LIST_DIR}/RicExportEclipseSectorModelUi.cpp ${CMAKE_CURRENT_LIST_DIR}/RicSaveEclipseResultAsInputPropertyExec.cpp ${CMAKE_CURRENT_LIST_DIR}/RicSaveEclipseResultAsInputPropertyFeature.cpp ${CMAKE_CURRENT_LIST_DIR}/RicSnapshotAllPlotsToFileFeature.cpp diff --git a/ApplicationCode/Commands/ExportCommands/RicAdvancedSnapshotExportFeature.cpp b/ApplicationCode/Commands/ExportCommands/RicAdvancedSnapshotExportFeature.cpp new file mode 100644 index 0000000000..358432e5f4 --- /dev/null +++ b/ApplicationCode/Commands/ExportCommands/RicAdvancedSnapshotExportFeature.cpp @@ -0,0 +1,327 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2016- Statoil ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "RicAdvancedSnapshotExportFeature.h" + +#include "RiaApplication.h" +#include "RiaViewRedrawScheduler.h" + +#include "RicSnapshotViewToFileFeature.h" + +#include "RigFemResultPosEnum.h" + +#include "RimCase.h" +#include "RimCellRangeFilter.h" +#include "RimCellRangeFilterCollection.h" +#include "RimEclipseCase.h" +#include "RimEclipseCellColors.h" +#include "RimEclipseView.h" +#include "RimGeoMechCase.h" +#include "RimGeoMechCellColors.h" +#include "RimGeoMechResultDefinition.h" +#include "RimGeoMechView.h" +#include "RimAdvancedSnapshotExportDefinition.h" +#include "RimProject.h" +#include "Rim3dView.h" + +#include "RiuAdvancedSnapshotExportWidget.h" +#include "RiuViewer.h" + +#include "cafCmdExecCommandManager.h" +#include "cafFrameAnimationControl.h" +#include "cafUtils.h" + +#include +#include +#include + + +CAF_CMD_SOURCE_INIT(RicAdvancedSnapshotExportFeature, "RicAdvancedSnapshotExportFeature"); + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RicAdvancedSnapshotExportFeature::isCommandEnabled() +{ + RimProject* proj = RiaApplication::instance()->project(); + + return proj; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicAdvancedSnapshotExportFeature::onActionTriggered(bool isChecked) +{ + this->disableModelChangeContribution(); + + RimProject* proj = RiaApplication::instance()->project(); + + if (proj) + { + // Enable the command system to be able to assign a value to multiple fields at the same time + caf::CmdExecCommandSystemActivator activator; + + RiuAdvancedSnapshotExportWidget dlg(nullptr, proj); + + Rim3dView* activeView = RiaApplication::instance()->activeReservoirView(); + if (activeView && proj->multiSnapshotDefinitions.size() == 0) + { + dlg.addSnapshotItemFromActiveView(); + dlg.addEmptySnapshotItems(4); + } + + dlg.exec(); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicAdvancedSnapshotExportFeature::setupActionLook(QAction* actionToSetup) +{ + actionToSetup->setText("Advanced Snapshot Export ..."); + actionToSetup->setIcon(QIcon(":/SnapShotSaveViews.png")); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicAdvancedSnapshotExportFeature::exportMultipleSnapshots(const QString& folder, RimProject* project) +{ + if (!project) return; + + QDir snapshotPath(folder); + if (!snapshotPath.exists()) + { + if (!snapshotPath.mkpath(".")) return; + } + + for (RimAdvancedSnapshotExportDefinition* msd : project->multiSnapshotDefinitions()) + { + if (!msd->isActive()) continue; + + Rim3dView* sourceView = msd->view(); + if (!sourceView) continue; + if (!sourceView->viewer()) continue; + + int initialFramIndex = sourceView->viewer()->currentFrameIndex(); + + //exportViewVariations(sourceView, msd, folder); + + for (RimCase* rimCase : msd->additionalCases()) + { + RimEclipseCase* eclCase = dynamic_cast(rimCase); + RimEclipseView* sourceEclipseView = dynamic_cast(sourceView); + if (eclCase && sourceEclipseView) + { + RimEclipseView* copyOfEclipseView = eclCase->createCopyAndAddView(sourceEclipseView); + CVF_ASSERT(copyOfEclipseView); + + copyOfEclipseView->loadDataAndUpdate(); + + exportViewVariations(copyOfEclipseView, msd, folder); + + eclCase->reservoirViews().removeChildObject(copyOfEclipseView); + + delete copyOfEclipseView; + } + + RimGeoMechCase* geomCase = dynamic_cast(rimCase); + RimGeoMechView* sourceGeoMechView = dynamic_cast(sourceView); + if (geomCase && sourceGeoMechView) + { + RimGeoMechView* copyOfGeoMechView = dynamic_cast(sourceGeoMechView->xmlCapability()->copyByXmlSerialization(caf::PdmDefaultObjectFactory::instance())); + CVF_ASSERT(copyOfGeoMechView); + + geomCase->geoMechViews().push_back(copyOfGeoMechView); + + copyOfGeoMechView->setGeoMechCase(geomCase); + + // Resolve references after reservoir view has been inserted into Rim structures + copyOfGeoMechView->resolveReferencesRecursively(); + copyOfGeoMechView->initAfterReadRecursively(); + + copyOfGeoMechView->loadDataAndUpdate(); + + exportViewVariations(copyOfGeoMechView, msd, folder); + + geomCase->geoMechViews().removeChildObject(copyOfGeoMechView); + + delete copyOfGeoMechView; + } + } + + // Set view back to initial state + sourceView->viewer()->setCurrentFrame(initialFramIndex); + sourceView->viewer()->animationControl()->setCurrentFrameOnly(initialFramIndex); + + sourceView->scheduleCreateDisplayModelAndRedraw(); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicAdvancedSnapshotExportFeature::exportViewVariations(Rim3dView* rimView, RimAdvancedSnapshotExportDefinition* msd, const QString& folder) +{ + if (msd->selectedEclipseResults().size() > 0) + { + RimEclipseCase* eclCase = dynamic_cast(rimView->ownerCase()); + + RimEclipseView* copyOfView = eclCase->createCopyAndAddView(dynamic_cast(rimView)); + + copyOfView->cellResult()->setResultType(msd->eclipseResultType()); + + for (QString s : msd->selectedEclipseResults()) + { + copyOfView->cellResult()->setResultVariable(s); + + copyOfView->loadDataAndUpdate(); + + exportViewVariationsToFolder(copyOfView, msd, folder); + } + + eclCase->reservoirViews().removeChildObject(copyOfView); + + delete copyOfView; + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicAdvancedSnapshotExportFeature::exportViewVariationsToFolder(RimGridView* rimView, RimAdvancedSnapshotExportDefinition* msd, const QString& folder) +{ + RimCase* rimCase = rimView->ownerCase(); + CVF_ASSERT(rimCase); + + RiuViewer* viewer = rimView->viewer(); + QStringList timeSteps = rimCase->timeStepStrings(); + + QString resName = resultName(rimView); + QString viewCaseResultString = rimCase->caseUserDescription() + "_" + rimView->name() + "_" + resName; + viewCaseResultString = caf::Utils::makeValidFileBasename(viewCaseResultString); + + for (int i = msd->timeStepStart(); i <= msd->timeStepEnd(); i++) + { + QString timeStepIndexString = QString("%1").arg(i, 2, 10, QLatin1Char('0')); + + QString timeStepString = timeStepIndexString + "_" + timeSteps[i].replace(".", "-"); + + if (viewer) + { + // Force update of scheduled display models modifying the time step + // This is required due to visualization structures updated by the update functions, + // and this is not triggered by changing time step only + RiaViewRedrawScheduler::instance()->updateAndRedrawScheduledViews(); + + viewer->setCurrentFrame(i); + viewer->animationControl()->setCurrentFrameOnly(i); + } + + if (msd->sliceDirection == RimAdvancedSnapshotExportDefinition::NO_RANGEFILTER) + { + QString fileName = viewCaseResultString + "_" + timeStepString; + fileName.replace(" ", "_"); + + QString absoluteFileName = caf::Utils::constructFullFileName(folder, fileName, ".png"); + + RicSnapshotViewToFileFeature::saveSnapshotAs(absoluteFileName, rimView); + } + else + { + RimCellRangeFilter* rangeFilter = new RimCellRangeFilter; + rimView->rangeFilterCollection()->rangeFilters.push_back(rangeFilter); + + bool rangeFilterInitState = rimView->rangeFilterCollection()->isActive(); + rimView->rangeFilterCollection()->isActive = true; + + for (int sliceIndex = msd->startSliceIndex(); sliceIndex <= msd->endSliceIndex(); sliceIndex++) + { + QString rangeFilterString = msd->sliceDirection().text() + "-" + QString::number(sliceIndex); + QString fileName = viewCaseResultString + "_" + timeStepString + "_" + rangeFilterString; + + rangeFilter->setDefaultValues(); + if (msd->sliceDirection == RimAdvancedSnapshotExportDefinition::RANGEFILTER_I) + { + rangeFilter->cellCountI = 1; + rangeFilter->startIndexI = sliceIndex; + } + else if (msd->sliceDirection == RimAdvancedSnapshotExportDefinition::RANGEFILTER_J) + { + rangeFilter->cellCountJ = 1; + rangeFilter->startIndexJ = sliceIndex; + } + else if (msd->sliceDirection == RimAdvancedSnapshotExportDefinition::RANGEFILTER_K) + { + rangeFilter->cellCountK = 1; + rangeFilter->startIndexK = sliceIndex; + } + + rimView->rangeFilterCollection()->updateDisplayModeNotifyManagedViews(rangeFilter); + fileName.replace(" ", "_"); + + QString absoluteFileName = caf::Utils::constructFullFileName(folder, fileName, ".png"); + + RicSnapshotViewToFileFeature::saveSnapshotAs(absoluteFileName, rimView); + } + + rimView->rangeFilterCollection()->rangeFilters.removeChildObject(rangeFilter); + delete rangeFilter; + + rimView->rangeFilterCollection()->isActive = rangeFilterInitState; + } + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RicAdvancedSnapshotExportFeature::resultName(Rim3dView* rimView) +{ + if (dynamic_cast(rimView)) + { + RimEclipseView* eclView = dynamic_cast(rimView); + + return caf::Utils::makeValidFileBasename(eclView->cellResult()->resultVariableUiShortName()); + } + else if (dynamic_cast(rimView)) + { + RimGeoMechView* geoMechView = dynamic_cast(rimView); + + RimGeoMechCellColors* cellResult = geoMechView->cellResult(); + + if (cellResult) + { + QString title = caf::AppEnum(cellResult->resultPositionType()).uiText() + "_" + + cellResult->resultFieldUiName(); + + if (!cellResult->resultComponentUiName().isEmpty()) + { + title += "_" + cellResult->resultComponentUiName(); + } + + return title; + } + } + + return ""; +} + diff --git a/ApplicationCode/Commands/ExportCommands/RicAdvancedSnapshotExportFeature.h b/ApplicationCode/Commands/ExportCommands/RicAdvancedSnapshotExportFeature.h new file mode 100644 index 0000000000..18aa85dcba --- /dev/null +++ b/ApplicationCode/Commands/ExportCommands/RicAdvancedSnapshotExportFeature.h @@ -0,0 +1,49 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2016- Statoil ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "cafCmdFeature.h" + +class RimAdvancedSnapshotExportDefinition; +class RimProject; +class Rim3dView; +class RimGridView; + +//================================================================================================== +/// +//================================================================================================== +class RicAdvancedSnapshotExportFeature : public caf::CmdFeature +{ + CAF_CMD_HEADER_INIT; + +protected: + bool isCommandEnabled() override; + void onActionTriggered( bool isChecked ) override; + void setupActionLook(QAction* actionToSetup) override; + +public: + static void exportMultipleSnapshots(const QString& folder, RimProject* project); + + static void exportViewVariations(Rim3dView* rimView, RimAdvancedSnapshotExportDefinition* msd, const QString& folder); + +private: + static void exportViewVariationsToFolder(RimGridView* rimView, RimAdvancedSnapshotExportDefinition* msd, const QString& folder); + static QString resultName(Rim3dView* rimView); +}; + diff --git a/ApplicationCode/Commands/ExportCommands/RicEclipseCellResultToFileImpl.cpp b/ApplicationCode/Commands/ExportCommands/RicEclipseCellResultToFileImpl.cpp index b1d32ca2fb..dc9230b846 100644 --- a/ApplicationCode/Commands/ExportCommands/RicEclipseCellResultToFileImpl.cpp +++ b/ApplicationCode/Commands/ExportCommands/RicEclipseCellResultToFileImpl.cpp @@ -45,7 +45,7 @@ bool RicEclipseCellResultToFileImpl::writePropertyToTextFile(const QString& if (!eclipseCase) return false; cvf::ref resultAccessor = - RigResultAccessorFactory::createFromUiResultName(eclipseCase, 0, RiaDefines::MATRIX_MODEL, timeStep, resultName); + RigResultAccessorFactory::createFromResultAddress(eclipseCase, 0, RiaDefines::MATRIX_MODEL, timeStep, RigEclipseResultAddress(resultName)); if (resultAccessor.isNull()) { return false; diff --git a/ApplicationCode/Commands/ExportCommands/RicExportCarfin.cpp b/ApplicationCode/Commands/ExportCommands/RicExportCarfin.cpp index 9bf720c5ee..6ae860522b 100644 --- a/ApplicationCode/Commands/ExportCommands/RicExportCarfin.cpp +++ b/ApplicationCode/Commands/ExportCommands/RicExportCarfin.cpp @@ -68,7 +68,7 @@ void RicExportCarfin::onActionTriggered(bool isChecked) exportCarfinObject->setCase(rimCase); caf::PdmUiPropertyViewDialog propertyDialog(nullptr, exportCarfinObject, "Export CARFIN to Eclipse Data", ""); - RicExportFeatureImpl::configureForExport(&propertyDialog); + RicExportFeatureImpl::configureForExport(propertyDialog.dialogButtonBox()); if (propertyDialog.exec() == QDialog::Accepted) { diff --git a/ApplicationCode/Commands/ExportCommands/RicExportEclipseSectorModelFeature.cpp b/ApplicationCode/Commands/ExportCommands/RicExportEclipseSectorModelFeature.cpp new file mode 100644 index 0000000000..46caa06aa3 --- /dev/null +++ b/ApplicationCode/Commands/ExportCommands/RicExportEclipseSectorModelFeature.cpp @@ -0,0 +1,300 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2019- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "RicExportEclipseSectorModelFeature.h" + +#include "RiaApplication.h" +#include "RiaLogging.h" + +#include "RicExportFeatureImpl.h" +#include "RicExportEclipseSectorModelUi.h" + +#include "RifEclipseInputFileTools.h" +#include "RifReaderEclipseOutput.h" + +#include "Rim3dView.h" +#include "RimDialogData.h" +#include "RimEclipseCase.h" +#include "RimEclipseCellColors.h" +#include "RimEclipseView.h" +#include "RimFaultInView.h" +#include "RimFaultInViewCollection.h" +#include "RimProject.h" + +#include "RigEclipseCaseData.h" +#include "RigMainGrid.h" + +#include "Riu3DMainWindowTools.h" +#include "RiuPropertyViewTabWidget.h" + +#include "cafPdmSettings.h" +#include "cafPdmUiPropertyViewDialog.h" +#include "cafProgressInfo.h" +#include "cafSelectionManager.h" + +#include +#include +#include + +CAF_CMD_SOURCE_INIT(RicExportEclipseSectorModelFeature, "RicExportEclipseInputGridFeature"); + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicExportEclipseSectorModelFeature::openDialogAndExecuteCommand(RimEclipseView* view) +{ + if (!view) return; + + RigEclipseCaseData* caseData = view->eclipseCase()->eclipseCaseData(); + + cvf::UByteArray cellVisibility; + view->calculateCurrentTotalCellVisibility(&cellVisibility, view->currentTimeStep()); + + cvf::Vec3i min, max; + std::tie(min, max) = getVisibleCellRange(view, cellVisibility); + + RicExportEclipseSectorModelUi* exportSettings = RiaApplication::instance()->project()->dialogData()->exportSectorModelUi(); + exportSettings->setCaseData(caseData, min, max); + + exportSettings->applyBoundaryDefaults(); + exportSettings->removeInvalidKeywords(); + + RiuPropertyViewTabWidget propertyDialog(Riu3DMainWindowTools::mainWindowWidget(), exportSettings, "Export Eclipse Sector Model", exportSettings->tabNames()); + + RicExportFeatureImpl::configureForExport(propertyDialog.dialogButtonBox()); + + if (propertyDialog.exec() == QDialog::Accepted) + { + executeCommand(view, *exportSettings, "ExportInputGrid"); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicExportEclipseSectorModelFeature::executeCommand(RimEclipseView* view, + const RicExportEclipseSectorModelUi& exportSettings, + const QString& logPrefix) +{ + int resultProgressPercentage = exportSettings.exportParameters() ? + std::min((int) exportSettings.selectedKeywords().size(), 20) : 0; + + int faultsProgressPercentage = exportSettings.exportFaults() ? 10 : 0; + + int gridProgressPercentage = 100 - resultProgressPercentage - faultsProgressPercentage; + caf::ProgressInfo progress(gridProgressPercentage + resultProgressPercentage + faultsProgressPercentage, + "Export Eclipse Sector Model"); + + cvf::Vec3st refinement(exportSettings.refinementCountI(), exportSettings.refinementCountJ(), exportSettings.refinementCountK()); + + CVF_ASSERT(refinement.x() > 0u && refinement.y() > 0u && refinement.z() > 0u); + + cvf::UByteArray cellVisibility; + view->calculateCurrentTotalCellVisibility(&cellVisibility, view->currentTimeStep()); + getVisibleCellRange(view, cellVisibility); + + cvf::Vec3st min(exportSettings.min()); + cvf::Vec3st max(exportSettings.max()); + + if (exportSettings.exportGrid()) + { + const cvf::UByteArray* cellVisibilityForActnum = exportSettings.makeInvisibleCellsInactive() ? &cellVisibility : nullptr; + auto task = progress.task("Export Grid", gridProgressPercentage); + + bool worked = RifEclipseInputFileTools::exportGrid(exportSettings.exportGridFilename(), + view->eclipseCase()->eclipseCaseData(), + exportSettings.exportInLocalCoordinates(), + cellVisibilityForActnum, + min, + max, + refinement); + + if (!worked) + { + RiaLogging::error( + QString("Unable to write grid to '%1'").arg(exportSettings.exportGridFilename)); + } + else + { + if (view->eclipseCase()->eclipseCaseData()->gridCount() > 1u) + { + RiaLogging::warning("Grid has LGRs but ResInsight only supports exporting the Main Grid"); + } + + QFileInfo info(exportSettings.exportGridFilename()); + RiaApplication::instance()->setLastUsedDialogDirectory("EXPORT_INPUT_GRID", info.absolutePath()); + } + } + + if (exportSettings.exportParameters() != RicExportEclipseSectorModelUi::EXPORT_NO_RESULTS) + { + auto task = progress.task("Export Properties", resultProgressPercentage); + std::vector keywords = exportSettings.selectedKeywords; + + if (exportSettings.exportParameters == RicExportEclipseSectorModelUi::EXPORT_TO_SEPARATE_FILE_PER_RESULT) + { + QFileInfo info(exportSettings.exportGridFilename()); + QDir dirPath = info.absoluteDir(); + QString fileWriteMode = "w"; + for (QString keyword : keywords) + { + QString fileName = dirPath.absoluteFilePath(keyword + ".GRDECL"); + bool worked = RifEclipseInputFileTools::exportKeywords(fileName, + view->eclipseCase()->eclipseCaseData(), + {keyword}, + fileWriteMode, + min, + max, + refinement); + if (!worked) + { + RiaLogging::error(QString("Unable to write results to '%1'").arg(fileName)); + } + } + } + else + { + QString fileWriteMode = "w"; + QString fileName = exportSettings.exportParametersFilename(); + if (exportSettings.exportParameters() == RicExportEclipseSectorModelUi::EXPORT_TO_GRID_FILE) + { + fileWriteMode = "a"; + fileName = exportSettings.exportGridFilename(); + } + + bool worked = RifEclipseInputFileTools::exportKeywords(fileName, + view->eclipseCase()->eclipseCaseData(), + keywords, + fileWriteMode, + min, + max, + refinement); + + if (!worked) + { + RiaLogging::error(QString("Unable to write results to '%1'").arg(fileName)); + } + } + } + + if (exportSettings.exportFaults() != RicExportEclipseSectorModelUi::EXPORT_NO_RESULTS) + { + auto task = progress.task("Export Faults", faultsProgressPercentage); + if (exportSettings.exportFaults == RicExportEclipseSectorModelUi::EXPORT_TO_SEPARATE_FILE_PER_RESULT) + { + QFileInfo info(exportSettings.exportGridFilename()); + QDir dirPath = info.absoluteDir(); + + for (auto faultInView : view->faultCollection()->faults()) + { + auto rigFault = faultInView->faultGeometry(); + QString fileName = QString("%1.GRDECL").arg(rigFault->name()); + RifEclipseInputFileTools::saveFault( + fileName, view->eclipseCase()->mainGrid(), rigFault->faultFaces(), rigFault->name(), min, max, refinement); + } + } + else + { + QString fileName = exportSettings.exportFaultsFilename(); + QIODevice::OpenMode openFlag = QIODevice::Truncate; + if (exportSettings.exportParameters() == RicExportEclipseSectorModelUi::EXPORT_TO_GRID_FILE) + { + openFlag = QIODevice::Append; + fileName = exportSettings.exportGridFilename(); + } + QFile exportFile(fileName); + + if (!exportFile.open(QIODevice::Text | QIODevice::WriteOnly | openFlag)) + { + RiaLogging::error("Could not open the file : " + fileName); + } + + QTextStream stream(&exportFile); + RifEclipseInputFileTools::saveFaults(stream, view->eclipseCase()->mainGrid(), min, max, refinement); + } + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::pair RicExportEclipseSectorModelFeature::getVisibleCellRange(RimEclipseView* view, const cvf::UByteArray& cellVisibillity) +{ + + const RigMainGrid* mainGrid = view->eclipseCase()->mainGrid(); + cvf::Vec3i max = cvf::Vec3i::ZERO; + cvf::Vec3i min = cvf::Vec3i(int(mainGrid->cellCountI() - 1), + int(mainGrid->cellCountJ() - 1), + int(mainGrid->cellCountK() - 1)); + + size_t cellCount = mainGrid->cellCount(); + for (size_t index = 0; index < cellCount; ++index) + { + if (cellVisibillity[index]) + { + cvf::Vec3st ijk; + mainGrid->ijkFromCellIndex(index, &ijk[0], &ijk[1], &ijk[2]); + for (int n = 0; n < 3; ++n) + { + min[n] = std::min(min[n], (int) ijk[n]); + max[n] = std::max(max[n], (int) ijk[n]); + } + } + } + return std::make_pair(min, max); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RicExportEclipseSectorModelFeature::isCommandEnabled() +{ + return selectedView() != nullptr; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicExportEclipseSectorModelFeature::onActionTriggered(bool isChecked) +{ + RimEclipseView* view = RicExportEclipseSectorModelFeature::selectedView(); + openDialogAndExecuteCommand(view); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicExportEclipseSectorModelFeature::setupActionLook(QAction* actionToSetup) +{ + actionToSetup->setText("Export Eclipse Sector Model"); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimEclipseView* RicExportEclipseSectorModelFeature::selectedView() const +{ + RimEclipseView* view = caf::SelectionManager::instance()->selectedItemAncestorOfType(); + if (view) + { + return view; + } + + Rim3dView* activeView = RiaApplication::instance()->activeReservoirView(); + return dynamic_cast(activeView); +} diff --git a/ApplicationCode/Commands/ExportCommands/RicExportEclipseSectorModelFeature.h b/ApplicationCode/Commands/ExportCommands/RicExportEclipseSectorModelFeature.h new file mode 100644 index 0000000000..9039bc6cac --- /dev/null +++ b/ApplicationCode/Commands/ExportCommands/RicExportEclipseSectorModelFeature.h @@ -0,0 +1,50 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2017- Statoil ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "cafCmdFeature.h" +#include "cvfBase.h" +#include "cvfArray.h" +#include "cvfVector3.h" + +class RimEclipseView; +class RicExportEclipseSectorModelUi; + +//================================================================================================== +/// +//================================================================================================== +class RicExportEclipseSectorModelFeature : public caf::CmdFeature +{ + CAF_CMD_HEADER_INIT; + +public : + static void openDialogAndExecuteCommand(RimEclipseView* view); + static void executeCommand(RimEclipseView* view, + const RicExportEclipseSectorModelUi& exportSettings, + const QString& logPrefix); + + static std::pair getVisibleCellRange(RimEclipseView* view, const cvf::UByteArray& cellVisibility); +protected: + bool isCommandEnabled() override; + void onActionTriggered(bool isChecked) override; + void setupActionLook(QAction* actionToSetup) override; + +private: + RimEclipseView* selectedView() const; +}; diff --git a/ApplicationCode/Commands/ExportCommands/RicExportEclipseSectorModelUi.cpp b/ApplicationCode/Commands/ExportCommands/RicExportEclipseSectorModelUi.cpp new file mode 100644 index 0000000000..f803b1436a --- /dev/null +++ b/ApplicationCode/Commands/ExportCommands/RicExportEclipseSectorModelUi.cpp @@ -0,0 +1,599 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2017- Statoil ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "RicExportEclipseSectorModelUi.h" + +#include "RiaApplication.h" +#include "RigActiveCellInfo.h" +#include "RigCaseCellResultsData.h" +#include "RigEclipseCaseData.h" +#include "RigMainGrid.h" + +#include "RimEclipseResultDefinition.h" + +#include "cafPdmUiFilePathEditor.h" +#include "cafPdmUiGroup.h" +#include "cafPdmUiLineEditor.h" +#include "cafPdmUiListEditor.h" +#include "cafPdmUiOrdering.h" + +#include +#include +#include + +#include + +CAF_PDM_SOURCE_INIT(RicExportEclipseSectorModelUi, "RicExportEclipseInputGridUi"); + +namespace caf +{ +template<> +void RicExportEclipseSectorModelUi::ResultExportOptionsEnum::setUp() +{ + addItem(RicExportEclipseSectorModelUi::EXPORT_NO_RESULTS, "NO_RESULTS", "Do not export"); + addItem(RicExportEclipseSectorModelUi::EXPORT_TO_GRID_FILE, "TO_GRID_FILE", "Append to grid file"); + addItem(RicExportEclipseSectorModelUi::EXPORT_TO_SINGLE_SEPARATE_FILE, "TO_SINGLE_RESULT_FILE", "Export to single file"); + addItem(RicExportEclipseSectorModelUi::EXPORT_TO_SEPARATE_FILE_PER_RESULT, "TO_SEPARATE_RESULT_FILES", "Export to a separate file per parameter"); + + setDefault(RicExportEclipseSectorModelUi::EXPORT_TO_SEPARATE_FILE_PER_RESULT); +} + +template<> +void RicExportEclipseSectorModelUi::GridBoxSelectionEnum::setUp() +{ + addItem(RicExportEclipseSectorModelUi::VISIBLE_CELLS_BOX, "VISIBLE_CELLS", "Box Containing all Visible Cells"); + addItem(RicExportEclipseSectorModelUi::ACTIVE_CELLS_BOX, "ACTIVE_CELLS", "Box Containing all Active Cells"); + addItem(RicExportEclipseSectorModelUi::FULL_GRID_BOX, "FULL_GRID", "Full Grid"); + addItem(RicExportEclipseSectorModelUi::MANUAL_SELECTION, "MANUAL_SELECTION", "User Defined Selection"); + + setDefault(RicExportEclipseSectorModelUi::VISIBLE_CELLS_BOX); +} + +} // namespace caf + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RicExportEclipseSectorModelUi::RicExportEclipseSectorModelUi() +{ + CAF_PDM_InitObject("Export Visible Cells as Eclipse Input Grid", "", "", ""); + + CAF_PDM_InitField(&exportGrid, "ExportGrid", true, "Export Grid Data", "", "Includes COORD, ZCORN and ACTNUM", ""); + CAF_PDM_InitField(&exportGridFilename, "ExportGridFilename", QString(), "Grid File Name", "", "", ""); + exportGridFilename.uiCapability()->setUiEditorTypeName(caf::PdmUiFilePathEditor::uiEditorTypeName()); + CAF_PDM_InitField(&exportInLocalCoordinates, "ExportInLocalCoords", false, "Export in Local Coordinates", "", "Remove UTM location on export", ""); + CAF_PDM_InitField(&makeInvisibleCellsInactive, "InvisibleCellActnum", false, "Make Invisible Cells Inactive", "", "", ""); + + CAF_PDM_InitFieldNoDefault(&exportGridBox, "GridBoxSelection", "Cells to Export", "", "", ""); + + QString minIJKLabel = "Min I, J, K"; + CAF_PDM_InitField(&minI, "MinI", std::numeric_limits::max(), minIJKLabel, "", "", ""); + CAF_PDM_InitField(&minJ, "MinJ", std::numeric_limits::max(), "", "", "", ""); + minJ.uiCapability()->setUiLabelPosition(caf::PdmUiItemInfo::HIDDEN); + CAF_PDM_InitField(&minK, "MinK", std::numeric_limits::max(), "", "", "", ""); + minK.uiCapability()->setUiLabelPosition(caf::PdmUiItemInfo::HIDDEN); + QString maxIJKLabel = "Max I, J, K"; + CAF_PDM_InitField(&maxI, "MaxI", -std::numeric_limits::max(), maxIJKLabel, "", "", ""); + CAF_PDM_InitField(&maxJ, "MaxJ", -std::numeric_limits::max(), "", "", "", ""); + maxJ.uiCapability()->setUiLabelPosition(caf::PdmUiItemInfo::HIDDEN); + CAF_PDM_InitField(&maxK, "MaxK", -std::numeric_limits::max(), "", "", "", ""); + maxK.uiCapability()->setUiLabelPosition(caf::PdmUiItemInfo::HIDDEN); + + CAF_PDM_InitFieldNoDefault(&exportFaults, "ExportFaults", "Export Fault Data", "", "", ""); + exportFaults = EXPORT_TO_SINGLE_SEPARATE_FILE; + + CAF_PDM_InitField(&exportFaultsFilename, "ExportFaultsFilename", QString(), "Faults File Name", "", "", ""); + exportFaultsFilename.uiCapability()->setUiEditorTypeName(caf::PdmUiFilePathEditor::uiEditorTypeName()); + + QString ijkLabel = "Cell Count I, J, K"; + CAF_PDM_InitField(&refinementCountI, "RefinementCountI", 1, ijkLabel, "", "", ""); + CAF_PDM_InitField(&refinementCountJ, "RefinementCountJ", 1, "", "", "", ""); + CAF_PDM_InitField(&refinementCountK, "RefinementCountK", 1, "", "", "", ""); + + CAF_PDM_InitFieldNoDefault(&exportParameters, "ExportParams", "Export Parameters", "", "", ""); + CAF_PDM_InitField(&exportParametersFilename, "ExportParamsFilename", QString(), "File Name", "", "", ""); + exportParametersFilename.uiCapability()->setUiEditorTypeName(caf::PdmUiFilePathEditor::uiEditorTypeName()); + + CAF_PDM_InitFieldNoDefault(&selectedKeywords, "ExportMainKeywords", "Keywords to Export", "", "", ""); + + exportGridFilename = defaultGridFileName(); + exportParametersFilename = defaultResultsFileName(); + exportFaultsFilename = defaultFaultsFileName(); + + m_tabNames << "Grid Data"; + m_tabNames << "Parameters"; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RicExportEclipseSectorModelUi::~RicExportEclipseSectorModelUi() +{ +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +const QStringList& RicExportEclipseSectorModelUi::tabNames() const +{ + return m_tabNames; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicExportEclipseSectorModelUi::setCaseData(RigEclipseCaseData* caseData /*= nullptr*/, + const cvf::Vec3i& visibleMin /*= cvf::Vec3i::ZERO*/, + const cvf::Vec3i& visibleMax /*= cvf::Vec3i::ZERO*/) +{ + m_caseData = caseData; + m_visibleMin = visibleMin; + m_visibleMax = visibleMax; + + if (minI == std::numeric_limits::max()) + minI = m_visibleMin.x() + 1; + if (minJ == std::numeric_limits::max()) + minJ = m_visibleMin.y() + 1; + if (minK == std::numeric_limits::max()) + minK = m_visibleMin.z() + 1; + + if (maxI == -std::numeric_limits::max()) + maxI = m_visibleMax.x() + 1; + if (maxJ == std::numeric_limits::max()) + maxJ = m_visibleMax.y() + 1; + if (maxK == std::numeric_limits::max()) + maxK = m_visibleMax.z() + 1; + + if (selectedKeywords.v().empty()) + { + for (QString keyword : mainKeywords()) + { + if (caseData && caseData->results(RiaDefines::MATRIX_MODEL) + ->hasResultEntry(RigEclipseResultAddress(RiaDefines::STATIC_NATIVE, keyword))) + { + selectedKeywords.v().push_back(keyword); + } + } + } + else + { + std::vector validSelectedKeywords; + for (QString keyword : selectedKeywords()) + { + if (caseData && caseData->results(RiaDefines::MATRIX_MODEL) + ->hasResultEntry(RigEclipseResultAddress(RiaDefines::STATIC_NATIVE, keyword))) + { + validSelectedKeywords.push_back(keyword); + } + } + selectedKeywords.v() = validSelectedKeywords; + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +cvf::Vec3i RicExportEclipseSectorModelUi::min() const +{ + return cvf::Vec3i(minI() - 1, minJ() - 1, minK() - 1); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +cvf::Vec3i RicExportEclipseSectorModelUi::max() const +{ + return cvf::Vec3i(maxI() - 1, maxJ() - 1, maxK() - 1); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicExportEclipseSectorModelUi::setMin(const cvf::Vec3i& min) +{ + minI = min.x() + 1; minJ = min.y() + 1; minK = min.z() + 1; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicExportEclipseSectorModelUi::setMax(const cvf::Vec3i& max) +{ + maxI = max.x() + 1; maxJ = max.y() + 1; maxK = max.z() + 1; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicExportEclipseSectorModelUi::defineEditorAttribute(const caf::PdmFieldHandle* field, QString uiConfigName, caf::PdmUiEditorAttribute * attribute) +{ + if (!m_caseData) return; + + const RigMainGrid* mainGrid = m_caseData->mainGrid(); + cvf::Vec3i gridDimensions(int(mainGrid->cellCountI()), int(mainGrid->cellCountJ()), int(mainGrid->cellCountK())); + + caf::PdmUiLineEditorAttribute* lineEditorAttr = dynamic_cast(attribute); + + if (field == &exportParametersFilename || field == &exportGridFilename || field == &exportFaultsFilename) + { + caf::PdmUiFilePathEditorAttribute* myAttr = dynamic_cast(attribute); + if (myAttr) + { + myAttr->m_selectSaveFileName = true; + } + } + else if (field == &selectedKeywords) + { + caf::PdmUiListEditorAttribute* myAttr = dynamic_cast(attribute); + if (myAttr) + { + myAttr->m_heightHint = 280; + } + } + else if (field == &refinementCountI || field == &refinementCountJ || field == &refinementCountK) + { + if (lineEditorAttr) + { + QIntValidator* validator = new QIntValidator(1, 10, nullptr); + lineEditorAttr->validator = validator; + } + } + else if (field == &minI || field == &maxI) + { + if (lineEditorAttr) + { + lineEditorAttr->validator = new QIntValidator(1, (int)gridDimensions.x(), nullptr); + } + } + else if (field == &minJ || field == &maxJ) + { + if (lineEditorAttr) + { + lineEditorAttr->validator = new QIntValidator(1, (int)gridDimensions.y(), nullptr); + } + } + else if (field == &minK || field == &maxK) + { + if (lineEditorAttr) + { + lineEditorAttr->validator = new QIntValidator(1, (int)gridDimensions.z(), nullptr); + } + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicExportEclipseSectorModelUi::defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering) +{ + if (uiConfigName == m_tabNames[0]) + { + caf::PdmUiGroup* gridGroup = uiOrdering.addNewGroup("Grid Export"); + gridGroup->add(&exportGrid); + gridGroup->add(&exportGridFilename); + exportGridFilename.uiCapability()->setUiReadOnly(!exportGrid()); + gridGroup->add(&exportInLocalCoordinates); + exportInLocalCoordinates.uiCapability()->setUiReadOnly(!exportGrid()); + + caf::PdmUiGroup* gridBoxGroup = uiOrdering.addNewGroup("Grid Box Selection"); + gridBoxGroup->add(&exportGridBox, { true, 4, 1 }); + + gridBoxGroup->add(&minI, { true, 2, 1 }); + gridBoxGroup->add(&minJ, false); + gridBoxGroup->add(&minK, false); + + gridBoxGroup->add(&maxI, { true, 2, 1 }); + gridBoxGroup->add(&maxJ, false); + gridBoxGroup->add(&maxK, false); + gridBoxGroup->add(&makeInvisibleCellsInactive, { true, 2, 1 }); + + minI.uiCapability()->setUiReadOnly(exportGridBox() != MANUAL_SELECTION); + minJ.uiCapability()->setUiReadOnly(exportGridBox() != MANUAL_SELECTION); + minK.uiCapability()->setUiReadOnly(exportGridBox() != MANUAL_SELECTION); + maxI.uiCapability()->setUiReadOnly(exportGridBox() != MANUAL_SELECTION); + maxJ.uiCapability()->setUiReadOnly(exportGridBox() != MANUAL_SELECTION); + maxK.uiCapability()->setUiReadOnly(exportGridBox() != MANUAL_SELECTION); + + caf::PdmUiGroup* gridRefinement = uiOrdering.addNewGroup("Grid Refinement"); + gridRefinement->add(&refinementCountI, {true, 2, 1}); + gridRefinement->add(&refinementCountJ, {false}); + gridRefinement->add(&refinementCountK, {false}); + refinementCountI.uiCapability()->setUiReadOnly(!exportGrid()); + refinementCountJ.uiCapability()->setUiReadOnly(!exportGrid()); + refinementCountK.uiCapability()->setUiReadOnly(!exportGrid()); + + caf::PdmUiGroup* faultsGroup = uiOrdering.addNewGroup("Faults"); + faultsGroup->add(&exportFaults); + if (exportFaults() != EXPORT_NO_RESULTS) + { + if (exportFaults() == EXPORT_TO_SINGLE_SEPARATE_FILE) + { + faultsGroup->add(&exportFaultsFilename); + } + } + } + else if (uiConfigName == m_tabNames[1]) + { + caf::PdmUiGroup* resultsGroup = uiOrdering.addNewGroup("Parameter Export"); + + resultsGroup->add(&exportParameters); + if (exportParameters() != EXPORT_NO_RESULTS) + { + if (exportParameters() == EXPORT_TO_SINGLE_SEPARATE_FILE) + { + resultsGroup->add(&exportParametersFilename); + } + } + + if (exportParameters() != EXPORT_NO_RESULTS) + { + resultsGroup->add(&selectedKeywords); + } + } + uiOrdering.skipRemainingFields(true); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicExportEclipseSectorModelUi::fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue) +{ + if (changedField == &exportGrid) + { + if (!exportGrid()) + { + if (exportFaults() == EXPORT_TO_GRID_FILE) + { + exportFaults = EXPORT_TO_SINGLE_SEPARATE_FILE; + } + if (exportParameters() == EXPORT_TO_GRID_FILE) + { + exportParameters = EXPORT_TO_SEPARATE_FILE_PER_RESULT; + } + this->updateConnectedEditors(); + } + } + else if (changedField == &exportGridBox) + { + applyBoundaryDefaults(); + this->updateConnectedEditors(); + } + else if (changedField == &exportGridFilename) + { + QFileInfo info(exportGridFilename()); + QDir dirPath = info.absoluteDir(); + + if (exportParametersFilename() == defaultResultsFileName()) + { + exportParametersFilename = dirPath.absoluteFilePath("RESULTS.GRDECL"); + } + if (exportFaultsFilename() == defaultFaultsFileName()) + { + exportFaultsFilename = dirPath.absoluteFilePath("FAULTS.GRDECL"); + } + } + else if (changedField == &exportParametersFilename) + { + QFileInfo info(exportParametersFilename()); + QDir dirPath = info.absoluteDir(); + + if (exportGridFilename() == defaultGridFileName()) + { + exportGridFilename = dirPath.absoluteFilePath("GRID.GRDECL"); + } + if (exportFaultsFilename() == defaultFaultsFileName()) + { + exportFaultsFilename = dirPath.absoluteFilePath("FAULTS.GRDECL"); + } + } + else if (changedField == &exportFaultsFilename) + { + QFileInfo info(exportFaultsFilename()); + QDir dirPath = info.absoluteDir(); + + if (exportGridFilename() == defaultGridFileName()) + { + exportGridFilename = dirPath.absoluteFilePath("GRID.GRDECL"); + } + if (exportParametersFilename() == defaultResultsFileName()) + { + exportParametersFilename = dirPath.absoluteFilePath("RESULTS.GRDECL"); + } + } +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QList + RicExportEclipseSectorModelUi::calculateValueOptions(const caf::PdmFieldHandle* fieldNeedingOptions, bool* useOptionsOnly) +{ + QList options; + if (fieldNeedingOptions == &selectedKeywords) + { + RigCaseCellResultsData* resultData = m_caseData->results(RiaDefines::MATRIX_MODEL); + QList allOptions = RimEclipseResultDefinition::calcOptionsForVariableUiFieldStandard(RiaDefines::STATIC_NATIVE, resultData); + + std::set mainKeywords = this->mainKeywords(); + for (caf::PdmOptionItemInfo option : allOptions) + { + if (mainKeywords.count(option.optionUiText())) + { + if (resultData->hasResultEntry(RigEclipseResultAddress(RiaDefines::STATIC_NATIVE, option.optionUiText()))) + { + options.push_back(option); + } + } + } + for (caf::PdmOptionItemInfo option : allOptions) + { + if (!mainKeywords.count(option.optionUiText()) && option.optionUiText() != "None") + { + if (resultData->hasResultEntry(RigEclipseResultAddress(RiaDefines::STATIC_NATIVE, option.optionUiText()))) + { + if (option.optionUiText() == "ACTNUM" && exportGrid()) + { + if (exportParameters() != EXPORT_TO_GRID_FILE) + options.push_back(caf::PdmOptionItemInfo("ACTNUM (included in Grid File)", "ACTNUM")); + } + else + { + options.push_back(option); + } + } + } + } + } + else if (fieldNeedingOptions == &exportFaults) + { + std::set validFaultOptions = { EXPORT_NO_RESULTS, EXPORT_TO_GRID_FILE, EXPORT_TO_SINGLE_SEPARATE_FILE }; + if (!exportGrid()) + validFaultOptions.erase(EXPORT_TO_GRID_FILE); + for (ResultExportOptions option : validFaultOptions) + { + options.push_back(caf::PdmOptionItemInfo(ResultExportOptionsEnum::uiText(option), option)); + } + } + else if (fieldNeedingOptions == &exportParameters) + { + std::set validFaultOptions = { EXPORT_NO_RESULTS, EXPORT_TO_GRID_FILE, EXPORT_TO_SINGLE_SEPARATE_FILE, EXPORT_TO_SEPARATE_FILE_PER_RESULT }; + if (!exportGrid()) + validFaultOptions.erase(EXPORT_TO_GRID_FILE); + for (ResultExportOptions option : validFaultOptions) + { + options.push_back(caf::PdmOptionItemInfo(ResultExportOptionsEnum::uiText(option), option)); + } + } + return options; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::set RicExportEclipseSectorModelUi::mainKeywords() +{ + return { RiaDefines::eqlnumResultName(), "FIPNUM", "NTG", "PERMX", "PERMY", "PERMZ", "PORO", "PVTNUM", "SATNUM", "SWATINIT" }; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RicExportEclipseSectorModelUi::defaultFolder() const +{ + QString projectDirectory = RiaApplication::instance()->currentProjectPath(); + QString fallbackDirectory = projectDirectory; + if (fallbackDirectory.isEmpty()) + { + QString generalFallback = RiaApplication::instance()->lastUsedDialogDirectory("GENERAL_DATA"); + fallbackDirectory = RiaApplication::instance()->lastUsedDialogDirectoryWithFallback("BINARY_GRID", generalFallback); + } + return RiaApplication::instance()->lastUsedDialogDirectoryWithFallback("EXPORT_INPUT_GRID", fallbackDirectory); + +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RicExportEclipseSectorModelUi::defaultGridFileName() const +{ + + QDir baseDir(defaultFolder()); + return baseDir.absoluteFilePath("GRID.GRDECL"); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RicExportEclipseSectorModelUi::defaultResultsFileName() const +{ + QDir baseDir(defaultFolder()); + return baseDir.absoluteFilePath("RESULTS.GRDECL"); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RicExportEclipseSectorModelUi::defaultFaultsFileName() const +{ + QDir baseDir(defaultFolder()); + return baseDir.absoluteFilePath("FAULTS.GRDECL"); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicExportEclipseSectorModelUi::applyBoundaryDefaults() +{ + if (exportGridBox == ACTIVE_CELLS_BOX) + { + cvf::Vec3st minActive, maxActive; + m_caseData->activeCellInfo(RiaDefines::MATRIX_MODEL)->IJKBoundingBox(minActive, maxActive); + setMin(cvf::Vec3i(minActive)); + setMax(cvf::Vec3i(maxActive)); + } + else if (exportGridBox == VISIBLE_CELLS_BOX) + { + setMin(m_visibleMin); + setMax(m_visibleMax); + } + else if (exportGridBox == FULL_GRID_BOX) + { + const RigMainGrid* mainGrid = m_caseData->mainGrid(); + cvf::Vec3i gridDimensions( + int(mainGrid->cellCountI() - 1), int(mainGrid->cellCountJ() - 1), int(mainGrid->cellCountK() - 1)); + + setMin(cvf::Vec3i(0, 0, 0)); + setMax(gridDimensions); + } + else + { + const RigMainGrid* mainGrid = m_caseData->mainGrid(); + + if (maxI() > (int) mainGrid->cellCountI()) + { + maxI = (int) mainGrid->cellCountI(); + } + if (maxJ() > (int) mainGrid->cellCountJ()) + { + maxJ = (int) mainGrid->cellCountJ(); + } + if (maxK() > (int) mainGrid->cellCountK()) + { + maxK = (int) mainGrid->cellCountK(); + } + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicExportEclipseSectorModelUi::removeInvalidKeywords() +{ + RigCaseCellResultsData* resultData = m_caseData->results(RiaDefines::MATRIX_MODEL); + + std::vector validKeywords; + for (QString keyword : selectedKeywords()) + { + if (resultData->hasResultEntry(RigEclipseResultAddress(RiaDefines::STATIC_NATIVE, keyword))) + { + validKeywords.push_back(keyword); + } + } + selectedKeywords.v().swap(validKeywords); +} diff --git a/ApplicationCode/Commands/ExportCommands/RicExportEclipseSectorModelUi.h b/ApplicationCode/Commands/ExportCommands/RicExportEclipseSectorModelUi.h new file mode 100644 index 0000000000..62facb2339 --- /dev/null +++ b/ApplicationCode/Commands/ExportCommands/RicExportEclipseSectorModelUi.h @@ -0,0 +1,122 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2017- Statoil ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "cafAppEnum.h" +#include "cafPdmField.h" +#include "cafPdmObject.h" +#include "cafPdmChildArrayField.h" + +#include "cvfBase.h" +#include "cvfVector3.h" + +#include +#include + +#include +#include + +class RigEclipseCaseData; + +//================================================================================================== +/// +//================================================================================================== +class RicExportEclipseSectorModelUi : public caf::PdmObject +{ + CAF_PDM_HEADER_INIT; + + enum ResultExportOptions + { + EXPORT_NO_RESULTS, + EXPORT_TO_GRID_FILE, + EXPORT_TO_SINGLE_SEPARATE_FILE, + EXPORT_TO_SEPARATE_FILE_PER_RESULT + }; + typedef caf::AppEnum ResultExportOptionsEnum; + + enum GridBoxSelection + { + VISIBLE_CELLS_BOX, + ACTIVE_CELLS_BOX, + FULL_GRID_BOX, + MANUAL_SELECTION + }; + typedef caf::AppEnum GridBoxSelectionEnum; + +public: + RicExportEclipseSectorModelUi(); + ~RicExportEclipseSectorModelUi() override; + const QStringList& tabNames() const; + + void setCaseData(RigEclipseCaseData* caseData = nullptr, + const cvf::Vec3i& visibleMin = cvf::Vec3i::ZERO, + const cvf::Vec3i& visibleMax = cvf::Vec3i::ZERO); + + cvf::Vec3i min() const; + cvf::Vec3i max() const; + void setMin(const cvf::Vec3i& min); + void setMax(const cvf::Vec3i& max); + void applyBoundaryDefaults(); + void removeInvalidKeywords(); + + caf::PdmField exportGrid; + caf::PdmField exportGridFilename; + caf::PdmField exportInLocalCoordinates; + caf::PdmField makeInvisibleCellsInactive; + + caf::PdmField exportFaults; + caf::PdmField exportFaultsFilename; + + caf::PdmField exportParameters; + caf::PdmField exportParametersFilename; + + caf::PdmField> selectedKeywords; + + caf::PdmField exportGridBox; + + caf::PdmField refinementCountI; + caf::PdmField refinementCountJ; + caf::PdmField refinementCountK; + +protected: + caf::PdmField minI; + caf::PdmField maxI; + caf::PdmField minJ; + caf::PdmField maxJ; + caf::PdmField minK; + caf::PdmField maxK; + + void defineEditorAttribute(const caf::PdmFieldHandle* field, QString uiConfigName, caf::PdmUiEditorAttribute* attribute) override; + void defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering) override; + void fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue) override; + QList calculateValueOptions(const caf::PdmFieldHandle* fieldNeedingOptions, + bool* useOptionsOnly) override; + + static std::set mainKeywords(); + QString defaultFolder() const; + QString defaultGridFileName() const; + QString defaultResultsFileName() const; + QString defaultFaultsFileName() const; + +private: + RigEclipseCaseData* m_caseData; + cvf::Vec3i m_visibleMin; + cvf::Vec3i m_visibleMax; + QStringList m_tabNames; +}; diff --git a/ApplicationCode/Commands/ExportCommands/RicExportFaultsFeature.cpp b/ApplicationCode/Commands/ExportCommands/RicExportFaultsFeature.cpp index 0c715839b2..f914182934 100644 --- a/ApplicationCode/Commands/ExportCommands/RicExportFaultsFeature.cpp +++ b/ApplicationCode/Commands/ExportCommands/RicExportFaultsFeature.cpp @@ -26,6 +26,8 @@ #include "RigFault.h" #include "RigMainGrid.h" +#include "RifEclipseInputFileTools.h" + #include "RimEclipseCase.h" #include "RimFaultInView.h" @@ -91,7 +93,7 @@ void RicExportFaultsFeature::onActionTriggered(bool isChecked) QString completeFilename = selectedDir + "/" + baseFilename + ".grdecl"; - RicExportFaultsFeature::saveFault( + RifEclipseInputFileTools::saveFault( completeFilename, eclCase->eclipseCaseData()->mainGrid(), rimFault->faultGeometry()->faultFaces(), faultName); } } @@ -110,145 +112,3 @@ void RicExportFaultsFeature::setupActionLook(QAction* actionToSetup) actionToSetup->setText("Export Faults ..."); actionToSetup->setIcon(QIcon(":/Save.png")); } - -//-------------------------------------------------------------------------------------------------- -/// Order FaultCellAndFace by i, j, face then k. -//-------------------------------------------------------------------------------------------------- -bool RicExportFaultsFeature::faultOrdering(FaultCellAndFace first, FaultCellAndFace second) - { - size_t i1, i2, j1, j2, k1, k2; - cvf::StructGridInterface::FaceType f1, f2; - std::tie(i1, j1, k1, f1) = first; - std::tie(i2, j2, k2, f2) = second; - if (i1 == i2) - { - if (j1 == j2) - { - if (f1 == f2) - { - return k1 < k2; - } - else - { - return f1 < f2; - } - } - else - { - return j1 < j2; - } - } - else - { - return i1 < i2; - } -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -QString RicExportFaultsFeature::faceText(cvf::StructGridInterface::FaceType faceType) -{ - switch (faceType) - { - case cvf::StructGridInterface::POS_I: return QString(" I"); - case cvf::StructGridInterface::NEG_I: return QString("-I"); - case cvf::StructGridInterface::POS_J: return QString(" J"); - case cvf::StructGridInterface::NEG_J: return QString("-J"); - case cvf::StructGridInterface::POS_K: return QString(" K"); - case cvf::StructGridInterface::NEG_K: return QString("-K"); - default: CVF_ASSERT(false); - } - return ""; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RicExportFaultsFeature::writeLine(QTextStream & stream, QString faultName, size_t i, size_t j, size_t startK, size_t endK, cvf::StructGridInterface::FaceType faceType) -{ - // Convert indices to eclipse format - i++; - j++; - startK++; - endK++; - - stream << "'" << faultName << "'" << " " << i << " " << i - << " " << j << " " << j - << " " << startK << " " << endK - << " " << RicExportFaultsFeature::faceText(faceType) << " / "; - stream << endl; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- - -void RicExportFaultsFeature::saveFault(QString completeFilename, const RigMainGrid* mainGrid, const std::vector& faultFaces, QString faultName) -{ - QFile exportFile(completeFilename); - - if (!exportFile.open(QIODevice::WriteOnly | QIODevice::Text) ) - { - RiaLogging::error("Could not open the file : " + completeFilename); - } - - QTextStream stream(&exportFile); - - stream << "FAULTS" << endl; - - stream << "-- Name I1 I2 J1 J2 K1 K2 Face ( I/J/K )" << endl; - - // 'NAME' 1 1 1 1 1 2 J / - - std::vector faultCellAndFaces; - - for (const RigFault::FaultFace& faultCellAndFace : faultFaces) - { - size_t i, j, k; - bool ok = mainGrid->ijkFromCellIndex(faultCellAndFace.m_nativeReservoirCellIndex, &i, &j, &k); - if (!ok) continue; - - faultCellAndFaces.push_back(std::make_tuple(i, j, k, faultCellAndFace.m_nativeFace)); - } - - // Sort order: i, j, face then k. - std::sort(faultCellAndFaces.begin(), faultCellAndFaces.end(), RicExportFaultsFeature::faultOrdering); - - size_t lastI = std::numeric_limits::max(); - size_t lastJ = std::numeric_limits::max(); - size_t lastK = std::numeric_limits::max(); - size_t startK = std::numeric_limits::max(); - cvf::StructGridInterface::FaceType lastFaceType = cvf::StructGridInterface::FaceType::NO_FACE; - - for (const FaultCellAndFace &faultCellAndFace : faultCellAndFaces) - { - size_t i, j, k; - cvf::StructGridInterface::FaceType faceType; - std::tie(i, j, k, faceType) = faultCellAndFace; - - if (i != lastI || j != lastJ || lastFaceType != faceType || k != lastK+1) - { - // No fault should have no face - if (lastFaceType != cvf::StructGridInterface::FaceType::NO_FACE) - { - RicExportFaultsFeature::writeLine(stream, faultName, lastI, lastJ, startK, lastK, lastFaceType); - } - lastI = i; - lastJ = j; - lastK = k; - lastFaceType = faceType; - startK = k; - } - else - { - lastK = k; - } - } - // No fault should have no face - if (lastFaceType != cvf::StructGridInterface::FaceType::NO_FACE) - { - RicExportFaultsFeature::writeLine(stream, faultName, lastI, lastJ, startK, lastK, lastFaceType); - } - stream << "/" << endl; -} diff --git a/ApplicationCode/Commands/ExportCommands/RicExportFaultsFeature.h b/ApplicationCode/Commands/ExportCommands/RicExportFaultsFeature.h index 379e9591a3..39e60d7057 100644 --- a/ApplicationCode/Commands/ExportCommands/RicExportFaultsFeature.h +++ b/ApplicationCode/Commands/ExportCommands/RicExportFaultsFeature.h @@ -20,13 +20,13 @@ #include "cafCmdFeature.h" +#include "RigFault.h" + #include #include -#include "RigFault.h" class RigMainGrid; -typedef std::tuple FaultCellAndFace; //================================================================================================== /// @@ -40,11 +40,5 @@ class RicExportFaultsFeature : public caf::CmdFeature bool isCommandEnabled() override; void onActionTriggered( bool isChecked ) override; void setupActionLook( QAction* actionToSetup ) override; - -private: - static void saveFault(QString completeFilename, const RigMainGrid* mainGrid, const std::vector& faultFaces, QString faultName); - static bool faultOrdering(FaultCellAndFace first, FaultCellAndFace second); - static QString faceText(cvf::StructGridInterface::FaceType faceType); - static void writeLine(QTextStream &stream, QString faultName, size_t i, size_t j, size_t startK, size_t endK, cvf::StructGridInterface::FaceType faceType); }; diff --git a/ApplicationCode/Commands/ExportCommands/RicExportLgrFeature.cpp b/ApplicationCode/Commands/ExportCommands/RicExportLgrFeature.cpp index 0caaace5f7..2887bf31f8 100644 --- a/ApplicationCode/Commands/ExportCommands/RicExportLgrFeature.cpp +++ b/ApplicationCode/Commands/ExportCommands/RicExportLgrFeature.cpp @@ -116,7 +116,6 @@ class LgrNameFactory LgrNameFactory(); QString newName(RigCompletionData::CompletionType completionType); QString newName(const QString& baseName, int number); - void resetNumbering(); private: std::map> m_counters; @@ -678,189 +677,6 @@ RicExportLgrFeature::cellsIntersectingCompletions(RimEclipseCase* eclipseCase, return cells; } -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -std::vector cellsIntersectingCompletion(const std::map>& allCells, - caf::PdmObject* sourcePdmObject) -{ - std::vector cells; - for (const auto& intInfo : allCells) - { - for (const auto& completion : intInfo.second) - { - if (completion.sourcePdmObject() == sourcePdmObject) cells.push_back(intInfo.first); - } - } - return cells; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -std::vector>> - createOrderedIntersectionList(const std::vector& allWellPathCells, - const std::map>& completionCells) -{ - // All cell indices intersecting a completion and lookup into map - std::set complCellIndices; - std::map complCellLookup; - std::set cellsOnWellPath; - std::vector> cellsNotOnWellPath; - { - for (const auto& complCell : completionCells) - { - complCellIndices.insert(complCell.first.globalCellIndex()); - complCellLookup.insert({complCell.first.globalCellIndex(), complCell.first}); - - bool cellFoundOnWellPath = false; - for (const auto& wellPathCell : allWellPathCells) - { - if (complCell.first.globalCellIndex() == wellPathCell.globCellIndex) - { - cellsOnWellPath.insert(CellInfo(complCell.first.globalCellIndex(), wellPathCell.startMD, wellPathCell.endMD)); - cellFoundOnWellPath = true; - break; - } - } - - if (!cellFoundOnWellPath) - { - cellsNotOnWellPath.emplace_back( true, CellInfo(complCell.first.globalCellIndex()) ); - } - } - } - - std::set cellsTaken; - std::vector>> result; - - // Walk along well path - for (const auto& cellOnWellPath : cellsOnWellPath) - { - // Add cell on well path first - auto complDataGridCell = complCellLookup.at(cellOnWellPath.globCellIndex); - auto complDataList = completionCells.at(complDataGridCell); - result.emplace_back(complDataGridCell, complDataList); - - // Check intersected completions in current cell - RigCompletionData::CompletionType complTypes[] = { RigCompletionData::FRACTURE, RigCompletionData::FISHBONES, RigCompletionData::PERFORATION }; - - for (auto complType : complTypes) - { - const caf::PdmObject* completion = nullptr; - for (const auto& complData : complDataList) - { - if (complData.completionType() == complType) - { - completion = complData.sourcePdmObject(); - break; - } - } - - if (completion) - { - // Add all cells intersecting this completion - for (auto& cellNotOnWellPath : cellsNotOnWellPath) - { - if (!cellNotOnWellPath.first) continue; - - auto complDataList2 = completionCells.at(complCellLookup.at(cellNotOnWellPath.second.globCellIndex)); - auto itr = std::find_if(complDataList2.begin(), complDataList2.end(), - [&completion](const RigCompletionData& cd) { return cd.sourcePdmObject() == completion; }); - - if (itr != complDataList2.end()) - { - result.emplace_back( complCellLookup.at(cellNotOnWellPath.second.globCellIndex), complDataList2); - cellNotOnWellPath.first = false; - } - } - } - } - } - - return result; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -//std::map> -// RicExportLgrFeature::cellsIntersectingCompletions_PerCompletion_old(RimEclipseCase* eclipseCase, -// const RimWellPath* wellPath, -// size_t timeStep, -// const std::set& completionTypes, -// bool* isIntersectingOtherLgrs) -//{ -// std::map> completionToCells; -// -// *isIntersectingOtherLgrs = false; -// -// auto wellPathGeometry = wellPath->wellPathGeometry(); -// auto completions = eclipseCase->computeAndGetVirtualPerforationTransmissibilities(); -// if (wellPathGeometry && completions) -// { -// const auto& intCells = completions->multipleCompletionsPerEclipseCell(wellPath, timeStep); -// CompletionInfo lastCompletionInfo; -// -// auto wpIntCells = RigWellPathIntersectionTools::findCellIntersectionInfosAlongPath(eclipseCase->eclipseCaseData(), -// wellPathGeometry->wellPathPoints(), -// wellPathGeometry->measureDepths()); -// -// auto wpComplCells = createOrderedIntersectionList(wpIntCells, intCells); -// -// // This loop assumes that cells are ordered downwards along well path -// for (auto intCell : wpComplCells) -// { -// if (!intCell.first.isMainGridCell()) -// { -// *isIntersectingOtherLgrs = true; -// continue; -// } -// -// auto filteredCompletions = filterCompletionsOnType(intCell.second, completionTypes); -// if (filteredCompletions.empty()) continue; -// -// auto completion = findCompletionByPriority(filteredCompletions); -// -// QString name = completionName(completion.sourcePdmObject()); -// CompletionInfo completionInfo(completion.completionType(), name, 0); -// -// if (!lastCompletionInfo.isValid()) lastCompletionInfo = completionInfo; -// -// if (completionInfo != lastCompletionInfo && completionToCells.count(completionInfo) > 0) -// { -// completionInfo.number++; -// } -// completionToCells[completionInfo].push_back(intCell.first); -// lastCompletionInfo = completionInfo; -// } -// } -// return completionToCells; -//} - - -template -void appendVector(std::vector& dest, const std::vector& append) -{ - dest.insert(dest.end(), append.begin(), append.end()); -} - -void appendIntersectedCells(std::map>& dest, - const std::map>& append) -{ - for (auto& intCell : append) - { - if (dest.count(intCell.first) == 0) - { - dest.insert(intCell); - } - else - { - appendVector(dest[intCell.first], intCell.second); - } - } -} - //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -1123,13 +939,3 @@ QString LgrNameFactory::newName(const QString& baseName, int number) return lgrName.replace(" ", "_"); } -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void LgrNameFactory::resetNumbering() -{ - for (auto& counter : m_counters) - { - counter.second.second = 1; - } -} diff --git a/ApplicationCode/Commands/ExportCommands/RicExportLgrFeature.h b/ApplicationCode/Commands/ExportCommands/RicExportLgrFeature.h index 436db3034f..20c304917f 100644 --- a/ApplicationCode/Commands/ExportCommands/RicExportLgrFeature.h +++ b/ApplicationCode/Commands/ExportCommands/RicExportLgrFeature.h @@ -97,7 +97,6 @@ class CompletionInfo CompletionInfo(RigCompletionData::CompletionType type, const QString& name) : type(type) , name(name) - , wellPathName(wellPathName) { } RigCompletionData::CompletionType type; @@ -214,12 +213,6 @@ class RicExportLgrFeature : public caf::CmdFeature size_t timeStep, const std::set& completionTypes, bool* isIntersectingOtherLgrs); - //static std::map> - // cellsIntersectingCompletions_PerCompletion_old(RimEclipseCase* eclipseCase, - // const RimWellPath* wellPath, - // size_t timeStep, - // const std::set& completionTypes, - // bool* isIntersectingOtherLgrs); static std::map> cellsIntersectingCompletions_PerCompletion(RimEclipseCase* eclipseCase, diff --git a/ApplicationCode/Commands/ExportCommands/RicExportMultipleSnapshotsFeature.cpp b/ApplicationCode/Commands/ExportCommands/RicExportMultipleSnapshotsFeature.cpp deleted file mode 100644 index d3ae5ed35b..0000000000 --- a/ApplicationCode/Commands/ExportCommands/RicExportMultipleSnapshotsFeature.cpp +++ /dev/null @@ -1,327 +0,0 @@ -///////////////////////////////////////////////////////////////////////////////// -// -// Copyright (C) 2016- Statoil ASA -// -// ResInsight 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 3 of the License, or -// (at your option) any later version. -// -// ResInsight 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 at -// for more details. -// -///////////////////////////////////////////////////////////////////////////////// - -#include "RicExportMultipleSnapshotsFeature.h" - -#include "RiaApplication.h" -#include "RiaViewRedrawScheduler.h" - -#include "RicSnapshotViewToFileFeature.h" - -#include "RigFemResultPosEnum.h" - -#include "RimCase.h" -#include "RimCellRangeFilter.h" -#include "RimCellRangeFilterCollection.h" -#include "RimEclipseCase.h" -#include "RimEclipseCellColors.h" -#include "RimEclipseView.h" -#include "RimGeoMechCase.h" -#include "RimGeoMechCellColors.h" -#include "RimGeoMechResultDefinition.h" -#include "RimGeoMechView.h" -#include "RimMultiSnapshotDefinition.h" -#include "RimProject.h" -#include "Rim3dView.h" - -#include "RiuExportMultipleSnapshotsWidget.h" -#include "RiuViewer.h" - -#include "cafCmdExecCommandManager.h" -#include "cafFrameAnimationControl.h" -#include "cafUtils.h" - -#include -#include -#include - - -CAF_CMD_SOURCE_INIT(RicExportMultipleSnapshotsFeature, "RicExportMultipleSnapshotsFeature"); - - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -bool RicExportMultipleSnapshotsFeature::isCommandEnabled() -{ - RimProject* proj = RiaApplication::instance()->project(); - - return proj; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RicExportMultipleSnapshotsFeature::onActionTriggered(bool isChecked) -{ - this->disableModelChangeContribution(); - - RimProject* proj = RiaApplication::instance()->project(); - - if (proj) - { - // Enable the command system to be able to assign a value to multiple fields at the same time - caf::CmdExecCommandSystemActivator activator; - - RiuExportMultipleSnapshotsWidget dlg(nullptr, proj); - - Rim3dView* activeView = RiaApplication::instance()->activeReservoirView(); - if (activeView && proj->multiSnapshotDefinitions.size() == 0) - { - dlg.addSnapshotItemFromActiveView(); - dlg.addEmptySnapshotItems(4); - } - - dlg.exec(); - } -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RicExportMultipleSnapshotsFeature::setupActionLook(QAction* actionToSetup) -{ - actionToSetup->setText("Advanced Snapshot Export ..."); - actionToSetup->setIcon(QIcon(":/SnapShotSaveViews.png")); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RicExportMultipleSnapshotsFeature::exportMultipleSnapshots(const QString& folder, RimProject* project) -{ - if (!project) return; - - QDir snapshotPath(folder); - if (!snapshotPath.exists()) - { - if (!snapshotPath.mkpath(".")) return; - } - - for (RimMultiSnapshotDefinition* msd : project->multiSnapshotDefinitions()) - { - if (!msd->isActive()) continue; - - Rim3dView* sourceView = msd->view(); - if (!sourceView) continue; - if (!sourceView->viewer()) continue; - - int initialFramIndex = sourceView->viewer()->currentFrameIndex(); - - //exportViewVariations(sourceView, msd, folder); - - for (RimCase* rimCase : msd->additionalCases()) - { - RimEclipseCase* eclCase = dynamic_cast(rimCase); - RimEclipseView* sourceEclipseView = dynamic_cast(sourceView); - if (eclCase && sourceEclipseView) - { - RimEclipseView* copyOfEclipseView = eclCase->createCopyAndAddView(sourceEclipseView); - CVF_ASSERT(copyOfEclipseView); - - copyOfEclipseView->loadDataAndUpdate(); - - exportViewVariations(copyOfEclipseView, msd, folder); - - eclCase->reservoirViews().removeChildObject(copyOfEclipseView); - - delete copyOfEclipseView; - } - - RimGeoMechCase* geomCase = dynamic_cast(rimCase); - RimGeoMechView* sourceGeoMechView = dynamic_cast(sourceView); - if (geomCase && sourceGeoMechView) - { - RimGeoMechView* copyOfGeoMechView = dynamic_cast(sourceGeoMechView->xmlCapability()->copyByXmlSerialization(caf::PdmDefaultObjectFactory::instance())); - CVF_ASSERT(copyOfGeoMechView); - - geomCase->geoMechViews().push_back(copyOfGeoMechView); - - copyOfGeoMechView->setGeoMechCase(geomCase); - - // Resolve references after reservoir view has been inserted into Rim structures - copyOfGeoMechView->resolveReferencesRecursively(); - copyOfGeoMechView->initAfterReadRecursively(); - - copyOfGeoMechView->loadDataAndUpdate(); - - exportViewVariations(copyOfGeoMechView, msd, folder); - - geomCase->geoMechViews().removeChildObject(copyOfGeoMechView); - - delete copyOfGeoMechView; - } - } - - // Set view back to initial state - sourceView->viewer()->setCurrentFrame(initialFramIndex); - sourceView->viewer()->animationControl()->setCurrentFrameOnly(initialFramIndex); - - sourceView->scheduleCreateDisplayModelAndRedraw(); - } -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RicExportMultipleSnapshotsFeature::exportViewVariations(Rim3dView* rimView, RimMultiSnapshotDefinition* msd, const QString& folder) -{ - if (msd->selectedEclipseResults().size() > 0) - { - RimEclipseCase* eclCase = dynamic_cast(rimView->ownerCase()); - - RimEclipseView* copyOfView = eclCase->createCopyAndAddView(dynamic_cast(rimView)); - - copyOfView->cellResult()->setResultType(msd->eclipseResultType()); - - for (QString s : msd->selectedEclipseResults()) - { - copyOfView->cellResult()->setResultVariable(s); - - copyOfView->loadDataAndUpdate(); - - exportViewVariationsToFolder(copyOfView, msd, folder); - } - - eclCase->reservoirViews().removeChildObject(copyOfView); - - delete copyOfView; - } -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RicExportMultipleSnapshotsFeature::exportViewVariationsToFolder(RimGridView* rimView, RimMultiSnapshotDefinition* msd, const QString& folder) -{ - RimCase* rimCase = rimView->ownerCase(); - CVF_ASSERT(rimCase); - - RiuViewer* viewer = rimView->viewer(); - QStringList timeSteps = rimCase->timeStepStrings(); - - QString resName = resultName(rimView); - QString viewCaseResultString = rimCase->caseUserDescription() + "_" + rimView->name() + "_" + resName; - viewCaseResultString = caf::Utils::makeValidFileBasename(viewCaseResultString); - - for (int i = msd->timeStepStart(); i <= msd->timeStepEnd(); i++) - { - QString timeStepIndexString = QString("%1").arg(i, 2, 10, QLatin1Char('0')); - - QString timeStepString = timeStepIndexString + "_" + timeSteps[i].replace(".", "-"); - - if (viewer) - { - // Force update of scheduled display models modifying the time step - // This is required due to visualization structures updated by the update functions, - // and this is not triggered by changing time step only - RiaViewRedrawScheduler::instance()->updateAndRedrawScheduledViews(); - - viewer->setCurrentFrame(i); - viewer->animationControl()->setCurrentFrameOnly(i); - } - - if (msd->sliceDirection == RimMultiSnapshotDefinition::NO_RANGEFILTER) - { - QString fileName = viewCaseResultString + "_" + timeStepString; - fileName.replace(" ", "_"); - - QString absoluteFileName = caf::Utils::constructFullFileName(folder, fileName, ".png"); - - RicSnapshotViewToFileFeature::saveSnapshotAs(absoluteFileName, rimView); - } - else - { - RimCellRangeFilter* rangeFilter = new RimCellRangeFilter; - rimView->rangeFilterCollection()->rangeFilters.push_back(rangeFilter); - - bool rangeFilterInitState = rimView->rangeFilterCollection()->isActive(); - rimView->rangeFilterCollection()->isActive = true; - - for (int sliceIndex = msd->startSliceIndex(); sliceIndex <= msd->endSliceIndex(); sliceIndex++) - { - QString rangeFilterString = msd->sliceDirection().text() + "-" + QString::number(sliceIndex); - QString fileName = viewCaseResultString + "_" + timeStepString + "_" + rangeFilterString; - - rangeFilter->setDefaultValues(); - if (msd->sliceDirection == RimMultiSnapshotDefinition::RANGEFILTER_I) - { - rangeFilter->cellCountI = 1; - rangeFilter->startIndexI = sliceIndex; - } - else if (msd->sliceDirection == RimMultiSnapshotDefinition::RANGEFILTER_J) - { - rangeFilter->cellCountJ = 1; - rangeFilter->startIndexJ = sliceIndex; - } - else if (msd->sliceDirection == RimMultiSnapshotDefinition::RANGEFILTER_K) - { - rangeFilter->cellCountK = 1; - rangeFilter->startIndexK = sliceIndex; - } - - rimView->rangeFilterCollection()->updateDisplayModeNotifyManagedViews(rangeFilter); - fileName.replace(" ", "_"); - - QString absoluteFileName = caf::Utils::constructFullFileName(folder, fileName, ".png"); - - RicSnapshotViewToFileFeature::saveSnapshotAs(absoluteFileName, rimView); - } - - rimView->rangeFilterCollection()->rangeFilters.removeChildObject(rangeFilter); - delete rangeFilter; - - rimView->rangeFilterCollection()->isActive = rangeFilterInitState; - } - } -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -QString RicExportMultipleSnapshotsFeature::resultName(Rim3dView* rimView) -{ - if (dynamic_cast(rimView)) - { - RimEclipseView* eclView = dynamic_cast(rimView); - - return caf::Utils::makeValidFileBasename(eclView->cellResult()->resultVariableUiShortName()); - } - else if (dynamic_cast(rimView)) - { - RimGeoMechView* geoMechView = dynamic_cast(rimView); - - RimGeoMechCellColors* cellResult = geoMechView->cellResult(); - - if (cellResult) - { - QString title = caf::AppEnum(cellResult->resultPositionType()).uiText() + "_" - + cellResult->resultFieldUiName(); - - if (!cellResult->resultComponentUiName().isEmpty()) - { - title += "_" + cellResult->resultComponentUiName(); - } - - return title; - } - } - - return ""; -} - diff --git a/ApplicationCode/Commands/ExportCommands/RicExportMultipleSnapshotsFeature.h b/ApplicationCode/Commands/ExportCommands/RicExportMultipleSnapshotsFeature.h deleted file mode 100644 index f05b1dc7bd..0000000000 --- a/ApplicationCode/Commands/ExportCommands/RicExportMultipleSnapshotsFeature.h +++ /dev/null @@ -1,49 +0,0 @@ -///////////////////////////////////////////////////////////////////////////////// -// -// Copyright (C) 2016- Statoil ASA -// -// ResInsight 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 3 of the License, or -// (at your option) any later version. -// -// ResInsight 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 at -// for more details. -// -///////////////////////////////////////////////////////////////////////////////// - -#pragma once - -#include "cafCmdFeature.h" - -class RimMultiSnapshotDefinition; -class RimProject; -class Rim3dView; -class RimGridView; - -//================================================================================================== -/// -//================================================================================================== -class RicExportMultipleSnapshotsFeature : public caf::CmdFeature -{ - CAF_CMD_HEADER_INIT; - -protected: - bool isCommandEnabled() override; - void onActionTriggered( bool isChecked ) override; - void setupActionLook(QAction* actionToSetup) override; - -public: - static void exportMultipleSnapshots(const QString& folder, RimProject* project); - - static void exportViewVariations(Rim3dView* rimView, RimMultiSnapshotDefinition* msd, const QString& folder); - -private: - static void exportViewVariationsToFolder(RimGridView* rimView, RimMultiSnapshotDefinition* msd, const QString& folder); - static QString resultName(Rim3dView* rimView); -}; - diff --git a/ApplicationCode/Commands/ExportCommands/RicExportSelectedWellPathsFeature.cpp b/ApplicationCode/Commands/ExportCommands/RicExportSelectedWellPathsFeature.cpp index 9ad10316f7..efe978e6e3 100644 --- a/ApplicationCode/Commands/ExportCommands/RicExportSelectedWellPathsFeature.cpp +++ b/ApplicationCode/Commands/ExportCommands/RicExportSelectedWellPathsFeature.cpp @@ -106,7 +106,7 @@ void RicExportSelectedWellPathsFeature::writeWellPathGeometryToStream(QTextStrea double endMd = wellPathGeom->measureDepths().back(); RifEclipseDataTableFormatter formatter(stream); - formatter.setCommentPrefix("#"); + formatter.setCommentPrefix("# "); formatter.setTableRowPrependText(" "); if (writeProjectInfo) diff --git a/ApplicationCode/Commands/ExportCommands/RicExportToLasFileFeature.cpp b/ApplicationCode/Commands/ExportCommands/RicExportToLasFileFeature.cpp index 89db296f87..814b95eb01 100644 --- a/ApplicationCode/Commands/ExportCommands/RicExportToLasFileFeature.cpp +++ b/ApplicationCode/Commands/ExportCommands/RicExportToLasFileFeature.cpp @@ -77,7 +77,7 @@ void RicExportToLasFileFeature::onActionTriggered(bool isChecked) } caf::PdmUiPropertyViewDialog propertyDialog(nullptr, &featureUi, "Export Curve Data to LAS file(s)", "", QDialogButtonBox::Ok | QDialogButtonBox::Cancel); - RicExportFeatureImpl::configureForExport(&propertyDialog); + RicExportFeatureImpl::configureForExport(propertyDialog.dialogButtonBox()); propertyDialog.resize(QSize(400, 330)); if (propertyDialog.exec() == QDialog::Accepted && diff --git a/ApplicationCode/Commands/ExportCommands/RicExportWellPathsUi.cpp b/ApplicationCode/Commands/ExportCommands/RicExportWellPathsUi.cpp index c4d7baf293..dad50cc336 100644 --- a/ApplicationCode/Commands/ExportCommands/RicExportWellPathsUi.cpp +++ b/ApplicationCode/Commands/ExportCommands/RicExportWellPathsUi.cpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018 Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by diff --git a/ApplicationCode/Commands/ExportCommands/RicExportWellPathsUi.h b/ApplicationCode/Commands/ExportCommands/RicExportWellPathsUi.h index 0a3759a65d..ffa1e3b7aa 100644 --- a/ApplicationCode/Commands/ExportCommands/RicExportWellPathsUi.h +++ b/ApplicationCode/Commands/ExportCommands/RicExportWellPathsUi.h @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018 Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by diff --git a/ApplicationCode/Commands/ExportCommands/RicSaveEclipseInputPropertyFeature.cpp b/ApplicationCode/Commands/ExportCommands/RicSaveEclipseInputPropertyFeature.cpp index 5780514643..93b33d4da0 100644 --- a/ApplicationCode/Commands/ExportCommands/RicSaveEclipseInputPropertyFeature.cpp +++ b/ApplicationCode/Commands/ExportCommands/RicSaveEclipseInputPropertyFeature.cpp @@ -101,7 +101,7 @@ void RicSaveEclipseInputPropertyFeature::onActionTriggered(bool isChecked) } caf::PdmUiPropertyViewDialog propertyDialog(Riu3DMainWindowTools::mainWindowWidget(), &exportSettings, "Export Eclipse Property to Text File", ""); - RicExportFeatureImpl::configureForExport(&propertyDialog); + RicExportFeatureImpl::configureForExport(propertyDialog.dialogButtonBox()); if (propertyDialog.exec() == QDialog::Accepted) { diff --git a/ApplicationCode/Commands/ExportCommands/RicSaveEclipseInputVisibleCellsFeature.cpp b/ApplicationCode/Commands/ExportCommands/RicSaveEclipseInputVisibleCellsFeature.cpp index 43b1eefa7d..becb69634e 100644 --- a/ApplicationCode/Commands/ExportCommands/RicSaveEclipseInputVisibleCellsFeature.cpp +++ b/ApplicationCode/Commands/ExportCommands/RicSaveEclipseInputVisibleCellsFeature.cpp @@ -53,7 +53,7 @@ void RicSaveEclipseInputVisibleCellsFeature::openDialogAndExecuteCommand(RimEcli RicSaveEclipseInputVisibleCellsUi exportSettings; caf::PdmUiPropertyViewDialog propertyDialog(Riu3DMainWindowTools::mainWindowWidget(), &exportSettings, "Export FLUXNUM/MULTNUM", ""); - RicExportFeatureImpl::configureForExport(&propertyDialog); + RicExportFeatureImpl::configureForExport(propertyDialog.dialogButtonBox()); if (propertyDialog.exec() == QDialog::Accepted) { @@ -131,33 +131,22 @@ void RicSaveEclipseInputVisibleCellsFeature::setupActionLook(QAction* actionToSe //-------------------------------------------------------------------------------------------------- RimEclipseView* RicSaveEclipseInputVisibleCellsFeature::selectedView() const { - RimEclipseView* view = dynamic_cast(caf::SelectionManager::instance()->selectedItem()); + RimEclipseView* view = caf::SelectionManager::instance()->selectedItemAncestorOfType(); if (view) { return view; } - RimEclipseCellColors* cellResultItem = dynamic_cast(caf::SelectionManager::instance()->selectedItem()); - if (cellResultItem) - { - cellResultItem->firstAncestorOrThisOfType(view); - } - - return view; + Rim3dView* activeView = RiaApplication::instance()->activeReservoirView(); + return dynamic_cast(activeView); } - - - - - - //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- bool RicSaveEclipseInputActiveVisibleCellsFeature::isCommandEnabled() { - return true; + return selectedView() != nullptr; } //-------------------------------------------------------------------------------------------------- @@ -165,7 +154,7 @@ bool RicSaveEclipseInputActiveVisibleCellsFeature::isCommandEnabled() //-------------------------------------------------------------------------------------------------- void RicSaveEclipseInputActiveVisibleCellsFeature::onActionTriggered(bool isChecked) { - RimEclipseView* view = RicSaveEclipseInputActiveVisibleCellsFeature::getEclipseActiveView(); + RimEclipseView* view = RicSaveEclipseInputActiveVisibleCellsFeature::selectedView(); RicSaveEclipseInputVisibleCellsFeature::openDialogAndExecuteCommand(view); } @@ -180,10 +169,15 @@ void RicSaveEclipseInputActiveVisibleCellsFeature::setupActionLook(QAction* acti //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -RimEclipseView* RicSaveEclipseInputActiveVisibleCellsFeature::getEclipseActiveView() +RimEclipseView* RicSaveEclipseInputActiveVisibleCellsFeature::selectedView() { - Rim3dView* activeView = RiaApplication::instance()->activeReservoirView(); + RimEclipseView* view = caf::SelectionManager::instance()->selectedItemAncestorOfType(); + if (view) + { + return view; + } + Rim3dView* activeView = RiaApplication::instance()->activeReservoirView(); return dynamic_cast(activeView); } diff --git a/ApplicationCode/Commands/ExportCommands/RicSaveEclipseInputVisibleCellsFeature.h b/ApplicationCode/Commands/ExportCommands/RicSaveEclipseInputVisibleCellsFeature.h index bdb363c0b6..f288c44c81 100644 --- a/ApplicationCode/Commands/ExportCommands/RicSaveEclipseInputVisibleCellsFeature.h +++ b/ApplicationCode/Commands/ExportCommands/RicSaveEclipseInputVisibleCellsFeature.h @@ -58,5 +58,5 @@ class RicSaveEclipseInputActiveVisibleCellsFeature : public caf::CmdFeature void setupActionLook( QAction* actionToSetup ) override; private: - static RimEclipseView* getEclipseActiveView(); + static RimEclipseView* selectedView(); }; diff --git a/ApplicationCode/Commands/ExportCommands/RicSaveEclipseResultAsInputPropertyExec.cpp b/ApplicationCode/Commands/ExportCommands/RicSaveEclipseResultAsInputPropertyExec.cpp index 0093f2abfe..0628968c45 100644 --- a/ApplicationCode/Commands/ExportCommands/RicSaveEclipseResultAsInputPropertyExec.cpp +++ b/ApplicationCode/Commands/ExportCommands/RicSaveEclipseResultAsInputPropertyExec.cpp @@ -91,7 +91,7 @@ void RicSaveEclipseResultAsInputPropertyExec::redo() } caf::PdmUiPropertyViewDialog propertyDialog(Riu3DMainWindowTools::mainWindowWidget(), &exportSettings, "Export Binary Eclipse Data to Text File", ""); - RicExportFeatureImpl::configureForExport(&propertyDialog); + RicExportFeatureImpl::configureForExport(propertyDialog.dialogButtonBox()); if (propertyDialog.exec() == QDialog::Accepted) { diff --git a/ApplicationCode/Commands/FlowCommands/RicPlotProductionRateFeature.cpp b/ApplicationCode/Commands/FlowCommands/RicPlotProductionRateFeature.cpp index 2312bd3b27..a0d32c9007 100644 --- a/ApplicationCode/Commands/FlowCommands/RicPlotProductionRateFeature.cpp +++ b/ApplicationCode/Commands/FlowCommands/RicPlotProductionRateFeature.cpp @@ -190,7 +190,7 @@ void RicPlotProductionRateFeature::onActionTriggered(bool isChecked) mainPlotWindow->selectAsCurrentItem(summaryPlotToSelect); mainPlotWindow->setExpanded(summaryPlotToSelect); - mainPlotWindow->tileWindows(); + mainPlotWindow->tileSubWindows(); } } } @@ -292,7 +292,7 @@ RimSummaryCurve* RicPlotProductionRateFeature::addSummaryCurve( RimSummaryPlot* plot->addCurveAndUpdate(newCurve); newCurve->setSummaryCaseY(gridSummaryCase); - newCurve->setSummaryAddressY(addr); + newCurve->setSummaryAddressYAndApplyInterpolation(addr); newCurve->setColor(color); newCurve->setLeftOrRightAxisY(plotAxis); newCurve->loadDataAndUpdate(true); diff --git a/ApplicationCode/Commands/FlowCommands/RicSelectViewUI.cpp b/ApplicationCode/Commands/FlowCommands/RicSelectViewUI.cpp index 199a4426d5..e5c54e2a43 100644 --- a/ApplicationCode/Commands/FlowCommands/RicSelectViewUI.cpp +++ b/ApplicationCode/Commands/FlowCommands/RicSelectViewUI.cpp @@ -32,7 +32,7 @@ RicSelectViewUI::RicSelectViewUI() CAF_PDM_InitObject("RicSelectViewUI", "", "", ""); CAF_PDM_InitFieldNoDefault(&m_selectedView, "MasterView", "Select view", "", "", ""); - CAF_PDM_InitField(&m_createNewView, "CreateNewView", false, "Create New View", "", "", ""); + CAF_PDM_InitField(&m_createNewView, "CreateNewView", true, "Create New View", "", "", ""); CAF_PDM_InitField(&m_newViewName, "NewViewName", QString("ShowContributingWells"), "New View Name", "", "", ""); m_currentView = nullptr; @@ -59,6 +59,14 @@ void RicSelectViewUI::setCase(RimEclipseResultCase* currentCase) m_currentCase = currentCase; } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicSelectViewUI::setNewViewName(const QString& name) +{ + m_newViewName = name; +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/Commands/FlowCommands/RicSelectViewUI.h b/ApplicationCode/Commands/FlowCommands/RicSelectViewUI.h index e6748fa86c..7c72e2e6f5 100644 --- a/ApplicationCode/Commands/FlowCommands/RicSelectViewUI.h +++ b/ApplicationCode/Commands/FlowCommands/RicSelectViewUI.h @@ -37,6 +37,7 @@ class RicSelectViewUI : public caf::PdmObject void setView(RimEclipseView* currentView); void setCase(RimEclipseResultCase* currentCase); + void setNewViewName(const QString& name); RimEclipseView* selectedView() const; bool createNewView() const; diff --git a/ApplicationCode/Commands/FlowCommands/RicShowContributingWellsFeature.cpp b/ApplicationCode/Commands/FlowCommands/RicShowContributingWellsFeature.cpp index 19f30db1c7..457025409e 100644 --- a/ApplicationCode/Commands/FlowCommands/RicShowContributingWellsFeature.cpp +++ b/ApplicationCode/Commands/FlowCommands/RicShowContributingWellsFeature.cpp @@ -89,7 +89,7 @@ void RicShowContributingWellsFeature::onActionTriggered(bool isChecked) RimEclipseResultCase* eclipseResultCase = nullptr; well->firstAncestorOrThisOfTypeAsserted(eclipseResultCase); - RimEclipseView* modifiedView = RicShowContributingWellsFeatureImpl::maniuplateSelectedView(eclipseResultCase, well->name(), eclipseView->currentTimeStep()); + RimEclipseView* modifiedView = RicShowContributingWellsFeatureImpl::manipulateSelectedView(eclipseResultCase, well->name(), eclipseView->currentTimeStep()); if (modifiedView) { modifiedView->createDisplayModelAndRedraw(); diff --git a/ApplicationCode/Commands/FlowCommands/RicShowContributingWellsFeatureImpl.cpp b/ApplicationCode/Commands/FlowCommands/RicShowContributingWellsFeatureImpl.cpp index b5de57a139..4c50301b35 100644 --- a/ApplicationCode/Commands/FlowCommands/RicShowContributingWellsFeatureImpl.cpp +++ b/ApplicationCode/Commands/FlowCommands/RicShowContributingWellsFeatureImpl.cpp @@ -1,17 +1,17 @@ ///////////////////////////////////////////////////////////////////////////////// // // Copyright (C) 2017 Statoil ASA -// +// // ResInsight 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 3 of the License, or // (at your option) any later version. -// +// // ResInsight 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 at +// +// See the GNU General Public License at // for more details. // ///////////////////////////////////////////////////////////////////////////////// @@ -30,11 +30,11 @@ #include "RimEclipsePropertyFilterCollection.h" #include "RimEclipseResultCase.h" #include "RimEclipseView.h" -#include "RimSimWellInViewCollection.h" #include "RimFaultInViewCollection.h" #include "RimFlowDiagSolution.h" #include "RimProject.h" #include "RimSimWellInView.h" +#include "RimSimWellInViewCollection.h" #include "RimViewManipulator.h" #include "Riu3DMainWindowTools.h" @@ -43,14 +43,16 @@ #include "cafCmdFeatureManager.h" //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- -RimEclipseView* RicShowContributingWellsFeatureImpl::maniuplateSelectedView(RimEclipseResultCase* eclipseResultCase, QString wellName, int timeStep) +RimEclipseView* RicShowContributingWellsFeatureImpl::manipulateSelectedView(RimEclipseResultCase* eclipseResultCase, + QString wellName, + int timeStep) { - RimEclipseView* viewToManipulate = RicSelectOrCreateViewFeatureImpl::showViewSelection(eclipseResultCase, "lastUsedWellAllocationView", "Show Contributing Wells in View"); - - if (!viewToManipulate) return nullptr; + RimEclipseView* viewToManipulate = RicSelectOrCreateViewFeatureImpl::showViewSelection( + eclipseResultCase, "lastUsedWellAllocationView", "ContributingWells_" + wellName, "Show Contributing Wells in View"); + if (!viewToManipulate) return nullptr; RicShowContributingWellsFeatureImpl::modifyViewToShowContributingWells(viewToManipulate, wellName, timeStep); @@ -63,9 +65,11 @@ RimEclipseView* RicShowContributingWellsFeatureImpl::maniuplateSelectedView(RimE } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- -void RicShowContributingWellsFeatureImpl::modifyViewToShowContributingWells(RimEclipseView* viewToModify, const QString& wellName, int timeStep) +void RicShowContributingWellsFeatureImpl::modifyViewToShowContributingWells(RimEclipseView* viewToModify, + const QString& wellName, + int timeStep) { CVF_ASSERT(viewToModify); @@ -91,7 +95,7 @@ void RicShowContributingWellsFeatureImpl::modifyViewToShowContributingWells(RimE flowDiagSolution = eclipseResultCase->defaultFlowDiagSolution(); } - //assert(flowDiagSolution); + // assert(flowDiagSolution); CVF_ASSERT(flowDiagSolution); RimFlowDiagSolution::TracerStatusType tracerStatus = flowDiagSolution->tracerStatusInTimeStep(selectedWell->name(), timeStep); @@ -99,7 +103,7 @@ void RicShowContributingWellsFeatureImpl::modifyViewToShowContributingWells(RimE { return; } - + viewToModify->setCurrentTimeStep(timeStep); viewToModify->cellResult()->setResultType(RiaDefines::FLOW_DIAGNOSTICS); viewToModify->cellResult()->setResultVariable("MaxFractionTracer"); @@ -107,27 +111,27 @@ void RicShowContributingWellsFeatureImpl::modifyViewToShowContributingWells(RimE switch (tracerStatus) { - case RimFlowDiagSolution::PRODUCER: - viewToModify->cellResult()->setFlowDiagTracerSelectionType(RimEclipseResultDefinition::FLOW_TR_INJECTORS); - break; - case RimFlowDiagSolution::INJECTOR: - viewToModify->cellResult()->setFlowDiagTracerSelectionType(RimEclipseResultDefinition::FLOW_TR_PRODUCERS); - break; - - default: - CVF_ASSERT(false); - break; + case RimFlowDiagSolution::PRODUCER: + viewToModify->cellResult()->setFlowDiagTracerSelectionType(RimEclipseResultDefinition::FLOW_TR_INJECTORS); + break; + case RimFlowDiagSolution::INJECTOR: + viewToModify->cellResult()->setFlowDiagTracerSelectionType(RimEclipseResultDefinition::FLOW_TR_PRODUCERS); + break; + + default: + CVF_ASSERT(false); + break; } viewToModify->cellResult()->loadDataAndUpdate(); viewToModify->cellResult()->updateConnectedEditors(); - + std::vector tracerNames = findContributingTracerNames(flowDiagSolution, selectedWell->simWellData(), timeStep); for (RimSimWellInView* w : viewToModify->wellCollection()->wells()) { - if (std::find(tracerNames.begin(), tracerNames.end(), w->name()) != tracerNames.end() - || selectedWell->name() == w->name()) + if (std::find(tracerNames.begin(), tracerNames.end(), w->name()) != tracerNames.end() || + selectedWell->name() == w->name()) { w->showWell = true; } @@ -166,12 +170,11 @@ void RicShowContributingWellsFeatureImpl::modifyViewToShowContributingWells(RimE } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- -std::vector RicShowContributingWellsFeatureImpl::findContributingTracerNames( - const RimFlowDiagSolution* flowDiagSolution, - const RigSimWellData* simWellData, - int timeStep) +std::vector RicShowContributingWellsFeatureImpl::findContributingTracerNames(const RimFlowDiagSolution* flowDiagSolution, + const RigSimWellData* simWellData, + int timeStep) { std::vector tracerCellFractionValues; @@ -180,8 +183,7 @@ std::vector RicShowContributingWellsFeatureImpl::findContributingTracer RimFlowDiagSolution::TracerStatusType requestedTracerType = RimFlowDiagSolution::UNDEFINED; const RigWellResultFrame::WellProductionType prodType = simWellData->wellProductionType(timeStep); - if ( prodType == RigWellResultFrame::PRODUCER - || prodType == RigWellResultFrame::UNDEFINED_PRODUCTION_TYPE) + if (prodType == RigWellResultFrame::PRODUCER || prodType == RigWellResultFrame::UNDEFINED_PRODUCTION_TYPE) { requestedTracerType = RimFlowDiagSolution::INJECTOR; } @@ -202,4 +204,3 @@ std::vector RicShowContributingWellsFeatureImpl::findContributingTracer return tracerCellFractionValues; } - diff --git a/ApplicationCode/Commands/FlowCommands/RicShowContributingWellsFeatureImpl.h b/ApplicationCode/Commands/FlowCommands/RicShowContributingWellsFeatureImpl.h index 3492c2cfac..2bcc5cd505 100644 --- a/ApplicationCode/Commands/FlowCommands/RicShowContributingWellsFeatureImpl.h +++ b/ApplicationCode/Commands/FlowCommands/RicShowContributingWellsFeatureImpl.h @@ -34,7 +34,7 @@ class RimSimWellInView; class RicShowContributingWellsFeatureImpl { public: - static RimEclipseView* maniuplateSelectedView(RimEclipseResultCase* wellAllocationResultCase, QString wellName, int timeStep); + static RimEclipseView* manipulateSelectedView(RimEclipseResultCase* wellAllocationResultCase, QString wellName, int timeStep); private: static void modifyViewToShowContributingWells(RimEclipseView* viewToModify, const QString& wellName, int timeStep); diff --git a/ApplicationCode/Commands/FlowCommands/RicShowContributingWellsFromPlotFeature.cpp b/ApplicationCode/Commands/FlowCommands/RicShowContributingWellsFromPlotFeature.cpp index 40f4e73c58..dc275d9442 100644 --- a/ApplicationCode/Commands/FlowCommands/RicShowContributingWellsFromPlotFeature.cpp +++ b/ApplicationCode/Commands/FlowCommands/RicShowContributingWellsFromPlotFeature.cpp @@ -1,17 +1,17 @@ ///////////////////////////////////////////////////////////////////////////////// // // Copyright (C) 2017 Statoil ASA -// +// // ResInsight 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 3 of the License, or // (at your option) any later version. -// +// // ResInsight 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 at +// +// See the GNU General Public License at // for more details. // ///////////////////////////////////////////////////////////////////////////////// @@ -31,39 +31,41 @@ CAF_CMD_SOURCE_INIT(RicShowContributingWellsFromPlotFeature, "RicShowContributingWellsFromPlotFeature"); //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- bool RicShowContributingWellsFromPlotFeature::isCommandEnabled() { - RimWellAllocationPlot* wellAllocationPlot = dynamic_cast(RiaApplication::instance()->activePlotWindow()); + RimWellAllocationPlot* wellAllocationPlot = + dynamic_cast(RiaApplication::instance()->activePlotWindow()); if (wellAllocationPlot) return true; - + return false; } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RicShowContributingWellsFromPlotFeature::onActionTriggered(bool isChecked) { - RimWellAllocationPlot* wellAllocationPlot = dynamic_cast(RiaApplication::instance()->activePlotWindow()); + RimWellAllocationPlot* wellAllocationPlot = + dynamic_cast(RiaApplication::instance()->activePlotWindow()); if (!wellAllocationPlot) return; - int timeStep = wellAllocationPlot->timeStep(); + int timeStep = wellAllocationPlot->timeStep(); QString wellName = wellAllocationPlot->wellName(); RimEclipseResultCase* wellAllocationResultCase = wellAllocationPlot->rimCase(); - RicShowContributingWellsFeatureImpl::maniuplateSelectedView(wellAllocationResultCase, wellName, timeStep); + RicShowContributingWellsFeatureImpl::manipulateSelectedView(wellAllocationResultCase, wellName, timeStep); } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RicShowContributingWellsFromPlotFeature::setupActionLook(QAction* actionToSetup) { - //actionToSetup->setIcon(QIcon(":/new_icon16x16.png")); + // actionToSetup->setIcon(QIcon(":/new_icon16x16.png")); actionToSetup->setText("Show Contributing Wells"); } diff --git a/ApplicationCode/Commands/FlowCommands/RicShowContributingWellsFromPlotFeature.h b/ApplicationCode/Commands/FlowCommands/RicShowContributingWellsFromPlotFeature.h index 428abc63bd..093d78cab5 100644 --- a/ApplicationCode/Commands/FlowCommands/RicShowContributingWellsFromPlotFeature.h +++ b/ApplicationCode/Commands/FlowCommands/RicShowContributingWellsFromPlotFeature.h @@ -1,17 +1,17 @@ ///////////////////////////////////////////////////////////////////////////////// // // Copyright (C) 2017 Statoil ASA -// +// // ResInsight 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 3 of the License, or // (at your option) any later version. -// +// // ResInsight 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 at +// +// See the GNU General Public License at // for more details. // ///////////////////////////////////////////////////////////////////////////////// @@ -20,19 +20,15 @@ #include "cafCmdFeature.h" - //================================================================================================== -/// +/// //================================================================================================== class RicShowContributingWellsFromPlotFeature : public caf::CmdFeature { CAF_CMD_HEADER_INIT; protected: - // Overrides bool isCommandEnabled() override; - void onActionTriggered( bool isChecked ) override; - void setupActionLook( QAction* actionToSetup ) override; + void onActionTriggered(bool isChecked) override; + void setupActionLook(QAction* actionToSetup) override; }; - - diff --git a/ApplicationCode/Commands/FractureCommands/RicCreateDuplicateTemplateInOtherUnitSystemFeature.cpp b/ApplicationCode/Commands/FractureCommands/RicCreateDuplicateTemplateInOtherUnitSystemFeature.cpp index 4cacae58dd..975ec04997 100644 --- a/ApplicationCode/Commands/FractureCommands/RicCreateDuplicateTemplateInOtherUnitSystemFeature.cpp +++ b/ApplicationCode/Commands/FractureCommands/RicCreateDuplicateTemplateInOtherUnitSystemFeature.cpp @@ -88,7 +88,7 @@ void RicCreateDuplicateTemplateInOtherUnitSystemFeature::onActionTriggered(bool copyOfTemplate->loadDataAndUpdate(); copyOfTemplate->updateConnectedEditors(); - RicNewEllipseFractureTemplateFeature::selectFractureTemplateAndUpdate(fractureTemplateCollection, copyOfTemplate); + RicNewEllipseFractureTemplateFeature::selectFractureTemplateAndUpdate(copyOfTemplate); } //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/Commands/FractureCommands/RicCreateMultipleFracturesFeature.cpp b/ApplicationCode/Commands/FractureCommands/RicCreateMultipleFracturesFeature.cpp index 0992cc5e0f..aceb579cd8 100644 --- a/ApplicationCode/Commands/FractureCommands/RicCreateMultipleFracturesFeature.cpp +++ b/ApplicationCode/Commands/FractureCommands/RicCreateMultipleFracturesFeature.cpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018- Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by diff --git a/ApplicationCode/Commands/FractureCommands/RicCreateMultipleFracturesFeature.h b/ApplicationCode/Commands/FractureCommands/RicCreateMultipleFracturesFeature.h index 39cf157f1b..da99c6d7c9 100644 --- a/ApplicationCode/Commands/FractureCommands/RicCreateMultipleFracturesFeature.h +++ b/ApplicationCode/Commands/FractureCommands/RicCreateMultipleFracturesFeature.h @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018- Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by diff --git a/ApplicationCode/Commands/FractureCommands/RicCreateMultipleFracturesOptionItemUi.cpp b/ApplicationCode/Commands/FractureCommands/RicCreateMultipleFracturesOptionItemUi.cpp index 043a390077..166619f12c 100644 --- a/ApplicationCode/Commands/FractureCommands/RicCreateMultipleFracturesOptionItemUi.cpp +++ b/ApplicationCode/Commands/FractureCommands/RicCreateMultipleFracturesOptionItemUi.cpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018- Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -109,7 +109,7 @@ void RicCreateMultipleFracturesOptionItemUi::fieldChangedByUi(const caf::PdmFiel { if (m_topKOneBased > m_baseKOneBased) m_baseKOneBased = m_topKOneBased; } - else if (changedField = &m_baseKOneBased) + else if (changedField == &m_baseKOneBased) { if (m_baseKOneBased < m_topKOneBased) m_topKOneBased = m_baseKOneBased; } @@ -138,7 +138,7 @@ QList if (fieldNeedingOptions == &m_fractureTemplate) { RimOilField* oilField = proj->activeOilField(); - if (oilField && oilField->fractureDefinitionCollection) + if (oilField && oilField->fractureDefinitionCollection()) { RimFractureTemplateCollection* fracDefColl = oilField->fractureDefinitionCollection(); diff --git a/ApplicationCode/Commands/FractureCommands/RicCreateMultipleFracturesOptionItemUi.h b/ApplicationCode/Commands/FractureCommands/RicCreateMultipleFracturesOptionItemUi.h index dd31db1956..935022bd62 100644 --- a/ApplicationCode/Commands/FractureCommands/RicCreateMultipleFracturesOptionItemUi.h +++ b/ApplicationCode/Commands/FractureCommands/RicCreateMultipleFracturesOptionItemUi.h @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018- Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by diff --git a/ApplicationCode/Commands/FractureCommands/RicCreateMultipleFracturesUi.cpp b/ApplicationCode/Commands/FractureCommands/RicCreateMultipleFracturesUi.cpp index e9d9ec46e5..d3115e76b4 100644 --- a/ApplicationCode/Commands/FractureCommands/RicCreateMultipleFracturesUi.cpp +++ b/ApplicationCode/Commands/FractureCommands/RicCreateMultipleFracturesUi.cpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018- Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by diff --git a/ApplicationCode/Commands/FractureCommands/RicCreateMultipleFracturesUi.h b/ApplicationCode/Commands/FractureCommands/RicCreateMultipleFracturesUi.h index b0114e0ab4..1c95cb3593 100644 --- a/ApplicationCode/Commands/FractureCommands/RicCreateMultipleFracturesUi.h +++ b/ApplicationCode/Commands/FractureCommands/RicCreateMultipleFracturesUi.h @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018- Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by diff --git a/ApplicationCode/Commands/FractureCommands/RicDeleteOptionItemFeature.cpp b/ApplicationCode/Commands/FractureCommands/RicDeleteOptionItemFeature.cpp index 02b73dffaa..8654f7b368 100644 --- a/ApplicationCode/Commands/FractureCommands/RicDeleteOptionItemFeature.cpp +++ b/ApplicationCode/Commands/FractureCommands/RicDeleteOptionItemFeature.cpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018- Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by diff --git a/ApplicationCode/Commands/FractureCommands/RicDeleteOptionItemFeature.h b/ApplicationCode/Commands/FractureCommands/RicDeleteOptionItemFeature.h index a32509d405..9d0174b1b2 100644 --- a/ApplicationCode/Commands/FractureCommands/RicDeleteOptionItemFeature.h +++ b/ApplicationCode/Commands/FractureCommands/RicDeleteOptionItemFeature.h @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018- Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by diff --git a/ApplicationCode/Commands/FractureCommands/RicNewEllipseFractureTemplateFeature.cpp b/ApplicationCode/Commands/FractureCommands/RicNewEllipseFractureTemplateFeature.cpp index b23ecc84ab..0d7bdf8aaf 100644 --- a/ApplicationCode/Commands/FractureCommands/RicNewEllipseFractureTemplateFeature.cpp +++ b/ApplicationCode/Commands/FractureCommands/RicNewEllipseFractureTemplateFeature.cpp @@ -1,6 +1,7 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2016- Statoil ASA +// Copyright (C) 2016-2018 Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -25,6 +26,7 @@ #include "RimFractureTemplateCollection.h" #include "RimOilField.h" #include "RimProject.h" +#include "RimWellPathFracture.h" #include "Riu3DMainWindowTools.h" @@ -39,25 +41,27 @@ CAF_CMD_SOURCE_INIT(RicNewEllipseFractureTemplateFeature, "RicNewEllipseFracture //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RicNewEllipseFractureTemplateFeature::selectFractureTemplateAndUpdate(RimFractureTemplateCollection* templateCollection, - RimFractureTemplate* fractureTemplate) +void RicNewEllipseFractureTemplateFeature::createNewTemplateForFractureAndUpdate(RimFracture* fracture) +{ + RimEllipseFractureTemplate* fractureTemplate = createNewTemplate(); + fracture->setFractureTemplate(fractureTemplate); + selectFractureTemplateAndUpdate(fractureTemplate); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicNewEllipseFractureTemplateFeature::selectFractureTemplateAndUpdate(RimFractureTemplate* fractureTemplate) { fractureTemplate->loadDataAndUpdate(); + RimFractureTemplateCollection* templateCollection = nullptr; + fractureTemplate->firstAncestorOrThisOfTypeAsserted(templateCollection); templateCollection->updateConnectedEditors(); RimProject* project = RiaApplication::instance()->project(); - - std::vector views; - project->allVisibleViews(views); - - for (Rim3dView* view : views) - { - if (dynamic_cast(view)) - { - view->updateConnectedEditors(); - } - } + + project->scheduleCreateDisplayModelAndRedrawAllViews(); Riu3DMainWindowTools::selectAsCurrentItem(fractureTemplate); } @@ -65,27 +69,30 @@ void RicNewEllipseFractureTemplateFeature::selectFractureTemplateAndUpdate(RimFr //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RicNewEllipseFractureTemplateFeature::onActionTriggered(bool isChecked) +RimEllipseFractureTemplate* RicNewEllipseFractureTemplateFeature::createNewTemplate() { - RimProject* project = RiaApplication::instance()->project(); + RimProject* project = RiaApplication::instance()->project(); CVF_ASSERT(project); RimOilField* oilfield = project->activeOilField(); - if (oilfield == nullptr) return; + if (oilfield == nullptr) return nullptr; RimFractureTemplateCollection* fracDefColl = oilfield->fractureDefinitionCollection(); if (fracDefColl) { - RimEllipseFractureTemplate* ellipseFractureTemplate = new RimEllipseFractureTemplate(); - - fracDefColl->addFractureTemplate(ellipseFractureTemplate); - ellipseFractureTemplate->setName("Ellipse Fracture Template"); - ellipseFractureTemplate->setFractureTemplateUnit(fracDefColl->defaultUnitSystemType()); - ellipseFractureTemplate->setDefaultValuesFromUnit(); - - selectFractureTemplateAndUpdate(fracDefColl, ellipseFractureTemplate); + return fracDefColl->addDefaultEllipseTemplate(); } + return nullptr; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicNewEllipseFractureTemplateFeature::onActionTriggered(bool isChecked) +{ + RimEllipseFractureTemplate* ellipseFractureTemplate = createNewTemplate(); + selectFractureTemplateAndUpdate(ellipseFractureTemplate); } //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/Commands/FractureCommands/RicNewEllipseFractureTemplateFeature.h b/ApplicationCode/Commands/FractureCommands/RicNewEllipseFractureTemplateFeature.h index 26a440b44c..118a76f7b2 100644 --- a/ApplicationCode/Commands/FractureCommands/RicNewEllipseFractureTemplateFeature.h +++ b/ApplicationCode/Commands/FractureCommands/RicNewEllipseFractureTemplateFeature.h @@ -1,6 +1,8 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2016- Statoil ASA +// Copyright (C) 2016-2018 Statoil ASA +// Copyright (C) 2018- Equinor ASA + // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -22,6 +24,8 @@ #include +class RimEllipseFractureTemplate; +class RimFracture; class RimFractureTemplate; class RimFractureTemplateCollection; @@ -33,10 +37,10 @@ class RicNewEllipseFractureTemplateFeature : public caf::CmdFeature CAF_CMD_HEADER_INIT; public: - static void selectFractureTemplateAndUpdate(RimFractureTemplateCollection* templateCollection, - RimFractureTemplate* ellipseFractureTemplate); - + static void createNewTemplateForFractureAndUpdate(RimFracture* fracture); + static void selectFractureTemplateAndUpdate(RimFractureTemplate* fractureTemplate); protected: + static RimEllipseFractureTemplate* createNewTemplate(); void onActionTriggered(bool isChecked) override; void setupActionLook(QAction* actionToSetup) override; bool isCommandEnabled() override; diff --git a/ApplicationCode/Commands/FractureCommands/RicNewOptionItemFeature.cpp b/ApplicationCode/Commands/FractureCommands/RicNewOptionItemFeature.cpp index 16809fa500..f18d3ee796 100644 --- a/ApplicationCode/Commands/FractureCommands/RicNewOptionItemFeature.cpp +++ b/ApplicationCode/Commands/FractureCommands/RicNewOptionItemFeature.cpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018- Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by diff --git a/ApplicationCode/Commands/FractureCommands/RicNewOptionItemFeature.h b/ApplicationCode/Commands/FractureCommands/RicNewOptionItemFeature.h index 5dafff108d..8d570760a5 100644 --- a/ApplicationCode/Commands/FractureCommands/RicNewOptionItemFeature.h +++ b/ApplicationCode/Commands/FractureCommands/RicNewOptionItemFeature.h @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018- Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by diff --git a/ApplicationCode/Commands/FractureCommands/RicNewSimWellFractureAtPosFeature.cpp b/ApplicationCode/Commands/FractureCommands/RicNewSimWellFractureAtPosFeature.cpp index e02543f14c..4e2c2eec18 100644 --- a/ApplicationCode/Commands/FractureCommands/RicNewSimWellFractureAtPosFeature.cpp +++ b/ApplicationCode/Commands/FractureCommands/RicNewSimWellFractureAtPosFeature.cpp @@ -35,7 +35,7 @@ #include "RimStimPlanColors.h" #include "Riu3DMainWindowTools.h" -#include "RiuSelectionManager.h" +#include "Riu3dSelectionManager.h" #include "RivSimWellPipeSourceInfo.h" #include "cafSelectionManager.h" @@ -57,8 +57,8 @@ void RicNewSimWellFractureAtPosFeature::onActionTriggered(bool isChecked) Rim3dView* activeView = RiaApplication::instance()->activeReservoirView(); if (!activeView) return; - RiuSelectionManager* riuSelManager = RiuSelectionManager::instance(); - RiuSelectionItem* selItem = riuSelManager->selectedItem(RiuSelectionManager::RUI_TEMPORARY); + Riu3dSelectionManager* riuSelManager = Riu3dSelectionManager::instance(); + RiuSelectionItem* selItem = riuSelManager->selectedItem(Riu3dSelectionManager::RUI_TEMPORARY); RiuSimWellSelectionItem* simWellItem = static_cast(selItem); if (!simWellItem) return; @@ -105,7 +105,7 @@ void RicNewSimWellFractureAtPosFeature::onActionTriggered(bool isChecked) fracture->setFractureUnit(unitSet); } - RimFractureTemplate* fracDef = oilfield->fractureDefinitionCollection->firstFractureOfUnit(unitSet); + RimFractureTemplate* fracDef = oilfield->fractureDefinitionCollection()->firstFractureOfUnit(unitSet); fracture->setFractureTemplate(fracDef); simWell->updateConnectedEditors(); @@ -129,7 +129,7 @@ void RicNewSimWellFractureAtPosFeature::onActionTriggered(bool isChecked) void RicNewSimWellFractureAtPosFeature::setupActionLook(QAction* actionToSetup) { actionToSetup->setIcon(QIcon(":/FractureSymbol16x16.png")); - actionToSetup->setText("New Fracture"); + actionToSetup->setText("Create Fracture"); } //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/Commands/FractureCommands/RicNewSimWellFractureFeature.cpp b/ApplicationCode/Commands/FractureCommands/RicNewSimWellFractureFeature.cpp index b6e83e4ef8..950011c593 100644 --- a/ApplicationCode/Commands/FractureCommands/RicNewSimWellFractureFeature.cpp +++ b/ApplicationCode/Commands/FractureCommands/RicNewSimWellFractureFeature.cpp @@ -92,7 +92,7 @@ void RicNewSimWellFractureFeature::onActionTriggered(bool isChecked) fracture->setFractureUnit(unitSet); } - RimFractureTemplate* fracDef = oilfield->fractureDefinitionCollection->firstFractureOfUnit(unitSet); + RimFractureTemplate* fracDef = oilfield->fractureDefinitionCollection()->firstFractureOfUnit(unitSet); fracture->setFractureTemplate(fracDef); fracture->updateFracturePositionFromLocation(); diff --git a/ApplicationCode/Commands/FractureCommands/RicNewStimPlanFractureTemplateFeature.cpp b/ApplicationCode/Commands/FractureCommands/RicNewStimPlanFractureTemplateFeature.cpp index e3e231be1c..cbc13c5c97 100644 --- a/ApplicationCode/Commands/FractureCommands/RicNewStimPlanFractureTemplateFeature.cpp +++ b/ApplicationCode/Commands/FractureCommands/RicNewStimPlanFractureTemplateFeature.cpp @@ -1,6 +1,7 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2017- Statoil ASA +// Copyright (C) 2017-2018 Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -25,6 +26,7 @@ #include "RimOilField.h" #include "RimProject.h" #include "RimStimPlanFractureTemplate.h" +#include "RimWellPathFracture.h" #include "Riu3DMainWindowTools.h" @@ -39,26 +41,60 @@ CAF_CMD_SOURCE_INIT(RicNewStimPlanFractureTemplateFeature, "RicNewStimPlanFractureTemplateFeature"); //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- -void RicNewStimPlanFractureTemplateFeature::onActionTriggered(bool isChecked) +void RicNewStimPlanFractureTemplateFeature::createNewTemplateForFractureAndUpdate(RimFracture* fracture) +{ + std::vector newTemplates = createNewTemplates(); + if (!newTemplates.empty()) + { + RimStimPlanFractureTemplate* lastTemplateCreated = newTemplates.back(); + fracture->setFractureTemplate(lastTemplateCreated); + + selectFractureTemplateAndUpdate(lastTemplateCreated); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicNewStimPlanFractureTemplateFeature::selectFractureTemplateAndUpdate(RimFractureTemplate* fractureTemplate) { - RiaApplication* app = RiaApplication::instance(); - QString defaultDir = app->lastUsedDialogDirectory("BINARY_GRID"); - QStringList fileNames = QFileDialog::getOpenFileNames(nullptr, "Open StimPlan XML File", defaultDir, "StimPlan XML File (*.xml);;All files(*.*)"); + fractureTemplate->loadDataAndUpdate(); - if (fileNames.isEmpty()) return; + RimFractureTemplateCollection* templateCollection = nullptr; + fractureTemplate->firstAncestorOrThisOfTypeAsserted(templateCollection); + templateCollection->updateConnectedEditors(); + + RimProject* project = RiaApplication::instance()->project(); + + project->scheduleCreateDisplayModelAndRedrawAllViews(); + Riu3DMainWindowTools::selectAsCurrentItem(fractureTemplate); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector RicNewStimPlanFractureTemplateFeature::createNewTemplates() +{ + RiaApplication* app = RiaApplication::instance(); + QString defaultDir = app->lastUsedDialogDirectory("BINARY_GRID"); + QStringList fileNames = + QFileDialog::getOpenFileNames(nullptr, "Open StimPlan XML File", defaultDir, "StimPlan XML File (*.xml);;All files(*.*)"); + + if (fileNames.isEmpty()) return std::vector(); RimProject* project = RiaApplication::instance()->project(); CVF_ASSERT(project); RimOilField* oilfield = project->activeOilField(); - if (oilfield == nullptr) return; + if (oilfield == nullptr) return std::vector(); RimFractureTemplateCollection* fracDefColl = oilfield->fractureDefinitionCollection(); - if (!fracDefColl) return; + if (!fracDefColl) return std::vector(); - for(auto fileName : fileNames) + std::vector newFractures; + for (auto fileName : fileNames) { if (fileName.isEmpty()) continue; @@ -66,7 +102,7 @@ void RicNewStimPlanFractureTemplateFeature::onActionTriggered(bool isChecked) fracDefColl->addFractureTemplate(fractureDef); QFileInfo stimplanfileFileInfo(fileName); - QString name = stimplanfileFileInfo.baseName(); + QString name = stimplanfileFileInfo.baseName(); if (name.isEmpty()) { name = "StimPlan Fracture Template"; @@ -79,21 +115,20 @@ void RicNewStimPlanFractureTemplateFeature::onActionTriggered(bool isChecked) fractureDef->setDefaultsBasedOnXMLfile(); fractureDef->setDefaultWellDiameterFromUnit(); fractureDef->updateFractureGrid(); + newFractures.push_back(fractureDef); + } + return newFractures; +} - fracDefColl->updateConnectedEditors(); - - std::vector views; - project->allVisibleViews(views); - - for (Rim3dView* view : views) - { - if (dynamic_cast(view)) - { - view->updateConnectedEditors(); - } - } - - Riu3DMainWindowTools::selectAsCurrentItem(fractureDef); +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicNewStimPlanFractureTemplateFeature::onActionTriggered(bool isChecked) +{ + std::vector newFractures = createNewTemplates(); + if (!newFractures.empty()) + { + selectFractureTemplateAndUpdate(newFractures.back()); } } diff --git a/ApplicationCode/Commands/FractureCommands/RicNewStimPlanFractureTemplateFeature.h b/ApplicationCode/Commands/FractureCommands/RicNewStimPlanFractureTemplateFeature.h index 271af8184d..bd17b5075b 100644 --- a/ApplicationCode/Commands/FractureCommands/RicNewStimPlanFractureTemplateFeature.h +++ b/ApplicationCode/Commands/FractureCommands/RicNewStimPlanFractureTemplateFeature.h @@ -1,6 +1,7 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2017- Statoil ASA +// Copyright (C) 2017-2018 Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -22,6 +23,9 @@ #include +class RimFracture; +class RimFractureTemplate; +class RimStimPlanFractureTemplate; //================================================================================================== /// @@ -29,8 +33,11 @@ class RicNewStimPlanFractureTemplateFeature : public caf::CmdFeature { CAF_CMD_HEADER_INIT; -protected: + static void createNewTemplateForFractureAndUpdate(RimFracture* fracture); + static void selectFractureTemplateAndUpdate(RimFractureTemplate* fractureTemplate); +protected: + static std::vector createNewTemplates(); void onActionTriggered(bool isChecked) override; void setupActionLook(QAction* actionToSetup) override; bool isCommandEnabled() override; diff --git a/ApplicationCode/Commands/FractureCommands/RicNewWellPathFractureAtPosFeature.cpp b/ApplicationCode/Commands/FractureCommands/RicNewWellPathFractureAtPosFeature.cpp index 3b2368b175..4e43050739 100644 --- a/ApplicationCode/Commands/FractureCommands/RicNewWellPathFractureAtPosFeature.cpp +++ b/ApplicationCode/Commands/FractureCommands/RicNewWellPathFractureAtPosFeature.cpp @@ -24,7 +24,7 @@ #include "RimProject.h" -#include "RiuSelectionManager.h" +#include "Riu3dSelectionManager.h" #include @@ -37,11 +37,8 @@ CAF_CMD_SOURCE_INIT(RicNewWellPathFractureAtPosFeature, "RicNewWellPathFractureA //-------------------------------------------------------------------------------------------------- void RicNewWellPathFractureAtPosFeature::onActionTriggered(bool isChecked) { - RimProject* proj = RiaApplication::instance()->project(); - if (proj->allFractureTemplates().empty()) return; - - RiuSelectionManager* riuSelManager = RiuSelectionManager::instance(); - RiuSelectionItem* selItem = riuSelManager->selectedItem(RiuSelectionManager::RUI_TEMPORARY); + Riu3dSelectionManager* riuSelManager = Riu3dSelectionManager::instance(); + RiuSelectionItem* selItem = riuSelManager->selectedItem(Riu3dSelectionManager::RUI_TEMPORARY); RiuWellPathSelectionItem* wellPathItem = dynamic_cast(selItem); if (!wellPathItem) return; @@ -58,7 +55,7 @@ void RicNewWellPathFractureAtPosFeature::onActionTriggered(bool isChecked) void RicNewWellPathFractureAtPosFeature::setupActionLook(QAction* actionToSetup) { actionToSetup->setIcon(QIcon(":/FractureSymbol16x16.png")); - actionToSetup->setText("New Fracture"); + actionToSetup->setText("Create Fracture at this Depth"); } //-------------------------------------------------------------------------------------------------- @@ -66,8 +63,5 @@ void RicNewWellPathFractureAtPosFeature::setupActionLook(QAction* actionToSetup) //-------------------------------------------------------------------------------------------------- bool RicNewWellPathFractureAtPosFeature::isCommandEnabled() { - RimProject* proj = RiaApplication::instance()->project(); - if (proj->allFractureTemplates().empty()) return false; - return true; } diff --git a/ApplicationCode/Commands/FractureCommands/RicNewWellPathFractureFeature.cpp b/ApplicationCode/Commands/FractureCommands/RicNewWellPathFractureFeature.cpp index bf376908e6..33c1799a5d 100644 --- a/ApplicationCode/Commands/FractureCommands/RicNewWellPathFractureFeature.cpp +++ b/ApplicationCode/Commands/FractureCommands/RicNewWellPathFractureFeature.cpp @@ -1,6 +1,7 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2016- Statoil ASA +// Copyright (C) 2016-2018 Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -26,13 +27,13 @@ #include "RimCase.h" #include "RimEclipseView.h" -#include "RimEllipseFractureTemplate.h" #include "RimFractureTemplateCollection.h" #include "RimOilField.h" #include "RimProject.h" #include "RimStimPlanColors.h" #include "RimWellPath.h" #include "RimWellPathCollection.h" +#include "RimWellPathCompletions.h" #include "RimWellPathFracture.h" #include "RimWellPathFractureCollection.h" @@ -89,8 +90,11 @@ void RicNewWellPathFractureFeature::addFracture(RimWellPath* wellPath, double me auto unitSet = wellPath->unitSystem(); fracture->setFractureUnit(unitSet); - RimFractureTemplate* fracDef = oilfield->fractureDefinitionCollection->firstFractureOfUnit(unitSet); - fracture->setFractureTemplate(fracDef); + RimFractureTemplate* fracDef = oilfield->fractureDefinitionCollection()->firstFractureOfUnit(unitSet); + if (fracDef) + { + fracture->setFractureTemplate(fracDef); + } wellPath->updateConnectedEditors(); Riu3DMainWindowTools::selectAsCurrentItem(fracture); @@ -108,9 +112,6 @@ void RicNewWellPathFractureFeature::addFracture(RimWellPath* wellPath, double me //-------------------------------------------------------------------------------------------------- void RicNewWellPathFractureFeature::onActionTriggered(bool isChecked) { - RimProject* proj = RiaApplication::instance()->project(); - if (proj->allFractureTemplates().empty()) return; - RimWellPathFractureCollection* fractureColl = RicNewWellPathFractureFeature::selectedWellPathFractureCollection(); if (!fractureColl) return; @@ -127,7 +128,7 @@ void RicNewWellPathFractureFeature::onActionTriggered(bool isChecked) void RicNewWellPathFractureFeature::setupActionLook(QAction* actionToSetup) { actionToSetup->setIcon(QIcon(":/FractureSymbol16x16.png")); - actionToSetup->setText("New Fracture"); + actionToSetup->setText("Create Fracture"); } //-------------------------------------------------------------------------------------------------- @@ -135,9 +136,6 @@ void RicNewWellPathFractureFeature::setupActionLook(QAction* actionToSetup) //-------------------------------------------------------------------------------------------------- bool RicNewWellPathFractureFeature::isCommandEnabled() { - RimProject* proj = RiaApplication::instance()->project(); - if (proj->allFractureTemplates().empty()) return false; - if (selectedWellPathFractureCollection()) { return true; @@ -151,9 +149,13 @@ bool RicNewWellPathFractureFeature::isCommandEnabled() //-------------------------------------------------------------------------------------------------- RimWellPathFractureCollection* RicNewWellPathFractureFeature::selectedWellPathFractureCollection() { + std::vector allSelectedItems; + caf::SelectionManager::instance()->selectedItems(allSelectedItems); + if (allSelectedItems.size() != 1u) return nullptr; + RimWellPathFractureCollection* objToFind = nullptr; - caf::PdmUiItem* pdmUiItem = caf::SelectionManager::instance()->selectedItem(); + caf::PdmUiItem* pdmUiItem = allSelectedItems.front(); caf::PdmObjectHandle* objHandle = dynamic_cast(pdmUiItem); if (objHandle) @@ -169,6 +171,11 @@ RimWellPathFractureCollection* RicNewWellPathFractureFeature::selectedWellPathFr { return wellPaths[0]->fractureCollection(); } + RimWellPathCompletions* completions = caf::SelectionManager::instance()->selectedItemOfType(); + if (completions) + { + return completions->fractureCollection(); + } } return objToFind; diff --git a/ApplicationCode/Commands/FractureCommands/RicPasteEllipseFractureFeature.cpp b/ApplicationCode/Commands/FractureCommands/RicPasteEllipseFractureFeature.cpp index 068b7bd101..a08619812a 100644 --- a/ApplicationCode/Commands/FractureCommands/RicPasteEllipseFractureFeature.cpp +++ b/ApplicationCode/Commands/FractureCommands/RicPasteEllipseFractureFeature.cpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018 Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -78,7 +78,7 @@ void RicPasteEllipseFractureFeature::onActionTriggered(bool isChecked) fractureTemplateColl->addFractureTemplate(templ); - RicNewEllipseFractureTemplateFeature::selectFractureTemplateAndUpdate(fractureTemplateColl, templ); + RicNewEllipseFractureTemplateFeature::selectFractureTemplateAndUpdate(templ); } return; diff --git a/ApplicationCode/Commands/FractureCommands/RicPasteEllipseFractureFeature.h b/ApplicationCode/Commands/FractureCommands/RicPasteEllipseFractureFeature.h index 51ab307958..82c2432e9e 100644 --- a/ApplicationCode/Commands/FractureCommands/RicPasteEllipseFractureFeature.h +++ b/ApplicationCode/Commands/FractureCommands/RicPasteEllipseFractureFeature.h @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018 Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by diff --git a/ApplicationCode/Commands/FractureCommands/RicPasteStimPlanFractureFeature.cpp b/ApplicationCode/Commands/FractureCommands/RicPasteStimPlanFractureFeature.cpp index ed429b4219..1ad8443e1a 100644 --- a/ApplicationCode/Commands/FractureCommands/RicPasteStimPlanFractureFeature.cpp +++ b/ApplicationCode/Commands/FractureCommands/RicPasteStimPlanFractureFeature.cpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018 Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -78,7 +78,7 @@ void RicPasteStimPlanFractureFeature::onActionTriggered(bool isChecked) fractureTemplateColl->addFractureTemplate(copyOfStimPlanTemplate); - RicNewEllipseFractureTemplateFeature::selectFractureTemplateAndUpdate(fractureTemplateColl, copyOfStimPlanTemplate); + RicNewEllipseFractureTemplateFeature::selectFractureTemplateAndUpdate(copyOfStimPlanTemplate); } return; diff --git a/ApplicationCode/Commands/FractureCommands/RicPasteStimPlanFractureFeature.h b/ApplicationCode/Commands/FractureCommands/RicPasteStimPlanFractureFeature.h index f49bb8e7be..3d9857cb67 100644 --- a/ApplicationCode/Commands/FractureCommands/RicPasteStimPlanFractureFeature.h +++ b/ApplicationCode/Commands/FractureCommands/RicPasteStimPlanFractureFeature.h @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018 Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by diff --git a/ApplicationCode/Commands/GridCrossPlotCommands/CMakeLists_files.cmake b/ApplicationCode/Commands/GridCrossPlotCommands/CMakeLists_files.cmake new file mode 100644 index 0000000000..a2333941be --- /dev/null +++ b/ApplicationCode/Commands/GridCrossPlotCommands/CMakeLists_files.cmake @@ -0,0 +1,28 @@ + +set (SOURCE_GROUP_HEADER_FILES +${CMAKE_CURRENT_LIST_DIR}/RicCreateGridCrossPlotFeature.h +${CMAKE_CURRENT_LIST_DIR}/RicCreateGridCrossPlotDataSetFeature.h +${CMAKE_CURRENT_LIST_DIR}/RicSwapGridCrossPlotDataSetAxesFeature.h +${CMAKE_CURRENT_LIST_DIR}/RicPasteGridCrossPlotDataSetFeature.h +${CMAKE_CURRENT_LIST_DIR}/RicCreateSaturationPressurePlotsFeature.h +${CMAKE_CURRENT_LIST_DIR}/RicSaturationPressureUi.h +) + +set (SOURCE_GROUP_SOURCE_FILES +${CMAKE_CURRENT_LIST_DIR}/RicCreateGridCrossPlotFeature.cpp +${CMAKE_CURRENT_LIST_DIR}/RicCreateGridCrossPlotDataSetFeature.cpp +${CMAKE_CURRENT_LIST_DIR}/RicSwapGridCrossPlotDataSetAxesFeature.cpp +${CMAKE_CURRENT_LIST_DIR}/RicPasteGridCrossPlotDataSetFeature.cpp +${CMAKE_CURRENT_LIST_DIR}/RicCreateSaturationPressurePlotsFeature.cpp +${CMAKE_CURRENT_LIST_DIR}/RicSaturationPressureUi.cpp +) + +list(APPEND CODE_HEADER_FILES +${SOURCE_GROUP_HEADER_FILES} +) + +list(APPEND CODE_SOURCE_FILES +${SOURCE_GROUP_SOURCE_FILES} +) + +source_group( "CommandFeature\\GridCrossPlot" FILES ${SOURCE_GROUP_HEADER_FILES} ${SOURCE_GROUP_SOURCE_FILES} ${CMAKE_CURRENT_LIST_DIR}/CMakeLists_files.cmake ) diff --git a/ApplicationCode/Commands/GridCrossPlotCommands/RicCreateGridCrossPlotDataSetFeature.cpp b/ApplicationCode/Commands/GridCrossPlotCommands/RicCreateGridCrossPlotDataSetFeature.cpp new file mode 100644 index 0000000000..dd64da706d --- /dev/null +++ b/ApplicationCode/Commands/GridCrossPlotCommands/RicCreateGridCrossPlotDataSetFeature.cpp @@ -0,0 +1,63 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2019- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// +#include "RicCreateGridCrossPlotDataSetFeature.h" + +#include "RiaApplication.h" + +#include "RimGridCrossPlot.h" +#include "RimGridCrossPlotDataSet.h" +#include "RimProject.h" + +#include "RiuPlotMainWindowTools.h" + +#include "cafSelectionManager.h" + +#include + +CAF_CMD_SOURCE_INIT(RicCreateGridCrossPlotDataSetFeature, "RicCreateGridCrossPlotDataSetFeature"); + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RicCreateGridCrossPlotDataSetFeature::isCommandEnabled() +{ + return caf::SelectionManager::instance()->selectedItemOfType() != nullptr; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicCreateGridCrossPlotDataSetFeature::onActionTriggered(bool isChecked) +{ + RimGridCrossPlot* crossPlot = caf::SelectionManager::instance()->selectedItemOfType(); + + RimGridCrossPlotDataSet* dataSet = crossPlot->createDataSet(); + dataSet->loadDataAndUpdate(true); + + RiaApplication::instance()->getOrCreateMainPlotWindow(); + RiuPlotMainWindowTools::selectAsCurrentItem(dataSet); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicCreateGridCrossPlotDataSetFeature::setupActionLook(QAction* actionToSetup) +{ + actionToSetup->setText("Create Data Set"); + actionToSetup->setIcon(QIcon(":/WellLogCurve16x16.png")); +} diff --git a/ApplicationCode/Commands/GridCrossPlotCommands/RicCreateGridCrossPlotDataSetFeature.h b/ApplicationCode/Commands/GridCrossPlotCommands/RicCreateGridCrossPlotDataSetFeature.h new file mode 100644 index 0000000000..71b04739ac --- /dev/null +++ b/ApplicationCode/Commands/GridCrossPlotCommands/RicCreateGridCrossPlotDataSetFeature.h @@ -0,0 +1,36 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2019- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// +#pragma once + +#include "cafCmdFeature.h" + +//================================================================================================== +/// +//================================================================================================== +class RicCreateGridCrossPlotDataSetFeature : public caf::CmdFeature +{ + CAF_CMD_HEADER_INIT; + +protected: + bool isCommandEnabled() override; + void onActionTriggered(bool isChecked) override; + void setupActionLook(QAction* actionToSetup) override; +}; + + + diff --git a/ApplicationCode/Commands/GridCrossPlotCommands/RicCreateGridCrossPlotFeature.cpp b/ApplicationCode/Commands/GridCrossPlotCommands/RicCreateGridCrossPlotFeature.cpp new file mode 100644 index 0000000000..b25e39c465 --- /dev/null +++ b/ApplicationCode/Commands/GridCrossPlotCommands/RicCreateGridCrossPlotFeature.cpp @@ -0,0 +1,94 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2019- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// +#include "RicCreateGridCrossPlotFeature.h" + +#include "RiaApplication.h" + +#include "RimEclipseView.h" +#include "RimGridCrossPlot.h" +#include "RimGridCrossPlotCollection.h" +#include "RimGridCrossPlotDataSet.h" +#include "RimGridView.h" +#include "RimMainPlotCollection.h" +#include "RimProject.h" + +#include "RiuPlotMainWindowTools.h" + +#include "cafSelectionManager.h" + +#include + +CAF_CMD_SOURCE_INIT(RicCreateGridCrossPlotFeature, "RicCreateGridCrossPlotFeature"); + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RicCreateGridCrossPlotFeature::isCommandEnabled() +{ + return true; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicCreateGridCrossPlotFeature::onActionTriggered(bool isChecked) +{ + RimProject* project = RiaApplication::instance()->project(); + + bool launchedFromPlotCollection = true; + RimGridCrossPlotCollection* collection = + caf::SelectionManager::instance()->selectedItemAncestorOfType(); + if (!collection) + { + collection = project->mainPlotCollection()->gridCrossPlotCollection(); + launchedFromPlotCollection = false; + } + RimGridCrossPlot* plot = collection->createGridCrossPlot(); + RimGridCrossPlotDataSet* dataSet = plot->createDataSet(); + + if (!launchedFromPlotCollection) + { + dataSet->setCellFilterView(RiaApplication::instance()->activeGridView()); + } + + plot->loadDataAndUpdate(); + plot->zoomAll(); + plot->updateConnectedEditors(); + + collection->updateAllRequiredEditors(); + RiaApplication::instance()->getOrCreateAndShowMainPlotWindow(); + RiuPlotMainWindowTools::selectAsCurrentItem(dataSet); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicCreateGridCrossPlotFeature::setupActionLook(QAction* actionToSetup) +{ + RimGridCrossPlotCollection* collection = + caf::SelectionManager::instance()->selectedItemAncestorOfType(); + if (!collection) + { + actionToSetup->setText("Create Grid Cross Plot from 3d View"); + } + else + { + actionToSetup->setText("Create Grid Cross Plot"); + } + actionToSetup->setIcon(QIcon(":/SummaryXPlotsLight16x16.png")); +} diff --git a/ApplicationCode/Commands/GridCrossPlotCommands/RicCreateGridCrossPlotFeature.h b/ApplicationCode/Commands/GridCrossPlotCommands/RicCreateGridCrossPlotFeature.h new file mode 100644 index 0000000000..eef808f046 --- /dev/null +++ b/ApplicationCode/Commands/GridCrossPlotCommands/RicCreateGridCrossPlotFeature.h @@ -0,0 +1,37 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2019- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// +#pragma once + +#include "cafCmdFeature.h" + +#include + +//================================================================================================== +/// +//================================================================================================== +class RicCreateGridCrossPlotFeature : public caf::CmdFeature +{ + CAF_CMD_HEADER_INIT; + +protected: + bool isCommandEnabled() override; + void onActionTriggered(bool isChecked) override; + void setupActionLook(QAction* actionToSetup) override; +}; + + diff --git a/ApplicationCode/Commands/GridCrossPlotCommands/RicCreateSaturationPressurePlotsFeature.cpp b/ApplicationCode/Commands/GridCrossPlotCommands/RicCreateSaturationPressurePlotsFeature.cpp new file mode 100644 index 0000000000..a290bccfe6 --- /dev/null +++ b/ApplicationCode/Commands/GridCrossPlotCommands/RicCreateSaturationPressurePlotsFeature.cpp @@ -0,0 +1,200 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2019- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "RicCreateSaturationPressurePlotsFeature.h" +#include "RicSaturationPressureUi.h" + +#include "RiaApplication.h" +#include "RiaLogging.h" +#include "RiaPorosityModel.h" + +#include "RigCaseCellResultsData.h" +#include "RigEclipseCaseData.h" +#include "RigEclipseResultAddress.h" +#include "RigEquil.h" + +#include "RimEclipseResultCase.h" +#include "RimMainPlotCollection.h" +#include "RimProject.h" +#include "RimSaturationPressurePlot.h" +#include "RimSaturationPressurePlotCollection.h" + +#include "RiuPlotMainWindow.h" +#include "RiuPlotMainWindowTools.h" + +#include "cafPdmUiPropertyViewDialog.h" +#include "cafSelectionManager.h" + +#include +#include + +CAF_CMD_SOURCE_INIT(RicCreateSaturationPressurePlotsFeature, "RicCreateSaturationPressurePlotsFeature"); + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector + RicCreateSaturationPressurePlotsFeature::createPlots(RimEclipseResultCase* eclipseResultCase) +{ + std::vector plots; + + if (!eclipseResultCase) + { + RiaLogging::error( + "RicCreateSaturationPressurePlotsFeature:: No case specified for creation of saturation pressure plots"); + + return plots; + } + + RimProject* project = RiaApplication::instance()->project(); + + RimSaturationPressurePlotCollection* collection = project->mainPlotCollection()->saturationPressurePlotCollection(); + + if (eclipseResultCase && eclipseResultCase->ensureReservoirCaseIsOpen()) + { + eclipseResultCase->ensureDeckIsParsedForEquilData(); + + RigEclipseCaseData* eclipseCaseData = eclipseResultCase->eclipseCaseData(); + + bool requiredInputDataPresent = false; + if (!eclipseCaseData->equilData().empty()) + { + if (eclipseCaseData && eclipseCaseData->results(RiaDefines::MATRIX_MODEL)) + { + RigCaseCellResultsData* resultData = eclipseCaseData->results(RiaDefines::MATRIX_MODEL); + + if (resultData->hasResultEntry(RigEclipseResultAddress(RiaDefines::DYNAMIC_NATIVE, "PRESSURE")) && + resultData->hasResultEntry(RigEclipseResultAddress(RiaDefines::DYNAMIC_NATIVE, "PDEW")) && + resultData->hasResultEntry(RigEclipseResultAddress(RiaDefines::DYNAMIC_NATIVE, "PBUB"))) + { + requiredInputDataPresent = true; + } + } + } + + if (requiredInputDataPresent) + { + plots = collection->createSaturationPressurePlots(eclipseResultCase); + for (auto plot : plots) + { + plot->loadDataAndUpdate(); + plot->zoomAll(); + plot->updateConnectedEditors(); + } + } + } + + return plots; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RicCreateSaturationPressurePlotsFeature::isCommandEnabled() +{ + return true; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicCreateSaturationPressurePlotsFeature::onActionTriggered(bool isChecked) +{ + RimProject* project = RiaApplication::instance()->project(); + + RimSaturationPressurePlotCollection* collection = project->mainPlotCollection()->saturationPressurePlotCollection(); + + std::vector eclipseCases; + { + RiaApplication* app = RiaApplication::instance(); + std::vector cases; + app->project()->allCases(cases); + for (auto* rimCase : cases) + { + auto erc = dynamic_cast(rimCase); + if (erc) + { + eclipseCases.push_back(erc); + } + } + } + + RimEclipseResultCase* eclipseResultCase = nullptr; + + if (!eclipseCases.empty()) + { + if (eclipseCases.size() == 1) + { + eclipseResultCase = eclipseCases[0]; + } + else + { + RicSaturationPressureUi saturationPressureUi; + saturationPressureUi.setSelectedCase(eclipseCases[0]); + + RiuPlotMainWindow* plotwindow = RiaApplication::instance()->mainPlotWindow(); + + caf::PdmUiPropertyViewDialog propertyDialog( + plotwindow, &saturationPressureUi, "Select Case to create Pressure Saturation plots", ""); + + if (propertyDialog.exec() == QDialog::Accepted) + { + eclipseResultCase = dynamic_cast(saturationPressureUi.selectedCase()); + } + } + } + + caf::PdmObject* objectToSelect = nullptr; + + std::vector plots = createPlots(eclipseResultCase); + if (plots.empty()) + { + QString text = "No plots generated.\n\n"; + text += "Data required to generate saturation/pressure plots:\n"; + text += " - EQLNUM property defining at least one region\n"; + text += " - Dynamic properties PRESSURE, PBUB and PDEW\n\n"; + text += "Make sure to add 'PBPD' to the RPTRST keyword in the SOLUTION selection. "; + text += "If this is a two phase run (Oil/water or Gas/Water) or if both VAPOIL "; + text += "and DISGAS are disabled, saturation pressure are not valid."; + + QMessageBox::warning(nullptr, "Saturation Pressure Plots", text); + + RiaLogging::warning(text); + } + else + { + objectToSelect = plots.front(); + } + + collection->updateAllRequiredEditors(); + RiaApplication::instance()->getOrCreateAndShowMainPlotWindow(); + + if (objectToSelect) + { + RiuPlotMainWindowTools::selectAsCurrentItem(objectToSelect); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicCreateSaturationPressurePlotsFeature::setupActionLook(QAction* actionToSetup) +{ + actionToSetup->setText("Create Saturation Pressure Plots"); + actionToSetup->setIcon(QIcon(":/SummaryXPlotsLight16x16.png")); +} diff --git a/ApplicationCode/Commands/GridCrossPlotCommands/RicCreateSaturationPressurePlotsFeature.h b/ApplicationCode/Commands/GridCrossPlotCommands/RicCreateSaturationPressurePlotsFeature.h new file mode 100644 index 0000000000..6d7a048ddd --- /dev/null +++ b/ApplicationCode/Commands/GridCrossPlotCommands/RicCreateSaturationPressurePlotsFeature.h @@ -0,0 +1,40 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2019- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "cafCmdFeature.h" + +class RimEclipseResultCase; +class RimSaturationPressurePlot; + +//================================================================================================== +/// +//================================================================================================== +class RicCreateSaturationPressurePlotsFeature : public caf::CmdFeature +{ + CAF_CMD_HEADER_INIT; + +public: + static std::vector createPlots(RimEclipseResultCase* eclipseCase); + +protected: + bool isCommandEnabled() override; + void onActionTriggered(bool isChecked) override; + void setupActionLook(QAction* actionToSetup) override; +}; diff --git a/ApplicationCode/Commands/GridCrossPlotCommands/RicPasteGridCrossPlotDataSetFeature.cpp b/ApplicationCode/Commands/GridCrossPlotCommands/RicPasteGridCrossPlotDataSetFeature.cpp new file mode 100644 index 0000000000..999937fab3 --- /dev/null +++ b/ApplicationCode/Commands/GridCrossPlotCommands/RicPasteGridCrossPlotDataSetFeature.cpp @@ -0,0 +1,103 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2019- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "RicPasteGridCrossPlotDataSetFeature.h" + +#include "RiaApplication.h" +#include "RimGridCrossPlot.h" +#include "RimGridCrossPlotDataSet.h" +#include "RiuPlotMainWindowTools.h" + +#include "OperationsUsingObjReferences/RicPasteFeatureImpl.h" + +#include "cafPdmObjectGroup.h" +#include "cafSelectionManager.h" + +#include + +CAF_CMD_SOURCE_INIT(RicPasteGridCrossPlotDataSetFeature, "RicPasteGridCrossPlotDataSetFeature"); + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RicPasteGridCrossPlotDataSetFeature::isCommandEnabled() +{ + auto curvesOnClipboard = gridCrossPlotDataSetsOnClipboard(); + if (curvesOnClipboard.empty()) return false; + + return caf::SelectionManager::instance()->selectedItemAncestorOfType() != nullptr; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicPasteGridCrossPlotDataSetFeature::onActionTriggered(bool isChecked) +{ + RimGridCrossPlot* crossPlot = caf::SelectionManager::instance()->selectedItemAncestorOfType(); + + if (crossPlot) + { + auto curvesOnClipboard = gridCrossPlotDataSetsOnClipboard(); + if (!curvesOnClipboard.empty()) + { + RimGridCrossPlotDataSet* objectToSelect = nullptr; + + for (RimGridCrossPlotDataSet* dataSet : gridCrossPlotDataSetsOnClipboard()) + { + RimGridCrossPlotDataSet* newDataSet = dynamic_cast( + dataSet->xmlCapability()->copyByXmlSerialization(caf::PdmDefaultObjectFactory::instance())); + + crossPlot->addDataSet(newDataSet); + newDataSet->resolveReferencesRecursively(); + newDataSet->initAfterReadRecursively(); + + objectToSelect = newDataSet; + } + + + RiaApplication::instance()->getOrCreateMainPlotWindow(); + crossPlot->updateAllRequiredEditors(); + crossPlot->loadDataAndUpdate(); + + RiuPlotMainWindowTools::selectAsCurrentItem(objectToSelect); + } + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicPasteGridCrossPlotDataSetFeature::setupActionLook(QAction* actionToSetup) +{ + actionToSetup->setText("Paste Data Set"); + RicPasteFeatureImpl::setIconAndShortcuts(actionToSetup); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector> RicPasteGridCrossPlotDataSetFeature::gridCrossPlotDataSetsOnClipboard() +{ + caf::PdmObjectGroup objectGroup; + RicPasteFeatureImpl::findObjectsFromClipboardRefs(&objectGroup); + + std::vector> typedObjects; + objectGroup.objectsByType(&typedObjects); + + return typedObjects; +} diff --git a/ApplicationCode/Commands/GridCrossPlotCommands/RicPasteGridCrossPlotDataSetFeature.h b/ApplicationCode/Commands/GridCrossPlotCommands/RicPasteGridCrossPlotDataSetFeature.h new file mode 100644 index 0000000000..9ba7a8a1c2 --- /dev/null +++ b/ApplicationCode/Commands/GridCrossPlotCommands/RicPasteGridCrossPlotDataSetFeature.h @@ -0,0 +1,44 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2019- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "cafCmdFeature.h" +#include "cafPdmPointer.h" + +class RimGridCrossPlotDataSet; + +//================================================================================================== +/// +//================================================================================================== +class RicPasteGridCrossPlotDataSetFeature : public caf::CmdFeature +{ + CAF_CMD_HEADER_INIT; + +protected: + bool isCommandEnabled() override; + void onActionTriggered(bool isChecked) override; + void setupActionLook(QAction* actionToSetup) override; + +private: + static std::vector> gridCrossPlotDataSetsOnClipboard(); + +}; + + + diff --git a/ApplicationCode/Commands/GridCrossPlotCommands/RicSaturationPressureUi.cpp b/ApplicationCode/Commands/GridCrossPlotCommands/RicSaturationPressureUi.cpp new file mode 100644 index 0000000000..1d83159d63 --- /dev/null +++ b/ApplicationCode/Commands/GridCrossPlotCommands/RicSaturationPressureUi.cpp @@ -0,0 +1,67 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2017- Statoil ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "RicSaturationPressureUi.h" + +#include "RimTools.h" + +#include "cafPdmUiFilePathEditor.h" + +CAF_PDM_SOURCE_INIT(RicSaturationPressureUi, "RicSaturationPressureUi"); + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RicSaturationPressureUi::RicSaturationPressureUi() +{ + CAF_PDM_InitObject("RicSaturationPressureUi", "", "", ""); + + CAF_PDM_InitFieldNoDefault(&m_caseToApply, "CaseToApply", "Case to Apply", "", "", ""); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicSaturationPressureUi::setSelectedCase(RimEclipseCase* eclipseCase) +{ + m_caseToApply = eclipseCase; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimEclipseCase* RicSaturationPressureUi::selectedCase() const +{ + return m_caseToApply(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QList RicSaturationPressureUi::calculateValueOptions(const caf::PdmFieldHandle* fieldNeedingOptions, + bool* useOptionsOnly) +{ + QList options; + + if (fieldNeedingOptions == &m_caseToApply) + { + RimTools::caseOptionItems(&options); + } + + return options; +} diff --git a/ApplicationCode/Commands/GridCrossPlotCommands/RicSaturationPressureUi.h b/ApplicationCode/Commands/GridCrossPlotCommands/RicSaturationPressureUi.h new file mode 100644 index 0000000000..8683951228 --- /dev/null +++ b/ApplicationCode/Commands/GridCrossPlotCommands/RicSaturationPressureUi.h @@ -0,0 +1,47 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2017- Statoil ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "RimEclipseCase.h" + +#include "cafPdmField.h" +#include "cafPdmObject.h" +#include "cafPdmPtrField.h" + +//================================================================================================== +/// +/// +//================================================================================================== +class RicSaturationPressureUi : public caf::PdmObject +{ + CAF_PDM_HEADER_INIT; + +public: + RicSaturationPressureUi(); + + void setSelectedCase(RimEclipseCase* eclipseCase); + RimEclipseCase* selectedCase() const; + +protected: + QList calculateValueOptions(const caf::PdmFieldHandle* fieldNeedingOptions, + bool* useOptionsOnly) override; + +private: + caf::PdmPtrField m_caseToApply; +}; diff --git a/ApplicationCode/Commands/GridCrossPlotCommands/RicSwapGridCrossPlotDataSetAxesFeature.cpp b/ApplicationCode/Commands/GridCrossPlotCommands/RicSwapGridCrossPlotDataSetAxesFeature.cpp new file mode 100644 index 0000000000..1f46016bb0 --- /dev/null +++ b/ApplicationCode/Commands/GridCrossPlotCommands/RicSwapGridCrossPlotDataSetAxesFeature.cpp @@ -0,0 +1,61 @@ +#include "RicSwapGridCrossPlotDataSetAxesFeature.h" + +#include "RimGridCrossPlot.h" +#include "RimGridCrossPlotDataSet.h" + +#include + +#include + +CAF_CMD_SOURCE_INIT(RicSwapGridCrossPlotDataSetAxesFeature, "RicSwapGridCrossPlotDataSetAxesFeature"); + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RicSwapGridCrossPlotDataSetAxesFeature::isCommandEnabled() +{ + if (caf::SelectionManager::instance()->selectedItemOfType()) + { + return true; + } + else if (caf::SelectionManager::instance()->selectedItemOfType()) + { + auto plot = caf::SelectionManager::instance()->selectedItemOfType(); + if (!plot->dataSets().empty()) + return true; + } + return false; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicSwapGridCrossPlotDataSetAxesFeature::onActionTriggered(bool isChecked) +{ + if (caf::SelectionManager::instance()->selectedItemOfType()) + { + auto dataSet = caf::SelectionManager::instance()->selectedItemOfType(); + dataSet->swapAxisProperties(true); + } + else if (caf::SelectionManager::instance()->selectedItemOfType()) + { + auto plot = caf::SelectionManager::instance()->selectedItemOfType(); + plot->swapAxes(); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicSwapGridCrossPlotDataSetAxesFeature::setupActionLook(QAction* actionToSetup) +{ + if (caf::SelectionManager::instance()->selectedItemOfType()) + { + actionToSetup->setText("Swap Axis Properties"); + } + else + { + actionToSetup->setText("Swap Axis Properties for all Data Sets in Plot"); + } + actionToSetup->setIcon(QIcon(":/Swap.png")); +} diff --git a/ApplicationCode/Commands/GridCrossPlotCommands/RicSwapGridCrossPlotDataSetAxesFeature.h b/ApplicationCode/Commands/GridCrossPlotCommands/RicSwapGridCrossPlotDataSetAxesFeature.h new file mode 100644 index 0000000000..9336fe2f36 --- /dev/null +++ b/ApplicationCode/Commands/GridCrossPlotCommands/RicSwapGridCrossPlotDataSetAxesFeature.h @@ -0,0 +1,38 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2019- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// +#pragma once + +#include "cafCmdFeature.h" + +//================================================================================================== +/// +//================================================================================================== +class RicSwapGridCrossPlotDataSetAxesFeature : public caf::CmdFeature +{ + CAF_CMD_HEADER_INIT; + +protected: + bool isCommandEnabled() override; + void onActionTriggered(bool isChecked) override; + void setupActionLook(QAction* actionToSetup) override; +}; + + + + + diff --git a/ApplicationCode/Commands/HoloLensCommands/CMakeLists_files.cmake b/ApplicationCode/Commands/HoloLensCommands/CMakeLists_files.cmake index dd22c000e5..94db1a4de9 100644 --- a/ApplicationCode/Commands/HoloLensCommands/CMakeLists_files.cmake +++ b/ApplicationCode/Commands/HoloLensCommands/CMakeLists_files.cmake @@ -10,10 +10,14 @@ ${CMAKE_CURRENT_LIST_DIR}/RicHoloLensRestClient.h ${CMAKE_CURRENT_LIST_DIR}/RicHoloLensServerSettings.h ${CMAKE_CURRENT_LIST_DIR}/RicHoloLensCreateSessionUi.h ${CMAKE_CURRENT_LIST_DIR}/RicHoloLensSession.h +${CMAKE_CURRENT_LIST_DIR}/RicHoloLensSessionObserver.h ${CMAKE_CURRENT_LIST_DIR}/RicHoloLensSessionManager.h ${CMAKE_CURRENT_LIST_DIR}/RicHoloLensCreateDummyFileBackedSessionFeature.h +${CMAKE_CURRENT_LIST_DIR}/RicHoloLensAutoExportToSharingServerFeature.h +${CMAKE_CURRENT_LIST_DIR}/RicExportToSharingServerScheduler.h ${CMAKE_CURRENT_LIST_DIR}/VdeArrayDataPacket.h +${CMAKE_CURRENT_LIST_DIR}/VdeCachingHashedIdFactory.h ${CMAKE_CURRENT_LIST_DIR}/VdeExportPart.h ${CMAKE_CURRENT_LIST_DIR}/VdeFileExporter.h ${CMAKE_CURRENT_LIST_DIR}/VdePacketDirectory.h @@ -33,8 +37,11 @@ ${CMAKE_CURRENT_LIST_DIR}/RicHoloLensCreateSessionUi.cpp ${CMAKE_CURRENT_LIST_DIR}/RicHoloLensSession.cpp ${CMAKE_CURRENT_LIST_DIR}/RicHoloLensSessionManager.cpp ${CMAKE_CURRENT_LIST_DIR}/RicHoloLensCreateDummyFileBackedSessionFeature.cpp +${CMAKE_CURRENT_LIST_DIR}/RicHoloLensAutoExportToSharingServerFeature.cpp +${CMAKE_CURRENT_LIST_DIR}/RicExportToSharingServerScheduler.cpp ${CMAKE_CURRENT_LIST_DIR}/VdeArrayDataPacket.cpp +${CMAKE_CURRENT_LIST_DIR}/VdeCachingHashedIdFactory.cpp ${CMAKE_CURRENT_LIST_DIR}/VdeExportPart.cpp ${CMAKE_CURRENT_LIST_DIR}/VdeFileExporter.cpp ${CMAKE_CURRENT_LIST_DIR}/VdePacketDirectory.cpp @@ -53,6 +60,7 @@ ${SOURCE_GROUP_SOURCE_FILES} set (QT_MOC_HEADERS ${QT_MOC_HEADERS} ${CMAKE_CURRENT_LIST_DIR}/RicHoloLensRestClient.h +${CMAKE_CURRENT_LIST_DIR}/RicExportToSharingServerScheduler.h ) diff --git a/ApplicationCode/Commands/HoloLensCommands/RicExportToSharingServerScheduler.cpp b/ApplicationCode/Commands/HoloLensCommands/RicExportToSharingServerScheduler.cpp new file mode 100644 index 0000000000..6d280ea65f --- /dev/null +++ b/ApplicationCode/Commands/HoloLensCommands/RicExportToSharingServerScheduler.cpp @@ -0,0 +1,98 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2019- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "RicExportToSharingServerScheduler.h" + +#include "RicHoloLensAutoExportToSharingServerFeature.h" + +#include "cafCmdFeatureManager.h" +#include "cafProgressState.h" + +#include +#include + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RicExportToSharingServerScheduler* RicExportToSharingServerScheduler::instance() +{ + static RicExportToSharingServerScheduler theInstance; + + return &theInstance; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicExportToSharingServerScheduler::scheduleUpdateSession() +{ + startTimer(0); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicExportToSharingServerScheduler::startTimer(int msecs) +{ + if (!m_timer) + { + m_timer = new QTimer(this); + connect(m_timer, SIGNAL(timeout()), this, SLOT(slotTriggerUpdateSessionWhenReady())); + } + + if (!m_timer->isActive()) + { + m_timer->setSingleShot(true); + m_timer->start(msecs); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicExportToSharingServerScheduler::triggerUpdateSession() +{ + auto* cmdFeature = dynamic_cast( + caf::CmdFeatureManager::instance()->getCommandFeature("RicHoloLensAutoExportToSharingServerFeature")); + if (cmdFeature) + { + cmdFeature->triggerUpdateSession(); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicExportToSharingServerScheduler::slotTriggerUpdateSessionWhenReady() +{ + if (caf::ProgressState::isActive()) + { + startTimer(100); + return; + } + + triggerUpdateSession(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RicExportToSharingServerScheduler::~RicExportToSharingServerScheduler() +{ + delete m_timer; +} diff --git a/ApplicationCode/Commands/HoloLensCommands/RicExportToSharingServerScheduler.h b/ApplicationCode/Commands/HoloLensCommands/RicExportToSharingServerScheduler.h new file mode 100644 index 0000000000..3a2e6588c4 --- /dev/null +++ b/ApplicationCode/Commands/HoloLensCommands/RicExportToSharingServerScheduler.h @@ -0,0 +1,55 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2019- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include + +class QTimer; + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +class RicExportToSharingServerScheduler : public QObject +{ + Q_OBJECT; + +public: + static RicExportToSharingServerScheduler* instance(); + void scheduleUpdateSession(); + +private slots: + void slotTriggerUpdateSessionWhenReady(); + +private: + RicExportToSharingServerScheduler() + : m_timer(nullptr) + { + } + + ~RicExportToSharingServerScheduler() override; + + RicExportToSharingServerScheduler(const RicExportToSharingServerScheduler& o) = delete; + void operator=(const RicExportToSharingServerScheduler& o) = delete; + + void startTimer(int msecs); + void triggerUpdateSession(); + +private: + QTimer* m_timer; +}; diff --git a/ApplicationCode/Commands/HoloLensCommands/RicHoloLensAutoExportToSharingServerFeature.cpp b/ApplicationCode/Commands/HoloLensCommands/RicHoloLensAutoExportToSharingServerFeature.cpp new file mode 100644 index 0000000000..cbeec74488 --- /dev/null +++ b/ApplicationCode/Commands/HoloLensCommands/RicHoloLensAutoExportToSharingServerFeature.cpp @@ -0,0 +1,148 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2019- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "RicHoloLensAutoExportToSharingServerFeature.h" +#include "RicHoloLensSession.h" +#include "RicHoloLensSessionManager.h" + +#include "RiaApplication.h" +#include "RiaLogging.h" + +#include "RimGridView.h" + +#include + +CAF_CMD_SOURCE_INIT(RicHoloLensAutoExportToSharingServerFeature, "RicHoloLensAutoExportToSharingServerFeature"); + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RicHoloLensAutoExportToSharingServerFeature::RicHoloLensAutoExportToSharingServerFeature() + : m_isActive(false) +{ +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicHoloLensAutoExportToSharingServerFeature::setActive(bool enable) +{ + m_isActive = enable; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RicHoloLensAutoExportToSharingServerFeature::isActive() const +{ + if (isSessionValid()) + { + return m_isActive; + } + + return false; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicHoloLensAutoExportToSharingServerFeature::triggerUpdateSession() +{ + if (m_isActive && isSessionValid()) + { + RimGridView* activeView = RiaApplication::instance()->activeGridView(); + if (!activeView) + { + RiaLogging::error("No active view"); + return; + } + + RicHoloLensSession* session = RicHoloLensSessionManager::instance()->session(); + + session->updateSessionDataFromView(*activeView); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RicHoloLensAutoExportToSharingServerFeature::isCommandEnabled() +{ + return isSessionValid(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicHoloLensAutoExportToSharingServerFeature::onActionTriggered(bool isChecked) +{ + m_isActive = !m_isActive; + + if (!isSessionValid()) + { + RiaLogging::error("No valid HoloLens session present"); + m_isActive = false; + } + + RimGridView* activeView = RiaApplication::instance()->activeGridView(); + if (!activeView) + { + RiaLogging::error("No active view"); + m_isActive = false; + } + + if (m_isActive) + { + triggerUpdateSession(); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicHoloLensAutoExportToSharingServerFeature::setupActionLook(QAction* actionToSetup) +{ + actionToSetup->setIcon(QIcon(":/HoloLensSendContinously24x24.png")); + + actionToSetup->setText("Export to HoloLens Server Continuously"); + actionToSetup->setCheckable(true); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RicHoloLensAutoExportToSharingServerFeature::isCommandChecked() +{ + return isActive(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RicHoloLensAutoExportToSharingServerFeature::isSessionValid() const +{ + RicHoloLensSession* session = RicHoloLensSessionManager::instance()->session(); + if (session && session->isSessionValid()) + { + return true; + } + else + { + return false; + } +} diff --git a/ApplicationCode/Commands/HoloLensCommands/RicHoloLensAutoExportToSharingServerFeature.h b/ApplicationCode/Commands/HoloLensCommands/RicHoloLensAutoExportToSharingServerFeature.h new file mode 100644 index 0000000000..5dea652987 --- /dev/null +++ b/ApplicationCode/Commands/HoloLensCommands/RicHoloLensAutoExportToSharingServerFeature.h @@ -0,0 +1,48 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2019- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "cafCmdFeature.h" + +//================================================================================================== +/// +//================================================================================================== +class RicHoloLensAutoExportToSharingServerFeature : public caf::CmdFeature +{ + CAF_CMD_HEADER_INIT; + +public: + RicHoloLensAutoExportToSharingServerFeature(); + + void setActive(bool enable); + bool isActive() const; + + void triggerUpdateSession(); + +private: + bool isCommandEnabled() override; + void onActionTriggered(bool isChecked) override; + void setupActionLook(QAction* actionToSetup) override; + bool isCommandChecked() override; + + bool isSessionValid() const; + +private: + bool m_isActive; +}; diff --git a/ApplicationCode/Commands/HoloLensCommands/RicHoloLensCreateDummyFileBackedSessionFeature.cpp b/ApplicationCode/Commands/HoloLensCommands/RicHoloLensCreateDummyFileBackedSessionFeature.cpp index 05fc22768b..45e0639bdd 100644 --- a/ApplicationCode/Commands/HoloLensCommands/RicHoloLensCreateDummyFileBackedSessionFeature.cpp +++ b/ApplicationCode/Commands/HoloLensCommands/RicHoloLensCreateDummyFileBackedSessionFeature.cpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018 Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -20,8 +20,6 @@ #include "RicHoloLensSessionManager.h" -#include "RiaQIconTools.h" - #include CAF_CMD_SOURCE_INIT(RicHoloLensCreateDummyFiledBackedSessionFeature, "RicHoloLensCreateDummyFiledBackedSessionFeature"); @@ -49,11 +47,7 @@ void RicHoloLensCreateDummyFiledBackedSessionFeature::onActionTriggered(bool isC //-------------------------------------------------------------------------------------------------- void RicHoloLensCreateDummyFiledBackedSessionFeature::setupActionLook(QAction* actionToSetup) { - QPixmap pixmap(":/hololens.png"); - QPixmap overlayPixmap(":/plus-sign-green.png"); - - QPixmap combinedPixmap = RiaQIconTools::appendPixmapUpperLeft(pixmap, overlayPixmap); - actionToSetup->setIcon(QIcon(combinedPixmap)); + actionToSetup->setIcon(QIcon(":/HoloLensConnect24x24.png")); - actionToSetup->setText("Create Dummy File Backed Session"); + actionToSetup->setText("Create File-Backed Dummy-Session"); } diff --git a/ApplicationCode/Commands/HoloLensCommands/RicHoloLensCreateDummyFileBackedSessionFeature.h b/ApplicationCode/Commands/HoloLensCommands/RicHoloLensCreateDummyFileBackedSessionFeature.h index 9518596fea..7d8e481968 100644 --- a/ApplicationCode/Commands/HoloLensCommands/RicHoloLensCreateDummyFileBackedSessionFeature.h +++ b/ApplicationCode/Commands/HoloLensCommands/RicHoloLensCreateDummyFileBackedSessionFeature.h @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018 Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by diff --git a/ApplicationCode/Commands/HoloLensCommands/RicHoloLensCreateSessionFeature.cpp b/ApplicationCode/Commands/HoloLensCommands/RicHoloLensCreateSessionFeature.cpp index 606f88c8c0..dc44b358c1 100644 --- a/ApplicationCode/Commands/HoloLensCommands/RicHoloLensCreateSessionFeature.cpp +++ b/ApplicationCode/Commands/HoloLensCommands/RicHoloLensCreateSessionFeature.cpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018 Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -18,12 +18,12 @@ #include "RicHoloLensCreateSessionFeature.h" -#include "RiaQIconTools.h" - #include "RicHoloLensCreateSessionUi.h" #include "RicHoloLensServerSettings.h" #include "RicHoloLensSessionManager.h" +#include "RiuMainWindow.h" + #include "cafPdmSettings.h" #include "cafPdmUiPropertyViewDialog.h" @@ -47,7 +47,7 @@ void RicHoloLensCreateSessionFeature::onActionTriggered(bool isChecked) { RicHoloLensCreateSessionUi createSessionUi; - caf::PdmUiPropertyViewDialog propertyDialog(nullptr, &createSessionUi, "HoloLens - Create Session", ""); + caf::PdmUiPropertyViewDialog propertyDialog(RiuMainWindow::instance(), &createSessionUi, "HoloLens - Create Session", ""); propertyDialog.resize(QSize(400, 330)); { @@ -73,11 +73,7 @@ void RicHoloLensCreateSessionFeature::onActionTriggered(bool isChecked) //-------------------------------------------------------------------------------------------------- void RicHoloLensCreateSessionFeature::setupActionLook(QAction* actionToSetup) { - QPixmap pixmap(":/hololens.png"); - QPixmap overlayPixmap(":/plus-sign-green.png"); - - QPixmap combinedPixmap = RiaQIconTools::appendPixmapUpperLeft(pixmap, overlayPixmap); - actionToSetup->setIcon(QIcon(combinedPixmap)); + actionToSetup->setIcon(QIcon(":/HoloLensConnect24x24.png")); - actionToSetup->setText("Create Session"); + actionToSetup->setText("Connect to HoloLens Server"); } diff --git a/ApplicationCode/Commands/HoloLensCommands/RicHoloLensCreateSessionFeature.h b/ApplicationCode/Commands/HoloLensCommands/RicHoloLensCreateSessionFeature.h index ee61ab8314..e07103a9ea 100644 --- a/ApplicationCode/Commands/HoloLensCommands/RicHoloLensCreateSessionFeature.h +++ b/ApplicationCode/Commands/HoloLensCommands/RicHoloLensCreateSessionFeature.h @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018 Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by diff --git a/ApplicationCode/Commands/HoloLensCommands/RicHoloLensCreateSessionUi.cpp b/ApplicationCode/Commands/HoloLensCommands/RicHoloLensCreateSessionUi.cpp index a890b21c37..c5ec0cacbc 100644 --- a/ApplicationCode/Commands/HoloLensCommands/RicHoloLensCreateSessionUi.cpp +++ b/ApplicationCode/Commands/HoloLensCommands/RicHoloLensCreateSessionUi.cpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018 Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by diff --git a/ApplicationCode/Commands/HoloLensCommands/RicHoloLensCreateSessionUi.h b/ApplicationCode/Commands/HoloLensCommands/RicHoloLensCreateSessionUi.h index d250767055..55d08443a0 100644 --- a/ApplicationCode/Commands/HoloLensCommands/RicHoloLensCreateSessionUi.h +++ b/ApplicationCode/Commands/HoloLensCommands/RicHoloLensCreateSessionUi.h @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018 Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by diff --git a/ApplicationCode/Commands/HoloLensCommands/RicHoloLensExportImpl.cpp b/ApplicationCode/Commands/HoloLensCommands/RicHoloLensExportImpl.cpp index fb3a716aba..14b7edb7fe 100644 --- a/ApplicationCode/Commands/HoloLensCommands/RicHoloLensExportImpl.cpp +++ b/ApplicationCode/Commands/HoloLensCommands/RicHoloLensExportImpl.cpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018 Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -38,12 +38,14 @@ #include "RivMeshLinesSourceInfo.h" #include "RivSimWellPipeSourceInfo.h" #include "RivSourceInfo.h" +#include "RivTextLabelSourceInfo.h" #include "RivWellPathSourceInfo.h" #include "cafEffectGenerator.h" #include "cvfPart.h" #include "cvfRenderState.h" +#include "cvfRenderStateCullFace.h" #include "cvfRenderStateTextureBindings.h" #include "cvfRenderState_FF.h" #include "cvfTexture.h" @@ -131,6 +133,26 @@ std::vector RicHoloLensExportImpl::partsForExport(const RimGridVi } } + if (visiblePart->effect()) + { + const cvf::RenderStateCullFace* renderStateCullFace = dynamic_cast( + visiblePart->effect()->renderStateOfType(cvf::RenderState::CULL_FACE)); + if (renderStateCullFace) + { + // The logic below that inverts the culling mode simply does not make sense. We should be able to just utilize the cull mode set + // in the render state. The proper solution is probably to put more effort into correctly determining the winding in further up + // in this function, but currently there is no clear way to accomplish this. + if (renderStateCullFace->mode() == cvf::RenderStateCullFace::BACK) + { + exportPart.setCullFace(VdeExportPart::CF_FRONT); + } + else if (renderStateCullFace->mode() == cvf::RenderStateCullFace::FRONT) + { + exportPart.setCullFace(VdeExportPart::CF_BACK); + } + } + } + appendTextureImage(exportPart, visiblePart.p()); exportParts.push_back(exportPart); @@ -195,6 +217,27 @@ std::vector RicHoloLensExportImpl::partsForExport(const RimGridVi return exportParts; } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector> RicHoloLensExportImpl::labelsForExport(const RimGridView& view) +{ + std::vector> labelAndPositions; + + auto visibleParts = view.viewer()->visibleParts(); + + for (auto& visiblePart : visibleParts) + { + const RivTextLabelSourceInfo* textLabel = dynamic_cast(visiblePart->sourceInfo()); + if (textLabel) + { + labelAndPositions.push_back(std::make_pair(textLabel->textPositionDisplayCoord(), textLabel->text())); + } + } + + return labelAndPositions; +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/Commands/HoloLensCommands/RicHoloLensExportImpl.h b/ApplicationCode/Commands/HoloLensCommands/RicHoloLensExportImpl.h index d95913bc1d..ee928b1ced 100644 --- a/ApplicationCode/Commands/HoloLensCommands/RicHoloLensExportImpl.h +++ b/ApplicationCode/Commands/HoloLensCommands/RicHoloLensExportImpl.h @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018 Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -40,6 +40,7 @@ class RicHoloLensExportImpl { public: static std::vector partsForExport(const RimGridView& view); + static std::vector> labelsForExport(const RimGridView& view); private: static void appendTextureImage(VdeExportPart& exportPart, cvf::Part* part); diff --git a/ApplicationCode/Commands/HoloLensCommands/RicHoloLensExportToFolderFeature.cpp b/ApplicationCode/Commands/HoloLensCommands/RicHoloLensExportToFolderFeature.cpp index 4e8716d2e7..cf03371e51 100644 --- a/ApplicationCode/Commands/HoloLensCommands/RicHoloLensExportToFolderFeature.cpp +++ b/ApplicationCode/Commands/HoloLensCommands/RicHoloLensExportToFolderFeature.cpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018 Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by diff --git a/ApplicationCode/Commands/HoloLensCommands/RicHoloLensExportToFolderFeature.h b/ApplicationCode/Commands/HoloLensCommands/RicHoloLensExportToFolderFeature.h index 1b8eeaa0f7..628e1d9b8e 100644 --- a/ApplicationCode/Commands/HoloLensCommands/RicHoloLensExportToFolderFeature.h +++ b/ApplicationCode/Commands/HoloLensCommands/RicHoloLensExportToFolderFeature.h @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018 Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by diff --git a/ApplicationCode/Commands/HoloLensCommands/RicHoloLensExportToFolderUi.cpp b/ApplicationCode/Commands/HoloLensCommands/RicHoloLensExportToFolderUi.cpp index 0a136e822d..7908137e54 100644 --- a/ApplicationCode/Commands/HoloLensCommands/RicHoloLensExportToFolderUi.cpp +++ b/ApplicationCode/Commands/HoloLensCommands/RicHoloLensExportToFolderUi.cpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018 Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by diff --git a/ApplicationCode/Commands/HoloLensCommands/RicHoloLensExportToFolderUi.h b/ApplicationCode/Commands/HoloLensCommands/RicHoloLensExportToFolderUi.h index 8e3089bd1f..1ada8b20fc 100644 --- a/ApplicationCode/Commands/HoloLensCommands/RicHoloLensExportToFolderUi.h +++ b/ApplicationCode/Commands/HoloLensCommands/RicHoloLensExportToFolderUi.h @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018 Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by diff --git a/ApplicationCode/Commands/HoloLensCommands/RicHoloLensExportToSharingServerFeature.cpp b/ApplicationCode/Commands/HoloLensCommands/RicHoloLensExportToSharingServerFeature.cpp index 12ebb0b322..c4ce72e991 100644 --- a/ApplicationCode/Commands/HoloLensCommands/RicHoloLensExportToSharingServerFeature.cpp +++ b/ApplicationCode/Commands/HoloLensCommands/RicHoloLensExportToSharingServerFeature.cpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018 Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -21,7 +21,6 @@ #include "RicHoloLensSession.h" #include "RiaApplication.h" -#include "RiaQIconTools.h" #include "RiaLogging.h" #include "RimGridView.h" @@ -74,11 +73,7 @@ void RicHoloLensExportToSharingServerFeature::onActionTriggered(bool isChecked) //-------------------------------------------------------------------------------------------------- void RicHoloLensExportToSharingServerFeature::setupActionLook(QAction* actionToSetup) { - QPixmap pixmap(":/hololens.png"); - QPixmap overlayPixmap(":/arrow-right-green.png"); + actionToSetup->setIcon(QIcon(":/HoloLensSendOnce24x24.png")); - QPixmap combinedPixmap = RiaQIconTools::appendPixmapUpperLeft(pixmap, overlayPixmap); - actionToSetup->setIcon(QIcon(combinedPixmap)); - - actionToSetup->setText("Export to Sharing Server"); + actionToSetup->setText("Send to HoloLens Server Once"); } diff --git a/ApplicationCode/Commands/HoloLensCommands/RicHoloLensExportToSharingServerFeature.h b/ApplicationCode/Commands/HoloLensCommands/RicHoloLensExportToSharingServerFeature.h index 31eb82beba..f7d7d429e3 100644 --- a/ApplicationCode/Commands/HoloLensCommands/RicHoloLensExportToSharingServerFeature.h +++ b/ApplicationCode/Commands/HoloLensCommands/RicHoloLensExportToSharingServerFeature.h @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018 Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by diff --git a/ApplicationCode/Commands/HoloLensCommands/RicHoloLensRestClient.cpp b/ApplicationCode/Commands/HoloLensCommands/RicHoloLensRestClient.cpp index d6667addda..1d3d30f2d0 100644 --- a/ApplicationCode/Commands/HoloLensCommands/RicHoloLensRestClient.cpp +++ b/ApplicationCode/Commands/HoloLensCommands/RicHoloLensRestClient.cpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018 Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -23,6 +23,13 @@ #include #include +#include + +// For getting time stamps for round-trip timing +#if defined (__linux__) +#include +#include +#endif #ifndef QT_NO_OPENSSL @@ -44,7 +51,8 @@ RicHoloLensRestClient::RicHoloLensRestClient(QString serverUrl, QString sessionName, RicHoloLensRestResponseHandler* responseHandler) : m_serverUrl(serverUrl), m_sessionName(sessionName), - m_responseHandler(responseHandler) + m_responseHandler(responseHandler), + m_dbgDisableCertificateVerification(false) { } @@ -59,7 +67,15 @@ void RicHoloLensRestClient::clearResponseHandler() //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RicHoloLensRestClient::createSession() +void RicHoloLensRestClient::dbgDisableCertificateVerification() +{ + m_dbgDisableCertificateVerification = true; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicHoloLensRestClient::createSession(const QByteArray& sessionPinCode) { const QString url = m_serverUrl + "/sessions/create/" + m_sessionName; cvf::Trace::show("createSession: POST on url: %s", url.toLatin1().constData()); @@ -67,19 +83,23 @@ void RicHoloLensRestClient::createSession() QNetworkRequest request(url); //request.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("application/octet-stream")); request.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("application/x-www-form-urlencoded")); + request.setRawHeader("PinCode", sessionPinCode); + #ifdef EXPERIMENTAL_SSL_SUPPORT // NOTE !!! // Apparently something like this is currently needed in order to get SSL/HTTPS going // Still, can't quite figure it out since it appears to be sufficient to do this on the first request - // This will have to be investigated further, SP 20181924 + // This will have to be investigated further, SP 20180924 QSslConfiguration sslConf = request.sslConfiguration(); // Needed this one to be able to connect to sharing server sslConf.setProtocol(QSsl::AnyProtocol); - // !!MUST!! remove this code in production - sslConf.setPeerVerifyMode(QSslSocket::VerifyNone); + if (m_dbgDisableCertificateVerification) + { + sslConf.setPeerVerifyMode(QSslSocket::VerifyNone); + } request.setSslConfiguration(sslConf); #endif @@ -106,9 +126,22 @@ void RicHoloLensRestClient::slotCreateSessionFinished() if (detectAndHandleErrorReply("createSession", reply)) { reply->deleteLater(); + + m_responseHandler->handleFailedCreateSession(); + return; } + const QByteArray serverData = reply->readAll(); + //cvf::Trace::show(" serverResponse: %s", serverData.constData()); + + // Currently we get the bearer token back in the response wholesale + // The format we get is typically: "Bearer " + // For example: "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9" + // Presumably the format of the response will change, but for now just strip away the starting "Bearer " string and consider the rest as the actual token + m_bearerToken = serverData; + m_bearerToken.replace("Bearer ", ""); + reply->deleteLater(); cvf::Trace::show("createSession OK"); @@ -129,6 +162,7 @@ void RicHoloLensRestClient::deleteSession() QNetworkRequest request(url); //request.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("application/octet-stream")); request.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("application/x-www-form-urlencoded")); + addBearerAuthenticationHeaderToRequest(&request); QNetworkReply* reply = m_accessManager.deleteResource(request); connect(reply, SIGNAL(finished()), SLOT(slotDeleteSessionFinished())); @@ -168,13 +202,17 @@ void RicHoloLensRestClient::sendMetaData(int metaDataSequenceNumber, const QStri const QString url = m_serverUrl + "/sessions/" + m_sessionName + "/metadata"; cvf::Trace::show("sendMetaData (metaDataSequenceNumber=%d): POST on url: %s", metaDataSequenceNumber, url.toLatin1().constData()); + const qint64 sendStartTimeStamp_ms = getCurrentTimeStamp_ms(); + QNetworkRequest request(url); request.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("application/json")); + addBearerAuthenticationHeaderToRequest(&request); const QByteArray jsonByteArr = jsonMetaDataString.toLatin1(); QNetworkReply* reply = m_accessManager.post(request, jsonByteArr); - reply->setProperty("metaDataSequenceNumber", QVariant(metaDataSequenceNumber)); + reply->setProperty("holo_metaDataSequenceNumber", QVariant(metaDataSequenceNumber)); + reply->setProperty("holo_sendStartTimeStamp_ms", QVariant(sendStartTimeStamp_ms)); connect(reply, SIGNAL(finished()), SLOT(slotSendMetaDataFinished())); @@ -202,36 +240,58 @@ void RicHoloLensRestClient::slotSendMetaDataFinished() int metaDataSequenceNumber = -1; { - QVariant var = reply->property("metaDataSequenceNumber"); + QVariant var = reply->property("holo_metaDataSequenceNumber"); if (var.type() == QVariant::Int) { metaDataSequenceNumber = var.toInt(); } } + double elapsedTime_s = -1; + { + QVariant var = reply->property("holo_sendStartTimeStamp_ms"); + if (var.type() == QVariant::LongLong) + { + const qint64 startTimeStamp_ms = var.toLongLong(); + elapsedTime_s = (getCurrentTimeStamp_ms() - startTimeStamp_ms)/1000.0; + } + } + + const QByteArray serverData = reply->readAll(); + //cvf::Trace::show(" serverResponse: %s", serverData.constData()); + reply->deleteLater(); - cvf::Trace::show("sendMetaData (metaDataSequenceNumber=%d) OK", metaDataSequenceNumber); + cvf::Trace::show("sendMetaData (metaDataSequenceNumber=%d) OK, elapsedTime=%.2fs", metaDataSequenceNumber, elapsedTime_s); if (m_responseHandler) { - m_responseHandler->handleSuccessfulSendMetaData(metaDataSequenceNumber); + m_responseHandler->handleSuccessfulSendMetaData(metaDataSequenceNumber, serverData); } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RicHoloLensRestClient::sendBinaryData(const QByteArray& binaryDataArr) +void RicHoloLensRestClient::sendBinaryData(const QByteArray& binaryDataArr, QByteArray dbgTagString) { const QString url = m_serverUrl + "/sessions/" + m_sessionName + "/data"; - cvf::Trace::show("sendBinaryData: POST on url: %s", url.toLatin1().constData()); + cvf::Trace::show("sendBinaryData(%s): POST on url: %s", dbgTagString.constData(), url.toLatin1().constData()); + + const qint64 sendStartTimeStamp_ms = getCurrentTimeStamp_ms(); QNetworkRequest request(url); request.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("application/octet-stream")); + addBearerAuthenticationHeaderToRequest(&request); QNetworkReply* reply = m_accessManager.post(request, binaryDataArr); + reply->setProperty("holo_sendStartTimeStamp_ms", QVariant(sendStartTimeStamp_ms)); + reply->setProperty("holo_dbgTagString", QVariant(dbgTagString)); + connect(reply, SIGNAL(finished()), SLOT(slotSendBinaryDataFinished())); + // Debugging! + connect(reply, SIGNAL(uploadProgress(qint64, qint64)), SLOT(slotDbgUploadProgress(qint64, qint64))); + #ifdef EXPERIMENTAL_SSL_SUPPORT connect(reply, SIGNAL(sslErrors(const QList&)), SLOT(slotSslErrors(const QList&))); #endif @@ -254,9 +314,69 @@ void RicHoloLensRestClient::slotSendBinaryDataFinished() return; } + double elapsedTime_s = -1; + { + QVariant var = reply->property("holo_sendStartTimeStamp_ms"); + if (var.type() == QVariant::LongLong) + { + const qint64 startTimeStamp_ms = var.toLongLong(); + elapsedTime_s = (getCurrentTimeStamp_ms() - startTimeStamp_ms)/1000.0; + } + } + + QByteArray dbgTagString; + { + QVariant var = reply->property("holo_dbgTagString"); + if (var.type() == QVariant::ByteArray) + { + dbgTagString = var.toByteArray(); + } + } + reply->deleteLater(); - cvf::Trace::show("sendBinaryData OK"); + cvf::Trace::show("sendBinaryData(%s) OK, elapsedTime=%.2fs", dbgTagString.constData(), elapsedTime_s); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicHoloLensRestClient::slotDbgUploadProgress(qint64 bytesSent, qint64 bytesTotal) +{ + static int sl_lastPct = -1; + int pct = 0; + if (bytesTotal > 0) + { + pct = static_cast(100*(bytesSent/static_cast(bytesTotal))); + } + + if (pct % 10 == 0 && pct != sl_lastPct) + { + double elapsedTime_s = -1; + QByteArray dbgTagString; + QNetworkReply* reply = dynamic_cast(sender()); + if (reply) + { + { + QVariant var = reply->property("holo_sendStartTimeStamp_ms"); + if (var.type() == QVariant::LongLong) + { + const qint64 startTimeStamp_ms = var.toLongLong(); + elapsedTime_s = (getCurrentTimeStamp_ms() - startTimeStamp_ms)/1000.0; + } + } + { + QVariant var = reply->property("holo_dbgTagString"); + if (var.type() == QVariant::ByteArray) + { + dbgTagString = var.toByteArray(); + } + } + } + + cvf::Trace::show("Progress sendBinaryData(%s): %3d%%, %.2f/%.2fMB (elapsedTime=%.2fs)", dbgTagString.constData(), pct, bytesSent/(1024.0*1024.0), bytesTotal/(1024.0*1024.0), elapsedTime_s); + sl_lastPct = pct; + } } //-------------------------------------------------------------------------------------------------- @@ -273,6 +393,16 @@ void RicHoloLensRestClient::slotSslErrors(const QList& errors) #endif } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicHoloLensRestClient::addBearerAuthenticationHeaderToRequest(QNetworkRequest* request) const +{ + CVF_ASSERT(request); + + request->setRawHeader("Authorization", "Bearer " + m_bearerToken); +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -358,3 +488,23 @@ QString RicHoloLensRestClient::networkErrorCodeAsString(QNetworkReply::NetworkEr return "UnknownErrorCode"; } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +qint64 RicHoloLensRestClient::getCurrentTimeStamp_ms() +{ +#if QT_VERSION >= 0x040700 + const qint64 timeStamp_ms = QDateTime::currentMSecsSinceEpoch(); + return timeStamp_ms; +#elif defined(__linux__) + struct timespec ts; + if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) + { + return static_cast(ts.tv_sec*1000 + ts.tv_nsec/1000000); + } +#else + return 0; +#endif +} + + diff --git a/ApplicationCode/Commands/HoloLensCommands/RicHoloLensRestClient.h b/ApplicationCode/Commands/HoloLensCommands/RicHoloLensRestClient.h index d378b68556..14feb76844 100644 --- a/ApplicationCode/Commands/HoloLensCommands/RicHoloLensRestClient.h +++ b/ApplicationCode/Commands/HoloLensCommands/RicHoloLensRestClient.h @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018 Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -34,7 +34,9 @@ class RicHoloLensRestResponseHandler { public: virtual void handleSuccessfulCreateSession() = 0; - virtual void handleSuccessfulSendMetaData(int metaDataSequenceNumber) = 0; + virtual void handleFailedCreateSession() = 0; + + virtual void handleSuccessfulSendMetaData(int metaDataSequenceNumber, const QByteArray& jsonServerResponseString) = 0; virtual void handleError(const QString& errMsg, const QString& url, const QString& serverData) = 0; }; @@ -54,20 +56,25 @@ class RicHoloLensRestClient : public QObject void clearResponseHandler(); - void createSession(); + void dbgDisableCertificateVerification(); + + void createSession(const QByteArray& sessionPinCode); void deleteSession(); void sendMetaData(int metaDataSequenceNumber, const QString& jsonMetaDataString); - void sendBinaryData(const QByteArray& binaryDataArr); + void sendBinaryData(const QByteArray& binaryDataArr, QByteArray dbgTagString); private: + void addBearerAuthenticationHeaderToRequest(QNetworkRequest* request) const; bool detectAndHandleErrorReply(QString operationName, QNetworkReply* reply); static QString networkErrorCodeAsString(QNetworkReply::NetworkError nwErr); + static qint64 getCurrentTimeStamp_ms(); private slots: void slotCreateSessionFinished(); void slotDeleteSessionFinished(); void slotSendMetaDataFinished(); void slotSendBinaryDataFinished(); + void slotDbgUploadProgress(qint64 bytesSent, qint64 bytesTotal); void slotSslErrors(const QList& errors); @@ -76,4 +83,8 @@ private slots: QString m_serverUrl; QString m_sessionName; RicHoloLensRestResponseHandler* m_responseHandler; + + bool m_dbgDisableCertificateVerification; // Debug option to disable certificate verification. Needed in order to work with self-signed certifiactes + + QByteArray m_bearerToken; }; diff --git a/ApplicationCode/Commands/HoloLensCommands/RicHoloLensServerSettings.cpp b/ApplicationCode/Commands/HoloLensCommands/RicHoloLensServerSettings.cpp index e1d9e8c283..cb82e70ed9 100644 --- a/ApplicationCode/Commands/HoloLensCommands/RicHoloLensServerSettings.cpp +++ b/ApplicationCode/Commands/HoloLensCommands/RicHoloLensServerSettings.cpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018 Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by diff --git a/ApplicationCode/Commands/HoloLensCommands/RicHoloLensServerSettings.h b/ApplicationCode/Commands/HoloLensCommands/RicHoloLensServerSettings.h index 7efa626dd6..11708b6089 100644 --- a/ApplicationCode/Commands/HoloLensCommands/RicHoloLensServerSettings.h +++ b/ApplicationCode/Commands/HoloLensCommands/RicHoloLensServerSettings.h @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018 Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by diff --git a/ApplicationCode/Commands/HoloLensCommands/RicHoloLensSession.cpp b/ApplicationCode/Commands/HoloLensCommands/RicHoloLensSession.cpp index 5155b3f433..c03ce1ec86 100644 --- a/ApplicationCode/Commands/HoloLensCommands/RicHoloLensSession.cpp +++ b/ApplicationCode/Commands/HoloLensCommands/RicHoloLensSession.cpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018 Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -17,7 +17,7 @@ ///////////////////////////////////////////////////////////////////////////////// #include "RicHoloLensSession.h" -#include "RicHoloLensSessionManager.h" +#include "RicHoloLensSessionObserver.h" #include "RiaLogging.h" #include "RiaPreferences.h" @@ -28,9 +28,11 @@ #include "VdeArrayDataPacket.h" #include "cvfAssert.h" +#include "cvfTimer.h" #include +#include //================================================================================================== @@ -45,7 +47,7 @@ RicHoloLensSession::RicHoloLensSession() : m_isSessionValid(false), m_lastExtractionMetaDataSequenceNumber(-1), - m_dbgEnableFileExport(false) + m_sessionObserver(nullptr) { } @@ -60,16 +62,28 @@ RicHoloLensSession::~RicHoloLensSession() //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -RicHoloLensSession* RicHoloLensSession::createSession(const QString& serverUrl, const QString& sessionName) +RicHoloLensSession* RicHoloLensSession::createSession(const QString& serverUrl, const QString& sessionName, const QByteArray& sessionPinCode, RicHoloLensSessionObserver* sessionObserver) { RicHoloLensSession* newSession = new RicHoloLensSession; newSession->m_restClient = new RicHoloLensRestClient(serverUrl, sessionName, newSession); - newSession->m_restClient->createSession(); + + if (RiaApplication::instance()->preferences()->holoLensDisableCertificateVerification()) + { + RiaLogging::warning("HoloLens: Disabling certificate verification for HTTPS connections"); + newSession->m_restClient->dbgDisableCertificateVerification(); + } + + newSession->m_restClient->createSession(sessionPinCode); + + newSession->m_sessionObserver = sessionObserver; - // For now, leave this on!!! - // We probably want to export this as a preference parameter - newSession->m_dbgEnableFileExport = true; + const QString dbgExportFolder = RiaApplication::instance()->preferences()->holoLensExportFolder(); + if (!dbgExportFolder.isEmpty()) + { + newSession->m_dbgFileExportDestinationFolder = dbgExportFolder; + RiaLogging::info(QString("HoloLens: Debug file export will be written to folder: %1").arg(dbgExportFolder)); + } return newSession; } @@ -83,7 +97,7 @@ RicHoloLensSession* RicHoloLensSession::createDummyFileBackedSession() newSession->m_isSessionValid = true; - newSession->m_dbgEnableFileExport = true; + newSession->m_dbgFileExportDestinationFolder = RiaApplication::instance()->preferences()->holoLensExportFolder(); return newSession; } @@ -127,33 +141,38 @@ void RicHoloLensSession::updateSessionDataFromView(const RimGridView& activeView { RiaLogging::info("HoloLens: Updating visualization data"); + // Grab the current max ID as an easy way to detect if new IDs have been added for debugging purposes + const int dbgMaxAssignedIdBeforeExtraction = m_cachingIdFactory.lastAssignedId(); + + // Note that we pass the caching ID factory on the constructor which will try and detect data payloads that + // are equal, and will then "recycle" the array IDs for these + VdeVizDataExtractor extractor(activeView, &m_cachingIdFactory); + QString modelMetaJsonStr; std::vector allReferencedPacketIds; - m_packetDirectory.clear(); - - VdeVizDataExtractor extractor(activeView); extractor.extractViewContents(&modelMetaJsonStr, &allReferencedPacketIds, &m_packetDirectory); + // Note! + // The packet directory should now contain all the packets that are being actively referenced. + // We now prune out any packets that are no longer being referenced. This means we do no caching of actual packet + // data over time and that we assume that the server will ask for data packets/arrays right after having received updated meta data + m_packetDirectory.pruneUnreferencedPackets(allReferencedPacketIds); + m_lastExtractionMetaDataSequenceNumber++; m_lastExtractionAllReferencedPacketIdsArr = allReferencedPacketIds; + if (m_restClient) { RiaLogging::info(QString("HoloLens: Sending updated meta data to sharing server (sequenceNumber=%1)").arg(m_lastExtractionMetaDataSequenceNumber)); m_restClient->sendMetaData(m_lastExtractionMetaDataSequenceNumber, modelMetaJsonStr); } + // Debug export to file - if (m_dbgEnableFileExport) + if (!m_dbgFileExportDestinationFolder.isEmpty()) { - const QString folderName = RiaApplication::instance()->preferences()->holoLensExportFolder(); - if (folderName.isEmpty()) - { - RiaLogging::warning("HoloLens: Debug export to file enabled, but no export folder has been set"); - return; - } - - const QDir outputDir(folderName); + const QDir outputDir(m_dbgFileExportDestinationFolder); const QString absOutputFolder = outputDir.absolutePath(); if (!outputDir.mkpath(".")) @@ -162,9 +181,23 @@ void RicHoloLensSession::updateSessionDataFromView(const RimGridView& activeView return; } - RiaLogging::info(QString("HoloLens: Doing debug export of data to folder: %1").arg(absOutputFolder)); + // For debugging, write only the new packets to file + // Determine which packets are new by comparing the IDs to the max known ID before extraction + std::vector packetIdsToWrite; + for (int packetId : allReferencedPacketIds) + { + if (packetId > dbgMaxAssignedIdBeforeExtraction) + { + packetIdsToWrite.push_back(packetId); + } + } + + // This will write all packets seen in this extraction to file + //packetIdsToWrite = allReferencedPacketIds; + + RiaLogging::info(QString("HoloLens: Doing debug export of data (%1 packets) to folder: %2").arg(packetIdsToWrite.size()).arg(absOutputFolder)); VdeFileExporter fileExporter(absOutputFolder); - if (!fileExporter.exportToFile(modelMetaJsonStr, m_packetDirectory, allReferencedPacketIds)) + if (!fileExporter.exportToFile(modelMetaJsonStr, m_packetDirectory, packetIdsToWrite)) { RiaLogging::error("HoloLens: Error exporting debug data to folder"); } @@ -181,37 +214,152 @@ void RicHoloLensSession::handleSuccessfulCreateSession() RiaLogging::info("HoloLens: Session successfully created"); m_isSessionValid = true; - // Slight hack here - reaching out to the manager to update GUI - // We should really just be notifying the manager that our state has changed - RicHoloLensSessionManager::refreshToolbarState(); + notifyObserver(RicHoloLensSessionObserver::CreateSessionSucceeded); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicHoloLensSession::handleFailedCreateSession() +{ + RiaLogging::error("HoloLens: Failed to create session"); + m_isSessionValid = false; + + notifyObserver(RicHoloLensSessionObserver::CreateSessionFailed); } //-------------------------------------------------------------------------------------------------- /// Handle the server response we receive after sending new meta data //-------------------------------------------------------------------------------------------------- -void RicHoloLensSession::handleSuccessfulSendMetaData(int metaDataSequenceNumber) +void RicHoloLensSession::handleSuccessfulSendMetaData(int metaDataSequenceNumber, const QByteArray& jsonServerResponseString) { - RiaLogging::info(QString("HoloLens: Processing server response to meta data (sequenceNumber=%1)").arg(metaDataSequenceNumber)); + cvf::Timer tim; + + RiaLogging::info(QString("HoloLens: Processing server response (meta data sequenceNumber=%1)").arg(metaDataSequenceNumber)); if (m_lastExtractionMetaDataSequenceNumber != metaDataSequenceNumber) { - RiaLogging::warning(QString("HoloLens: Ignoring server response, the sequenceNumber(%1) has been superseded").arg(metaDataSequenceNumber)); + RiaLogging::warning(QString("HoloLens: Ignoring server response, the meta data sequenceNumber(%1) has been superseded").arg(metaDataSequenceNumber)); + return; + } + + std::vector arrayIdsToSend; + + //cvf::Trace::show("Raw JSON response from server: '%s'", jsonServerResponseString.data()); + QByteArray trimmedServerResponseString = jsonServerResponseString.trimmed(); + if (trimmedServerResponseString.size() > 0) + { + if (!parseJsonIntegerArray(trimmedServerResponseString, &arrayIdsToSend)) + { + RiaLogging::error("HoloLens: Error parsing array server response with array Ids, no data will be sent to server"); + return; + } + } + else + { + // An empty server response means we should send all array referenced by the last sent meta data + if (m_lastExtractionAllReferencedPacketIdsArr.size() > 0) + { + arrayIdsToSend = m_lastExtractionAllReferencedPacketIdsArr; + RiaLogging::info("HoloLens: Empty server response, sending all arrays referenced by last meta data"); + } + } + + if (arrayIdsToSend.size() ==0) + { + RiaLogging::info("HoloLens: Nothing to do, no data requested by server"); return; } - if (m_lastExtractionAllReferencedPacketIdsArr.size() > 0) + RiaLogging::info(QString("HoloLens: Start sending data to server, %1 data arrays have been requested").arg(arrayIdsToSend.size())); + + size_t totalBytesSent = 0; + size_t totalNumArraysSent = 0; + + const bool sendAsIndividualPackets = false; + + // Sending data packets one by one + if (sendAsIndividualPackets) + { + for (size_t i = 0; i < arrayIdsToSend.size(); i++) + { + const int arrayId = arrayIdsToSend[i]; + const VdeArrayDataPacket* packet = m_packetDirectory.lookupPacket(arrayId); + if (!packet) + { + RiaLogging::warning(QString("HoloLens: Could not get the requested data from cache, array id: %1 ").arg(arrayId)); + continue; + } + + QByteArray packetByteArr(packet->fullPacketRawPtr(), static_cast(packet->fullPacketSize())); + + RiaLogging::info(QString("HoloLens: sending array id: %1, %2KB (%3 bytes)").arg(arrayId).arg(packetByteArr.size()/1024.0, 0, 'f', 2).arg(packetByteArr.size())); + + m_restClient->sendBinaryData(packetByteArr, "arrId" + QByteArray::number(arrayId)); + + totalNumArraysSent++; + totalBytesSent += packetByteArr.size(); + } + } + // Sending all requested arrays/packets in one combined packet + else { QByteArray combinedPacketArr; - if (!m_packetDirectory.getPacketsAsCombinedBuffer(m_lastExtractionAllReferencedPacketIdsArr, &combinedPacketArr)) + if (!m_packetDirectory.getPacketsAsCombinedBuffer(arrayIdsToSend, &combinedPacketArr)) { - RiaLogging::warning("HoloLens: Error gathering the requested packets, no data will be sent"); + RiaLogging::warning("HoloLens: Error gathering the requested arrays, no data will be sent"); return; } - RiaLogging::info(QString("HoloLens: Sending new data to sharing server (%1 packets)").arg(m_lastExtractionAllReferencedPacketIdsArr.size())); + totalNumArraysSent = arrayIdsToSend.size(); + totalBytesSent = combinedPacketArr.size(); + + RiaLogging::info(QString("HoloLens: Sending data to server (%1 arrays combined), %2KB (%3 bytes)").arg(totalNumArraysSent).arg(totalBytesSent/1024.0, 0, 'f', 2).arg(totalBytesSent)); - m_restClient->sendBinaryData(combinedPacketArr); + m_restClient->sendBinaryData(combinedPacketArr, "metaSeqNum" + QByteArray::number(metaDataSequenceNumber)); } + + const double totalMb = totalBytesSent/(1024.0*1024.0); + RiaLogging::info(QString("HoloLens: Finished sending data to server, %1 arrays, total %2MB (%3 bytes) in %4ms").arg(totalNumArraysSent).arg(totalMb, 0, 'f', 2).arg(totalBytesSent).arg(static_cast(tim.time()*1000))); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RicHoloLensSession::parseJsonIntegerArray(const QByteArray& jsonString, std::vector* integerArr) +{ + //cvf::Trace::show("jsonString: '%s'", jsonString.data()); + + const int openBraceIdx = jsonString.indexOf('['); + const int closeBraceIdx = jsonString.lastIndexOf(']'); + if (openBraceIdx < 0 || closeBraceIdx < 0) + { + RiaLogging::debug("Error parsing JSON array, could not find opening or closing braces"); + return false; + } + + if (closeBraceIdx <= openBraceIdx) + { + RiaLogging::debug("Error parsing JSON array, wrong placement of braces"); + return false; + } + + QByteArray arrayContents = jsonString.mid(openBraceIdx + 1, closeBraceIdx - openBraceIdx - 1).trimmed(); + //cvf::Trace::show("arrayContents: '%s'", arrayContents.data()); + + QList stringList = arrayContents.split(','); + for (const QByteArray& entry : stringList) + { + bool convertOk = false; + const int intVal = entry.toInt(&convertOk); + if (convertOk) + { + integerArr->push_back(intVal); + } + + } + + return true; } //-------------------------------------------------------------------------------------------------- @@ -229,5 +377,19 @@ void RicHoloLensSession::handleError(const QString& errMsg, const QString& url, fullMsg += "\n url: " + url; RiaLogging::error(fullMsg); + + // It is probably not correct to always consider an error a state change, but for now + notifyObserver(RicHoloLensSessionObserver::GeneralError); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicHoloLensSession::notifyObserver(RicHoloLensSessionObserver::Notification notification) +{ + if (m_sessionObserver) + { + m_sessionObserver->handleSessionNotification(this, notification); + } } diff --git a/ApplicationCode/Commands/HoloLensCommands/RicHoloLensSession.h b/ApplicationCode/Commands/HoloLensCommands/RicHoloLensSession.h index 09a75dbe13..7bc39326d2 100644 --- a/ApplicationCode/Commands/HoloLensCommands/RicHoloLensSession.h +++ b/ApplicationCode/Commands/HoloLensCommands/RicHoloLensSession.h @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018 Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -18,9 +18,11 @@ #pragma once +#include "RicHoloLensSessionObserver.h" #include "RicHoloLensRestClient.h" #include "VdePacketDirectory.h" +#include "VdeCachingHashedIdFactory.h" #include #include @@ -30,7 +32,6 @@ class RimGridView; - //================================================================================================== // // @@ -39,9 +40,9 @@ class RimGridView; class RicHoloLensSession : public QObject, private RicHoloLensRestResponseHandler { public: - ~RicHoloLensSession(); + ~RicHoloLensSession() override; - static RicHoloLensSession* createSession(const QString& serverUrl, const QString& sessionName); + static RicHoloLensSession* createSession(const QString& serverUrl, const QString& sessionName, const QByteArray& sessionPinCode, RicHoloLensSessionObserver* sessionObserver); static RicHoloLensSession* createDummyFileBackedSession(); void destroySession(); @@ -52,9 +53,14 @@ class RicHoloLensSession : public QObject, private RicHoloLensRestResponseHandle private: RicHoloLensSession(); - virtual void handleSuccessfulCreateSession() override; - virtual void handleSuccessfulSendMetaData(int metaDataSequenceNumber) override; - virtual void handleError(const QString& errMsg, const QString& url, const QString& serverData) override; + void handleSuccessfulCreateSession() override; + void handleFailedCreateSession() override; + void handleSuccessfulSendMetaData(int metaDataSequenceNumber, const QByteArray& jsonServerResponseString) override; + void handleError(const QString& errMsg, const QString& url, const QString& serverData) override; + + static bool parseJsonIntegerArray(const QByteArray& jsonString, std::vector* integerArr); + + void notifyObserver(RicHoloLensSessionObserver::Notification notification); private: bool m_isSessionValid; @@ -62,10 +68,10 @@ class RicHoloLensSession : public QObject, private RicHoloLensRestResponseHandle int m_lastExtractionMetaDataSequenceNumber; std::vector m_lastExtractionAllReferencedPacketIdsArr; + VdeCachingHashedIdFactory m_cachingIdFactory; VdePacketDirectory m_packetDirectory; - bool m_dbgEnableFileExport; -}; - - + RicHoloLensSessionObserver* m_sessionObserver; + QString m_dbgFileExportDestinationFolder; +}; diff --git a/ApplicationCode/Commands/HoloLensCommands/RicHoloLensSessionManager.cpp b/ApplicationCode/Commands/HoloLensCommands/RicHoloLensSessionManager.cpp index 45ffe49646..e92abfe5f2 100644 --- a/ApplicationCode/Commands/HoloLensCommands/RicHoloLensSessionManager.cpp +++ b/ApplicationCode/Commands/HoloLensCommands/RicHoloLensSessionManager.cpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018 Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -50,7 +50,7 @@ RicHoloLensSessionManager* RicHoloLensSessionManager::instance() //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -bool RicHoloLensSessionManager::createSession(const QString& serverUrl, const QString& sessionName, const QString& /*sessionPinCode*/) +bool RicHoloLensSessionManager::createSession(const QString& serverUrl, const QString& sessionName, const QString& sessionPinCode) { if (m_session) { @@ -58,8 +58,8 @@ bool RicHoloLensSessionManager::createSession(const QString& serverUrl, const QS return false; } - RiaLogging::info(QString("Creating HoloLens session: '%1', server url: %2").arg(sessionName).arg(serverUrl)); - m_session = RicHoloLensSession::createSession(serverUrl, sessionName); + RiaLogging::info(QString("Creating HoloLens session: '%1' with pin code: %2, server url: %3").arg(sessionName).arg(sessionPinCode).arg(serverUrl)); + m_session = RicHoloLensSession::createSession(serverUrl, sessionName, sessionPinCode.toLatin1(), this); refreshToolbarState(); @@ -96,11 +96,14 @@ void RicHoloLensSessionManager::terminateSession() } RiaLogging::info("Terminating HoloLens session"); + + RicHoloLensSession* sessionToDelete = m_session; m_session->destroySession(); - m_session->deleteLater(); m_session = nullptr; refreshToolbarState(); + + sessionToDelete->deleteLater(); } //-------------------------------------------------------------------------------------------------- @@ -120,8 +123,25 @@ void RicHoloLensSessionManager::refreshToolbarState() commandIds << "RicHoloLensCreateSessionFeature"; commandIds << "RicHoloLensExportToSharingServerFeature"; + commandIds << "RicHoloLensAutoExportToSharingServerFeature"; commandIds << "RicHoloLensTerminateSessionFeature"; - caf::CmdFeatureManager::instance()->refreshEnabledState(commandIds); + caf::CmdFeatureManager::instance()->refreshStates(commandIds); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicHoloLensSessionManager::handleSessionNotification(const RicHoloLensSession* session, Notification notification) +{ + if (notification == RicHoloLensSessionObserver::CreateSessionFailed) + { + if (m_session && m_session == session) + terminateSession(); + } + else + { + refreshToolbarState(); + } } diff --git a/ApplicationCode/Commands/HoloLensCommands/RicHoloLensSessionManager.h b/ApplicationCode/Commands/HoloLensCommands/RicHoloLensSessionManager.h index afc0766716..6a19b775af 100644 --- a/ApplicationCode/Commands/HoloLensCommands/RicHoloLensSessionManager.h +++ b/ApplicationCode/Commands/HoloLensCommands/RicHoloLensSessionManager.h @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018 Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -18,20 +18,19 @@ #pragma once -#include "RicHoloLensRestClient.h" +#include "RicHoloLensSessionObserver.h" #include class RicHoloLensSession; - //================================================================================================== // // // //================================================================================================== -class RicHoloLensSessionManager +class RicHoloLensSessionManager : private RicHoloLensSessionObserver { public: static RicHoloLensSessionManager* instance(); @@ -44,6 +43,9 @@ class RicHoloLensSessionManager static void refreshToolbarState(); +private: + void handleSessionNotification(const RicHoloLensSession* session, Notification notification) override; + private: RicHoloLensSessionManager(); diff --git a/ApplicationCode/Commands/HoloLensCommands/RicHoloLensSessionObserver.h b/ApplicationCode/Commands/HoloLensCommands/RicHoloLensSessionObserver.h new file mode 100644 index 0000000000..90467ffb9c --- /dev/null +++ b/ApplicationCode/Commands/HoloLensCommands/RicHoloLensSessionObserver.h @@ -0,0 +1,43 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2018- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +class RicHoloLensSession; + + + +//================================================================================================== +// +// +// +//================================================================================================== +class RicHoloLensSessionObserver +{ +public: + enum Notification + { + CreateSessionSucceeded, + CreateSessionFailed, + GeneralError + }; + +public: + virtual ~RicHoloLensSessionObserver() {} + virtual void handleSessionNotification(const RicHoloLensSession* session, Notification notification) = 0; +}; diff --git a/ApplicationCode/Commands/HoloLensCommands/RicHoloLensTerminateSessionFeature.cpp b/ApplicationCode/Commands/HoloLensCommands/RicHoloLensTerminateSessionFeature.cpp index b01e19d5e3..fa42404c11 100644 --- a/ApplicationCode/Commands/HoloLensCommands/RicHoloLensTerminateSessionFeature.cpp +++ b/ApplicationCode/Commands/HoloLensCommands/RicHoloLensTerminateSessionFeature.cpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018 Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -18,10 +18,12 @@ #include "RicHoloLensTerminateSessionFeature.h" +#include "RicHoloLensAutoExportToSharingServerFeature.h" #include "RicHoloLensSessionManager.h" #include "RiaLogging.h" -#include "RiaQIconTools.h" + +#include "cafCmdFeatureManager.h" #include @@ -40,6 +42,13 @@ bool RicHoloLensTerminateSessionFeature::isCommandEnabled() //-------------------------------------------------------------------------------------------------- void RicHoloLensTerminateSessionFeature::onActionTriggered(bool isChecked) { + auto* cmdFeature = dynamic_cast( + caf::CmdFeatureManager::instance()->getCommandFeature("RicHoloLensAutoExportToSharingServerFeature")); + if (cmdFeature) + { + cmdFeature->setActive(false); + } + RicHoloLensSessionManager::instance()->terminateSession(); RicHoloLensSessionManager::refreshToolbarState(); @@ -50,11 +59,7 @@ void RicHoloLensTerminateSessionFeature::onActionTriggered(bool isChecked) //-------------------------------------------------------------------------------------------------- void RicHoloLensTerminateSessionFeature::setupActionLook(QAction* actionToSetup) { - QPixmap pixmap(":/hololens.png"); - QPixmap overlayPixmap(":/minus-sign-red.png"); - - QPixmap combinedPixmap = RiaQIconTools::appendPixmapUpperLeft(pixmap, overlayPixmap); - actionToSetup->setIcon(QIcon(combinedPixmap)); + actionToSetup->setIcon(QIcon(":/HoloLensDisconnect24x24.png")); - actionToSetup->setText("Terminate Session"); + actionToSetup->setText("Disconnect from HoloLens server"); } diff --git a/ApplicationCode/Commands/HoloLensCommands/RicHoloLensTerminateSessionFeature.h b/ApplicationCode/Commands/HoloLensCommands/RicHoloLensTerminateSessionFeature.h index 24cff2f896..06f8326c3f 100644 --- a/ApplicationCode/Commands/HoloLensCommands/RicHoloLensTerminateSessionFeature.h +++ b/ApplicationCode/Commands/HoloLensCommands/RicHoloLensTerminateSessionFeature.h @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018 Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by diff --git a/ApplicationCode/Commands/HoloLensCommands/VdeArrayDataPacket.cpp b/ApplicationCode/Commands/HoloLensCommands/VdeArrayDataPacket.cpp index 111e84a389..8466c03d8b 100644 --- a/ApplicationCode/Commands/HoloLensCommands/VdeArrayDataPacket.cpp +++ b/ApplicationCode/Commands/HoloLensCommands/VdeArrayDataPacket.cpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018 Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -178,40 +178,40 @@ unsigned char VdeArrayDataPacket::imageComponentCount() const //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -VdeArrayDataPacket VdeArrayDataPacket::fromFloat32Arr(int arrayId, const float* srcArr, size_t srcArrElementCount) +std::unique_ptr VdeArrayDataPacket::fromFloat32Arr(int arrayId, const float* srcArr, size_t srcArrElementCount) { size_t payloadByteCount = srcArrElementCount*sizeof(float); const char* rawSrcPtr = reinterpret_cast(srcArr); - VdeArrayDataPacket packet; - packet.assign(arrayId, Float32, srcArrElementCount, 0, 0, 0, rawSrcPtr, payloadByteCount); + std::unique_ptr packet(new VdeArrayDataPacket); + packet->assign(arrayId, Float32, srcArrElementCount, 0, 0, 0, rawSrcPtr, payloadByteCount); return packet; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -VdeArrayDataPacket VdeArrayDataPacket::fromUint32Arr(int arrayId, const unsigned int* srcArr, size_t srcArrElementCount) +std::unique_ptr VdeArrayDataPacket::fromUint32Arr(int arrayId, const unsigned int* srcArr, size_t srcArrElementCount) { size_t payloadByteCount = srcArrElementCount*sizeof(unsigned int); const char* rawSrcPtr = reinterpret_cast(srcArr); - VdeArrayDataPacket packet; - packet.assign(arrayId, Uint32, srcArrElementCount, 0, 0, 0, rawSrcPtr, payloadByteCount); + std::unique_ptr packet(new VdeArrayDataPacket); + packet->assign(arrayId, Uint32, srcArrElementCount, 0, 0, 0, rawSrcPtr, payloadByteCount); return packet; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -VdeArrayDataPacket VdeArrayDataPacket::fromUint8ImageRGBArr(int arrayId, unsigned short imageWidth, unsigned short imageHeight, const unsigned char* srcArr, size_t srcArrElementCount) +std::unique_ptr VdeArrayDataPacket::fromUint8ImageRGBArr(int arrayId, unsigned short imageWidth, unsigned short imageHeight, const unsigned char* srcArr, size_t srcArrElementCount) { const char* rawSrcPtr = reinterpret_cast(srcArr); assert(3*imageWidth*imageHeight == srcArrElementCount); - VdeArrayDataPacket packet; - packet.assign(arrayId, Uint8, srcArrElementCount, imageWidth, imageHeight, 3, rawSrcPtr, srcArrElementCount); + std::unique_ptr packet(new VdeArrayDataPacket); + packet->assign(arrayId, Uint8, srcArrElementCount, imageWidth, imageHeight, 3, rawSrcPtr, srcArrElementCount); return packet; } diff --git a/ApplicationCode/Commands/HoloLensCommands/VdeArrayDataPacket.h b/ApplicationCode/Commands/HoloLensCommands/VdeArrayDataPacket.h index dd0847a64d..ee9489cad0 100644 --- a/ApplicationCode/Commands/HoloLensCommands/VdeArrayDataPacket.h +++ b/ApplicationCode/Commands/HoloLensCommands/VdeArrayDataPacket.h @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018 Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -21,6 +21,7 @@ #include #include #include +#include //================================================================================================== @@ -42,26 +43,26 @@ class VdeArrayDataPacket public: VdeArrayDataPacket(); - bool isValid() const; - int arrayId() const; + bool isValid() const; + int arrayId() const; - ElementType elementType() const; - size_t elementSize() const; - size_t elementCount() const; - const char* arrayData() const; + ElementType elementType() const; + size_t elementSize() const; + size_t elementCount() const; + const char* arrayData() const; - unsigned short imageWidth() const; - unsigned short imageHeight() const; - unsigned char imageComponentCount() const; + unsigned short imageWidth() const; + unsigned short imageHeight() const; + unsigned char imageComponentCount() const; - size_t fullPacketSize() const; - const char* fullPacketRawPtr() const; + size_t fullPacketSize() const; + const char* fullPacketRawPtr() const; - static VdeArrayDataPacket fromFloat32Arr(int arrayId, const float* srcArr, size_t srcArrElementCount); - static VdeArrayDataPacket fromUint32Arr(int arrayId, const unsigned int* srcArr, size_t srcArrElementCount); - static VdeArrayDataPacket fromUint8ImageRGBArr(int arrayId, unsigned short imageWidth, unsigned short imageHeight, const unsigned char* srcArr, size_t srcArrElementCount); + static std::unique_ptr fromFloat32Arr(int arrayId, const float* srcArr, size_t srcArrElementCount); + static std::unique_ptr fromUint32Arr(int arrayId, const unsigned int* srcArr, size_t srcArrElementCount); + static std::unique_ptr fromUint8ImageRGBArr(int arrayId, unsigned short imageWidth, unsigned short imageHeight, const unsigned char* srcArr, size_t srcArrElementCount); - static VdeArrayDataPacket fromRawPacketBuffer(const char* rawPacketBuffer, size_t bufferSize, std::string* errString); + static VdeArrayDataPacket fromRawPacketBuffer(const char* rawPacketBuffer, size_t bufferSize, std::string* errString); private: bool assign(int arrayId, ElementType elementType, size_t elementCount, unsigned short imageWidth, unsigned short imageHeight, unsigned char imageCompCount, const char* arrayDataPtr, size_t arrayDataSizeInBytes); diff --git a/ApplicationCode/Commands/HoloLensCommands/VdeCachingHashedIdFactory.cpp b/ApplicationCode/Commands/HoloLensCommands/VdeCachingHashedIdFactory.cpp new file mode 100644 index 0000000000..f2ac4ff7cc --- /dev/null +++ b/ApplicationCode/Commands/HoloLensCommands/VdeCachingHashedIdFactory.cpp @@ -0,0 +1,257 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2018- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "VdeCachingHashedIdFactory.h" + +#define FARMHASH_NO_BUILTIN_EXPECT +#define NAMESPACE_FOR_HASH_FUNCTIONS farmhash +#include "farmhash/farmhash.h" + +#ifdef _MSC_VER +#pragma warning (push) +#pragma warning (disable: 4267 4307 4319 4244 4456) +#endif + +#include "farmhash/farmhash.cc" + +#ifdef _MSC_VER +#pragma warning (pop) +#endif + + + +//================================================================================================== +// +// +// +//================================================================================================== +class Checksum +{ +public: + static unsigned int crc(const void* data, size_t numBytes); +}; + + + +//================================================================================================== +// +// +// +//================================================================================================== + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool VdeCachingHashedIdFactory::Key::operator<(const Key& other) const +{ + if (hashVal != other.hashVal) + { + return hashVal < other.hashVal; + } + else if (role != other.role) + { + return role < other.role; + } + else if (elementType != other.elementType) + { + return elementType < other.elementType; + } + else + { + return elementCount < other.elementCount; + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +VdeCachingHashedIdFactory::VdeCachingHashedIdFactory() + : m_lastUsedId(-1) +{ +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +int VdeCachingHashedIdFactory::getOrCreateIdForFloatArr(ArrayRole arrayRole, const void* floatArr, size_t elementCount) +{ + return getOrCreateIdForArrOfType(arrayRole, Float32, sizeof(float), floatArr, elementCount); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +int VdeCachingHashedIdFactory::getOrCreateIdForUint32Arr(ArrayRole arrayRole, const unsigned int* uint32Arr, size_t elementCount) +{ + return getOrCreateIdForArrOfType(arrayRole, Uint32, sizeof(unsigned int), uint32Arr, elementCount); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +int VdeCachingHashedIdFactory::getOrCreateIdForUint8Arr(ArrayRole arrayRole, const unsigned char* uint8Arr, size_t elementCount) +{ + return getOrCreateIdForArrOfType(arrayRole, Uint8, sizeof(unsigned char), uint8Arr, elementCount); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +int VdeCachingHashedIdFactory::lastAssignedId() const +{ + return m_lastUsedId; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +int VdeCachingHashedIdFactory::getOrCreateIdForArrOfType(ArrayRole arrayRole, ElementType elementType, size_t elementSizeInBytes, const void* data, size_t elementCount) +{ + Key key; + key.elementType = elementType; + key.role = arrayRole; + key.elementCount = elementCount; + + const size_t arraySizeInBytes = elementCount*elementSizeInBytes; + //key.hashVal = Checksum::crc(data, arraySizeInBytes); + //key.hashVal = farmhash::Hash32(static_cast(data), arraySizeInBytes); + //key.hashVal = farmhash::Hash64(static_cast(data), arraySizeInBytes); + //key.hashVal = farmhash::Hash128to64(farmhash::Hash128(static_cast(data), arraySizeInBytes)); + key.hashVal = farmhash::Hash128(static_cast(data), arraySizeInBytes); + + std::map::iterator it = m_keyToIdMap.find(key); + if (it != m_keyToIdMap.end()) + { + return it->second; + } + + const int newId = ++m_lastUsedId; + + m_keyToIdMap[key] = newId; + + return newId; + + //const int newId = ++m_lastUsedId; + //return newId; +} + + + + +//================================================================================================== +// +// CRC Stuff +// +//================================================================================================== + +static const unsigned int crc_table[256] = { + 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, + 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, + 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, + 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, + 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, + 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, + 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, + 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, + 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, + 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, + 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, + 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, + 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, + 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, + 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, + 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, + 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, + 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, + 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, + 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, + 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, + 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, + 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, + 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, + 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, + 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, + 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, + 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, + 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, + 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, + 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, + 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, + 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, + 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, + 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, + 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, + 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, + 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, + 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, + 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, + 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, + 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, + 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, + 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, + 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, + 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, + 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, + 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, + 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, + 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, + 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, + 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, + 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, + 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, + 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, + 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, + 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, + 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, + 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, + 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, + 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, + 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, + 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, + 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d +}; + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +unsigned int Checksum::crc(const void* data, size_t numBytes) +{ + unsigned int sum = 0xffffffff; + + const unsigned char* p = reinterpret_cast(data); + + // Compute crc + { + unsigned int tbl_idx; + + while (numBytes--) { + tbl_idx = (sum ^ *p) & 0xff; + sum = (crc_table[tbl_idx] ^ (sum >> 8)) & 0xffffffff; + + p++; + } + + sum = sum & 0xffffffff; + } + + return sum ^ 0xffffffff; +} + + + diff --git a/ApplicationCode/Commands/HoloLensCommands/VdeCachingHashedIdFactory.h b/ApplicationCode/Commands/HoloLensCommands/VdeCachingHashedIdFactory.h new file mode 100644 index 0000000000..712a11f978 --- /dev/null +++ b/ApplicationCode/Commands/HoloLensCommands/VdeCachingHashedIdFactory.h @@ -0,0 +1,73 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2018- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include + + +//================================================================================================== +// +// +// +//================================================================================================== +class VdeCachingHashedIdFactory +{ +public: + enum ArrayRole + { + VertexArr, + ConnArr, + TexImage, + TexCoordsArr + }; + +public: + VdeCachingHashedIdFactory(); + + int getOrCreateIdForFloatArr(ArrayRole arrayRole, const void* floatArr, size_t elementCount); + int getOrCreateIdForUint32Arr(ArrayRole arrayRole, const unsigned int* uint32Arr, size_t elementCount); + int getOrCreateIdForUint8Arr(ArrayRole arrayRole, const unsigned char* uint8Arr, size_t elementCount); + + int lastAssignedId() const; + +private: + enum ElementType + { + Float32, + Uint32, + Uint8, + }; + + struct Key + { + std::pair hashVal; + ArrayRole role; + ElementType elementType; + size_t elementCount; + + bool operator<(const Key& other) const; + }; + +private: + int getOrCreateIdForArrOfType(ArrayRole arrayRole, ElementType elementType, size_t elementSizeInBytes, const void* data, size_t elementCount); + +private: + std::map m_keyToIdMap; + int m_lastUsedId; +}; diff --git a/ApplicationCode/Commands/HoloLensCommands/VdeExportPart.cpp b/ApplicationCode/Commands/HoloLensCommands/VdeExportPart.cpp index a89544c69b..006169dc3e 100644 --- a/ApplicationCode/Commands/HoloLensCommands/VdeExportPart.cpp +++ b/ApplicationCode/Commands/HoloLensCommands/VdeExportPart.cpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018 Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -28,6 +28,7 @@ VdeExportPart::VdeExportPart(cvf::Part* part) , m_color(cvf::Color3f::MAGENTA) , m_opacity(1.0) , m_winding(COUNTERCLOCKWISE) + , m_cullFace(CF_NONE) , m_role(GEOMETRY) { } @@ -88,6 +89,14 @@ void VdeExportPart::setWinding(Winding winding) m_winding = winding; } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void VdeExportPart::setCullFace(CullFace cullFace) +{ + m_cullFace = cullFace; +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -160,6 +169,14 @@ VdeExportPart::Winding VdeExportPart::winding() const return m_winding; } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +VdeExportPart::CullFace VdeExportPart::cullFace() const +{ + return m_cullFace; +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/Commands/HoloLensCommands/VdeExportPart.h b/ApplicationCode/Commands/HoloLensCommands/VdeExportPart.h index 50fa469a70..044686785a 100644 --- a/ApplicationCode/Commands/HoloLensCommands/VdeExportPart.h +++ b/ApplicationCode/Commands/HoloLensCommands/VdeExportPart.h @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018 Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -44,6 +44,13 @@ class VdeExportPart COUNTERCLOCKWISE }; + enum CullFace + { + CF_NONE, + CF_FRONT, + CF_BACK + }; + enum Role { GEOMETRY, @@ -60,6 +67,7 @@ class VdeExportPart void setColor(const cvf::Color3f& color); void setOpacity(float opacity); void setWinding(Winding winding); + void setCullFace(CullFace cullFace); void setRole(Role role); const cvf::Part* part() const; @@ -71,6 +79,7 @@ class VdeExportPart cvf::Color3f color() const; float opacity() const; Winding winding() const; + CullFace cullFace() const; Role role() const; private: @@ -83,5 +92,6 @@ class VdeExportPart cvf::Color3f m_color; float m_opacity; Winding m_winding; + CullFace m_cullFace; Role m_role; }; diff --git a/ApplicationCode/Commands/HoloLensCommands/VdeFileExporter.cpp b/ApplicationCode/Commands/HoloLensCommands/VdeFileExporter.cpp index 9bef8b453e..db37112ef2 100644 --- a/ApplicationCode/Commands/HoloLensCommands/VdeFileExporter.cpp +++ b/ApplicationCode/Commands/HoloLensCommands/VdeFileExporter.cpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018 Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -19,6 +19,7 @@ #include "VdeFileExporter.h" #include "VdeArrayDataPacket.h" #include "VdePacketDirectory.h" +#include "VdeCachingHashedIdFactory.h" #include "cvfTrace.h" @@ -72,7 +73,7 @@ bool VdeFileExporter::exportToFile(const QString& modelMetaJsonStr, const VdePac } } - cvf::Trace::show("Data exported to folder: %s", m_absOutputFolder.toLatin1().constData()); + cvf::Trace::show("Data exported (%d packets) to folder: %s", packetIdsToExport.size(), m_absOutputFolder.toLatin1().constData()); return true; } @@ -82,11 +83,12 @@ bool VdeFileExporter::exportToFile(const QString& modelMetaJsonStr, const VdePac //-------------------------------------------------------------------------------------------------- bool VdeFileExporter::exportViewContents(const RimGridView& view) { + VdeCachingHashedIdFactory localIdFactory; + VdeVizDataExtractor extractor(view, &localIdFactory); + QString modelMetaJsonStr; std::vector allReferencedArrayIds; VdePacketDirectory packetDirectory; - - VdeVizDataExtractor extractor(view); extractor.extractViewContents(&modelMetaJsonStr, &allReferencedArrayIds, &packetDirectory); if (!exportToFile(modelMetaJsonStr, packetDirectory, allReferencedArrayIds)) diff --git a/ApplicationCode/Commands/HoloLensCommands/VdeFileExporter.h b/ApplicationCode/Commands/HoloLensCommands/VdeFileExporter.h index e5435e91a0..82a821928c 100644 --- a/ApplicationCode/Commands/HoloLensCommands/VdeFileExporter.h +++ b/ApplicationCode/Commands/HoloLensCommands/VdeFileExporter.h @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018 Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by diff --git a/ApplicationCode/Commands/HoloLensCommands/VdePacketDirectory.cpp b/ApplicationCode/Commands/HoloLensCommands/VdePacketDirectory.cpp index 9db4a0379a..f38f622658 100644 --- a/ApplicationCode/Commands/HoloLensCommands/VdePacketDirectory.cpp +++ b/ApplicationCode/Commands/HoloLensCommands/VdePacketDirectory.cpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018 Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -18,6 +18,7 @@ #include "VdePacketDirectory.h" +#include //================================================================================================== @@ -36,10 +37,10 @@ VdePacketDirectory::VdePacketDirectory() //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void VdePacketDirectory::addPacket(const VdeArrayDataPacket& packet) +void VdePacketDirectory::addPacket(std::unique_ptr packet) { - const int id = packet.arrayId(); - m_idToPacketMap[id] = std::unique_ptr(new VdeArrayDataPacket(packet)); + const int id = packet->arrayId(); + m_idToPacketMap[id] = std::move(packet); } //-------------------------------------------------------------------------------------------------- @@ -64,6 +65,29 @@ void VdePacketDirectory::clear() m_idToPacketMap.clear(); } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void VdePacketDirectory::pruneUnreferencedPackets(const std::vector& packetIdsInUseArr) +{ + std::vector sortedPacketsIdsInUse(packetIdsInUseArr); + std::sort(sortedPacketsIdsInUse.begin(), sortedPacketsIdsInUse.end()); + + IdToPacketMap_T::const_iterator it = m_idToPacketMap.cbegin(); + while (it != m_idToPacketMap.cend()) + { + const int packetId = it->first; + if (!std::binary_search(sortedPacketsIdsInUse.begin(), sortedPacketsIdsInUse.end(), packetId)) + { + it = m_idToPacketMap.erase(it); + } + else + { + ++it; + } + } +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/Commands/HoloLensCommands/VdePacketDirectory.h b/ApplicationCode/Commands/HoloLensCommands/VdePacketDirectory.h index 3f5b0123d9..115f2b80c6 100644 --- a/ApplicationCode/Commands/HoloLensCommands/VdePacketDirectory.h +++ b/ApplicationCode/Commands/HoloLensCommands/VdePacketDirectory.h @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018 Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -36,9 +36,11 @@ class VdePacketDirectory public: VdePacketDirectory(); - void addPacket(const VdeArrayDataPacket& packet); + void addPacket(std::unique_ptr packet); const VdeArrayDataPacket* lookupPacket(int arrayId) const; + void clear(); + void pruneUnreferencedPackets(const std::vector& packetIdsInUseArr); bool getPacketsAsCombinedBuffer(const std::vector& packetIdsToGet, QByteArray* combinedPacketArr) const; diff --git a/ApplicationCode/Commands/HoloLensCommands/VdeVizDataExtractor.cpp b/ApplicationCode/Commands/HoloLensCommands/VdeVizDataExtractor.cpp index 57d4541ab2..88c6c2ea6f 100644 --- a/ApplicationCode/Commands/HoloLensCommands/VdeVizDataExtractor.cpp +++ b/ApplicationCode/Commands/HoloLensCommands/VdeVizDataExtractor.cpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018 Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -19,6 +19,7 @@ #include "VdeVizDataExtractor.h" #include "VdeArrayDataPacket.h" #include "VdePacketDirectory.h" +#include "VdeCachingHashedIdFactory.h" #include "RicHoloLensExportImpl.h" @@ -29,6 +30,8 @@ #include "cvfDrawableGeo.h" #include "cvfPrimitiveSet.h" #include "cvfTransform.h" +#include "cvfAssert.h" +#include "cvfTimer.h" #include "cvfTrace.h" @@ -43,9 +46,11 @@ //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -VdeVizDataExtractor::VdeVizDataExtractor(const RimGridView& view) - : m_view(view) +VdeVizDataExtractor::VdeVizDataExtractor(const RimGridView& view, VdeCachingHashedIdFactory* cachingIdFactory) + : m_view(view), + m_cachingIdFactory(cachingIdFactory) { + CVF_ASSERT(m_cachingIdFactory); } //-------------------------------------------------------------------------------------------------- @@ -53,84 +58,114 @@ VdeVizDataExtractor::VdeVizDataExtractor(const RimGridView& view) //-------------------------------------------------------------------------------------------------- void VdeVizDataExtractor::extractViewContents(QString* modelMetaJsonStr, std::vector* allReferencedArrayIds, VdePacketDirectory* packetDirectory) { + cvf::Timer tim; + // First extract the parts (cvfPart + info) to be exported from from the ResInsight view const std::vector exportPartsArr = RicHoloLensExportImpl::partsForExport(m_view); // Convert this to an array of export ready meshes - const std::vector meshArr = buildMeshArray(exportPartsArr); - const size_t meshCount = meshArr.size(); - cvf::Trace::show("Extracting %d meshes", meshCount); + const std::vector > meshArr = buildMeshArray(exportPartsArr); + const int buildMeshes_ms = static_cast(tim.lapTime()*1000); + - std::vector meshArrayIdsArr; + const size_t meshCount = meshArr.size(); + cvf::Trace::show("Analyzing and generating array packet data for %d meshes", meshCount); + std::vector allMeshesArrayIdsArr; size_t totNumPrimitives = 0; - int nextArrayId = 0; for (size_t i = 0; i < meshCount; i++) { - const VdeMesh& mesh = meshArr[i]; + const VdeMesh* mesh = meshArr[i].get(); - const size_t primCount = mesh.connArr.size()/mesh.verticesPerPrimitive; + const size_t primCount = mesh->connArr.size()/mesh->verticesPerPrimitive; totNumPrimitives += primCount; - cvf::Trace::show(" %2d: primCount=%d meshSourceObjName='%s'", i, primCount, mesh.meshSourceObjName.toLatin1().constData()); + cvf::Trace::show(" mesh %2d: primCount=%d vertsPerPrim=%d meshSourceObjName='%s' meshSourceObjType='%s'", i, primCount, mesh->verticesPerPrimitive, mesh->meshSourceObjName.toLatin1().constData(), mesh->meshSourceObjTypeStr.toLatin1().constData()); - VdeMeshArrayIds meshArrayIds; + VdeMeshArrayIds arrayIdsThisMesh; { - cvf::Trace::show(" exporting vertices"); - meshArrayIds.vertexArrId = nextArrayId++; - const float* floatArr = reinterpret_cast(mesh.vertexArr->ptr()); - VdeArrayDataPacket dataPacket = VdeArrayDataPacket::fromFloat32Arr(meshArrayIds.vertexArrId, floatArr, 3*mesh.vertexArr->size()); - packetDirectory->addPacket(dataPacket); - - // Debug testing of decoding - debugComparePackets(dataPacket, VdeArrayDataPacket::fromRawPacketBuffer(dataPacket.fullPacketRawPtr(), dataPacket.fullPacketSize(), nullptr)); + const float* floatArr = reinterpret_cast(mesh->vertexArr->ptr()); + const size_t arrElementCount = 3*mesh->vertexArr->size(); + arrayIdsThisMesh.vertexArrId = m_cachingIdFactory->getOrCreateIdForFloatArr(VdeCachingHashedIdFactory::VertexArr, floatArr, arrElementCount); + + if (!packetDirectory->lookupPacket(arrayIdsThisMesh.vertexArrId)) + { + cvf::Trace::show(" generating vertices, arrayId=%d", arrayIdsThisMesh.vertexArrId); + std::unique_ptr dataPacket = VdeArrayDataPacket::fromFloat32Arr(arrayIdsThisMesh.vertexArrId, floatArr, arrElementCount); + + // Debug testing of decoding + //debugComparePackets(*dataPacket, VdeArrayDataPacket::fromRawPacketBuffer(dataPacket->fullPacketRawPtr(), dataPacket->fullPacketSize(), nullptr)); + + packetDirectory->addPacket(std::move(dataPacket)); + } } { - cvf::Trace::show(" exporting connectivities"); - meshArrayIds.connArrId = nextArrayId++; - const unsigned int* uintArr = mesh.connArr.data(); - VdeArrayDataPacket dataPacket = VdeArrayDataPacket::fromUint32Arr(meshArrayIds.connArrId, uintArr, mesh.connArr.size()); - packetDirectory->addPacket(dataPacket); - - // Debug testing of decoding - debugComparePackets(dataPacket, VdeArrayDataPacket::fromRawPacketBuffer(dataPacket.fullPacketRawPtr(), dataPacket.fullPacketSize(), nullptr)); + const unsigned int* uintArr = mesh->connArr.data(); + const size_t arrElementCount = mesh->connArr.size(); + arrayIdsThisMesh.connArrId = m_cachingIdFactory->getOrCreateIdForUint32Arr(VdeCachingHashedIdFactory::ConnArr, uintArr, arrElementCount); + + if (!packetDirectory->lookupPacket(arrayIdsThisMesh.connArrId)) + { + cvf::Trace::show(" generating connectivities, arrayId=%d", arrayIdsThisMesh.connArrId); + std::unique_ptr dataPacket = VdeArrayDataPacket::fromUint32Arr(arrayIdsThisMesh.connArrId, uintArr, arrElementCount); + + // Debug testing of decoding + //debugComparePackets(*dataPacket, VdeArrayDataPacket::fromRawPacketBuffer(dataPacket->fullPacketRawPtr(), dataPacket->fullPacketSize(), nullptr)); + + packetDirectory->addPacket(std::move(dataPacket)); + } } - if (mesh.texCoordArr.notNull() && mesh.texImage.notNull()) + if (mesh->texCoordArr.notNull() && mesh->texImage.notNull()) { { - cvf::Trace::show(" exporting texture coords"); - meshArrayIds.texCoordsArrId = nextArrayId++; - const float* floatArr = reinterpret_cast(mesh.texCoordArr->ptr()); - VdeArrayDataPacket dataPacket = VdeArrayDataPacket::fromFloat32Arr(meshArrayIds.texCoordsArrId, floatArr, 2*mesh.texCoordArr->size()); - packetDirectory->addPacket(dataPacket); + const float* floatArr = reinterpret_cast(mesh->texCoordArr->ptr()); + const size_t arrElementCount = 2*mesh->texCoordArr->size(); + arrayIdsThisMesh.texCoordsArrId = m_cachingIdFactory->getOrCreateIdForFloatArr(VdeCachingHashedIdFactory::TexCoordsArr, floatArr, arrElementCount); - // Debug testing of decoding - debugComparePackets(dataPacket, VdeArrayDataPacket::fromRawPacketBuffer(dataPacket.fullPacketRawPtr(), dataPacket.fullPacketSize(), nullptr)); + if (!packetDirectory->lookupPacket(arrayIdsThisMesh.texCoordsArrId)) + { + cvf::Trace::show(" generating texture coords, arrayId=%d", arrayIdsThisMesh.texCoordsArrId); + std::unique_ptr dataPacket = VdeArrayDataPacket::fromFloat32Arr(arrayIdsThisMesh.texCoordsArrId, floatArr, arrElementCount); + + // Debug testing of decoding + //debugComparePackets(*dataPacket, VdeArrayDataPacket::fromRawPacketBuffer(dataPacket->fullPacketRawPtr(), dataPacket->fullPacketSize(), nullptr)); + + packetDirectory->addPacket(std::move(dataPacket)); + } } { - cvf::Trace::show(" exporting texture image"); - meshArrayIds.texImageArrId = nextArrayId++; - cvf::ref byteArr = mesh.texImage->toRgb(); - VdeArrayDataPacket dataPacket = VdeArrayDataPacket::fromUint8ImageRGBArr(meshArrayIds.texImageArrId, mesh.texImage->width(), mesh.texImage->height(), byteArr->ptr(), byteArr->size()); - packetDirectory->addPacket(dataPacket); + cvf::ref byteArr = mesh->texImage->toRgb(); + arrayIdsThisMesh.texImageArrId = m_cachingIdFactory->getOrCreateIdForUint8Arr(VdeCachingHashedIdFactory::TexImage, byteArr->ptr(), byteArr->size()); - // Debug testing of decoding - debugComparePackets(dataPacket, VdeArrayDataPacket::fromRawPacketBuffer(dataPacket.fullPacketRawPtr(), dataPacket.fullPacketSize(), nullptr)); + if (!packetDirectory->lookupPacket(arrayIdsThisMesh.texImageArrId)) + { + cvf::Trace::show(" generating texture image, arrayId=%d", arrayIdsThisMesh.texImageArrId); + std::unique_ptr dataPacket = VdeArrayDataPacket::fromUint8ImageRGBArr(arrayIdsThisMesh.texImageArrId, mesh->texImage->width(), mesh->texImage->height(), byteArr->ptr(), byteArr->size()); + + // Debug testing of decoding + //debugComparePackets(*dataPacket, VdeArrayDataPacket::fromRawPacketBuffer(dataPacket->fullPacketRawPtr(), dataPacket->fullPacketSize(), nullptr)); + + packetDirectory->addPacket(std::move(dataPacket)); + } } } - meshArrayIdsArr.push_back(meshArrayIds); + allMeshesArrayIdsArr.push_back(arrayIdsThisMesh); } - cvf::Trace::show("Total number of primitives extracted: %d", totNumPrimitives); + const int fillPacketDir_ms = static_cast(tim.lapTime()*1000); + + // Extract any exportable labels present in the view + const std::vector> labelAndPositionsArr = RicHoloLensExportImpl::labelsForExport(m_view); - *modelMetaJsonStr = createModelMetaJsonString(meshArr, meshArrayIdsArr); + // Actually create the JSON containing model meta data + *modelMetaJsonStr = createModelMetaJsonString(meshArr, allMeshesArrayIdsArr, labelAndPositionsArr); // Find all unique packet array IDs referenced std::set referencedIdsSet; - for (const VdeMeshArrayIds& meshArrayIds : meshArrayIdsArr) + for (const VdeMeshArrayIds& meshArrayIds : allMeshesArrayIdsArr) { if (meshArrayIds.vertexArrId != -1) referencedIdsSet.insert(meshArrayIds.vertexArrId); if (meshArrayIds.connArrId != -1) referencedIdsSet.insert(meshArrayIds.connArrId); @@ -139,20 +174,24 @@ void VdeVizDataExtractor::extractViewContents(QString* modelMetaJsonStr, std::ve } allReferencedArrayIds->assign(referencedIdsSet.begin(), referencedIdsSet.end()); + + RiaLogging::debug(QString("HoloLens: Extracted %1 meshes (total of %2 primitives) in %3ms (buildMeshes=%4ms, fillPacketDir=%5ms)").arg(meshCount).arg(totNumPrimitives).arg(static_cast(tim.time()*1000)).arg(buildMeshes_ms).arg(fillPacketDir_ms)); + + //cvf::Trace::show("Total number of primitives extracted: %d in %dms", totNumPrimitives, static_cast(tim.time()*1000)); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -std::vector VdeVizDataExtractor::buildMeshArray(const std::vector& exportPartsArr) +std::vector > VdeVizDataExtractor::buildMeshArray(const std::vector& exportPartsArr) { - std::vector meshArr; + std::vector > meshArr; for (const VdeExportPart& exportPart : exportPartsArr) { - VdeMesh mesh; - if (extractMeshFromExportPart(exportPart, &mesh)) + std::unique_ptr mesh = createMeshFromExportPart(exportPart); + if (mesh) { - meshArr.push_back(mesh); + meshArr.push_back(std::move(mesh)); } } @@ -162,26 +201,28 @@ std::vector VdeVizDataExtractor::buildMeshArray(const std::vector VdeVizDataExtractor::createMeshFromExportPart(const VdeExportPart& exportPart) { + //cvf::Timer tim; + const cvf::Part* cvfPart = exportPart.part(); const cvf::DrawableGeo* geo = dynamic_cast(cvfPart ? cvfPart->drawable() : nullptr); if (!geo) { - return false; + return nullptr; } if (geo->primitiveSetCount() != 1) { RiaLogging::debug("Only geometries with exactly one primitive set is supported"); - return false; + return nullptr; } const cvf::Vec3fArray* vertexArr = geo->vertexArray(); const cvf::PrimitiveSet* primSet = geo->primitiveSet(0); if (!vertexArr || !primSet || primSet->faceCount() == 0) { - return false; + return nullptr; } @@ -190,23 +231,24 @@ bool VdeVizDataExtractor::extractMeshFromExportPart(const VdeExportPart& exportP if (primType != cvf::PT_TRIANGLES && primType != cvf::PT_LINES) { RiaLogging::debug(QString("Currently only triangle and line primitive sets are supported (saw primitive type: %1)").arg(primType)); - return false; + return nullptr; } const int vertsPerPrimitive = (primType == cvf::PT_TRIANGLES) ? 3 : 2; - + + std::unique_ptr mesh(new VdeMesh); mesh->verticesPerPrimitive = vertsPerPrimitive; // Possibly transform the vertices if (cvfPart->transform()) { - const size_t vertexCount = vertexArr->size(); - cvf::ref transVertexArr = new cvf::Vec3fArray(vertexArr->size()); + const cvf::Mat4f m = cvf::Mat4f(cvfPart->transform()->worldTransform()); - cvf::Mat4f m = cvf::Mat4f(cvfPart->transform()->worldTransform()); + cvf::ref transVertexArr = new cvf::Vec3fArray(*vertexArr); + const size_t vertexCount = transVertexArr->size(); for (size_t i = 0; i < vertexCount; i++) { - transVertexArr->set(i, vertexArr->get(i).getTransformedPoint(m)); + transVertexArr->ptr(i)->transformPoint(m); } mesh->vertexArr = transVertexArr.p(); @@ -216,12 +258,15 @@ bool VdeVizDataExtractor::extractMeshFromExportPart(const VdeExportPart& exportP mesh->vertexArr = vertexArr; } + // Fetch connectivities // Using getFaceIndices() allows us to access strips and fans in the same way as triangles // Note that HoloLens visualization wants triangles in clockwise order so we try and fix the winding - // This point might be moot if the HoloLens visualization always has to use two-sideded lighting to get good results - cvf::UIntArray faceConn; + // This point might be moot if the HoloLens visualization always has to use two-sided lighting to get good results const size_t faceCount = primSet->faceCount(); + mesh->connArr.reserve(faceCount*vertsPerPrimitive); + + cvf::UIntArray faceConn; for (size_t iface = 0; iface < faceCount; iface++) { primSet->getFaceIndices(iface, &faceConn); @@ -259,26 +304,34 @@ bool VdeVizDataExtractor::extractMeshFromExportPart(const VdeExportPart& exportP mesh->color = exportPart.color(); mesh->opacity = exportPart.opacity(); - return true; + if (exportPart.cullFace() != VdeExportPart::CF_NONE) + { + if (exportPart.cullFace() == VdeExportPart::CF_FRONT) mesh->cullFaceModeStr = "front"; + else if (exportPart.cullFace() == VdeExportPart::CF_BACK) mesh->cullFaceModeStr = "back"; + else mesh->cullFaceModeStr = "none"; + } + + //cvf::Trace::show("createMeshFromExportPart(): numFaces=%d, time=%dms", faceCount, static_cast(tim.time()*1000)); + + return mesh; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -QString VdeVizDataExtractor::createModelMetaJsonString(const std::vector& meshArr, const std::vector& meshContentIdsArr) +QString VdeVizDataExtractor::createModelMetaJsonString(const std::vector >& meshArr, const std::vector& meshContentIdsArr, const std::vector >& labelAndPositionsArr) { QVariantList jsonMeshMetaList; - for (size_t i = 0; i < meshArr.size(); i++) { - const VdeMesh& mesh = meshArr[i]; + const VdeMesh* mesh = meshArr[i].get(); const VdeMeshArrayIds& meshIds = meshContentIdsArr[i]; QMap jsonMeshMeta; - jsonMeshMeta["meshSourceObjType"] = mesh.meshSourceObjTypeStr; - jsonMeshMeta["meshSourceObjName"] = mesh.meshSourceObjName; + jsonMeshMeta["meshSourceObjType"] = mesh->meshSourceObjTypeStr; + jsonMeshMeta["meshSourceObjName"] = mesh->meshSourceObjName; - jsonMeshMeta["verticesPerPrimitive"] = mesh.verticesPerPrimitive; + jsonMeshMeta["verticesPerPrimitive"] = mesh->verticesPerPrimitive; jsonMeshMeta["vertexArrId"] = meshIds.vertexArrId; jsonMeshMeta["connArrId"] = meshIds.connArrId; @@ -290,21 +343,47 @@ QString VdeVizDataExtractor::createModelMetaJsonString(const std::vector jsonColor; - jsonColor["r"] = mesh.color.r(); - jsonColor["g"] = mesh.color.g(); - jsonColor["b"] = mesh.color.b(); + jsonColor["r"] = mesh->color.r(); + jsonColor["g"] = mesh->color.g(); + jsonColor["b"] = mesh->color.b(); jsonMeshMeta["color"] = jsonColor; } - jsonMeshMeta["opacity"] = mesh.opacity; + jsonMeshMeta["opacity"] = mesh->opacity; + + if (!mesh->cullFaceModeStr.isEmpty()) + { + jsonMeshMeta["cullFaceMode"] = mesh->cullFaceModeStr; + } jsonMeshMetaList.push_back(jsonMeshMeta); } + + QVariantList jsonLabelList; + for (size_t i = 0; i < labelAndPositionsArr.size(); i++) + { + const cvf::Vec3f& pos = labelAndPositionsArr[i].first; + const cvf::String& txt = labelAndPositionsArr[i].second; + + QMap jsonPos; + jsonPos["x"] = pos.x(); + jsonPos["y"] = pos.y(); + jsonPos["z"] = pos.z(); + + QMap jsonLabelEntry; + jsonLabelEntry["position"] = jsonPos; + jsonLabelEntry["text"] = txt.toAscii().ptr(); + + jsonLabelList.push_back(jsonLabelEntry); + } + + QMap jsonModelMeta; jsonModelMeta["modelName"] = "ResInsightExport"; jsonModelMeta["meshArr"] = jsonMeshMetaList; + jsonModelMeta["labelsArr"] = jsonLabelList; ResInsightInternalJson::Json jsonCodec; const bool prettifyJson = true; diff --git a/ApplicationCode/Commands/HoloLensCommands/VdeVizDataExtractor.h b/ApplicationCode/Commands/HoloLensCommands/VdeVizDataExtractor.h index 42f6afc3da..d34eb0d4ba 100644 --- a/ApplicationCode/Commands/HoloLensCommands/VdeVizDataExtractor.h +++ b/ApplicationCode/Commands/HoloLensCommands/VdeVizDataExtractor.h @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018 Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -21,13 +21,18 @@ #include "cvfBase.h" #include "cvfColor3.h" #include "cvfArray.h" +#include "cvfVector3.h" +#include "cvfString.h" #include "cvfTextureImage.h" #include +#include + class VdeArrayDataPacket; class VdePacketDirectory; class VdeExportPart; +class VdeCachingHashedIdFactory; class RimGridView; @@ -45,6 +50,7 @@ struct VdeMesh cvf::Color3f color; float opacity; + QString cullFaceModeStr; // front, back or none (or empty) int verticesPerPrimitive; cvf::cref vertexArr; @@ -62,7 +68,7 @@ struct VdeMesh //================================================================================================== // -// +// The set of array IDs that are needed for a mesh // //================================================================================================== struct VdeMeshArrayIds @@ -89,17 +95,17 @@ struct VdeMeshArrayIds class VdeVizDataExtractor { public: - VdeVizDataExtractor(const RimGridView& view); + VdeVizDataExtractor(const RimGridView& view, VdeCachingHashedIdFactory* cachingIdFactory); void extractViewContents(QString* modelMetaJsonStr, std::vector* allReferencedArrayIds, VdePacketDirectory* packetDirectory); private: - static std::vector buildMeshArray(const std::vector& exportPartsArr); - static bool extractMeshFromExportPart(const VdeExportPart& exportPart, VdeMesh* mesh); - static QString createModelMetaJsonString(const std::vector& meshArr, const std::vector& meshContentIdsArr); - static void debugComparePackets(const VdeArrayDataPacket& packetA, const VdeArrayDataPacket& packetB); + static std::vector > buildMeshArray(const std::vector& exportPartsArr); + static std::unique_ptr createMeshFromExportPart(const VdeExportPart& exportPart); + static QString createModelMetaJsonString(const std::vector >& meshArr, const std::vector& meshContentIdsArr, const std::vector >& labelAndPositionsArr); + static void debugComparePackets(const VdeArrayDataPacket& packetA, const VdeArrayDataPacket& packetB); private: - const RimGridView& m_view; - + const RimGridView& m_view; + VdeCachingHashedIdFactory* m_cachingIdFactory; }; diff --git a/ApplicationCode/Commands/HoloLensCommands/farmhash/farmhash.cc b/ApplicationCode/Commands/HoloLensCommands/farmhash/farmhash.cc new file mode 100644 index 0000000000..f2b99ffc6a --- /dev/null +++ b/ApplicationCode/Commands/HoloLensCommands/farmhash/farmhash.cc @@ -0,0 +1,11840 @@ +// Copyright (c) 2014 Google, Inc. +// +// 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. +// +// FarmHash, by Geoff Pike + +#include "farmhash.h" +// FARMHASH ASSUMPTIONS: Modify as needed, or use -DFARMHASH_ASSUME_SSE42 etc. +// Note that if you use -DFARMHASH_ASSUME_SSE42 you likely need -msse42 +// (or its equivalent for your compiler); if you use -DFARMHASH_ASSUME_AESNI +// you likely need -maes (or its equivalent for your compiler). + +#ifdef FARMHASH_ASSUME_SSSE3 +#undef FARMHASH_ASSUME_SSSE3 +#define FARMHASH_ASSUME_SSSE3 1 +#endif + +#ifdef FARMHASH_ASSUME_SSE41 +#undef FARMHASH_ASSUME_SSE41 +#define FARMHASH_ASSUME_SSE41 1 +#endif + +#ifdef FARMHASH_ASSUME_SSE42 +#undef FARMHASH_ASSUME_SSE42 +#define FARMHASH_ASSUME_SSE42 1 +#endif + +#ifdef FARMHASH_ASSUME_AESNI +#undef FARMHASH_ASSUME_AESNI +#define FARMHASH_ASSUME_AESNI 1 +#endif + +#ifdef FARMHASH_ASSUME_AVX +#undef FARMHASH_ASSUME_AVX +#define FARMHASH_ASSUME_AVX 1 +#endif + +#if !defined(FARMHASH_CAN_USE_CXX11) && defined(LANG_CXX11) +#define FARMHASH_CAN_USE_CXX11 1 +#else +#undef FARMHASH_CAN_USE_CXX11 +#define FARMHASH_CAN_USE_CXX11 0 +#endif + +// FARMHASH PORTABILITY LAYER: Runtime error if misconfigured + +#ifndef FARMHASH_DIE_IF_MISCONFIGURED +#define FARMHASH_DIE_IF_MISCONFIGURED do { *(char*)(len % 17) = 0; } while (0) +#endif + +// FARMHASH PORTABILITY LAYER: "static inline" or similar + +#ifndef STATIC_INLINE +#define STATIC_INLINE static inline +#endif + +// FARMHASH PORTABILITY LAYER: LIKELY and UNLIKELY + +#if !defined(LIKELY) +#if defined(FARMHASH_NO_BUILTIN_EXPECT) || (defined(FARMHASH_OPTIONAL_BUILTIN_EXPECT) && !defined(HAVE_BUILTIN_EXPECT)) +#define LIKELY(x) (x) +#else +#define LIKELY(x) (__builtin_expect(!!(x), 1)) +#endif +#endif + +#undef UNLIKELY +#define UNLIKELY(x) !LIKELY(!(x)) + +// FARMHASH PORTABILITY LAYER: endianness and byteswapping functions + +#ifdef WORDS_BIGENDIAN +#undef FARMHASH_BIG_ENDIAN +#define FARMHASH_BIG_ENDIAN 1 +#endif + +#if defined(FARMHASH_LITTLE_ENDIAN) && defined(FARMHASH_BIG_ENDIAN) +#error +#endif + +#if !defined(FARMHASH_LITTLE_ENDIAN) && !defined(FARMHASH_BIG_ENDIAN) +#define FARMHASH_UNKNOWN_ENDIAN 1 +#endif + +#if !defined(bswap_32) || !defined(bswap_64) +#undef bswap_32 +#undef bswap_64 + +#if defined(HAVE_BUILTIN_BSWAP) || defined(__clang__) || \ + (defined(__GNUC__) && ((__GNUC__ == 4 && __GNUC_MINOR__ >= 8) || \ + __GNUC__ >= 5)) +// Easy case for bswap: no header file needed. +#define bswap_32(x) __builtin_bswap32(x) +#define bswap_64(x) __builtin_bswap64(x) +#endif + +#endif + +#if defined(FARMHASH_UNKNOWN_ENDIAN) || !defined(bswap_64) + +#ifdef _MSC_VER + +#undef bswap_32 +#undef bswap_64 +#define bswap_32(x) _byteswap_ulong(x) +#define bswap_64(x) _byteswap_uint64(x) + +#elif defined(__APPLE__) + +// Mac OS X / Darwin features +#include +#undef bswap_32 +#undef bswap_64 +#define bswap_32(x) OSSwapInt32(x) +#define bswap_64(x) OSSwapInt64(x) + +#elif defined(__sun) || defined(sun) + +#include +#undef bswap_32 +#undef bswap_64 +#define bswap_32(x) BSWAP_32(x) +#define bswap_64(x) BSWAP_64(x) + +#elif defined(__FreeBSD__) || defined(__DragonFly__) + +#include +#undef bswap_32 +#undef bswap_64 +#define bswap_32(x) bswap32(x) +#define bswap_64(x) bswap64(x) + +#elif defined(__OpenBSD__) + +#include +#undef bswap_32 +#undef bswap_64 +#define bswap_32(x) swap32(x) +#define bswap_64(x) swap64(x) + +#elif defined(__NetBSD__) + +#include +#include +#if defined(__BSWAP_RENAME) && !defined(__bswap_32) +#undef bswap_32 +#undef bswap_64 +#define bswap_32(x) bswap32(x) +#define bswap_64(x) bswap64(x) +#endif + +#elif defined(__HAIKU__) + +#define _BSD_SOURCE +#include +#undef bswap_32 +#undef bswap_64 +#define bswap_32(x) bswap32(x) +#define bswap_64(x) bswap64(x) + +#else + +#undef bswap_32 +#undef bswap_64 +#include + +#endif + +#ifdef WORDS_BIGENDIAN +#define FARMHASH_BIG_ENDIAN 1 +#endif + +#endif + +#ifdef FARMHASH_BIG_ENDIAN +#define uint32_in_expected_order(x) (bswap_32(x)) +#define uint64_in_expected_order(x) (bswap_64(x)) +#else +#define uint32_in_expected_order(x) (x) +#define uint64_in_expected_order(x) (x) +#endif + +namespace NAMESPACE_FOR_HASH_FUNCTIONS { + +STATIC_INLINE uint64_t Fetch64(const char *p) { + uint64_t result; + memcpy(&result, p, sizeof(result)); + return uint64_in_expected_order(result); +} + +STATIC_INLINE uint32_t Fetch32(const char *p) { + uint32_t result; + memcpy(&result, p, sizeof(result)); + return uint32_in_expected_order(result); +} + +STATIC_INLINE uint32_t Bswap32(uint32_t val) { return bswap_32(val); } +STATIC_INLINE uint64_t Bswap64(uint64_t val) { return bswap_64(val); } + +// FARMHASH PORTABILITY LAYER: bitwise rot + +STATIC_INLINE uint32_t BasicRotate32(uint32_t val, int shift) { + // Avoid shifting by 32: doing so yields an undefined result. + return shift == 0 ? val : ((val >> shift) | (val << (32 - shift))); +} + +STATIC_INLINE uint64_t BasicRotate64(uint64_t val, int shift) { + // Avoid shifting by 64: doing so yields an undefined result. + return shift == 0 ? val : ((val >> shift) | (val << (64 - shift))); +} + +#if defined(_MSC_VER) && defined(FARMHASH_ROTR) + +STATIC_INLINE uint32_t Rotate32(uint32_t val, int shift) { + return sizeof(unsigned long) == sizeof(val) ? + _lrotr(val, shift) : + BasicRotate32(val, shift); +} + +STATIC_INLINE uint64_t Rotate64(uint64_t val, int shift) { + return sizeof(unsigned long) == sizeof(val) ? + _lrotr(val, shift) : + BasicRotate64(val, shift); +} + +#else + +STATIC_INLINE uint32_t Rotate32(uint32_t val, int shift) { + return BasicRotate32(val, shift); +} +STATIC_INLINE uint64_t Rotate64(uint64_t val, int shift) { + return BasicRotate64(val, shift); +} + +#endif + +} // namespace NAMESPACE_FOR_HASH_FUNCTIONS + +// FARMHASH PORTABILITY LAYER: debug mode or max speed? +// One may use -DFARMHASH_DEBUG=1 or -DFARMHASH_DEBUG=0 to force the issue. + +#if !defined(FARMHASH_DEBUG) && (!defined(NDEBUG) || defined(_DEBUG)) +#define FARMHASH_DEBUG 1 +#endif + +#undef debug_mode +#if FARMHASH_DEBUG +#define debug_mode 1 +#else +#define debug_mode 0 +#endif + +// PLATFORM-SPECIFIC FUNCTIONS AND MACROS + +#undef x86_64 +#if defined (__x86_64) || defined (__x86_64__) +#define x86_64 1 +#else +#define x86_64 0 +#endif + +#undef x86 +#if defined(__i386__) || defined(__i386) || defined(__X86__) +#define x86 1 +#else +#define x86 x86_64 +#endif + +#if !defined(is_64bit) +#define is_64bit (x86_64 || (sizeof(void*) == 8)) +#endif + +#undef can_use_ssse3 +#if defined(__SSSE3__) || defined(FARMHASH_ASSUME_SSSE3) + +#include +#define can_use_ssse3 1 +// Now we can use _mm_hsub_epi16 and so on. + +#else +#define can_use_ssse3 0 +#endif + +#undef can_use_sse41 +#if defined(__SSE4_1__) || defined(FARMHASH_ASSUME_SSE41) + +#include +#define can_use_sse41 1 +// Now we can use _mm_insert_epi64 and so on. + +#else +#define can_use_sse41 0 +#endif + +#undef can_use_sse42 +#if defined(__SSE4_2__) || defined(FARMHASH_ASSUME_SSE42) + +#include +#define can_use_sse42 1 +// Now we can use _mm_crc32_u{32,16,8}. And on 64-bit platforms, _mm_crc32_u64. + +#else +#define can_use_sse42 0 +#endif + +#undef can_use_aesni +#if defined(__AES__) || defined(FARMHASH_ASSUME_AESNI) + +#include +#define can_use_aesni 1 +// Now we can use _mm_aesimc_si128 and so on. + +#else +#define can_use_aesni 0 +#endif + +#undef can_use_avx +#if defined(__AVX__) || defined(FARMHASH_ASSUME_AVX) + +#include +#define can_use_avx 1 + +#else +#define can_use_avx 0 +#endif + +#if can_use_ssse3 || can_use_sse41 || can_use_sse42 || can_use_aesni || can_use_avx +STATIC_INLINE __m128i Fetch128(const char* s) { + return _mm_loadu_si128(reinterpret_cast(s)); +} +#endif +// Building blocks for hash functions + +// std::swap() was in but is in from C++11 on. +#if !FARMHASH_CAN_USE_CXX11 +#include +#endif + +#undef PERMUTE3 +#define PERMUTE3(a, b, c) do { std::swap(a, b); std::swap(a, c); } while (0) + +namespace NAMESPACE_FOR_HASH_FUNCTIONS { + +// Some primes between 2^63 and 2^64 for various uses. +static const uint64_t k0 = 0xc3a5c85c97cb3127ULL; +static const uint64_t k1 = 0xb492b66fbe98f273ULL; +static const uint64_t k2 = 0x9ae16a3b2f90404fULL; + +// Magic numbers for 32-bit hashing. Copied from Murmur3. +static const uint32_t c1 = 0xcc9e2d51; +static const uint32_t c2 = 0x1b873593; + +// A 32-bit to 32-bit integer hash copied from Murmur3. +STATIC_INLINE uint32_t fmix(uint32_t h) +{ + h ^= h >> 16; + h *= 0x85ebca6b; + h ^= h >> 13; + h *= 0xc2b2ae35; + h ^= h >> 16; + return h; +} + +STATIC_INLINE uint32_t Mur(uint32_t a, uint32_t h) { + // Helper from Murmur3 for combining two 32-bit values. + a *= c1; + a = Rotate32(a, 17); + a *= c2; + h ^= a; + h = Rotate32(h, 19); + return h * 5 + 0xe6546b64; +} + +template STATIC_INLINE T DebugTweak(T x) { + if (debug_mode) { + if (sizeof(x) == 4) { + x = ~Bswap32(x * c1); + } else { + x = ~Bswap64(x * k1); + } + } + return x; +} + +template <> uint128_t DebugTweak(uint128_t x) { + if (debug_mode) { + uint64_t y = DebugTweak(Uint128Low64(x)); + uint64_t z = DebugTweak(Uint128High64(x)); + y += z; + z += y; + x = Uint128(y, z * k1); + } + return x; +} + +} // namespace NAMESPACE_FOR_HASH_FUNCTIONS + +using namespace std; +using namespace NAMESPACE_FOR_HASH_FUNCTIONS; +namespace farmhashna { +#undef Fetch +#define Fetch Fetch64 + +#undef Rotate +#define Rotate Rotate64 + +#undef Bswap +#define Bswap Bswap64 + +STATIC_INLINE uint64_t ShiftMix(uint64_t val) { + return val ^ (val >> 47); +} + +STATIC_INLINE uint64_t HashLen16(uint64_t u, uint64_t v) { + return Hash128to64(Uint128(u, v)); +} + +STATIC_INLINE uint64_t HashLen16(uint64_t u, uint64_t v, uint64_t mul) { + // Murmur-inspired hashing. + uint64_t a = (u ^ v) * mul; + a ^= (a >> 47); + uint64_t b = (v ^ a) * mul; + b ^= (b >> 47); + b *= mul; + return b; +} + +STATIC_INLINE uint64_t HashLen0to16(const char *s, size_t len) { + if (len >= 8) { + uint64_t mul = k2 + len * 2; + uint64_t a = Fetch(s) + k2; + uint64_t b = Fetch(s + len - 8); + uint64_t c = Rotate(b, 37) * mul + a; + uint64_t d = (Rotate(a, 25) + b) * mul; + return HashLen16(c, d, mul); + } + if (len >= 4) { + uint64_t mul = k2 + len * 2; + uint64_t a = Fetch32(s); + return HashLen16(len + (a << 3), Fetch32(s + len - 4), mul); + } + if (len > 0) { + uint8_t a = s[0]; + uint8_t b = s[len >> 1]; + uint8_t c = s[len - 1]; + uint32_t y = static_cast(a) + (static_cast(b) << 8); + uint32_t z = len + (static_cast(c) << 2); + return ShiftMix(y * k2 ^ z * k0) * k2; + } + return k2; +} + +// This probably works well for 16-byte strings as well, but it may be overkill +// in that case. +STATIC_INLINE uint64_t HashLen17to32(const char *s, size_t len) { + uint64_t mul = k2 + len * 2; + uint64_t a = Fetch(s) * k1; + uint64_t b = Fetch(s + 8); + uint64_t c = Fetch(s + len - 8) * mul; + uint64_t d = Fetch(s + len - 16) * k2; + return HashLen16(Rotate(a + b, 43) + Rotate(c, 30) + d, + a + Rotate(b + k2, 18) + c, mul); +} + +// Return a 16-byte hash for 48 bytes. Quick and dirty. +// Callers do best to use "random-looking" values for a and b. +STATIC_INLINE pair WeakHashLen32WithSeeds( + uint64_t w, uint64_t x, uint64_t y, uint64_t z, uint64_t a, uint64_t b) { + a += w; + b = Rotate(b + a + z, 21); + uint64_t c = a; + a += x; + a += y; + b += Rotate(a, 44); + return make_pair(a + z, b + c); +} + +// Return a 16-byte hash for s[0] ... s[31], a, and b. Quick and dirty. +STATIC_INLINE pair WeakHashLen32WithSeeds( + const char* s, uint64_t a, uint64_t b) { + return WeakHashLen32WithSeeds(Fetch(s), + Fetch(s + 8), + Fetch(s + 16), + Fetch(s + 24), + a, + b); +} + +// Return an 8-byte hash for 33 to 64 bytes. +STATIC_INLINE uint64_t HashLen33to64(const char *s, size_t len) { + uint64_t mul = k2 + len * 2; + uint64_t a = Fetch(s) * k2; + uint64_t b = Fetch(s + 8); + uint64_t c = Fetch(s + len - 8) * mul; + uint64_t d = Fetch(s + len - 16) * k2; + uint64_t y = Rotate(a + b, 43) + Rotate(c, 30) + d; + uint64_t z = HashLen16(y, a + Rotate(b + k2, 18) + c, mul); + uint64_t e = Fetch(s + 16) * mul; + uint64_t f = Fetch(s + 24); + uint64_t g = (y + Fetch(s + len - 32)) * mul; + uint64_t h = (z + Fetch(s + len - 24)) * mul; + return HashLen16(Rotate(e + f, 43) + Rotate(g, 30) + h, + e + Rotate(f + a, 18) + g, mul); +} + +uint64_t Hash64(const char *s, size_t len) { + const uint64_t seed = 81; + if (len <= 32) { + if (len <= 16) { + return HashLen0to16(s, len); + } else { + return HashLen17to32(s, len); + } + } else if (len <= 64) { + return HashLen33to64(s, len); + } + + // For strings over 64 bytes we loop. Internal state consists of + // 56 bytes: v, w, x, y, and z. + uint64_t x = seed; + uint64_t y = seed * k1 + 113; + uint64_t z = ShiftMix(y * k2 + 113) * k2; + pair v = make_pair(0, 0); + pair w = make_pair(0, 0); + x = x * k2 + Fetch(s); + + // Set end so that after the loop we have 1 to 64 bytes left to process. + const char* end = s + ((len - 1) / 64) * 64; + const char* last64 = end + ((len - 1) & 63) - 63; + assert(s + len - 64 == last64); + do { + x = Rotate(x + y + v.first + Fetch(s + 8), 37) * k1; + y = Rotate(y + v.second + Fetch(s + 48), 42) * k1; + x ^= w.second; + y += v.first + Fetch(s + 40); + z = Rotate(z + w.first, 33) * k1; + v = WeakHashLen32WithSeeds(s, v.second * k1, x + w.first); + w = WeakHashLen32WithSeeds(s + 32, z + w.second, y + Fetch(s + 16)); + std::swap(z, x); + s += 64; + } while (s != end); + uint64_t mul = k1 + ((z & 0xff) << 1); + // Make s point to the last 64 bytes of input. + s = last64; + w.first += ((len - 1) & 63); + v.first += w.first; + w.first += v.first; + x = Rotate(x + y + v.first + Fetch(s + 8), 37) * mul; + y = Rotate(y + v.second + Fetch(s + 48), 42) * mul; + x ^= w.second * 9; + y += v.first * 9 + Fetch(s + 40); + z = Rotate(z + w.first, 33) * mul; + v = WeakHashLen32WithSeeds(s, v.second * mul, x + w.first); + w = WeakHashLen32WithSeeds(s + 32, z + w.second, y + Fetch(s + 16)); + std::swap(z, x); + return HashLen16(HashLen16(v.first, w.first, mul) + ShiftMix(y) * k0 + z, + HashLen16(v.second, w.second, mul) + x, + mul); +} + +uint64_t Hash64WithSeeds(const char *s, size_t len, uint64_t seed0, uint64_t seed1); + +uint64_t Hash64WithSeed(const char *s, size_t len, uint64_t seed) { + return Hash64WithSeeds(s, len, k2, seed); +} + +uint64_t Hash64WithSeeds(const char *s, size_t len, uint64_t seed0, uint64_t seed1) { + return HashLen16(Hash64(s, len) - seed0, seed1); +} +} // namespace farmhashna +namespace farmhashuo { +#undef Fetch +#define Fetch Fetch64 + +#undef Rotate +#define Rotate Rotate64 + +STATIC_INLINE uint64_t H(uint64_t x, uint64_t y, uint64_t mul, int r) { + uint64_t a = (x ^ y) * mul; + a ^= (a >> 47); + uint64_t b = (y ^ a) * mul; + return Rotate(b, r) * mul; +} + +uint64_t Hash64WithSeeds(const char *s, size_t len, + uint64_t seed0, uint64_t seed1) { + if (len <= 64) { + return farmhashna::Hash64WithSeeds(s, len, seed0, seed1); + } + + // For strings over 64 bytes we loop. Internal state consists of + // 64 bytes: u, v, w, x, y, and z. + uint64_t x = seed0; + uint64_t y = seed1 * k2 + 113; + uint64_t z = farmhashna::ShiftMix(y * k2) * k2; + pair v = make_pair(seed0, seed1); + pair w = make_pair(0, 0); + uint64_t u = x - z; + x *= k2; + uint64_t mul = k2 + (u & 0x82); + + // Set end so that after the loop we have 1 to 64 bytes left to process. + const char* end = s + ((len - 1) / 64) * 64; + const char* last64 = end + ((len - 1) & 63) - 63; + assert(s + len - 64 == last64); + do { + uint64_t a0 = Fetch(s); + uint64_t a1 = Fetch(s + 8); + uint64_t a2 = Fetch(s + 16); + uint64_t a3 = Fetch(s + 24); + uint64_t a4 = Fetch(s + 32); + uint64_t a5 = Fetch(s + 40); + uint64_t a6 = Fetch(s + 48); + uint64_t a7 = Fetch(s + 56); + x += a0 + a1; + y += a2; + z += a3; + v.first += a4; + v.second += a5 + a1; + w.first += a6; + w.second += a7; + + x = Rotate(x, 26); + x *= 9; + y = Rotate(y, 29); + z *= mul; + v.first = Rotate(v.first, 33); + v.second = Rotate(v.second, 30); + w.first ^= x; + w.first *= 9; + z = Rotate(z, 32); + z += w.second; + w.second += z; + z *= 9; + std::swap(u, y); + + z += a0 + a6; + v.first += a2; + v.second += a3; + w.first += a4; + w.second += a5 + a6; + x += a1; + y += a7; + + y += v.first; + v.first += x - y; + v.second += w.first; + w.first += v.second; + w.second += x - y; + x += w.second; + w.second = Rotate(w.second, 34); + std::swap(u, z); + s += 64; + } while (s != end); + // Make s point to the last 64 bytes of input. + s = last64; + u *= 9; + v.second = Rotate(v.second, 28); + v.first = Rotate(v.first, 20); + w.first += ((len - 1) & 63); + u += y; + y += u; + x = Rotate(y - x + v.first + Fetch(s + 8), 37) * mul; + y = Rotate(y ^ v.second ^ Fetch(s + 48), 42) * mul; + x ^= w.second * 9; + y += v.first + Fetch(s + 40); + z = Rotate(z + w.first, 33) * mul; + v = farmhashna::WeakHashLen32WithSeeds(s, v.second * mul, x + w.first); + w = farmhashna::WeakHashLen32WithSeeds(s + 32, z + w.second, y + Fetch(s + 16)); + return H(farmhashna::HashLen16(v.first + x, w.first ^ y, mul) + z - u, + H(v.second + y, w.second + z, k2, 30) ^ x, + k2, + 31); +} + +uint64_t Hash64WithSeed(const char *s, size_t len, uint64_t seed) { + return len <= 64 ? farmhashna::Hash64WithSeed(s, len, seed) : + Hash64WithSeeds(s, len, 0, seed); +} + +uint64_t Hash64(const char *s, size_t len) { + return len <= 64 ? farmhashna::Hash64(s, len) : + Hash64WithSeeds(s, len, 81, 0); +} +} // namespace farmhashuo +namespace farmhashxo { +#undef Fetch +#define Fetch Fetch64 + +#undef Rotate +#define Rotate Rotate64 + +STATIC_INLINE uint64_t H32(const char *s, size_t len, uint64_t mul, + uint64_t seed0 = 0, uint64_t seed1 = 0) { + uint64_t a = Fetch(s) * k1; + uint64_t b = Fetch(s + 8); + uint64_t c = Fetch(s + len - 8) * mul; + uint64_t d = Fetch(s + len - 16) * k2; + uint64_t u = Rotate(a + b, 43) + Rotate(c, 30) + d + seed0; + uint64_t v = a + Rotate(b + k2, 18) + c + seed1; + a = farmhashna::ShiftMix((u ^ v) * mul); + b = farmhashna::ShiftMix((v ^ a) * mul); + return b; +} + +// Return an 8-byte hash for 33 to 64 bytes. +STATIC_INLINE uint64_t HashLen33to64(const char *s, size_t len) { + uint64_t mul0 = k2 - 30; + uint64_t mul1 = k2 - 30 + 2 * len; + uint64_t h0 = H32(s, 32, mul0); + uint64_t h1 = H32(s + len - 32, 32, mul1); + return ((h1 * mul1) + h0) * mul1; +} + +// Return an 8-byte hash for 65 to 96 bytes. +STATIC_INLINE uint64_t HashLen65to96(const char *s, size_t len) { + uint64_t mul0 = k2 - 114; + uint64_t mul1 = k2 - 114 + 2 * len; + uint64_t h0 = H32(s, 32, mul0); + uint64_t h1 = H32(s + 32, 32, mul1); + uint64_t h2 = H32(s + len - 32, 32, mul1, h0, h1); + return (h2 * 9 + (h0 >> 17) + (h1 >> 21)) * mul1; +} + +uint64_t Hash64(const char *s, size_t len) { + if (len <= 32) { + if (len <= 16) { + return farmhashna::HashLen0to16(s, len); + } else { + return farmhashna::HashLen17to32(s, len); + } + } else if (len <= 64) { + return HashLen33to64(s, len); + } else if (len <= 96) { + return HashLen65to96(s, len); + } else if (len <= 256) { + return farmhashna::Hash64(s, len); + } else { + return farmhashuo::Hash64(s, len); + } +} + +uint64_t Hash64WithSeeds(const char *s, size_t len, uint64_t seed0, uint64_t seed1) { + return farmhashuo::Hash64WithSeeds(s, len, seed0, seed1); +} + +uint64_t Hash64WithSeed(const char *s, size_t len, uint64_t seed) { + return farmhashuo::Hash64WithSeed(s, len, seed); +} +} // namespace farmhashxo +namespace farmhashte { +#if !can_use_sse41 || !x86_64 + +uint64_t Hash64(const char *s, size_t len) { + FARMHASH_DIE_IF_MISCONFIGURED; + return s == NULL ? 0 : len; +} + +uint64_t Hash64WithSeed(const char *s, size_t len, uint64_t seed) { + FARMHASH_DIE_IF_MISCONFIGURED; + return seed + Hash64(s, len); +} + +uint64_t Hash64WithSeeds(const char *s, size_t len, + uint64_t seed0, uint64_t seed1) { + FARMHASH_DIE_IF_MISCONFIGURED; + return seed0 + seed1 + Hash64(s, len); +} + +#else + +#undef Fetch +#define Fetch Fetch64 + +#undef Rotate +#define Rotate Rotate64 + +#undef Bswap +#define Bswap Bswap64 + +// Helpers for data-parallel operations (1x 128 bits or 2x 64 or 4x 32). +STATIC_INLINE __m128i Add(__m128i x, __m128i y) { return _mm_add_epi64(x, y); } +STATIC_INLINE __m128i Xor(__m128i x, __m128i y) { return _mm_xor_si128(x, y); } +STATIC_INLINE __m128i Mul(__m128i x, __m128i y) { return _mm_mullo_epi32(x, y); } +STATIC_INLINE __m128i Shuf(__m128i x, __m128i y) { return _mm_shuffle_epi8(y, x); } + +// Requires n >= 256. Requires SSE4.1. Should be slightly faster if the +// compiler uses AVX instructions (e.g., use the -mavx flag with GCC). +STATIC_INLINE uint64_t Hash64Long(const char* s, size_t n, + uint64_t seed0, uint64_t seed1) { + const __m128i kShuf = + _mm_set_epi8(4, 11, 10, 5, 8, 15, 6, 9, 12, 2, 14, 13, 0, 7, 3, 1); + const __m128i kMult = + _mm_set_epi8(0xbd, 0xd6, 0x33, 0x39, 0x45, 0x54, 0xfa, 0x03, + 0x34, 0x3e, 0x33, 0xed, 0xcc, 0x9e, 0x2d, 0x51); + uint64_t seed2 = (seed0 + 113) * (seed1 + 9); + uint64_t seed3 = (Rotate(seed0, 23) + 27) * (Rotate(seed1, 30) + 111); + __m128i d0 = _mm_cvtsi64_si128(seed0); + __m128i d1 = _mm_cvtsi64_si128(seed1); + __m128i d2 = Shuf(kShuf, d0); + __m128i d3 = Shuf(kShuf, d1); + __m128i d4 = Xor(d0, d1); + __m128i d5 = Xor(d1, d2); + __m128i d6 = Xor(d2, d4); + __m128i d7 = _mm_set1_epi32(seed2 >> 32); + __m128i d8 = Mul(kMult, d2); + __m128i d9 = _mm_set1_epi32(seed3 >> 32); + __m128i d10 = _mm_set1_epi32(seed3); + __m128i d11 = Add(d2, _mm_set1_epi32(seed2)); + const char* end = s + (n & ~static_cast(255)); + do { + __m128i z; + z = Fetch128(s); + d0 = Add(d0, z); + d1 = Shuf(kShuf, d1); + d2 = Xor(d2, d0); + d4 = Xor(d4, z); + d4 = Xor(d4, d1); + std::swap(d0, d6); + z = Fetch128(s + 16); + d5 = Add(d5, z); + d6 = Shuf(kShuf, d6); + d8 = Shuf(kShuf, d8); + d7 = Xor(d7, d5); + d0 = Xor(d0, z); + d0 = Xor(d0, d6); + std::swap(d5, d11); + z = Fetch128(s + 32); + d1 = Add(d1, z); + d2 = Shuf(kShuf, d2); + d4 = Shuf(kShuf, d4); + d5 = Xor(d5, z); + d5 = Xor(d5, d2); + std::swap(d10, d4); + z = Fetch128(s + 48); + d6 = Add(d6, z); + d7 = Shuf(kShuf, d7); + d0 = Shuf(kShuf, d0); + d8 = Xor(d8, d6); + d1 = Xor(d1, z); + d1 = Add(d1, d7); + z = Fetch128(s + 64); + d2 = Add(d2, z); + d5 = Shuf(kShuf, d5); + d4 = Add(d4, d2); + d6 = Xor(d6, z); + d6 = Xor(d6, d11); + std::swap(d8, d2); + z = Fetch128(s + 80); + d7 = Xor(d7, z); + d8 = Shuf(kShuf, d8); + d1 = Shuf(kShuf, d1); + d0 = Add(d0, d7); + d2 = Add(d2, z); + d2 = Add(d2, d8); + std::swap(d1, d7); + z = Fetch128(s + 96); + d4 = Shuf(kShuf, d4); + d6 = Shuf(kShuf, d6); + d8 = Mul(kMult, d8); + d5 = Xor(d5, d11); + d7 = Xor(d7, z); + d7 = Add(d7, d4); + std::swap(d6, d0); + z = Fetch128(s + 112); + d8 = Add(d8, z); + d0 = Shuf(kShuf, d0); + d2 = Shuf(kShuf, d2); + d1 = Xor(d1, d8); + d10 = Xor(d10, z); + d10 = Xor(d10, d0); + std::swap(d11, d5); + z = Fetch128(s + 128); + d4 = Add(d4, z); + d5 = Shuf(kShuf, d5); + d7 = Shuf(kShuf, d7); + d6 = Add(d6, d4); + d8 = Xor(d8, z); + d8 = Xor(d8, d5); + std::swap(d4, d10); + z = Fetch128(s + 144); + d0 = Add(d0, z); + d1 = Shuf(kShuf, d1); + d2 = Add(d2, d0); + d4 = Xor(d4, z); + d4 = Xor(d4, d1); + z = Fetch128(s + 160); + d5 = Add(d5, z); + d6 = Shuf(kShuf, d6); + d8 = Shuf(kShuf, d8); + d7 = Xor(d7, d5); + d0 = Xor(d0, z); + d0 = Xor(d0, d6); + std::swap(d2, d8); + z = Fetch128(s + 176); + d1 = Add(d1, z); + d2 = Shuf(kShuf, d2); + d4 = Shuf(kShuf, d4); + d5 = Mul(kMult, d5); + d5 = Xor(d5, z); + d5 = Xor(d5, d2); + std::swap(d7, d1); + z = Fetch128(s + 192); + d6 = Add(d6, z); + d7 = Shuf(kShuf, d7); + d0 = Shuf(kShuf, d0); + d8 = Add(d8, d6); + d1 = Xor(d1, z); + d1 = Xor(d1, d7); + std::swap(d0, d6); + z = Fetch128(s + 208); + d2 = Add(d2, z); + d5 = Shuf(kShuf, d5); + d4 = Xor(d4, d2); + d6 = Xor(d6, z); + d6 = Xor(d6, d9); + std::swap(d5, d11); + z = Fetch128(s + 224); + d7 = Add(d7, z); + d8 = Shuf(kShuf, d8); + d1 = Shuf(kShuf, d1); + d0 = Xor(d0, d7); + d2 = Xor(d2, z); + d2 = Xor(d2, d8); + std::swap(d10, d4); + z = Fetch128(s + 240); + d3 = Add(d3, z); + d4 = Shuf(kShuf, d4); + d6 = Shuf(kShuf, d6); + d7 = Mul(kMult, d7); + d5 = Add(d5, d3); + d7 = Xor(d7, z); + d7 = Xor(d7, d4); + std::swap(d3, d9); + s += 256; + } while (s != end); + d6 = Add(Mul(kMult, d6), _mm_cvtsi64_si128(n)); + if (n % 256 != 0) { + d7 = Add(_mm_shuffle_epi32(d8, (0 << 6) + (3 << 4) + (2 << 2) + (1 << 0)), d7); + d8 = Add(Mul(kMult, d8), _mm_cvtsi64_si128(farmhashxo::Hash64(s, n % 256))); + } + __m128i t[8]; + d0 = Mul(kMult, Shuf(kShuf, Mul(kMult, d0))); + d3 = Mul(kMult, Shuf(kShuf, Mul(kMult, d3))); + d9 = Mul(kMult, Shuf(kShuf, Mul(kMult, d9))); + d1 = Mul(kMult, Shuf(kShuf, Mul(kMult, d1))); + d0 = Add(d11, d0); + d3 = Xor(d7, d3); + d9 = Add(d8, d9); + d1 = Add(d10, d1); + d4 = Add(d3, d4); + d5 = Add(d9, d5); + d6 = Xor(d1, d6); + d2 = Add(d0, d2); + t[0] = d0; + t[1] = d3; + t[2] = d9; + t[3] = d1; + t[4] = d4; + t[5] = d5; + t[6] = d6; + t[7] = d2; + return farmhashxo::Hash64(reinterpret_cast(t), sizeof(t)); +} + +uint64_t Hash64(const char *s, size_t len) { + // Empirically, farmhashxo seems faster until length 512. + return len >= 512 ? Hash64Long(s, len, k2, k1) : farmhashxo::Hash64(s, len); +} + +uint64_t Hash64WithSeed(const char *s, size_t len, uint64_t seed) { + return len >= 512 ? Hash64Long(s, len, k1, seed) : + farmhashxo::Hash64WithSeed(s, len, seed); +} + +uint64_t Hash64WithSeeds(const char *s, size_t len, uint64_t seed0, uint64_t seed1) { + return len >= 512 ? Hash64Long(s, len, seed0, seed1) : + farmhashxo::Hash64WithSeeds(s, len, seed0, seed1); +} + +#endif +} // namespace farmhashte +namespace farmhashnt { +#if !can_use_sse41 || !x86_64 + +uint32_t Hash32(const char *s, size_t len) { + FARMHASH_DIE_IF_MISCONFIGURED; + return s == NULL ? 0 : len; +} + +uint32_t Hash32WithSeed(const char *s, size_t len, uint32_t seed) { + FARMHASH_DIE_IF_MISCONFIGURED; + return seed + Hash32(s, len); +} + +#else + +uint32_t Hash32(const char *s, size_t len) { + return static_cast(farmhashte::Hash64(s, len)); +} + +uint32_t Hash32WithSeed(const char *s, size_t len, uint32_t seed) { + return static_cast(farmhashte::Hash64WithSeed(s, len, seed)); +} + +#endif +} // namespace farmhashnt +namespace farmhashmk { +#undef Fetch +#define Fetch Fetch32 + +#undef Rotate +#define Rotate Rotate32 + +#undef Bswap +#define Bswap Bswap32 + +STATIC_INLINE uint32_t Hash32Len13to24(const char *s, size_t len, uint32_t seed = 0) { + uint32_t a = Fetch(s - 4 + (len >> 1)); + uint32_t b = Fetch(s + 4); + uint32_t c = Fetch(s + len - 8); + uint32_t d = Fetch(s + (len >> 1)); + uint32_t e = Fetch(s); + uint32_t f = Fetch(s + len - 4); + uint32_t h = d * c1 + len + seed; + a = Rotate(a, 12) + f; + h = Mur(c, h) + a; + a = Rotate(a, 3) + c; + h = Mur(e, h) + a; + a = Rotate(a + f, 12) + d; + h = Mur(b ^ seed, h) + a; + return fmix(h); +} + +STATIC_INLINE uint32_t Hash32Len0to4(const char *s, size_t len, uint32_t seed = 0) { + uint32_t b = seed; + uint32_t c = 9; + for (size_t i = 0; i < len; i++) { + signed char v = s[i]; + b = b * c1 + v; + c ^= b; + } + return fmix(Mur(b, Mur(len, c))); +} + +STATIC_INLINE uint32_t Hash32Len5to12(const char *s, size_t len, uint32_t seed = 0) { + uint32_t a = len, b = len * 5, c = 9, d = b + seed; + a += Fetch(s); + b += Fetch(s + len - 4); + c += Fetch(s + ((len >> 1) & 4)); + return fmix(seed ^ Mur(c, Mur(b, Mur(a, d)))); +} + +uint32_t Hash32(const char *s, size_t len) { + if (len <= 24) { + return len <= 12 ? + (len <= 4 ? Hash32Len0to4(s, len) : Hash32Len5to12(s, len)) : + Hash32Len13to24(s, len); + } + + // len > 24 + uint32_t h = len, g = c1 * len, f = g; + uint32_t a0 = Rotate(Fetch(s + len - 4) * c1, 17) * c2; + uint32_t a1 = Rotate(Fetch(s + len - 8) * c1, 17) * c2; + uint32_t a2 = Rotate(Fetch(s + len - 16) * c1, 17) * c2; + uint32_t a3 = Rotate(Fetch(s + len - 12) * c1, 17) * c2; + uint32_t a4 = Rotate(Fetch(s + len - 20) * c1, 17) * c2; + h ^= a0; + h = Rotate(h, 19); + h = h * 5 + 0xe6546b64; + h ^= a2; + h = Rotate(h, 19); + h = h * 5 + 0xe6546b64; + g ^= a1; + g = Rotate(g, 19); + g = g * 5 + 0xe6546b64; + g ^= a3; + g = Rotate(g, 19); + g = g * 5 + 0xe6546b64; + f += a4; + f = Rotate(f, 19) + 113; + size_t iters = (len - 1) / 20; + do { + uint32_t a = Fetch(s); + uint32_t b = Fetch(s + 4); + uint32_t c = Fetch(s + 8); + uint32_t d = Fetch(s + 12); + uint32_t e = Fetch(s + 16); + h += a; + g += b; + f += c; + h = Mur(d, h) + e; + g = Mur(c, g) + a; + f = Mur(b + e * c1, f) + d; + f += g; + g += f; + s += 20; + } while (--iters != 0); + g = Rotate(g, 11) * c1; + g = Rotate(g, 17) * c1; + f = Rotate(f, 11) * c1; + f = Rotate(f, 17) * c1; + h = Rotate(h + g, 19); + h = h * 5 + 0xe6546b64; + h = Rotate(h, 17) * c1; + h = Rotate(h + f, 19); + h = h * 5 + 0xe6546b64; + h = Rotate(h, 17) * c1; + return h; +} + +uint32_t Hash32WithSeed(const char *s, size_t len, uint32_t seed) { + if (len <= 24) { + if (len >= 13) return Hash32Len13to24(s, len, seed * c1); + else if (len >= 5) return Hash32Len5to12(s, len, seed); + else return Hash32Len0to4(s, len, seed); + } + uint32_t h = Hash32Len13to24(s, 24, seed ^ len); + return Mur(Hash32(s + 24, len - 24) + seed, h); +} +} // namespace farmhashmk +namespace farmhashsu { +#if !can_use_sse42 || !can_use_aesni + +uint32_t Hash32(const char *s, size_t len) { + FARMHASH_DIE_IF_MISCONFIGURED; + return s == NULL ? 0 : len; +} + +uint32_t Hash32WithSeed(const char *s, size_t len, uint32_t seed) { + FARMHASH_DIE_IF_MISCONFIGURED; + return seed + Hash32(s, len); +} + +#else + +#undef Fetch +#define Fetch Fetch32 + +#undef Rotate +#define Rotate Rotate32 + +#undef Bswap +#define Bswap Bswap32 + +// Helpers for data-parallel operations (4x 32-bits). +STATIC_INLINE __m128i Add(__m128i x, __m128i y) { return _mm_add_epi32(x, y); } +STATIC_INLINE __m128i Xor(__m128i x, __m128i y) { return _mm_xor_si128(x, y); } +STATIC_INLINE __m128i Or(__m128i x, __m128i y) { return _mm_or_si128(x, y); } +STATIC_INLINE __m128i Mul(__m128i x, __m128i y) { return _mm_mullo_epi32(x, y); } +STATIC_INLINE __m128i Mul5(__m128i x) { return Add(x, _mm_slli_epi32(x, 2)); } +STATIC_INLINE __m128i RotateLeft(__m128i x, int c) { + return Or(_mm_slli_epi32(x, c), + _mm_srli_epi32(x, 32 - c)); +} +STATIC_INLINE __m128i Rol17(__m128i x) { return RotateLeft(x, 17); } +STATIC_INLINE __m128i Rol19(__m128i x) { return RotateLeft(x, 19); } +STATIC_INLINE __m128i Shuffle0321(__m128i x) { + return _mm_shuffle_epi32(x, (0 << 6) + (3 << 4) + (2 << 2) + (1 << 0)); +} + +uint32_t Hash32(const char *s, size_t len) { + const uint32_t seed = 81; + if (len <= 24) { + return len <= 12 ? + (len <= 4 ? + farmhashmk::Hash32Len0to4(s, len) : + farmhashmk::Hash32Len5to12(s, len)) : + farmhashmk::Hash32Len13to24(s, len); + } + + if (len < 40) { + uint32_t a = len, b = seed * c2, c = a + b; + a += Fetch(s + len - 4); + b += Fetch(s + len - 20); + c += Fetch(s + len - 16); + uint32_t d = a; + a = NAMESPACE_FOR_HASH_FUNCTIONS::Rotate32(a, 21); + a = Mur(a, Mur(b, _mm_crc32_u32(c, d))); + a += Fetch(s + len - 12); + b += Fetch(s + len - 8); + d += a; + a += d; + b = Mur(b, d) * c2; + a = _mm_crc32_u32(a, b + c); + return farmhashmk::Hash32Len13to24(s, (len + 1) / 2, a) + b; + } + +#undef Mulc1 +#define Mulc1(x) Mul((x), cc1) + +#undef Mulc2 +#define Mulc2(x) Mul((x), cc2) + +#undef Murk +#define Murk(a, h) \ + Add(k, \ + Mul5( \ + Rol19( \ + Xor( \ + Mulc2( \ + Rol17( \ + Mulc1(a))), \ + (h))))) + + const __m128i cc1 = _mm_set1_epi32(c1); + const __m128i cc2 = _mm_set1_epi32(c2); + __m128i h = _mm_set1_epi32(seed); + __m128i g = _mm_set1_epi32(c1 * seed); + __m128i f = g; + __m128i k = _mm_set1_epi32(0xe6546b64); + __m128i q; + if (len < 80) { + __m128i a = Fetch128(s); + __m128i b = Fetch128(s + 16); + __m128i c = Fetch128(s + (len - 15) / 2); + __m128i d = Fetch128(s + len - 32); + __m128i e = Fetch128(s + len - 16); + h = Add(h, a); + g = Add(g, b); + q = g; + g = Shuffle0321(g); + f = Add(f, c); + __m128i be = Add(b, Mulc1(e)); + h = Add(h, f); + f = Add(f, h); + h = Add(Murk(d, h), e); + k = Xor(k, _mm_shuffle_epi8(g, f)); + g = Add(Xor(c, g), a); + f = Add(Xor(be, f), d); + k = Add(k, be); + k = Add(k, _mm_shuffle_epi8(f, h)); + f = Add(f, g); + g = Add(g, f); + g = Add(_mm_set1_epi32(len), Mulc1(g)); + } else { + // len >= 80 + // The following is loosely modelled after farmhashmk::Hash32. + size_t iters = (len - 1) / 80; + len -= iters * 80; + +#undef Chunk +#define Chunk() do { \ + __m128i a = Fetch128(s); \ + __m128i b = Fetch128(s + 16); \ + __m128i c = Fetch128(s + 32); \ + __m128i d = Fetch128(s + 48); \ + __m128i e = Fetch128(s + 64); \ + h = Add(h, a); \ + g = Add(g, b); \ + g = Shuffle0321(g); \ + f = Add(f, c); \ + __m128i be = Add(b, Mulc1(e)); \ + h = Add(h, f); \ + f = Add(f, h); \ + h = Add(h, d); \ + q = Add(q, e); \ + h = Rol17(h); \ + h = Mulc1(h); \ + k = Xor(k, _mm_shuffle_epi8(g, f)); \ + g = Add(Xor(c, g), a); \ + f = Add(Xor(be, f), d); \ + std::swap(f, q); \ + q = _mm_aesimc_si128(q); \ + k = Add(k, be); \ + k = Add(k, _mm_shuffle_epi8(f, h)); \ + f = Add(f, g); \ + g = Add(g, f); \ + f = Mulc1(f); \ +} while (0) + + q = g; + while (iters-- != 0) { + Chunk(); + s += 80; + } + + if (len != 0) { + h = Add(h, _mm_set1_epi32(len)); + s = s + len - 80; + Chunk(); + } + } + + g = Shuffle0321(g); + k = Xor(k, g); + k = Xor(k, q); + h = Xor(h, q); + f = Mulc1(f); + k = Mulc2(k); + g = Mulc1(g); + h = Mulc2(h); + k = Add(k, _mm_shuffle_epi8(g, f)); + h = Add(h, f); + f = Add(f, h); + g = Add(g, k); + k = Add(k, g); + k = Xor(k, _mm_shuffle_epi8(f, h)); + __m128i buf[4]; + buf[0] = f; + buf[1] = g; + buf[2] = k; + buf[3] = h; + s = reinterpret_cast(buf); + uint32_t x = Fetch(s); + uint32_t y = Fetch(s+4); + uint32_t z = Fetch(s+8); + x = _mm_crc32_u32(x, Fetch(s+12)); + y = _mm_crc32_u32(y, Fetch(s+16)); + z = _mm_crc32_u32(z * c1, Fetch(s+20)); + x = _mm_crc32_u32(x, Fetch(s+24)); + y = _mm_crc32_u32(y * c1, Fetch(s+28)); + uint32_t o = y; + z = _mm_crc32_u32(z, Fetch(s+32)); + x = _mm_crc32_u32(x * c1, Fetch(s+36)); + y = _mm_crc32_u32(y, Fetch(s+40)); + z = _mm_crc32_u32(z * c1, Fetch(s+44)); + x = _mm_crc32_u32(x, Fetch(s+48)); + y = _mm_crc32_u32(y * c1, Fetch(s+52)); + z = _mm_crc32_u32(z, Fetch(s+56)); + x = _mm_crc32_u32(x, Fetch(s+60)); + return (o - x + y - z) * c1; +} + +#undef Chunk +#undef Murk +#undef Mulc2 +#undef Mulc1 + +uint32_t Hash32WithSeed(const char *s, size_t len, uint32_t seed) { + if (len <= 24) { + if (len >= 13) return farmhashmk::Hash32Len13to24(s, len, seed * c1); + else if (len >= 5) return farmhashmk::Hash32Len5to12(s, len, seed); + else return farmhashmk::Hash32Len0to4(s, len, seed); + } + uint32_t h = farmhashmk::Hash32Len13to24(s, 24, seed ^ len); + return _mm_crc32_u32(Hash32(s + 24, len - 24) + seed, h); +} + +#endif +} // namespace farmhashsu +namespace farmhashsa { +#if !can_use_sse42 + +uint32_t Hash32(const char *s, size_t len) { + FARMHASH_DIE_IF_MISCONFIGURED; + return s == NULL ? 0 : len; +} + +uint32_t Hash32WithSeed(const char *s, size_t len, uint32_t seed) { + FARMHASH_DIE_IF_MISCONFIGURED; + return seed + Hash32(s, len); +} + +#else + +#undef Fetch +#define Fetch Fetch32 + +#undef Rotate +#define Rotate Rotate32 + +#undef Bswap +#define Bswap Bswap32 + +// Helpers for data-parallel operations (4x 32-bits). +STATIC_INLINE __m128i Add(__m128i x, __m128i y) { return _mm_add_epi32(x, y); } +STATIC_INLINE __m128i Xor(__m128i x, __m128i y) { return _mm_xor_si128(x, y); } +STATIC_INLINE __m128i Or(__m128i x, __m128i y) { return _mm_or_si128(x, y); } +STATIC_INLINE __m128i Mul(__m128i x, __m128i y) { return _mm_mullo_epi32(x, y); } +STATIC_INLINE __m128i Mul5(__m128i x) { return Add(x, _mm_slli_epi32(x, 2)); } +STATIC_INLINE __m128i Rotate(__m128i x, int c) { + return Or(_mm_slli_epi32(x, c), + _mm_srli_epi32(x, 32 - c)); +} +STATIC_INLINE __m128i Rot17(__m128i x) { return Rotate(x, 17); } +STATIC_INLINE __m128i Rot19(__m128i x) { return Rotate(x, 19); } +STATIC_INLINE __m128i Shuffle0321(__m128i x) { + return _mm_shuffle_epi32(x, (0 << 6) + (3 << 4) + (2 << 2) + (1 << 0)); +} + +uint32_t Hash32(const char *s, size_t len) { + const uint32_t seed = 81; + if (len <= 24) { + return len <= 12 ? + (len <= 4 ? + farmhashmk::Hash32Len0to4(s, len) : + farmhashmk::Hash32Len5to12(s, len)) : + farmhashmk::Hash32Len13to24(s, len); + } + + if (len < 40) { + uint32_t a = len, b = seed * c2, c = a + b; + a += Fetch(s + len - 4); + b += Fetch(s + len - 20); + c += Fetch(s + len - 16); + uint32_t d = a; + a = NAMESPACE_FOR_HASH_FUNCTIONS::Rotate32(a, 21); + a = Mur(a, Mur(b, Mur(c, d))); + a += Fetch(s + len - 12); + b += Fetch(s + len - 8); + d += a; + a += d; + b = Mur(b, d) * c2; + a = _mm_crc32_u32(a, b + c); + return farmhashmk::Hash32Len13to24(s, (len + 1) / 2, a) + b; + } + +#undef Mulc1 +#define Mulc1(x) Mul((x), cc1) + +#undef Mulc2 +#define Mulc2(x) Mul((x), cc2) + +#undef Murk +#define Murk(a, h) \ + Add(k, \ + Mul5( \ + Rot19( \ + Xor( \ + Mulc2( \ + Rot17( \ + Mulc1(a))), \ + (h))))) + + const __m128i cc1 = _mm_set1_epi32(c1); + const __m128i cc2 = _mm_set1_epi32(c2); + __m128i h = _mm_set1_epi32(seed); + __m128i g = _mm_set1_epi32(c1 * seed); + __m128i f = g; + __m128i k = _mm_set1_epi32(0xe6546b64); + if (len < 80) { + __m128i a = Fetch128(s); + __m128i b = Fetch128(s + 16); + __m128i c = Fetch128(s + (len - 15) / 2); + __m128i d = Fetch128(s + len - 32); + __m128i e = Fetch128(s + len - 16); + h = Add(h, a); + g = Add(g, b); + g = Shuffle0321(g); + f = Add(f, c); + __m128i be = Add(b, Mulc1(e)); + h = Add(h, f); + f = Add(f, h); + h = Add(Murk(d, h), e); + k = Xor(k, _mm_shuffle_epi8(g, f)); + g = Add(Xor(c, g), a); + f = Add(Xor(be, f), d); + k = Add(k, be); + k = Add(k, _mm_shuffle_epi8(f, h)); + f = Add(f, g); + g = Add(g, f); + g = Add(_mm_set1_epi32(len), Mulc1(g)); + } else { + // len >= 80 + // The following is loosely modelled after farmhashmk::Hash32. + size_t iters = (len - 1) / 80; + len -= iters * 80; + +#undef Chunk +#define Chunk() do { \ + __m128i a = Fetch128(s); \ + __m128i b = Fetch128(s + 16); \ + __m128i c = Fetch128(s + 32); \ + __m128i d = Fetch128(s + 48); \ + __m128i e = Fetch128(s + 64); \ + h = Add(h, a); \ + g = Add(g, b); \ + g = Shuffle0321(g); \ + f = Add(f, c); \ + __m128i be = Add(b, Mulc1(e)); \ + h = Add(h, f); \ + f = Add(f, h); \ + h = Add(Murk(d, h), e); \ + k = Xor(k, _mm_shuffle_epi8(g, f)); \ + g = Add(Xor(c, g), a); \ + f = Add(Xor(be, f), d); \ + k = Add(k, be); \ + k = Add(k, _mm_shuffle_epi8(f, h)); \ + f = Add(f, g); \ + g = Add(g, f); \ + f = Mulc1(f); \ +} while (0) + + while (iters-- != 0) { + Chunk(); + s += 80; + } + + if (len != 0) { + h = Add(h, _mm_set1_epi32(len)); + s = s + len - 80; + Chunk(); + } + } + + g = Shuffle0321(g); + k = Xor(k, g); + f = Mulc1(f); + k = Mulc2(k); + g = Mulc1(g); + h = Mulc2(h); + k = Add(k, _mm_shuffle_epi8(g, f)); + h = Add(h, f); + f = Add(f, h); + g = Add(g, k); + k = Add(k, g); + k = Xor(k, _mm_shuffle_epi8(f, h)); + __m128i buf[4]; + buf[0] = f; + buf[1] = g; + buf[2] = k; + buf[3] = h; + s = reinterpret_cast(buf); + uint32_t x = Fetch(s); + uint32_t y = Fetch(s+4); + uint32_t z = Fetch(s+8); + x = _mm_crc32_u32(x, Fetch(s+12)); + y = _mm_crc32_u32(y, Fetch(s+16)); + z = _mm_crc32_u32(z * c1, Fetch(s+20)); + x = _mm_crc32_u32(x, Fetch(s+24)); + y = _mm_crc32_u32(y * c1, Fetch(s+28)); + uint32_t o = y; + z = _mm_crc32_u32(z, Fetch(s+32)); + x = _mm_crc32_u32(x * c1, Fetch(s+36)); + y = _mm_crc32_u32(y, Fetch(s+40)); + z = _mm_crc32_u32(z * c1, Fetch(s+44)); + x = _mm_crc32_u32(x, Fetch(s+48)); + y = _mm_crc32_u32(y * c1, Fetch(s+52)); + z = _mm_crc32_u32(z, Fetch(s+56)); + x = _mm_crc32_u32(x, Fetch(s+60)); + return (o - x + y - z) * c1; +} + +#undef Chunk +#undef Murk +#undef Mulc2 +#undef Mulc1 + +uint32_t Hash32WithSeed(const char *s, size_t len, uint32_t seed) { + if (len <= 24) { + if (len >= 13) return farmhashmk::Hash32Len13to24(s, len, seed * c1); + else if (len >= 5) return farmhashmk::Hash32Len5to12(s, len, seed); + else return farmhashmk::Hash32Len0to4(s, len, seed); + } + uint32_t h = farmhashmk::Hash32Len13to24(s, 24, seed ^ len); + return _mm_crc32_u32(Hash32(s + 24, len - 24) + seed, h); +} + +#endif +} // namespace farmhashsa +namespace farmhashcc { +// This file provides a 32-bit hash equivalent to CityHash32 (v1.1.1) +// and a 128-bit hash equivalent to CityHash128 (v1.1.1). It also provides +// a seeded 32-bit hash function similar to CityHash32. + +#undef Fetch +#define Fetch Fetch32 + +#undef Rotate +#define Rotate Rotate32 + +#undef Bswap +#define Bswap Bswap32 + +STATIC_INLINE uint32_t Hash32Len13to24(const char *s, size_t len) { + uint32_t a = Fetch(s - 4 + (len >> 1)); + uint32_t b = Fetch(s + 4); + uint32_t c = Fetch(s + len - 8); + uint32_t d = Fetch(s + (len >> 1)); + uint32_t e = Fetch(s); + uint32_t f = Fetch(s + len - 4); + uint32_t h = len; + + return fmix(Mur(f, Mur(e, Mur(d, Mur(c, Mur(b, Mur(a, h))))))); +} + +STATIC_INLINE uint32_t Hash32Len0to4(const char *s, size_t len) { + uint32_t b = 0; + uint32_t c = 9; + for (size_t i = 0; i < len; i++) { + signed char v = s[i]; + b = b * c1 + v; + c ^= b; + } + return fmix(Mur(b, Mur(len, c))); +} + +STATIC_INLINE uint32_t Hash32Len5to12(const char *s, size_t len) { + uint32_t a = len, b = len * 5, c = 9, d = b; + a += Fetch(s); + b += Fetch(s + len - 4); + c += Fetch(s + ((len >> 1) & 4)); + return fmix(Mur(c, Mur(b, Mur(a, d)))); +} + +uint32_t Hash32(const char *s, size_t len) { + if (len <= 24) { + return len <= 12 ? + (len <= 4 ? Hash32Len0to4(s, len) : Hash32Len5to12(s, len)) : + Hash32Len13to24(s, len); + } + + // len > 24 + uint32_t h = len, g = c1 * len, f = g; + uint32_t a0 = Rotate(Fetch(s + len - 4) * c1, 17) * c2; + uint32_t a1 = Rotate(Fetch(s + len - 8) * c1, 17) * c2; + uint32_t a2 = Rotate(Fetch(s + len - 16) * c1, 17) * c2; + uint32_t a3 = Rotate(Fetch(s + len - 12) * c1, 17) * c2; + uint32_t a4 = Rotate(Fetch(s + len - 20) * c1, 17) * c2; + h ^= a0; + h = Rotate(h, 19); + h = h * 5 + 0xe6546b64; + h ^= a2; + h = Rotate(h, 19); + h = h * 5 + 0xe6546b64; + g ^= a1; + g = Rotate(g, 19); + g = g * 5 + 0xe6546b64; + g ^= a3; + g = Rotate(g, 19); + g = g * 5 + 0xe6546b64; + f += a4; + f = Rotate(f, 19); + f = f * 5 + 0xe6546b64; + size_t iters = (len - 1) / 20; + do { + uint32_t a0 = Rotate(Fetch(s) * c1, 17) * c2; + uint32_t a1 = Fetch(s + 4); + uint32_t a2 = Rotate(Fetch(s + 8) * c1, 17) * c2; + uint32_t a3 = Rotate(Fetch(s + 12) * c1, 17) * c2; + uint32_t a4 = Fetch(s + 16); + h ^= a0; + h = Rotate(h, 18); + h = h * 5 + 0xe6546b64; + f += a1; + f = Rotate(f, 19); + f = f * c1; + g += a2; + g = Rotate(g, 18); + g = g * 5 + 0xe6546b64; + h ^= a3 + a1; + h = Rotate(h, 19); + h = h * 5 + 0xe6546b64; + g ^= a4; + g = Bswap(g) * 5; + h += a4 * 5; + h = Bswap(h); + f += a0; + PERMUTE3(f, h, g); + s += 20; + } while (--iters != 0); + g = Rotate(g, 11) * c1; + g = Rotate(g, 17) * c1; + f = Rotate(f, 11) * c1; + f = Rotate(f, 17) * c1; + h = Rotate(h + g, 19); + h = h * 5 + 0xe6546b64; + h = Rotate(h, 17) * c1; + h = Rotate(h + f, 19); + h = h * 5 + 0xe6546b64; + h = Rotate(h, 17) * c1; + return h; +} + +uint32_t Hash32WithSeed(const char *s, size_t len, uint32_t seed) { + if (len <= 24) { + if (len >= 13) return farmhashmk::Hash32Len13to24(s, len, seed * c1); + else if (len >= 5) return farmhashmk::Hash32Len5to12(s, len, seed); + else return farmhashmk::Hash32Len0to4(s, len, seed); + } + uint32_t h = farmhashmk::Hash32Len13to24(s, 24, seed ^ len); + return Mur(Hash32(s + 24, len - 24) + seed, h); +} + +#undef Fetch +#define Fetch Fetch64 + +#undef Rotate +#define Rotate Rotate64 + +#undef Bswap +#define Bswap Bswap64 + +STATIC_INLINE uint64_t ShiftMix(uint64_t val) { + return val ^ (val >> 47); +} + +STATIC_INLINE uint64_t HashLen16(uint64_t u, uint64_t v) { + return Hash128to64(Uint128(u, v)); +} + +STATIC_INLINE uint64_t HashLen16(uint64_t u, uint64_t v, uint64_t mul) { + // Murmur-inspired hashing. + uint64_t a = (u ^ v) * mul; + a ^= (a >> 47); + uint64_t b = (v ^ a) * mul; + b ^= (b >> 47); + b *= mul; + return b; +} + +STATIC_INLINE uint64_t HashLen0to16(const char *s, size_t len) { + if (len >= 8) { + uint64_t mul = k2 + len * 2; + uint64_t a = Fetch(s) + k2; + uint64_t b = Fetch(s + len - 8); + uint64_t c = Rotate(b, 37) * mul + a; + uint64_t d = (Rotate(a, 25) + b) * mul; + return HashLen16(c, d, mul); + } + if (len >= 4) { + uint64_t mul = k2 + len * 2; + uint64_t a = Fetch32(s); + return HashLen16(len + (a << 3), Fetch32(s + len - 4), mul); + } + if (len > 0) { + uint8_t a = s[0]; + uint8_t b = s[len >> 1]; + uint8_t c = s[len - 1]; + uint32_t y = static_cast(a) + (static_cast(b) << 8); + uint32_t z = len + (static_cast(c) << 2); + return ShiftMix(y * k2 ^ z * k0) * k2; + } + return k2; +} + +// Return a 16-byte hash for 48 bytes. Quick and dirty. +// Callers do best to use "random-looking" values for a and b. +STATIC_INLINE pair WeakHashLen32WithSeeds( + uint64_t w, uint64_t x, uint64_t y, uint64_t z, uint64_t a, uint64_t b) { + a += w; + b = Rotate(b + a + z, 21); + uint64_t c = a; + a += x; + a += y; + b += Rotate(a, 44); + return make_pair(a + z, b + c); +} + +// Return a 16-byte hash for s[0] ... s[31], a, and b. Quick and dirty. +STATIC_INLINE pair WeakHashLen32WithSeeds( + const char* s, uint64_t a, uint64_t b) { + return WeakHashLen32WithSeeds(Fetch(s), + Fetch(s + 8), + Fetch(s + 16), + Fetch(s + 24), + a, + b); +} + + + +// A subroutine for CityHash128(). Returns a decent 128-bit hash for strings +// of any length representable in signed long. Based on City and Murmur. +STATIC_INLINE uint128_t CityMurmur(const char *s, size_t len, uint128_t seed) { + uint64_t a = Uint128Low64(seed); + uint64_t b = Uint128High64(seed); + uint64_t c = 0; + uint64_t d = 0; + signed long l = len - 16; + if (l <= 0) { // len <= 16 + a = ShiftMix(a * k1) * k1; + c = b * k1 + HashLen0to16(s, len); + d = ShiftMix(a + (len >= 8 ? Fetch(s) : c)); + } else { // len > 16 + c = HashLen16(Fetch(s + len - 8) + k1, a); + d = HashLen16(b + len, c + Fetch(s + len - 16)); + a += d; + do { + a ^= ShiftMix(Fetch(s) * k1) * k1; + a *= k1; + b ^= a; + c ^= ShiftMix(Fetch(s + 8) * k1) * k1; + c *= k1; + d ^= c; + s += 16; + l -= 16; + } while (l > 0); + } + a = HashLen16(a, c); + b = HashLen16(d, b); + return Uint128(a ^ b, HashLen16(b, a)); +} + +uint128_t CityHash128WithSeed(const char *s, size_t len, uint128_t seed) { + if (len < 128) { + return CityMurmur(s, len, seed); + } + + // We expect len >= 128 to be the common case. Keep 56 bytes of state: + // v, w, x, y, and z. + pair v, w; + uint64_t x = Uint128Low64(seed); + uint64_t y = Uint128High64(seed); + uint64_t z = len * k1; + v.first = Rotate(y ^ k1, 49) * k1 + Fetch(s); + v.second = Rotate(v.first, 42) * k1 + Fetch(s + 8); + w.first = Rotate(y + z, 35) * k1 + x; + w.second = Rotate(x + Fetch(s + 88), 53) * k1; + + // This is the same inner loop as CityHash64(), manually unrolled. + do { + x = Rotate(x + y + v.first + Fetch(s + 8), 37) * k1; + y = Rotate(y + v.second + Fetch(s + 48), 42) * k1; + x ^= w.second; + y += v.first + Fetch(s + 40); + z = Rotate(z + w.first, 33) * k1; + v = WeakHashLen32WithSeeds(s, v.second * k1, x + w.first); + w = WeakHashLen32WithSeeds(s + 32, z + w.second, y + Fetch(s + 16)); + std::swap(z, x); + s += 64; + x = Rotate(x + y + v.first + Fetch(s + 8), 37) * k1; + y = Rotate(y + v.second + Fetch(s + 48), 42) * k1; + x ^= w.second; + y += v.first + Fetch(s + 40); + z = Rotate(z + w.first, 33) * k1; + v = WeakHashLen32WithSeeds(s, v.second * k1, x + w.first); + w = WeakHashLen32WithSeeds(s + 32, z + w.second, y + Fetch(s + 16)); + std::swap(z, x); + s += 64; + len -= 128; + } while (LIKELY(len >= 128)); + x += Rotate(v.first + z, 49) * k0; + y = y * k0 + Rotate(w.second, 37); + z = z * k0 + Rotate(w.first, 27); + w.first *= 9; + v.first *= k0; + // If 0 < len < 128, hash up to 4 chunks of 32 bytes each from the end of s. + for (size_t tail_done = 0; tail_done < len; ) { + tail_done += 32; + y = Rotate(x + y, 42) * k0 + v.second; + w.first += Fetch(s + len - tail_done + 16); + x = x * k0 + w.first; + z += w.second + Fetch(s + len - tail_done); + w.second += v.first; + v = WeakHashLen32WithSeeds(s + len - tail_done, v.first + z, v.second); + v.first *= k0; + } + // At this point our 56 bytes of state should contain more than + // enough information for a strong 128-bit hash. We use two + // different 56-byte-to-8-byte hashes to get a 16-byte final result. + x = HashLen16(x, v.first); + y = HashLen16(y + z, w.first); + return Uint128(HashLen16(x + v.second, w.second) + y, + HashLen16(x + w.second, y + v.second)); +} + +STATIC_INLINE uint128_t CityHash128(const char *s, size_t len) { + return len >= 16 ? + CityHash128WithSeed(s + 16, len - 16, + Uint128(Fetch(s), Fetch(s + 8) + k0)) : + CityHash128WithSeed(s, len, Uint128(k0, k1)); +} + +uint128_t Fingerprint128(const char* s, size_t len) { + return CityHash128(s, len); +} +} // namespace farmhashcc +namespace NAMESPACE_FOR_HASH_FUNCTIONS { + +// BASIC STRING HASHING + +// Hash function for a byte array. See also Hash(), below. +// May change from time to time, may differ on different platforms, may differ +// depending on NDEBUG. +uint32_t Hash32(const char* s, size_t len) { + return DebugTweak( + (can_use_sse41 & x86_64) ? farmhashnt::Hash32(s, len) : + (can_use_sse42 & can_use_aesni) ? farmhashsu::Hash32(s, len) : + can_use_sse42 ? farmhashsa::Hash32(s, len) : + farmhashmk::Hash32(s, len)); +} + +// Hash function for a byte array. For convenience, a 32-bit seed is also +// hashed into the result. +// May change from time to time, may differ on different platforms, may differ +// depending on NDEBUG. +uint32_t Hash32WithSeed(const char* s, size_t len, uint32_t seed) { + return DebugTweak( + (can_use_sse41 & x86_64) ? farmhashnt::Hash32WithSeed(s, len, seed) : + (can_use_sse42 & can_use_aesni) ? farmhashsu::Hash32WithSeed(s, len, seed) : + can_use_sse42 ? farmhashsa::Hash32WithSeed(s, len, seed) : + farmhashmk::Hash32WithSeed(s, len, seed)); +} + +// Hash function for a byte array. For convenience, a 64-bit seed is also +// hashed into the result. See also Hash(), below. +// May change from time to time, may differ on different platforms, may differ +// depending on NDEBUG. +uint64_t Hash64(const char* s, size_t len) { + return DebugTweak( + (can_use_sse42 & x86_64) ? + farmhashte::Hash64(s, len) : + farmhashxo::Hash64(s, len)); +} + +// Hash function for a byte array. +// May change from time to time, may differ on different platforms, may differ +// depending on NDEBUG. +size_t Hash(const char* s, size_t len) { + return sizeof(size_t) == 8 ? Hash64(s, len) : Hash32(s, len); +} + +// Hash function for a byte array. For convenience, a 64-bit seed is also +// hashed into the result. +// May change from time to time, may differ on different platforms, may differ +// depending on NDEBUG. +uint64_t Hash64WithSeed(const char* s, size_t len, uint64_t seed) { + return DebugTweak(farmhashna::Hash64WithSeed(s, len, seed)); +} + +// Hash function for a byte array. For convenience, two seeds are also +// hashed into the result. +// May change from time to time, may differ on different platforms, may differ +// depending on NDEBUG. +uint64_t Hash64WithSeeds(const char* s, size_t len, uint64_t seed0, uint64_t seed1) { + return DebugTweak(farmhashna::Hash64WithSeeds(s, len, seed0, seed1)); +} + +// Hash function for a byte array. +// May change from time to time, may differ on different platforms, may differ +// depending on NDEBUG. +uint128_t Hash128(const char* s, size_t len) { + return DebugTweak(farmhashcc::Fingerprint128(s, len)); +} + +// Hash function for a byte array. For convenience, a 128-bit seed is also +// hashed into the result. +// May change from time to time, may differ on different platforms, may differ +// depending on NDEBUG. +uint128_t Hash128WithSeed(const char* s, size_t len, uint128_t seed) { + return DebugTweak(farmhashcc::CityHash128WithSeed(s, len, seed)); +} + +// BASIC NON-STRING HASHING + +// FINGERPRINTING (i.e., good, portable, forever-fixed hash functions) + +// Fingerprint function for a byte array. Most useful in 32-bit binaries. +uint32_t Fingerprint32(const char* s, size_t len) { + return farmhashmk::Hash32(s, len); +} + +// Fingerprint function for a byte array. +uint64_t Fingerprint64(const char* s, size_t len) { + return farmhashna::Hash64(s, len); +} + +// Fingerprint function for a byte array. +uint128_t Fingerprint128(const char* s, size_t len) { + return farmhashcc::Fingerprint128(s, len); +} + +// Older and still available but perhaps not as fast as the above: +// farmhashns::Hash32{,WithSeed}() + +} // namespace NAMESPACE_FOR_HASH_FUNCTIONS + +#if FARMHASHSELFTEST + +#ifndef FARMHASH_SELF_TEST_GUARD +#define FARMHASH_SELF_TEST_GUARD +#include +#include +#include + +using std::cout; +using std::cerr; +using std::endl; +using std::hex; + +static const uint64_t kSeed0 = 1234567; +static const uint64_t kSeed1 = k0; +static const int kDataSize = 1 << 20; +static const int kTestSize = 300; +#define kSeed128 Uint128(kSeed0, kSeed1) + +static char data[kDataSize]; + +static int completed_self_tests = 0; +static int errors = 0; + +// Initialize data to pseudorandom values. +void Setup() { + if (completed_self_tests == 0) { + uint64_t a = 9; + uint64_t b = 777; + for (int i = 0; i < kDataSize; i++) { + a += b; + b += a; + a = (a ^ (a >> 41)) * k0; + b = (b ^ (b >> 41)) * k0 + i; + uint8_t u = b >> 37; + memcpy(data + i, &u, 1); // uint8_t -> char + } + } +} + +int NoteErrors() { +#define NUM_SELF_TESTS 9 + if (++completed_self_tests == NUM_SELF_TESTS) + std::exit(errors > 0); + return errors; +} + +template inline bool IsNonZero(T x) { + return x != 0; +} + +template <> inline bool IsNonZero(uint128_t x) { + return x != Uint128(0, 0); +} + +#endif // FARMHASH_SELF_TEST_GUARD + +namespace farmhashccTest { + +uint32_t CreateSeed(int offset, int salt) { + uint32_t h = static_cast(salt & 0xffffffff); + h = h * c1; + h ^= (h >> 17); + h = h * c1; + h ^= (h >> 17); + h = h * c1; + h ^= (h >> 17); + h += static_cast(offset & 0xffffffff); + h = h * c1; + h ^= (h >> 17); + h = h * c1; + h ^= (h >> 17); + h = h * c1; + h ^= (h >> 17); + return h; +} + +#undef SEED +#undef SEED1 +#undef SEED0 +#define SEED CreateSeed(offset, -1) +#define SEED0 CreateSeed(offset, 0) +#define SEED1 CreateSeed(offset, 1) + +#undef TESTING +#define TESTING 1 +#if TESTING +uint32_t expected[] = { +4223616069u, +3696677242u, +1039179260u, 1690343979u, 1018511555u, 2464489001u, +20368522u, 2663783964u, 175201532u, 1619210592u, +4081014168u, +2576519988u, +3285042206u, 502478099u, 739479538u, 1500332790u, +13754768u, 3789353455u, 3473868058u, 1909255088u, +2212771159u, +1112731063u, +826915357u, 2893489933u, 118369799u, 1848668220u, +1308219822u, 249416982u, 64306364u, 4221800195u, +1020067935u, +3955445564u, +563346294u, 550236731u, 2339016688u, 1826259714u, +3872358639u, 2295981050u, 1870005390u, 4015628802u, +1451961420u, +653440099u, +1292493871u, 164377749u, 1717712483u, 463414587u, +3924343675u, 1050492084u, 3566618804u, 2046983362u, +31917516u, +2957164615u, +230718965u, 999595115u, 3534822176u, 2175709186u, +965707431u, 441796222u, 2481718051u, 1827777486u, +2590087362u, +3879448744u, +3515079898u, 1601433082u, 982764532u, 254808716u, +1293372530u, 4205605817u, 947001462u, 1138890052u, +176305566u, +2447367541u, +2973802542u, 4123621138u, 3083865840u, 1706367795u, +792114347u, 2880110657u, 440613768u, 195054868u, +1359016305u, +3363804638u, +649488537u, 1624045597u, 1441938215u, 3147758996u, +3199173578u, 2597283203u, 2191333609u, 3763129144u, +1117290165u, +1062549743u, +2565615889u, 1046361554u, 1581968261u, 1058773671u, +1123053168u, 3807622275u, 1486749916u, 3900816089u, +2437877004u, +1894455839u, +1912520953u, 1914997013u, 561048608u, 1643267444u, +3671572006u, 194811086u, 1468911468u, 2179206286u, +673206794u, +3486923651u, +3741426466u, 3292160512u, 697001377u, 1900763774u, +3726097344u, 629282039u, 3578723715u, 2868028489u, +3269862919u, +2303349487u, +3643953525u, 2307255916u, 849996280u, 732080434u, +909961480u, 3542445214u, 2628347095u, 4236856917u, +1380660650u, +2631821908u, +2007289004u, 3509705198u, 3788541675u, 789457322u, +3090670546u, 638977894u, 3503881773u, 947102987u, +1525325287u, +1816697045u, +2706647405u, 288763142u, 3505438495u, 481308609u, +2882636782u, 3745162621u, 3503467033u, 428247823u, +176408838u, +333551502u, +1001068721u, 1681483651u, 75380831u, 4191469679u, +3627361839u, 2736617386u, 3120737438u, 1297502456u, +864896482u, +85674920u, +2886047255u, 4119881331u, 2496990525u, 3442502055u, +1806582817u, 3186345024u, 4099591287u, 2560171465u, +3489229104u, +3065015872u, +2755089808u, 3098442882u, 378524719u, 2664097023u, +1771960725u, 2901182183u, 55258521u, 1266621443u, +581644891u, +37790450u, +1800731704u, 3601350920u, 53428754u, 2759476837u, +3391093099u, 1496510311u, 2511119507u, 2636877410u, +631613207u, +1573846064u, +260484875u, 1088212603u, 2369525206u, 322522428u, +3191396600u, 2076543340u, 1552496658u, 2739811558u, +3867875546u, +2051584261u, +2126250818u, 901517871u, 3651631165u, 1323139145u, +1521111765u, 477802997u, 3508559783u, 383954241u, +3804516756u, +4250206331u, +2655954340u, 2484996477u, 1417544845u, 1520282298u, +2745204366u, 2869345147u, 1872738335u, 2592877343u, +1619744564u, +1804962124u, +3458679890u, 423948620u, 273645618u, 4187865426u, +376057175u, 2943431463u, 3581950599u, 1035398331u, +1088213445u, +861988903u, +1323370244u, 777069428u, 506235917u, 369720851u, +2789995854u, 230915180u, 1505086948u, 940361236u, +3727873235u, +1159167499u, +1860302871u, 3456858862u, 3923555152u, 2131072714u, +2910461068u, 3671950363u, 2010742682u, 4088068851u, +3616470388u, +2087714788u, +221675509u, 1230154072u, 3450704646u, 1463226695u, +1998357699u, 266026801u, 619568740u, 3560427266u, +4148162586u, +3150417316u, +1356375822u, 2056097622u, 627905802u, 3881675638u, +2309738053u, 971916703u, 3447805361u, 1673575328u, +673084328u, +3317849401u, +2836362782u, 2377208890u, 3275350588u, 158350552u, +2553241779u, 2497264995u, 3262882649u, 3897937187u, +1598963653u, +3068514414u, +601541505u, 374517071u, 3380795976u, 235752573u, +284670003u, 2990192160u, 904937105u, 2306579150u, +2117362589u, +1635274830u, +3355572906u, 170799903u, 1226685528u, 664567688u, +413219134u, 878324258u, 4026159448u, 3620649295u, +1823625377u, +3175888439u, +1759344347u, 2640637095u, 3549558u, 2192984935u, +978623493u, 804017880u, 3877562323u, 3843116489u, +1641748342u, +1853539444u, +3001178468u, 3443560727u, 2685426077u, 1653064722u, +349231508u, 2726789654u, 3136215581u, 768402830u, +269384321u, +531936536u, +2592883487u, 1343156334u, 3628619802u, 1477143570u, +4269458419u, 3285611028u, 959104925u, 2712290710u, +3480237248u, +835796333u, +2020636251u, 1191914589u, 126521603u, 4288023938u, +3731699932u, 2136758855u, 985780142u, 193807575u, +1850544433u, +653947619u, +3929316796u, 381871169u, 950486363u, 1787262279u, +360480382u, 1800636585u, 1039258631u, 3682073259u, +1262819303u, +1786000319u, +1570627191u, 893065837u, 301304916u, 1478469809u, +623018819u, 2742232545u, 2058913014u, 1706060059u, +2421125401u, +1315829592u, +3208766775u, 1805586156u, 575853086u, 3085025513u, +4010908260u, 2344058256u, 3814407434u, 1458485673u, +2474514786u, +3581895658u, +2710719679u, 190812706u, 2135454262u, 2620080728u, +3400757986u, 1669914857u, 1559978393u, 1629811331u, +3096616493u, +1391424435u, +4158376003u, 1015657076u, 794783832u, 479952178u, +1150290207u, 2497437906u, 231815090u, 755078067u, +3832053281u, +63649475u, +2415822606u, 4105027719u, 1706992318u, 1106598740u, +3941945667u, 1271300761u, 505882259u, 760186809u, +2657183368u, +1925422058u, +1039773764u, 880219458u, 4275949176u, 1556833823u, +925882132u, 4216310340u, 757497522u, 461833914u, +3884002070u, +2790957660u, +2100050089u, 651959176u, 1380301291u, 1289124125u, +452314403u, 226156280u, 3306924715u, 1750807758u, +2290180542u, +1953760569u, +2253069096u, 3960924806u, 1786291620u, 60736185u, +2569018293u, 3870479674u, 2247005661u, 2239850953u, +4261808536u, +3282975782u, +780945879u, 3349849383u, 1579362556u, 2265045884u, +905088740u, 725212379u, 3156479246u, 2501620391u, +3062836263u, +4070422690u, +996797869u, 4082582315u, 976105756u, 303983602u, +1862104804u, 3864508254u, 3383979677u, 2835500286u, +2798364010u, +519359476u, +3447342725u, 194373889u, 3313466630u, 232399983u, +2841787856u, 1672751454u, 3345183154u, 1805381384u, +2226129336u, +2847829057u, +2350774567u, 2838540121u, 2757948482u, 1017002062u, +2329150951u, 2171488196u, 3668619047u, 3874977844u, +3287966998u, +262346753u, +2493054715u, 2298644430u, 2926101182u, 1528457638u, +598656233u, 2615845874u, 989110727u, 820441411u, +253617372u, +2201077208u, +2047569338u, 3114356329u, 3335563734u, 2967673540u, +768438341u, 1417708203u, 3873718246u, 1538441843u, +1279167650u, +3917966776u, +2218481734u, 1015935150u, 1957845042u, 1318150213u, +3146423971u, 4218994877u, 1162470863u, 1519718292u, +2594658906u, +665870414u, +3430347817u, 3933868731u, 1597041394u, 3138684682u, +3398212027u, 1064647658u, 1576321132u, 14792918u, +224938029u, +3706456050u, +847274786u, 2645698692u, 1743374687u, 2343133224u, +3066596790u, 2857270120u, 200596308u, 452055528u, +2319312082u, +3488655402u, +4146865894u, 608206438u, 2699777051u, 3687240713u, +327957508u, 3664730153u, 568134564u, 2993484554u, +4159860363u, +4274533921u, +1079994063u, 2360220210u, 3609597760u, 3639708902u, +2836180437u, 1069910270u, 1892427666u, 1874729790u, +1267712826u, +121886940u, +3572289214u, 2475945610u, 783779452u, 588827737u, +1531395014u, 2085084212u, 2219189792u, 3981444548u, +2218885336u, +1691622694u, +2053232885u, 1386558530u, 2182946189u, 2365247285u, +1871081313u, 2935751853u, 38413723u, 543465863u, +900691890u, +2899905665u, +575120562u, 93133904u, 457154948u, 2983705792u, +4232229200u, 2038565963u, 614693984u, 3405328302u, +4083090010u, +2088004171u, +244031209u, 1861889294u, 2417109253u, 3299562328u, +4158642443u, 4199064449u, 3161611046u, 885015950u, +3677904099u, +2969861785u, +772348805u, 1712263832u, 3219357614u, 484271305u, +3645706114u, 2059620251u, 409557488u, 2278896731u, +224475749u, +3523022952u, +2057140088u, 449131785u, 1149879244u, 4255363996u, +3602720135u, 1690010854u, 2503998822u, 2750828466u, +3340671802u, +1447583863u, +2649684943u, 2764747249u, 3046070595u, 3441726138u, +3840332559u, 3156747501u, 1288666680u, 1472744459u, +3452391933u, +1617542784u, +217869690u, 3718469527u, 348639731u, 590532355u, +43789787u, 22606314u, 1621559290u, 2231743261u, +2234620879u, +544748955u, +3169387920u, 203343594u, 3272552527u, 1078282365u, +809576321u, 854207584u, 3625491053u, 1193737267u, +1628966807u, +2661421060u, +2433442061u, 3886639039u, 2149304418u, 303000565u, +1432830882u, 137378235u, 1135974068u, 318705754u, +2491227157u, +2627534472u, +3520352233u, 2488397682u, 3969194920u, 3843962181u, +2135981459u, 2611933220u, 799460731u, 2300968851u, +3412851628u, +3070914013u, +3555224260u, 4125937572u, 240359903u, 722496673u, +2061023600u, 3843919221u, 2759960043u, 1191155322u, +1504041490u, +3735253656u, +1773124736u, 101110011u, 1627699578u, 2645634551u, +263603947u, 1388368439u, 677146538u, 1644201982u, +2625699644u, +2403862553u, +2426069017u, 3613511705u, 915141802u, 2981654265u, +3474818167u, 2611101773u, 627891434u, 762754924u, +2143021902u, +51067670u, +4017746573u, 2269879853u, 3037857950u, 2388899692u, +582729171u, 1886116725u, 2281219772u, 264704948u, +3509984037u, +4078683368u, +2172959411u, 1807195632u, 3357092302u, 2253764928u, +2320369390u, 3076335959u, 2623583210u, 168378015u, +1435562650u, +1100977467u, +3160490319u, 2550328495u, 2396855930u, 1347823908u, +1617990918u, 3849653099u, 3224111576u, 1681539821u, +4171542880u, +552200045u, +3562947778u, 1676237880u, 3747732307u, 2453332913u, +865530667u, 3566636849u, 3485502777u, 336779723u, +2535942410u, +1685000184u, +820545711u, 1893670486u, 1273910461u, 1193758569u, +970365241u, 381205962u, 3612810852u, 1160577445u, +541488143u, +4005031080u, +2333965236u, 2419855455u, 3484533538u, 3073937876u, +908466956u, 661391539u, 2342122412u, 1467049112u, +1785800827u, +135343033u, +139643209u, 2438375667u, 974654058u, 3216478230u, +3807620420u, 779043363u, 2812846449u, 333254784u, +1025244024u, +2242303095u, +2476683742u, 350018683u, 174652916u, 933097576u, +826905896u, 559603581u, 2777181260u, 164915169u, +4070353203u, +1459055748u, +297303985u, 3103837241u, 3812514233u, 232265137u, +2032819099u, 1523091376u, 3531238208u, 1403510182u, +2886832080u, +2599705941u, +2789695716u, 68437968u, 3823813791u, 1040994569u, +3024194990u, 2461740520u, 3735391266u, 2042207153u, +2461678616u, +3519231840u, +1344224923u, 411442756u, 1179779351u, 7661528u, +778352196u, 3288808867u, 589356197u, 2627504511u, +3374744599u, +3312172905u, +357423007u, 3539567796u, 4044452215u, 1445118403u, +2937983820u, 184089910u, 346201845u, 2427295202u, +1345448010u, +2884434843u, +3085001879u, 2640105409u, 315310640u, 3530289798u, +3362974764u, 963602652u, 75228477u, 3509381180u, +4012777756u, +2380345941u, +1073137836u, 2083960378u, 1220315185u, 3628720934u, +3508867818u, 67148343u, 3558085158u, 1753943368u, +863309561u, +2844713625u, +441921850u, 854732254u, 816793316u, 2555428747u, +3440623414u, 1707304366u, 3189874375u, 1623229221u, +1220335976u, +806745430u, +3909262947u, 1680369031u, 2926179486u, 3410391660u, +3991630434u, 2876458763u, 1179167079u, 536360759u, +1592117159u, +1514343977u, +1032622306u, 2057494855u, 784938958u, 178402996u, +1152907972u, 2326185495u, 2939973666u, 4181120253u, +552831733u, +664251856u, +1297139539u, 1969357631u, 1474065957u, 3055419017u, +3395829380u, 3316562752u, 2168409017u, 614624786u, +3585854336u, +668291094u, +1162889217u, 3773171307u, 2263271126u, 355089668u, +3195850578u, 3396793277u, 3519870267u, 527857605u, +3972392320u, +2224315010u, +4047225561u, 3271434798u, 3192704713u, 2798505213u, +3932215896u, 3792924012u, 3796843756u, 453872975u, +4050552799u, +1056432676u, +928166947u, 121311642u, 930989547u, 2087070683u, +1288978057u, 1556325239u, 1812435626u, 1682385724u, +1214364933u, +904760776u, +3957045528u, 3949822847u, 2411065880u, 3716420732u, +3424837835u, 3833550693u, 1799375326u, 2012368921u, +2768764136u, +1786111037u, +4055479315u, 3751639533u, 2808224623u, 3492656387u, +1306824780u, 2624000170u, 3134795218u, 1778409297u, +3900821801u, +593336325u, +2772069220u, 2980873673u, 3574497158u, 3994780459u, +4246519854u, 3482758570u, 4228015183u, 33101083u, +1769887734u, +4158035314u, +3690638998u, 1119035482u, 4134969651u, 2483207353u, +3932823321u, 285829887u, 3485140138u, 1304815138u, +995608264u, +3133997465u, +1195477617u, 2147693728u, 3506673112u, 4234467492u, +1183174337u, 1395340482u, 769199343u, 193262308u, +2798920256u, +3827889422u, +3399695609u, 3036045724u, 2999477386u, 3567001759u, +2682864314u, 1414023907u, 3699872975u, 3369870701u, +2662284872u, +2179640019u, +2485080099u, 3234415609u, 3755915606u, 1339453220u, +1567403399u, 2076272391u, 293946298u, 3861962750u, +1291949822u, +2916864995u, +132642326u, 2215117062u, 2205863575u, 2488805750u, +405632860u, 3248129390u, 2952606864u, 896734759u, +2047417173u, +3865951392u, +657296855u, 1328547532u, 3966511825u, 3959682388u, +4171801020u, 2981416957u, 1868896247u, 790081075u, +3143666398u, +2950766549u, +2065854887u, 2737081890u, 995061774u, 1510712611u, +2865954809u, 565044286u, 1565631102u, 1500654931u, +494822108u, +2803515503u, +1058154996u, 3506280187u, 856885925u, 4204610546u, +800905649u, 1130711562u, 558146282u, 2053400666u, +449794061u, +2643520245u, +2101248725u, 3123292429u, 3583524041u, 983372394u, +1587743780u, 672870813u, 444833475u, 100741452u, +366232251u, +1717951248u, +524144122u, 1362432726u, 1304947719u, 674306020u, +405665887u, 4081931036u, 1580408204u, 2343242778u, +3901654006u, +2627173567u, +3015148205u, 814686701u, 1327920712u, 1346494176u, +2468632605u, 2259795544u, 2519278184u, 2129281928u, +2860266380u, +4001619412u, +1154910973u, 2841022216u, 1199925485u, 1372200293u, +2713179055u, 3609776550u, 2896463880u, 1056406892u, +177413841u, +40180172u, +3274788406u, 660921784u, 1686225028u, 4003382965u, +2532691887u, 4256809101u, 1186018983u, 667359096u, +2375266493u, +2760222015u, +745187078u, 312264012u, 396822261u, 2588536966u, +2026998998u, 1766454365u, 3218807676u, 3915487497u, +2630550356u, +4130063378u, +4231937074u, 752212123u, 3085144349u, 3267186363u, +4103872100u, 4193207863u, 1306401710u, 3014853131u, +1067760598u, +2306188342u, +2437881506u, 4258185052u, 2506507580u, 130876929u, +1076894205u, 4106981702u, 2799540844u, 945747327u, +1436722291u, +2499772225u, +2571537041u, 2038830635u, 2066826058u, 2892892912u, +524875858u, 3392572161u, 2869992096u, 1308273341u, +923668994u, +1980407857u, +2275009652u, 240598096u, 2658376530u, 3505603048u, +1022603789u, 582423424u, 846379327u, 4092636095u, +4177298326u, +1004173023u, +2154027018u, 2993634669u, 1098364089u, 3035642175u, +1335688126u, 1376393415u, 1252369770u, 3815033328u, +1999309358u, +1234054757u, +1388595255u, 2859334775u, 366532860u, 3453410395u, +4226967708u, 1321729870u, 2078463405u, 156766592u, +3157683394u, +3549293384u, +3348214547u, 2879648344u, 1144813399u, 2758966254u, +647753581u, 813615926u, 2035441590u, 1961053117u, +600168686u, +2192833387u, +3156481401u, 3627320321u, 383550248u, 81209584u, +2339331745u, 1284116690u, 1980144976u, 2955724163u, +789301728u, +3842040415u, +1115881490u, 965249078u, 4098663322u, 1870257033u, +2923150701u, 4217108433u, 183816559u, 2104089285u, +2640095343u, +3173757052u, +927847464u, 2383114981u, 4287174363u, 1886129652u, +70635161u, 1182924521u, 1121440038u, 4246220730u, +3890583049u, +975913757u, +2436253031u, 1074894869u, 1301280627u, 992471939u, +735658128u, 244441856u, 1541612456u, 3457776165u, +3503534059u, +1931651133u, +349142786u, 3669028584u, 1828812038u, 99128389u, +1364272849u, 1963678455u, 3971963311u, 2316950886u, +1308901796u, +2789591580u, +1460494965u, 2380227479u, 1577190651u, 1755822080u, +2911014607u, 859387544u, 13023113u, 2319243370u, +2522582211u, +2299110490u, +3342378874u, 2589323490u, 1884430765u, 3739058655u, +2419330954u, 355389916u, 273950915u, 3670136553u, +410946824u, +3174041420u, +2609010298u, 3059091350u, 2300275014u, 725729828u, +2548380995u, 1738849964u, 1257081412u, 79430455u, +810321297u, +3246190593u, +1007937684u, 912115394u, 40880059u, 3450073327u, +4289832174u, 2253485111u, 1065639151u, 2953189309u, +124779113u, +654299738u, +115760833u, 1250932069u, 884995826u, 3998908281u, +1382882981u, 1134187162u, 3202324501u, 487502928u, +3032756345u, +4057517628u, +933197381u, 2319223127u, 2044528655u, 2554572663u, +4049450620u, 1620812836u, 2832905391u, 2273005481u, +1913090121u, +1055456023u, +510593296u, 3285343192u, 2912822536u, 1645225063u, +638418430u, 452701300u, 1025483165u, 1639370512u, +167948643u, +2809842730u, +2983135664u, 407521332u, 1543756616u, 3949773145u, +4283462892u, 659962275u, 3878013463u, 1000748756u, +4053212051u, +4099239406u, +3467581965u, 354635541u, 21301844u, 3831212473u, +3189450571u, 2264401966u, 4096484849u, 1736448515u, +3976926096u, +3727194724u, +2243487039u, 585209095u, 3143046007u, 969558123u, +3037113502u, 3594170243u, 2835860223u, 3775493975u, +2787220812u, +2274252217u, +2915380701u, 3077533278u, 1252871826u, 1519790952u, +205297661u, 2950557658u, 3956882191u, 2724439401u, +3694608025u, +124028038u, +216019153u, 1533010676u, 2259986336u, 2014061617u, +2068617849u, 3078123052u, 2692046098u, 1582812948u, +396916232u, +1470894001u, +1694309312u, 300268215u, 1553892743u, 671176040u, +1544988994u, 2793402821u, 4194972569u, 2296476154u, +748354332u, +3491325898u, +4261053291u, 1104998242u, 797816835u, 243564059u, +2197717393u, 299029458u, 1675252188u, 3139770041u, +583018574u, +2532106100u, +2099391658u, 3760526730u, 3422719327u, 3556917689u, +2374009285u, 2130865894u, 3710563151u, 1437538307u, +3938030842u, +2006930694u, +2151243336u, 1939741287u, 1957068175u, 2135147479u, +649553342u, 1713643042u, 4188696599u, 1698739939u, +3549427584u, +1016382174u, +322644378u, 2476164549u, 2037263020u, 88036019u, +2548960923u, 539867919u, 2871157727u, 4031659929u, +754087252u, +972656559u, +4246379429u, 3877308578u, 2059459630u, 3614934323u, +1410565271u, 2102980459u, 215395636u, 1083393481u, +3775523015u, +2062750105u, +2475645882u, 3041186774u, 3534315423u, 758607219u, +1686100614u, 180500983u, 1155581185u, 1476664671u, +2918661695u, +3812731350u, +4003853737u, 4148884881u, 1468469436u, 3278880418u, +1045838071u, 1049161262u, 360450415u, 3158065524u, +814443735u, +3391401707u, +729968410u, 738771593u, 3662738792u, 1672830580u, +4199496163u, 188487238u, 219098233u, 2141731267u, +3890250614u, +2988780375u, +4026279523u, 3489429375u, 2468433807u, 1178270701u, +2685094218u, 2716621497u, 3718335529u, 2273344755u, +701110882u, +1925717409u, +1515176562u, 2325460593u, 3954798930u, 784566105u, +3769422266u, 1641530321u, 2703876862u, 2907480267u, +1828076455u, +1805635221u, +3883381245u, 1476756210u, 2072514392u, 3658557081u, +2003610746u, 2556845550u, 729594004u, 3303898266u, +1968227254u, +423204951u, +231828688u, 4223697811u, 698619045u, 3636824418u, +2738779239u, 2333529003u, 2833158642u, 580285428u, +3038148234u, +1012378004u, +1113647298u, 1424593483u, 4053247723u, 1167152941u, +2677383578u, 3419485379u, 2135673840u, 440478166u, +1682229112u, +3226724137u, +1217439806u, 3828726923u, 3636576271u, 3467643156u, +2005614908u, 2655346461u, 2345488441u, 1027557096u, +3594084220u, +1372306343u, +2342583762u, 4291342905u, 4094931814u, 3254771759u, +821978248u, 2404930117u, 1143937655u, 3156949255u, +3460606610u, +449701786u, +3474906110u, 1932585294u, 2283357584u, 1808481478u, +3522851029u, 3040164731u, 1530172182u, 2950426149u, +1402416557u, +756419859u, +4132576145u, 724994790u, 2852015871u, 2177908339u, +899914731u, 139675671u, 1423281870u, 3198458070u, +807581308u, +2021611521u, +1801452575u, 1425984297u, 2833835949u, 1536827865u, +3902351840u, 164546042u, 1872840974u, 3986194780u, +792156290u, +3378681896u, +941547959u, 3931328334u, 3661060482u, 2386420777u, +3920146272u, 3458621279u, 3348500844u, 2269586542u, +797371473u, +3188953649u, +80514771u, 2913333490u, 1246325623u, 3253846094u, +1723906239u, 1606413555u, 587500718u, 1412413859u, +2310046829u, +2113313263u, +3855635608u, 47271944u, 1112281934u, 3440228404u, +2633519166u, 425094457u, 307659635u, 67338587u, +2412987939u, +2363930989u, +2853008596u, 2844637339u, 922568813u, 130379293u, +2825204405u, 2904442145u, 1176875333u, 1511685505u, +599177514u, +1872681372u, +682394826u, 1888849790u, 3635304282u, 1761257265u, +1571292431u, 355247075u, 1177210823u, 1691529530u, +3629531121u, +3760474006u, +1129340625u, 868116266u, 3908237785u, 1942124366u, +1266630014u, 3214841995u, 334023850u, 1110037019u, +369650727u, +1288666741u, +70535706u, 20230114u, 4284225520u, 727856157u, +293696779u, 1244943770u, 3976592462u, 560421917u, +4171688499u, +2438786950u, +1218144639u, 3809125983u, 1302395746u, 534542359u, +2121993015u, 2899519374u, 3192177626u, 1761707794u, +3101683464u, +1555403906u, +3225675390u, 1875263768u, 4278894569u, 651707603u, +2111591484u, 3802716028u, 2900262228u, 1181469202u, +3254743797u, +1822684466u, +860641829u, 3046128268u, 1284833012u, 1125261608u, +461384524u, 2331344566u, 1274400010u, 990498321u, +3462536298u, +3796842585u, +2346607194u, 279495949u, 3951194590u, 3522664971u, +3169688303u, 726831706u, 1123875117u, 1816166599u, +3759808754u, +2918558151u, +3713203220u, 3369939267u, 466047109u, 384042536u, +587271104u, 2191634696u, 2449929095u, 1157932232u, +2084466674u, +841370485u, +3241372562u, 4277738486u, 2150836793u, 1173569449u, +778768930u, 2594706485u, 3065269405u, 3019263663u, +2660146610u, +2789946230u, +77056913u, 728174395u, 3647185904u, 804562358u, +2697276483u, 881311175u, 1178696435u, 2059173891u, +2308303791u, +221481230u, +50241451u, 3689414100u, 1969074761u, 2732071529u, +1900890356u, 840789500u, 2100609300u, 985565597u, +1220850414u, +2456636259u, +223607678u, 1016310244u, 1937434395u, 85717256u, +275058190u, 3712011133u, 171916016u, 2389569096u, +3679765802u, +3575358777u, +3481108261u, 3178286380u, 2489642395u, 2931039055u, +3086601621u, 3079518902u, 3027718495u, 2506894644u, +2976869602u, +2134336365u, +2420172217u, 918054427u, 661522682u, 1403791357u, +3587174388u, 2623673551u, 1355661457u, 4159477684u, +1109013587u, +3112183488u, +2217849279u, 3500291996u, 2419603731u, 2929886201u, +3854470013u, 1358382103u, 1357666555u, 21053566u, +2716621233u, +3094836862u, +3309729704u, 57086558u, 839187419u, 2757944838u, +3651040558u, 3607536716u, 3691257732u, 2312878285u, +1202511724u, +183479927u, +2509829803u, 109313218u, 478173887u, 2072044014u, +190631406u, 2495604975u, 1010416260u, 3679857586u, +726566957u, +258500881u, +1805873908u, 3081447051u, 2352101327u, 534922207u, +1584552873u, 813470716u, 255914637u, 249169434u, +3193498057u, +1038802706u, +2590158653u, 3147907290u, 663060128u, 1156177857u, +634616100u, 312879189u, 1545020368u, 2054634247u, +3271451914u, +3438291534u, +2181454946u, 3864535432u, 2398586877u, 896491075u, +2810631478u, 2770357487u, 3372930052u, 898070638u, +2051007323u, +392959778u, +36645539u, 3743556044u, 4134529680u, 4124451188u, +566806297u, 2936523982u, 1304761965u, 537399498u, +1940818842u, +40862381u, +36288410u, 3063605629u, 2826611650u, 3961972098u, +1871578006u, 2392095486u, 1136931591u, 513864488u, +173276451u, +3039055682u, +3543322032u, 1943592006u, 657217094u, 1751698246u, +2969618445u, 456616022u, 900309519u, 113892716u, +1126392103u, +1235651045u, +1882073852u, 2136610853u, 2353639710u, 2819956700u, +3980083530u, 828773559u, 224069850u, 902434120u, +2802008036u, +94358995u, +2777723394u, 2812641403u, 2525832595u, 4157388110u, +4235563782u, 937800324u, 141690749u, 568062536u, +550123849u, +1330316521u, +1949488696u, 2296431366u, 1958465262u, 3564751729u, +3748252207u, 120455129u, 1607318832u, 2525729790u, +2640987481u, +2332096657u, +1775969159u, 1555085077u, 2913525137u, 1347085183u, +2376253113u, 3194050574u, 1806090610u, 678641356u, +1499146713u, +383849715u, +3299835823u, 2284860330u, 2614269636u, 3913628844u, +2761334210u, 1959484587u, 529797021u, 239966995u, +3102194829u, +3602307804u, +1122192627u, 3577510006u, 164486066u, 1680137310u, +1473396395u, 1467801424u, 903493660u, 1185943071u, +2798556505u, +2306744492u, +3167201310u, 3577947177u, 3067592134u, 2905506289u, +1210366329u, 204484056u, 2347778932u, 3862374472u, +3277439508u, +4187414621u, +1646699310u, 621385800u, 3934869089u, 3975491588u, +3580085916u, 1925674500u, 2436305348u, 3983301539u, +2739439523u, +3291507446u, +3395637920u, 3753389171u, 2955202032u, 2654255623u, +3771089254u, 2140443405u, 2779834738u, 3261942805u, +3526889244u, +1842009139u, +4048484340u, 2106218403u, 2161244271u, 772152700u, +1158647659u, 3776791619u, 3882186721u, 699525237u, +2954670460u, +1007105869u, +3359152025u, 1146388699u, 1401550303u, 2326582541u, +4181783540u, 1085644043u, 1942143795u, 1038368308u, +1526153809u, +4042547244u, +1891441000u, 2573991874u, 1281441253u, 3635098284u, +1980545715u, 825985487u, 3934748116u, 4228386979u, +1480870944u, +1042194545u, +2397771642u, 2248490001u, 3817869868u, 878654626u, +3785629484u, 1672470870u, 3229367873u, 1894538933u, +1010692731u, +1733824268u, +656620328u, 3048283803u, 3353340056u, 2324965120u, +4192585951u, 2284524675u, 3483884368u, 1510168293u, +1554942691u, +1309709396u, +1241133168u, 3162179280u, 4046378054u, 3171681593u, +1165297136u, 3496703563u, 150437903u, 1948622072u, +1076332463u, +2292479143u, +1464229958u, 3479738093u, 2328067598u, 2334503110u, +833324834u, 3981605747u, 3002629155u, 2854644186u, +2832201336u, +95796957u, +3269249397u, 2358313329u, 3411860910u, 4283292480u, +2802208697u, 1305947955u, 2156803420u, 1991340283u, +189678024u, +447602599u, +1055411517u, 1531748363u, 1555852656u, 412402681u, +3774988152u, 20597551u, 2925024131u, 1423989620u, +3749428061u, +1541439448u, +112270416u, 1936224776u, 132162941u, 3772011507u, +3814102518u, 1908807815u, 444154079u, 823765347u, +3362275567u, +3419047430u, +2108287005u, 2315102125u, 658593738u, 3195094029u, +3721937534u, 3176229204u, 3398835373u, 1271898712u, +1142546577u, +3185986817u, +3562705803u, 2046119567u, 912990621u, 1829977672u, +3459576979u, 1118045834u, 1369529376u, 3320601076u, +3954988953u, +4002467635u, +3359456351u, 1314849568u, 1766750942u, 2998874853u, +1181800239u, 707328036u, 3314954697u, 2066721120u, +598194215u, +1124451278u, +3156679616u, 3742684743u, 2960199690u, 2683497915u, +2566077529u, 937014607u, 102095219u, 4262922475u, +3132264275u, +1262099830u, +862722905u, 2717653494u, 3245583534u, 3427209989u, +3220278124u, 85457091u, 2222333500u, 3513997967u, +3522324951u, +2830855552u, +2215004781u, 3482411840u, 4227160614u, 2030964411u, +1741393851u, 2643723748u, 942813508u, 403442675u, +3112048748u, +530556423u, +3817755244u, 3543286628u, 2247276090u, 1532920842u, +4101962711u, 1446540991u, 3297821473u, 1861255389u, +1984398u, +2366525138u, +377589481u, 3549193828u, 1427765914u, 506831657u, +277278988u, 1447652775u, 3214362239u, 3142198690u, +2843087541u, +468915015u, +807895062u, 2198723907u, 4031145069u, 2417156212u, +4027298697u, 637175947u, 1229254212u, 1773257887u, +1659444818u, +451148891u, +2099741368u, 735351990u, 2534775713u, 3261804619u, +712519954u, 3527962772u, 3758642738u, 4245823575u, +1281314264u, +1167866160u, +1489546151u, 1197354389u, 1043278102u, 2563326586u, +371937794u, 2320164817u, 3189512691u, 573685198u, +4108603513u, +3758899588u, +3507030163u, 2947201212u, 2529492585u, 578234375u, +3362349842u, 3318878925u, 3611203517u, 3059253190u, +4270755916u, +4291274625u, +4237586791u, 4137422245u, 2927218651u, 2444687041u, +797128811u, 2043057612u, 396533859u, 2665256178u, +3346510674u, +1779586176u, +3076562062u, 1882746214u, 921095362u, 2026988397u, +514514911u, 3886379478u, 4218272420u, 1480386793u, +3900160816u, +2292273451u, +1276138356u, 1125461821u, 1912885715u, 3365266013u, +1333211627u, 4085009861u, 1390530102u, 3347984752u, +2721771301u, +1419492325u, +4066766256u, 3250852311u, 820111852u, 1382201318u, +2366036798u, 938032241u, 3100979439u, 487048687u, +2292851045u, +3241399180u, +3912670510u, 2416437067u, 2973194517u, 3507707986u, +1935099406u, 2533441488u, 104616731u, 2892622820u, +3801190339u, +4239188808u, +807238241u, 3300121546u, 2249406147u, 4032114017u, +3713738189u, 3324425575u, 4275607376u, 3663120298u, +4173658372u, +3984289690u, +1827636846u, 3264588778u, 3297165529u, 558623533u, +2728945672u, 1566297318u, 3447249966u, 481719551u, +1596842050u, +1838185946u, +265271620u, 1050246315u, 4046655705u, 1844193138u, +3807563245u, 1075384804u, 1292554949u, 1506525927u, +2921816148u, +2051885269u, +1930534041u, 3872721086u, 1564489377u, 2272482181u, +2849358683u, 589618304u, 2262072443u, 290363051u, +299168363u, +3867603931u, +2868688756u, 2545263115u, 1092098533u, 3885725603u, +2352430409u, 1981595469u, 2047946646u, 1332642839u, +793806516u, +214858837u, +1061484659u, 3192394476u, 1115054785u, 3690637234u, +996792368u, 2023479706u, 3046498231u, 4205835102u, +3870714754u, +257472875u, +3549864599u, 2040276129u, 2414778670u, 812235477u, +2674248196u, 1864096101u, 2257492689u, 1332556794u, +1079540713u, +465530720u, +2304763972u, 830724724u, 3354588920u, 2510713652u, +3103749409u, 468835585u, 1707620787u, 3038024846u, +1000303198u, +3462270146u, +2748698899u, 2100348093u, 511537258u, 1237187486u, +102049383u, 2268226698u, 3162251739u, 4219404629u, +838822407u, +1481440623u, +2989224077u, 2676681975u, 3246551821u, 3812079906u, +370572963u, 2283154352u, 3084789986u, 1961085583u, +1955640586u, +2409348147u, +2284780581u, 1634818716u, 4018221729u, 2320761377u, +3566831899u, 1799560520u, 91431959u, 1754113747u, +1459430477u, +3613658517u, +924489906u, 3406317699u, 866289774u, 3924821603u, +1265394945u, 1870668109u, 151949856u, 2747006534u, +3111906201u, +64039467u, +2314447545u, 2600195638u, 4095795204u, 4162096026u, +1026756826u, 2460047982u, 52686887u, 823198739u, +1518045160u, +2867527376u, +566410761u, 2200433819u, 2114146405u, 2893790965u, +881504901u, 974783212u, 490815659u, 937300283u, +1523735309u, +2511976468u, +2634644947u, 355119367u, 1373773092u, 309232995u, +3088671051u, 787126032u, 3442836843u, 4289194567u, +2177850062u, +1174136430u, +3248982914u, 3129039732u, 1166851580u, 2196451882u, +469595580u, 2130837700u, 3783349021u, 3745262548u, +1236930515u, +3032131496u, +1525591437u, 1823628217u, 1939019255u, 1950270463u, +3659899927u, 3688643445u, 3004399289u, 1155199552u, +357547234u, +2213110526u, +3122658210u, 2667800490u, 2718690333u, 3512372076u, +1098611683u, 2657518392u, 4248458835u, 3109874532u, +1592908438u, +2864927516u, +3635248840u, 1251777186u, 3797340158u, 3508496870u, +303354834u, 1482394062u, 2087100120u, 1595931912u, +608574156u, +723367884u, +907938402u, 3357047807u, 1619629851u, 3092082995u, +89030300u, 916336992u, 1861180168u, 3436334155u, +1375000544u, +3472936241u, +1321217853u, 791356402u, 2872410224u, 2326250297u, +2657644088u, 1748314108u, 4146771421u, 2913114440u, +2924821844u, +2101101496u, +3268017251u, 2109603066u, 690665520u, 1830067573u, +951427661u, 2982533150u, 3884512506u, 2358657479u, +2833210784u, +3419798214u, +3785893994u, 2103940206u, 86759766u, 4031230616u, +3745237192u, 2739453927u, 497038072u, 3303159408u, +1251537249u, +1993408196u, +3185905715u, 2885948408u, 3154277110u, 2444150313u, +2505582079u, 2120610195u, 3266465773u, 1814611964u, +3080050407u, +1079915522u, +1819346505u, 2529946763u, 892097374u, 3740257161u, +3618100441u, 1079900094u, 3607172225u, 737863389u, +360704560u, +3341993089u, +1139047381u, 3132219631u, 1248981859u, 1109338159u, +2004908615u, 4022302594u, 4166640860u, 2959140950u, +3949235962u, +2832278473u, +2200524012u, 2634933043u, 2495844522u, 2613799818u, +4034096813u, 683271795u, 1673546817u, 1363163726u, +1805395136u, +511749501u, +1231032599u, 2305979751u, 345737783u, 3339868854u, +2931857933u, 2323251738u, 1332068477u, 51846558u, +3927238177u, +1387182179u, +1701238601u, 1419275173u, 2580882268u, 3357874599u, +1726558907u, 1292901039u, 1371322339u, 1311713044u, +3526735232u, +4017884184u, +3366093428u, 77140994u, 2128996229u, 1357915765u, +4019691901u, 483989024u, 2390311750u, 2766065288u, +3938587520u, +3064810344u, +1054589198u, 1274997019u, 4040589616u, 1277751144u, +2274907047u, 4170399945u, 2886368209u, 4168922115u, +3901237033u, +3252972311u, +2205185840u, 3403097556u, 3385493699u, 2809751370u, +555319628u, 399539034u, 2998971454u, 1521596214u, +178870216u, +1471733541u, +519629198u, 514159209u, 1500582242u, 1928616587u, +2686427928u, 4133138798u, 1225914083u, 1432713584u, +3559310915u, +3925489366u, +1055613123u, 4126676029u, 2723867653u, 3290604111u, +1377022957u, 2373608155u, 3615237379u, 594338683u, +2645257602u, +2408427260u, +917033274u, 750455097u, 625657657u, 121713200u, +2191273413u, 4043949724u, 3293146785u, 3809297972u, +3947296919u, +115456894u, +1529576616u, 1459278275u, 2157117997u, 1747859293u, +4106665903u, 996939232u, 2007976332u, 4274649009u, +1017725787u, +4244666096u, +1219631331u, 3072426253u, 3547691720u, 1620822012u, +1397717508u, 2031597325u, 3345983430u, 2459068000u, +3645130467u, +2308642742u, +359955852u, 1348467968u, 1133123059u, 2435919062u, +2800365907u, 4213217210u, 4056565603u, 2811666556u, +2318007236u, +3823652401u, +3654086429u, 1273260424u, 1591610446u, 943349350u, +3441227678u, 3779964757u, 233818224u, 3469971032u, +3764095096u, +4009204587u, +678472092u, 1990559652u, 2583121088u, 2978143652u, +2496370864u, 2139539656u, 4287972050u, 295832576u, +3536742861u, +2257466133u, +2738052161u, 1988611898u, 2466189642u, 3294419573u, +2311186273u, 474374532u, 3081964174u, 2515138278u, +835731677u, +1178182694u, +3352119543u, 2884763225u, 3462399574u, 2900817210u, +1993698511u, 2868445043u, 2746444849u, 1205258179u, +2353442946u, +4079040070u, +3624133102u, 2907136076u, 2902521697u, 426813211u, +1418185512u, 3711189488u, 1351506552u, 1934749519u, +46595543u, +401688809u, +3514602124u, 1396852607u, 1951477943u, 2502249173u, +3199695820u, 2890250638u, 4205072507u, 1715623846u, +3266686789u, +3218688128u, +1697759742u, 851227671u, 2358709645u, 4174233268u, +500583683u, 3805940955u, 736234120u, 2710563712u, +1949664540u, +3139414003u, +4293073253u, 1284406972u, 1785182449u, 1051548274u, +2994248357u, 2499882522u, 717208669u, 2039517285u, +518424929u, +143136433u, +2303774671u, 1272930860u, 2286410920u, 788459311u, +273225293u, 2439291703u, 2254505236u, 3446287701u, +3655156558u, +1546628787u, +340081500u, 3285722006u, 1324810435u, 1053980860u, +1779472859u, 2700355724u, 686005017u, 3762376315u, +3963193100u, +1370881135u, +661300087u, 1152753704u, 2349891598u, 3910051187u, +2109444785u, 1311123870u, 2639837565u, 1896770931u, +1081414128u, +869877586u, +4284220400u, 63045374u, 235968615u, 184451062u, +1271099822u, 1319179857u, 3274963209u, 4172272710u, +3388797445u, +2965973320u, +3793110097u, 3327241723u, 2991804005u, 1199544355u, +771553759u, 2031749842u, 2596517372u, 1199888213u, +858347951u, +3340178832u, +2903875412u, 763490382u, 76949161u, 2056544406u, +1145227689u, 998233136u, 2354530024u, 427713587u, +3537837347u, +604661755u, +923986833u, 1023730418u, 798294227u, 432557449u, +801802449u, 1861313429u, 3899128441u, 4068407979u, +2352677083u, +3783539925u, +10731973u, 3390767975u, 3949540249u, 1920121661u, +3248580201u, 641956426u, 2104847395u, 604835744u, +1491663404u, +4255204651u, +1520970746u, 2845653368u, 3247412938u, 3730629005u, +855569514u, 3073294700u, 2429691698u, 3818342476u, +3938869985u, +2731201328u, +2335202643u, 778117742u, 13298408u, 228780590u, +2871715314u, 3253688653u, 4150999702u, 3846220408u, +930808u, +1397128726u, +1964216488u, 2781092828u, 116285375u, 2271239476u, +3724347554u, 2931203895u, 3893169206u, 1883912528u, +2093892660u, +3658787024u, +3095016046u, 1094059199u, 3640239610u, 558564267u, +2102812456u, 464734873u, 925262247u, 1609838036u, +588364741u, +1731409233u, +1576165139u, 3933979268u, 375316394u, 4247099643u, +3670508019u, 4080496835u, 2371248533u, 183762693u, +2078935389u, +2699810414u, +1491815683u, 2999180789u, 1831158425u, 1603373553u, +2006136905u, 3210230591u, 416748595u, 1536971415u, +3271869367u, +1266062739u, +2138414557u, 3337114778u, 1634586826u, 36472629u, +4482244u, 568009609u, 2721216780u, 4037289545u, +2235138807u, +1789351460u, +4067539527u, 1323062829u, 3864620647u, 4192026301u, +4278901241u, 1399025382u, 2826652805u, 1363860382u, +1801770651u, +1613381526u, +1165249276u, 4046576622u, 2535596946u, 3260388176u, +1078898578u, 2259750862u, 643387587u, 237144235u, +4199571427u, +3440917581u, +3067939258u, 2018625455u, 1460528353u, 3138629939u, +1666223528u, 3841139376u, 2528281125u, 885565193u, +2609492686u, +2517257479u, +560864620u, 2261471820u, 3491559165u, 1329620416u, +622383582u, 1759597655u, 2877873893u, 584692817u, +1901728399u, +2599000260u, +3169771644u, 296332336u, 774719455u, 4175920823u, +2287316070u, 4115615023u, 1073335619u, 4240292725u, +1359158837u, +1960974237u, +3173724597u, 1619084286u, 2876340752u, 4065675347u, +480741335u, 1237329941u, 701055566u, 3729009837u, +1314736422u, +4003180069u, +3118519317u, 3035354420u, 3380357671u, 4020909015u, +253958714u, 3545798863u, 3008185002u, 2624719888u, +3219955575u, +3060719376u, +573101682u, 1580316843u, 2610493412u, 3490983536u, +3601975611u, 851470366u, 635384901u, 3427048824u, +1470002757u, +3592460087u, +2265226856u, 4124282457u, 2106385486u, 3334305617u, +4208282753u, 3798749815u, 225396466u, 118791182u, +2523395972u, +194595464u, +2563824631u, 2521301383u, 4224409406u, 468670274u, +1761966400u, 1300908277u, 2570709228u, 1847901526u, +1470099163u, +2690466752u, +1472536718u, 2399279735u, 4150607803u, 1775080054u, +2082537685u, 4080034578u, 1256001880u, 392967725u, +2055838940u, +3349115816u, +1745947263u, 2213925887u, 1836572741u, 2417722792u, +636223705u, 2423329294u, 3960951311u, 1543591052u, +1547914361u, +2760945653u, +3519014111u, 313543871u, 4119598884u, 1071003714u, +2192556597u, 1526995535u, 3929839778u, 536388591u, +3040873792u, +3752682932u, +1640614237u, 2432794021u, 385337403u, 2794410617u, +2386128075u, 1055206708u, 1422747714u, 3759330929u, +2533597496u, +30440955u, +1482899460u, 3350385050u, 616259409u, 3980103795u, +1211364140u, 1040071544u, 594746920u, 1645973936u, +2547331531u, +1097726368u, +700666526u, 2976247482u, 1144906608u, 996506677u, +1997130756u, 800321417u, 1392942823u, 1601662248u, +2079778663u, +529512908u, +2925120134u, 4106433085u, 630221833u, 2423086156u, +1119859778u, 1726827981u, 1870859181u, 2559832707u, +1792284257u, +2059356387u, +3572353364u, 3229407475u, 575621095u, 3221893291u, +2372428048u, 2020123035u, 961449593u, 2243824063u, +3803906611u, +3735348189u, +2981620804u, 4180681078u, 1555330629u, 230736535u, +2075526640u, 749652975u, 713664372u, 2152096659u, +2142067223u, +3322302242u, +1421646830u, 2092832615u, 1213735101u, 3192136753u, +1106723940u, 3455398230u, 2541685524u, 2529956739u, +3789430647u, +1950084508u, +2157395621u, 850457360u, 2758902426u, 2848030169u, +6506379u, 1162213157u, 2981459221u, 272690871u, +3059420255u, +4242691285u, +588065598u, 1206949936u, 3968214184u, 566348532u, +126142880u, 1480567086u, 2959621988u, 2050218418u, +2242731195u, +3833514449u, +1898070331u, 3687399477u, 3891859374u, 868185955u, +2335308774u, 3676335246u, 3871121805u, 2189032743u, +3275728647u, +860492892u, +1590764344u, 4130384758u, 262871548u, 3004764525u, +2685542071u, 991231482u, 435122019u, 3031116998u, +2898921700u, +2917932604u, +4238665148u, 2459072654u, 3444612545u, 4207731740u, +1808564313u, 2798532269u, 3944553556u, 3926395409u, +1633200670u, +4138335224u, +2524878605u, 4184292650u, 3563398268u, 4288943552u, +3802121210u, 957502058u, 2410820887u, 4227117506u, +4018625153u, +4284329158u, +530216712u, 2978986531u, 863452221u, 1910162118u, +4088211378u, 4091971261u, 3150811451u, 4200871487u, +3794038652u, +3041564310u, +2045287082u, 887805614u, 2889167251u, 4120352181u, +1699912580u, 3478922097u, 3211994687u, 3136177842u, +1500806861u, +3211881347u, +2147976385u, 3342722260u, 3359650541u, 4197378460u, +781354073u, 1533623029u, 2204677828u, 3228172832u, +3248592437u, +3355841359u, +560815159u, 1144951236u, 4027015711u, 2882625391u, +339363613u, 2354572719u, 1769831876u, 4238589331u, +1519732871u, +2185834614u, +1601096831u, 129709881u, 39655633u, 367604993u, +1737681770u, 3259114599u, 2767070452u, 872365177u, +1574125529u, +3405020189u, +4181346685u, 1134030380u, 403769171u, 2193351164u, +1426232618u, 2885309450u, 3033612627u, 924948363u, +935514094u, +3202053329u, +912294839u, 1618472324u, 4159158431u, 3744999487u, +777064358u, 3974213124u, 1990246048u, 309725290u, +2449849392u, +1943692420u, +2288635750u, 2433793635u, 2168904061u, 683315308u, +3081493019u, 3477759434u, 3815496269u, 2823504699u, +586945121u, +3088963200u, +3492287335u, 636875049u, 1111206944u, 2037346120u, +1282050044u, 1409681512u, 1786128584u, 755810950u, +2332676758u, +2178142310u, +957827166u, 1014983590u, 1888800725u, 3608595803u, +3200072714u, 2534008478u, 659336139u, 1281728287u, +4060560529u, +2915575125u, +3521503774u, 2926487340u, 1096297674u, 653489861u, +2352326980u, 2561136777u, 1224141198u, 1250479629u, +1297625391u, +2409997371u, +1942483722u, 2481835750u, 1394715707u, 1673070941u, +2456039704u, 3980558014u, 3547934764u, 1882038812u, +1078160498u, +2488279087u, +1848235245u, 1211914722u, 2264928765u, 2807773070u, +270145554u, 583747883u, 3826009010u, 2996618216u, +425727157u, +992726957u, +3384462280u, 726650661u, 1955043265u, 1923879512u, +1854693773u, 2987614542u, 2660044993u, 2457260810u, +426299370u, +2671892900u, +1827308087u, 3083953443u, 1791749638u, 3265087416u, +2119752201u, 2547122538u, 3990783236u, 1912713468u, +3688865211u, +1815780016u, +303699291u, 2416763742u, 2690891610u, 1535193548u, +1107803989u, 1504143133u, 2235270371u, 2545884083u, +2276278682u, +411724404u, +3416925704u, 2565792091u, 3383911757u, 546058824u, +3374654444u, 2364630415u, 2693473470u, 2622125691u, +261864817u, +55682470u, +857617568u, 141304067u, 1885488541u, 155368182u, +1281949051u, 3384522408u, 3254816901u, 1959816782u, +1452224057u, +2830267691u, +3709231247u, 58988202u, 4218130458u, 2984061349u, +1888707848u, 4223605071u, 4241442486u, 375269213u, +3208327038u, +2199916493u, +550337252u, 2855061437u, 276088636u, 114362204u, +2321163647u, 2127813633u, 3289403024u, 2686973202u, +2717376797u, +3593428039u, +3648831666u, 890925902u, 3289404818u, 3289516821u, +4248913260u, 1858916580u, 3303932308u, 1752797086u, +1628149686u, +3245893605u, +1568537311u, 2844194502u, 1593855770u, 2408174109u, +124797514u, 2085649512u, 3188565660u, 2264996276u, +1926696513u, +3053957740u, +2238806881u, 2189050973u, 203685243u, 379855590u, +3920271562u, 1058600179u, 3698061923u, 4255106849u, +608401664u, +1598041932u, +3318266418u, 2535016555u, 852760884u, 1918098822u, +2200437599u, 1532285043u, 3425662132u, 3561293706u, +2231633206u, +4108785088u, +3359152801u, 173534780u, 208383607u, 2862988169u, +2406642243u, 426814583u, 2777335795u, 3322703596u, +954190623u, +615093090u, +4179102978u, 2452847930u, 100239619u, 42471741u, +818352432u, 2190624654u, 504379960u, 3631619975u, +633412456u, +1018421783u, +842645419u, 711808707u, 3424580813u, 2132457941u, +1158335882u, 3567952480u, 2302183699u, 1145788151u, +3474264138u, +3105085243u, +3115506027u, 2783713015u, 3871785309u, 539583269u, +1400252405u, 3857849984u, 4231186588u, 1278653799u, +1760227022u, +761044088u, +3838185417u, 2439542532u, 585283357u, 2055995220u, +937117124u, 3831944855u, 1823586038u, 3287917855u, +485082427u, +3209172809u, +1984570176u, 2818337297u, 2691869057u, 3790476953u, +839035557u, 3203129010u, 669981176u, 4121157385u, +3519870450u, +3792633352u, +3017650322u, 1603459507u, 4225677666u, 376555451u, +473780127u, 2018786277u, 3299822439u, 1010254499u, +2383887565u, +3155009499u, +3108110655u, 2641738274u, 3684908622u, 1606463047u, +3311068174u, 52708046u, 754181455u, 1018079176u, +3915670272u, +3366999425u, +1012880204u, 1339439715u, 466437962u, 1402662350u, +2504046911u, 736323938u, 2037800124u, 1725908589u, +716341840u, +1750123474u, +3366342464u, 1743666195u, 2975303189u, 3821364027u, +3253707772u, 3635548377u, 3840413796u, 1955642085u, +1018315169u, +1258092848u, +2095540656u, 1076256607u, 117289557u, 1311658655u, +2118301000u, 68721550u, 2886814107u, 2712432819u, +4201862886u, +753807148u, +1940229047u, 731347296u, 1068901393u, 3873155894u, +2852787666u, 1973464853u, 79735652u, 3966380587u, +3245740712u, +2525773438u, +734938109u, 3045656416u, 3335746354u, 4099732691u, +1911896517u, 1697006473u, 1145487066u, 1605663299u, +3053606724u, +2386289465u, +3821211369u, 1006215345u, 1256304829u, 1053001668u, +1289194958u, 118761054u, 1853688730u, 2803418011u, +188650809u, +3763686458u, +1006829556u, 2961984133u, 3390525025u, 2061199893u, +141792681u, 2439893463u, 2652982650u, 1804942682u, +1546510005u, +1246961405u, +2407577046u, 565772575u, 3751844810u, 2943166103u, +3750052451u, 3022527280u, 25162928u, 397381043u, +1818337632u, +3447363730u, +3936437150u, 2569420703u, 2215592390u, 2171555672u, +3665571006u, 4021712412u, 2939158353u, 4057813172u, +1823237318u, +103999245u, +3251978010u, 3591914940u, 3582495283u, 2519035265u, +3905726135u, 3180393349u, 2743117123u, 55247368u, +3325286701u, +705195946u, +1857526853u, 1480518550u, 3809990433u, 1398189338u, +3126362926u, 3959531492u, 1503658285u, 1977847740u, +3043964489u, +2613086143u, +1518119282u, 4238434900u, 3905746486u, 3064949667u, +1028122931u, 3309119457u, 4071194920u, 3096098907u, +4137180520u, +494467959u, +1231408687u, 1691606157u, 1793452569u, 2722196118u, +3478603952u, 1059665738u, 2282032278u, 3990268388u, +1719514651u, +4248311578u, +3799146721u, 898026304u, 3367808954u, 4162472815u, +170495870u, 1308116609u, 3428285344u, 1714716475u, +395576794u, +4153638621u, +2999745812u, 3483315953u, 304980828u, 595337120u, +3486516729u, 2331563143u, 2583609459u, 1885928417u, +3834283777u, +979337825u, +932057378u, 3124081189u, 1930356777u, 3865887996u, +4178282217u, 4214219408u, 3669465884u, 1472413856u, +3356866587u, +1012769806u, +3043639963u, 996996396u, 207308216u, 982967331u, +2991319933u, 318066902u, 721489670u, 1249967713u, +749240921u, +591392325u, +2379365192u, 2250868849u, 2163259329u, 143191325u, +3778285606u, 982149096u, 3536906200u, 2244353244u, +1443862317u, +3161549210u, +2183127464u, 2015409516u, 547003700u, 2032484282u, +523677821u, 4275663308u, 3827205526u, 3903778273u, +2444530525u, +2543645801u, +1173958423u, 784740616u, 2878693675u, 3127696736u, +3832037316u, 3161002398u, 4084166400u, 4213346853u, +223390424u, +4273380883u, +2130315482u, 3429606032u, 3367732613u, 1912357694u, +422632590u, 1266957023u, 3437535648u, 736404240u, +2281709372u, +415859912u, +212948797u, 351612650u, 3920561440u, 112963586u, +2230727543u, 2851076612u, 1990662634u, 2264296857u, +3131463650u, +2704034623u, +3541637839u, 2954232792u, 533986918u, 4158757533u, +65174248u, 4232639593u, 865906667u, 1948225652u, +779656112u, +3873989249u, +2372984749u, 2346988193u, 1104345713u, 1165654138u, +4045762610u, 3588205178u, 461363991u, 1111215752u, +1389675192u, +2404325151u, +2152228101u, 3808973622u, 1901235912u, 3458690696u, +314513238u, 2539459143u, 2847998873u, 952026138u, +2325705328u, +407844712u, +3727960715u, 2996448351u, 2374336760u, 3138756390u, +2600015243u, 539980418u, 1876285352u, 1670330799u, +1709360377u, +2868531654u, +494777964u, 2773053597u, 599486162u, 3962209577u, +1871328846u, 2171933018u, 110279472u, 384074780u, +4147021936u, +2333589647u, +4251778066u, 40493468u, 3099342316u, 4108779767u, +2812424588u, 954542332u, 2040682331u, 2251152306u, +45915516u, +259525626u, +1045384743u, 4134656562u, 749389261u, 874399445u, +616549904u, 2200447504u, 436024539u, 78972290u, +3210485762u, +1907985531u, +3013721395u, 4214533685u, 4198804243u, 534879265u, +1517190881u, 3756787754u, 1152563554u, 1718750948u, +777737463u, +1402478860u, +1824562784u, 1879401449u, 3515818786u, 513165201u, +1423491227u, 2103067918u, 2291777410u, 1097943000u, +}; + +// Return false only if offset is -1 and a spot check of 3 hashes all yield 0. +bool Test(int offset, int len = 0) { +#undef Check +#undef IsAlive + +#define Check(x) do { \ + const uint32_t actual = (x), e = expected[index++]; \ + bool ok = actual == e; \ + if (!ok) { \ + cerr << "expected " << hex << e << " but got " << actual << endl; \ + ++errors; \ + } \ + assert(ok); \ +} while (0) + +#define IsAlive(x) do { alive += IsNonZero(x); } while (0) + + // After the following line is where the uses of "Check" and such will go. + static int index = 0; +if (offset == -1) { int alive = 0; IsAlive(farmhashcc::Hash32WithSeed(data, len++, SEED)); IsAlive(farmhashcc::Hash32(data, len++)); { uint128_t u = farmhashcc::Fingerprint128(data, len++); uint64_t h = Uint128Low64(u); IsAlive(h >> 32); IsAlive((h << 32) >> 32); h = Uint128High64(u); IsAlive(h >> 32); IsAlive((h << 32) >> 32); } len -= 3; return alive > 0; } +Check(farmhashcc::Hash32WithSeed(data + offset, len, SEED)); +Check(farmhashcc::Hash32(data + offset, len)); +{ uint128_t u = farmhashcc::Fingerprint128(data + offset, len); uint64_t h = Uint128Low64(u); Check(h >> 32); Check((h << 32) >> 32); h = Uint128High64(u); Check(h >> 32); Check((h << 32) >> 32); } +{ uint128_t u = farmhashcc::CityHash128WithSeed(data + offset, len, Uint128(SEED0, SEED1)); uint64_t h = Uint128Low64(u); Check(h >> 32); Check((h << 32) >> 32); h = Uint128High64(u); Check(h >> 32); Check((h << 32) >> 32); } + + return true; +#undef Check +#undef IsAlive +} + +int RunTest() { + Setup(); + int i = 0; + cout << "Running farmhashccTest"; + if (!Test(-1)) { + cout << "... Unavailable\n"; + return NoteErrors(); + } + // Good. The function is attempting to hash, so run the full test. + int errors_prior_to_test = errors; + for ( ; i < kTestSize - 1; i++) { + Test(i * i, i); + } + for ( ; i < kDataSize; i += i / 7) { + Test(0, i); + } + Test(0, kDataSize); + cout << (errors == errors_prior_to_test ? "... OK\n" : "... Failed\n"); + return NoteErrors(); +} + +#else + +// After the following line is where the code to print hash codes will go. +void Dump(int offset, int len) { +cout << farmhashcc::Hash32WithSeed(data + offset, len, SEED) << "u," << endl; +cout << farmhashcc::Hash32(data + offset, len) << "u," << endl; +{ uint128_t u = farmhashcc::Fingerprint128(data + offset, len); uint64_t h = Uint128Low64(u); cout << (h >> 32) << "u, " << ((h << 32) >> 32) << "u, "; h = Uint128High64(u); cout << (h >> 32) << "u, " << ((h << 32) >> 32) << "u," << endl; } +{ uint128_t u = farmhashcc::CityHash128WithSeed(data + offset, len, Uint128(SEED0, SEED1)); uint64_t h = Uint128Low64(u); cout << (h >> 32) << "u, " << ((h << 32) >> 32) << "u, "; h = Uint128High64(u); cout << (h >> 32) << "u, " << ((h << 32) >> 32) << "u," << endl; } +} + +#endif + +#undef SEED +#undef SEED1 +#undef SEED0 + +} // namespace farmhashccTest + +#if !TESTING +int main(int argc, char** argv) { + Setup(); + cout << "uint32_t expected[] = {\n"; + int i = 0; + for ( ; i < kTestSize - 1; i++) { + farmhashccTest::Dump(i * i, i); + } + for ( ; i < kDataSize; i += i / 7) { + farmhashccTest::Dump(0, i); + } + farmhashccTest::Dump(0, kDataSize); + cout << "};\n"; +} +#endif +#ifndef FARMHASH_SELF_TEST_GUARD +#define FARMHASH_SELF_TEST_GUARD +#include +#include +#include + +using std::cout; +using std::cerr; +using std::endl; +using std::hex; + +static const uint64_t kSeed0 = 1234567; +static const uint64_t kSeed1 = k0; +static const int kDataSize = 1 << 20; +static const int kTestSize = 300; +#define kSeed128 Uint128(kSeed0, kSeed1) + +static char data[kDataSize]; + +static int completed_self_tests = 0; +static int errors = 0; + +// Initialize data to pseudorandom values. +void Setup() { + if (completed_self_tests == 0) { + uint64_t a = 9; + uint64_t b = 777; + for (int i = 0; i < kDataSize; i++) { + a += b; + b += a; + a = (a ^ (a >> 41)) * k0; + b = (b ^ (b >> 41)) * k0 + i; + uint8_t u = b >> 37; + memcpy(data + i, &u, 1); // uint8_t -> char + } + } +} + +int NoteErrors() { +#define NUM_SELF_TESTS 9 + if (++completed_self_tests == NUM_SELF_TESTS) + std::exit(errors > 0); + return errors; +} + +template inline bool IsNonZero(T x) { + return x != 0; +} + +template <> inline bool IsNonZero(uint128_t x) { + return x != Uint128(0, 0); +} + +#endif // FARMHASH_SELF_TEST_GUARD + +namespace farmhashmkTest { + +uint32_t CreateSeed(int offset, int salt) { + uint32_t h = static_cast(salt & 0xffffffff); + h = h * c1; + h ^= (h >> 17); + h = h * c1; + h ^= (h >> 17); + h = h * c1; + h ^= (h >> 17); + h += static_cast(offset & 0xffffffff); + h = h * c1; + h ^= (h >> 17); + h = h * c1; + h ^= (h >> 17); + h = h * c1; + h ^= (h >> 17); + return h; +} + +#undef SEED +#undef SEED1 +#undef SEED0 +#define SEED CreateSeed(offset, -1) +#define SEED0 CreateSeed(offset, 0) +#define SEED1 CreateSeed(offset, 1) + +#undef TESTING +#define TESTING 1 +#if TESTING +uint32_t expected[] = { +4223616069u, +3696677242u, +4081014168u, +2576519988u, +2212771159u, +1112731063u, +1020067935u, +3955445564u, +1451961420u, +653440099u, +31917516u, +2957164615u, +2590087362u, +3879448744u, +176305566u, +2447367541u, +1359016305u, +3363804638u, +1117290165u, +1062549743u, +2437877004u, +1894455839u, +673206794u, +3486923651u, +3269862919u, +2303349487u, +1380660650u, +595525107u, +1525325287u, +2025609358u, +176408838u, +1592885012u, +864896482u, +2101378090u, +3489229104u, +2118965695u, +581644891u, +2718789079u, +631613207u, +4228658372u, +3867875546u, +3531368319u, +3804516756u, +3317755099u, +1619744564u, +2884717286u, +1088213445u, +2667691076u, +3727873235u, +2330406762u, +3616470388u, +967660719u, +4148162586u, +315219121u, +673084328u, +3047602355u, +1598963653u, +1267826661u, +2117362589u, +2861192253u, +1823625377u, +1380350078u, +1641748342u, +1176094482u, +269384321u, +2178982315u, +3480237248u, +2660755208u, +1850544433u, +3429699438u, +1262819303u, +640556464u, +2421125401u, +2188368608u, +2612932825u, +1474432581u, +173790449u, +2124882189u, +831272654u, +622960146u, +4238751051u, +3250317967u, +2120810248u, +1948231495u, +1389029321u, +2200398357u, +2134232963u, +2948072329u, +617717625u, +681164587u, +114859387u, +430545646u, +57239089u, +3163338012u, +3482496399u, +557662576u, +1102441413u, +2670159360u, +991116729u, +846014240u, +4233741566u, +1802317242u, +3129528802u, +1459456375u, +1305643039u, +3258671612u, +1578285833u, +868590079u, +1631034517u, +1695432937u, +561078856u, +1004115553u, +3086090507u, +3818348650u, +731596645u, +780926790u, +2544205955u, +158479164u, +3983514188u, +2004735250u, +3436218400u, +673684751u, +1463431419u, +2880490219u, +3223748024u, +2218318859u, +1474466194u, +2636437533u, +2206794961u, +140995728u, +1186394086u, +1805716888u, +1640037724u, +3942729099u, +1944727013u, +918951560u, +498666871u, +3486974657u, +2967205462u, +1167253804u, +1884281041u, +2866015002u, +4158319270u, +2627220079u, +3733319624u, +3317092271u, +438323662u, +3195868065u, +3426606709u, +360708338u, +1905491012u, +650004803u, +1351266252u, +3133279000u, +3722811115u, +2722412434u, +918432408u, +3678271248u, +269599647u, +621514057u, +3117077855u, +1545425390u, +2597567410u, +1221437820u, +3493254589u, +102787342u, +918861168u, +348795089u, +3439883229u, +2353641807u, +2209585469u, +4035884492u, +2686995435u, +1649888022u, +3852893848u, +3042700028u, +314103172u, +726977769u, +2489830276u, +2872753660u, +1316214989u, +1488801501u, +1811420390u, +639581627u, +2362837215u, +3634581834u, +3648576802u, +1257314182u, +762118371u, +4268447045u, +730167096u, +755561509u, +882614845u, +3696972894u, +228263661u, +1478636142u, +2767751651u, +1532617116u, +3838657661u, +1944359935u, +1401102137u, +3772933173u, +1050098254u, +1658079354u, +1846025728u, +2204244794u, +2017217424u, +1275162853u, +1429816745u, +2175565479u, +1716109139u, +1187506761u, +2434641075u, +2725597783u, +1795687662u, +1393312782u, +3511565397u, +627885430u, +4145733164u, +2519005353u, +231414775u, +1242015635u, +2760723497u, +2185540568u, +727314436u, +2358790354u, +1186393454u, +4234795645u, +350567813u, +866773875u, +3145590392u, +1158374055u, +3903123687u, +1862119793u, +2204587556u, +4266276976u, +4151548555u, +915250402u, +2874695320u, +2360311410u, +1099212769u, +1271542714u, +3473148363u, +1637325418u, +1807795989u, +2493819794u, +3800917924u, +4001205856u, +2582153621u, +3365872040u, +2890146216u, +2626363824u, +3133351295u, +4046827296u, +3053118771u, +4113026751u, +884356716u, +3828347401u, +10608262u, +830987972u, +1841080500u, +3202717763u, +3561778749u, +1906000052u, +3058284660u, +1432904514u, +2567431677u, +2550162530u, +665557986u, +936887821u, +2101205308u, +4253535847u, +1662043545u, +1253611611u, +2091370094u, +2635077370u, +2602176041u, +3624115809u, +748442714u, +2709749154u, +1023493343u, +860291012u, +3924715584u, +1536436740u, +2551145800u, +2391782865u, +1467705048u, +2583909796u, +3616666170u, +1162857372u, +4228631071u, +1510132376u, +2739165009u, +2656606142u, +3454996358u, +3155038853u, +1022087316u, +100044110u, +494208296u, +2746186477u, +4216782431u, +225448834u, +3728320521u, +335282866u, +3148194874u, +953503703u, +1293353960u, +202372387u, +1326119870u, +4045123735u, +3819994846u, +1629004186u, +1081099186u, +3591584153u, +1670825804u, +3404257979u, +3262192301u, +2572846095u, +3714992543u, +4264142572u, +529616678u, +2882154574u, +3006354178u, +3865969421u, +2007174907u, +308283107u, +2629833703u, +3159124075u, +1146492131u, +494104332u, +493149727u, +1342910585u, +521642387u, +2201695937u, +2517980959u, +2426821287u, +777374655u, +2228189792u, +4027055486u, +228976000u, +3842083468u, +1723920223u, +1192126094u, +787744493u, +2740368380u, +2284153001u, +2773829458u, +442000614u, +387830783u, +2169780670u, +2253144627u, +3532502484u, +1969684059u, +1165351416u, +3055056536u, +3582324253u, +231419363u, +770979865u, +3213983597u, +3690452836u, +935794639u, +3230602762u, +2841762457u, +407598927u, +1164479891u, +3721799696u, +354738136u, +1801566618u, +3206038542u, +2621379981u, +1943487262u, +3534745636u, +1074424589u, +1304517521u, +4133400969u, +2339317978u, +2135116860u, +4180643791u, +2415309340u, +1855926417u, +3418648630u, +1968113037u, +597304222u, +3668824865u, +3810008716u, +3014702569u, +3151212026u, +156057449u, +373134533u, +2068234004u, +191580563u, +3832754488u, +2924104199u, +2026044494u, +4065780435u, +122565840u, +4194985167u, +2744823717u, +2494098735u, +3753793370u, +1885739217u, +2488161225u, +3643797615u, +2653367310u, +2494061477u, +189968132u, +899646597u, +392100396u, +4012318310u, +3855777086u, +3566860954u, +2698574996u, +2414249905u, +1330623339u, +1263222732u, +1277741760u, +2194959402u, +1629656136u, +120494320u, +1072368005u, +1084245077u, +4011372748u, +1366613353u, +3108643228u, +3332219532u, +2114746095u, +3964007334u, +371687128u, +1084813876u, +126459896u, +4292782331u, +321283184u, +398168499u, +3604983506u, +560701543u, +2073961354u, +4240841868u, +4151211362u, +1338986875u, +4093476832u, +2269279497u, +3500846299u, +2510225147u, +598000444u, +1330391422u, +1432533385u, +4171226231u, +426821154u, +2932270996u, +3378981077u, +2217871549u, +1619647984u, +4051608043u, +3180237819u, +12919578u, +1375401767u, +371320427u, +2986640571u, +2336669859u, +3796464715u, +1892383284u, +306814912u, +2125823211u, +1863678891u, +3249703818u, +3840225752u, +281579900u, +264680257u, +4266359110u, +4182229890u, +2239659703u, +3627947372u, +2373929191u, +224082765u, +4053639058u, +1862360303u, +3187739624u, +3392706679u, +948039509u, +817505760u, +1215842393u, +3462222651u, +536021853u, +182346832u, +2731944883u, +2346674384u, +2640961678u, +3446695687u, +2271722179u, +1301069656u, +2803881468u, +2832614405u, +1691544398u, +698756814u, +3980620906u, +3565421410u, +754769376u, +4115923404u, +3909962218u, +2747614077u, +2888289845u, +1016920862u, +2790946178u, +3067070960u, +3173251481u, +1572132982u, +255048203u, +2996538818u, +3405398987u, +136106013u, +3581605228u, +4277437977u, +2147300534u, +3728426265u, +3483629996u, +1478452694u, +20756076u, +2774992067u, +432987927u, +1516771026u, +3511588664u, +2130994978u, +509385406u, +873090347u, +2163904107u, +4192239086u, +2532489989u, +1090772651u, +3910797408u, +3710882132u, +155010959u, +1369823531u, +1599664937u, +4035593587u, +1212746925u, +795822552u, +116689518u, +3674240941u, +1135576664u, +756750261u, +1027431362u, +390555140u, +2228460216u, +1506940482u, +3733857700u, +3048762971u, +2511703196u, +548609887u, +1607354252u, +659053982u, +259884450u, +1793130460u, +4083364495u, +3148555881u, +1764350138u, +2436485683u, +4031563025u, +3261860724u, +2475833430u, +2101726086u, +3191176464u, +2646658847u, +2127042126u, +771316100u, +2115922959u, +3208515045u, +2355437783u, +3621147793u, +1580163615u, +3211555675u, +3299188490u, +191613920u, +466733956u, +2939029038u, +1509152039u, +130591314u, +1892874677u, +1646908044u, +3452406523u, +3998376606u, +1199243832u, +2187108812u, +3189230066u, +4161151481u, +3371454980u, +3681788646u, +180842187u, +3685022399u, +3058749895u, +3250165163u, +2895367943u, +2627101723u, +771755098u, +1332921024u, +3638871848u, +514215135u, +3591227378u, +2300310870u, +3689533503u, +851607114u, +114330368u, +2709027386u, +1743034877u, +1013693860u, +288169008u, +3545190686u, +1052165084u, +3995862307u, +96902755u, +1097819851u, +2645431442u, +2184148618u, +2151206566u, +350979797u, +3467920900u, +421116779u, +1246252u, +4057835428u, +329324407u, +4104482417u, +844624570u, +3306265806u, +3787625025u, +4263241191u, +3251413927u, +2921204431u, +2931915325u, +992134330u, +3986338354u, +1327895216u, +1458363596u, +1480608532u, +728594368u, +3804366693u, +794404223u, +1643240863u, +793417255u, +4167916443u, +2683488959u, +3124925324u, +4184843652u, +3750971752u, +308509829u, +1054550805u, +2797511972u, +4043123412u, +1587158240u, +4050518606u, +3030062190u, +2589912753u, +603440067u, +937013191u, +1071662315u, +2100661456u, +2602005741u, +435516078u, +2260470147u, +1256268350u, +3612035u, +3368856141u, +151516099u, +3081868591u, +3363755681u, +2049963149u, +2885320434u, +84682005u, +2411758308u, +2695174275u, +3099904644u, +1787308684u, +1132379308u, +564634346u, +510236510u, +2804443681u, +3931864252u, +2064427949u, +1893979229u, +2916544974u, +1885887717u, +2978018250u, +494192125u, +2642662373u, +901112508u, +636035003u, +1658643797u, +172746975u, +517504890u, +3440019372u, +4144498044u, +1854755456u, +3672653905u, +4176892856u, +382159097u, +282871690u, +3629300472u, +2500754041u, +1677659759u, +1067175061u, +161654075u, +1672575536u, +346120493u, +2730229631u, +203466442u, +1244549529u, +199761971u, +2744895408u, +3195315331u, +2124618519u, +3261045496u, +985339699u, +3385585455u, +1545740710u, +3636652160u, +2167020081u, +1207897204u, +28752417u, +2895834146u, +3640845375u, +3750293073u, +548997850u, +4207814196u, +4183030708u, +2462810989u, +3929965401u, +}; + +// Return false only if offset is -1 and a spot check of 3 hashes all yield 0. +bool Test(int offset, int len = 0) { +#undef Check +#undef IsAlive + +#define Check(x) do { \ + const uint32_t actual = (x), e = expected[index++]; \ + bool ok = actual == e; \ + if (!ok) { \ + cerr << "expected " << hex << e << " but got " << actual << endl; \ + ++errors; \ + } \ + assert(ok); \ +} while (0) + +#define IsAlive(x) do { alive += IsNonZero(x); } while (0) + + // After the following line is where the uses of "Check" and such will go. + static int index = 0; +if (offset == -1) { int alive = 0; IsAlive(farmhashmk::Hash32WithSeed(data, len++, SEED)); IsAlive(farmhashmk::Hash32(data, len++)); IsAlive(farmhashmk::Hash32(data, len++)); len -= 3; return alive > 0; } +Check(farmhashmk::Hash32WithSeed(data + offset, len, SEED)); +Check(farmhashmk::Hash32(data + offset, len)); + + return true; +#undef Check +#undef IsAlive +} + +int RunTest() { + Setup(); + int i = 0; + cout << "Running farmhashmkTest"; + if (!Test(-1)) { + cout << "... Unavailable\n"; + return NoteErrors(); + } + // Good. The function is attempting to hash, so run the full test. + int errors_prior_to_test = errors; + for ( ; i < kTestSize - 1; i++) { + Test(i * i, i); + } + for ( ; i < kDataSize; i += i / 7) { + Test(0, i); + } + Test(0, kDataSize); + cout << (errors == errors_prior_to_test ? "... OK\n" : "... Failed\n"); + return NoteErrors(); +} + +#else + +// After the following line is where the code to print hash codes will go. +void Dump(int offset, int len) { +cout << farmhashmk::Hash32WithSeed(data + offset, len, SEED) << "u," << endl; +cout << farmhashmk::Hash32(data + offset, len) << "u," << endl; +} + +#endif + +#undef SEED +#undef SEED1 +#undef SEED0 + +} // namespace farmhashmkTest + +#if !TESTING +int main(int argc, char** argv) { + Setup(); + cout << "uint32_t expected[] = {\n"; + int i = 0; + for ( ; i < kTestSize - 1; i++) { + farmhashmkTest::Dump(i * i, i); + } + for ( ; i < kDataSize; i += i / 7) { + farmhashmkTest::Dump(0, i); + } + farmhashmkTest::Dump(0, kDataSize); + cout << "};\n"; +} +#endif +#ifndef FARMHASH_SELF_TEST_GUARD +#define FARMHASH_SELF_TEST_GUARD +#include +#include +#include + +using std::cout; +using std::cerr; +using std::endl; +using std::hex; + +static const uint64_t kSeed0 = 1234567; +static const uint64_t kSeed1 = k0; +static const int kDataSize = 1 << 20; +static const int kTestSize = 300; +#define kSeed128 Uint128(kSeed0, kSeed1) + +static char data[kDataSize]; + +static int completed_self_tests = 0; +static int errors = 0; + +// Initialize data to pseudorandom values. +void Setup() { + if (completed_self_tests == 0) { + uint64_t a = 9; + uint64_t b = 777; + for (int i = 0; i < kDataSize; i++) { + a += b; + b += a; + a = (a ^ (a >> 41)) * k0; + b = (b ^ (b >> 41)) * k0 + i; + uint8_t u = b >> 37; + memcpy(data + i, &u, 1); // uint8_t -> char + } + } +} + +int NoteErrors() { +#define NUM_SELF_TESTS 9 + if (++completed_self_tests == NUM_SELF_TESTS) + std::exit(errors > 0); + return errors; +} + +template inline bool IsNonZero(T x) { + return x != 0; +} + +template <> inline bool IsNonZero(uint128_t x) { + return x != Uint128(0, 0); +} + +#endif // FARMHASH_SELF_TEST_GUARD + +namespace farmhashnaTest { + +uint32_t CreateSeed(int offset, int salt) { + uint32_t h = static_cast(salt & 0xffffffff); + h = h * c1; + h ^= (h >> 17); + h = h * c1; + h ^= (h >> 17); + h = h * c1; + h ^= (h >> 17); + h += static_cast(offset & 0xffffffff); + h = h * c1; + h ^= (h >> 17); + h = h * c1; + h ^= (h >> 17); + h = h * c1; + h ^= (h >> 17); + return h; +} + +#undef SEED +#undef SEED1 +#undef SEED0 +#define SEED CreateSeed(offset, -1) +#define SEED0 CreateSeed(offset, 0) +#define SEED1 CreateSeed(offset, 1) + +#undef TESTING +#define TESTING 1 +#if TESTING +uint32_t expected[] = { +1140953930u, 861465670u, +3277735313u, 2681724312u, +2598464059u, 797982799u, +890626835u, 800175912u, +2603993599u, 921001710u, +1410420968u, 2134990486u, +3283896453u, 1867689945u, +2914424215u, 2244477846u, +255297188u, 2992121793u, +1110588164u, 4186314283u, +161451183u, 3943596029u, +4019337850u, 452431531u, +283198166u, 2741341286u, +3379021470u, 2557197665u, +299850021u, 2532580744u, +452473466u, 1706958772u, +1298374911u, 3099673830u, +2199864459u, 3696623795u, +236935126u, 2976578695u, +4055299123u, 3281581178u, +1053458494u, 1882212500u, +2305012065u, 2169731866u, +3456121707u, 275903667u, +458884671u, 3033004529u, +3058973506u, 2379411653u, +1898235244u, 1402319660u, +2700149065u, 2699376854u, +147814787u, 720739346u, +2433714046u, 4222949502u, +4220361840u, 1712034059u, +3425469811u, 3690733394u, +4148372108u, 1330324210u, +594028478u, 2921867846u, +1635026870u, 192883107u, +780716741u, 1728752234u, +3280331829u, 326029180u, +3969463346u, 1436364519u, +393215742u, 3349570000u, +3824583307u, 1612122221u, +2859809759u, 3808705738u, +1379537552u, 1646032583u, +2233466664u, 1432476832u, +4023053163u, 2650381482u, +2052294713u, 3552092450u, +1628777059u, 1499109081u, +3476440786u, 3829307897u, +2960536756u, 1554038301u, +1145519619u, 3190844552u, +2902102606u, 3600725550u, +237495366u, 540224401u, +65721842u, 489963606u, +1448662590u, 397635823u, +1596489240u, 1562872448u, +1790705123u, 2128624475u, +180854224u, 2604346966u, +1435705557u, 1262831810u, +155445229u, 1672724608u, +1669465176u, 1341975128u, +663607706u, 2077310004u, +3610042449u, 1911523866u, +1043692997u, 1454396064u, +2563776023u, 294527927u, +1099072299u, 1389770549u, +703505868u, 678706990u, +2952353448u, 2026137563u, +3603803785u, 629449419u, +1933894405u, 3043213226u, +226132789u, 2489287368u, +1552847036u, 645684964u, +3828089804u, 3632594520u, +187883449u, 230403464u, +3151491850u, 3272648435u, +3729087873u, 1303930448u, +2002861219u, 165370827u, +916494250u, 1230085527u, +3103338579u, 3064290191u, +3807265751u, 3628174014u, +231181488u, 851743255u, +2295806711u, 1781190011u, +2988893883u, 1554380634u, +1142264800u, 3667013118u, +1968445277u, 315203929u, +2638023604u, 2290487377u, +732137533u, 1909203251u, +440398219u, 1891630171u, +1380301172u, 1498556724u, +4072067757u, 4165088768u, +4204318635u, 441430649u, +3931792696u, 197618179u, +956300927u, 914413116u, +3010839769u, 2837339569u, +2148126371u, 1913303225u, +3074915312u, 3117299654u, +4139181436u, 2993479124u, +3178848746u, 1357272220u, +1438494951u, 507436733u, +667183474u, 2084369203u, +3854939912u, 1413396341u, +126024219u, 146044391u, +1016656857u, 3022024459u, +3254014218u, 429095991u, +165589978u, 1578546616u, +985653208u, 1718653828u, +623071693u, 366414107u, +249776086u, 1207522198u, +3047342438u, 2991127487u, +3120876698u, 1684583131u, +46987739u, 1157614300u, +863214540u, 1087193030u, +199124911u, 520792961u, +3614377032u, 586863115u, +3331828431u, 1013201099u, +1716848157u, 4033596884u, +1164298657u, 4140791139u, +1146169032u, 1434258493u, +3824360466u, 3242407770u, +3725511003u, 232064808u, +872586426u, 762243036u, +2736953692u, 816692935u, +512845449u, 3748861010u, +2266795890u, 3781899767u, +4290630595u, 517646945u, +22638523u, 648000590u, +959214578u, 558910384u, +1283799121u, 3047062993u, +1024246061u, 4027776454u, +3544509313u, 622325861u, +834785312u, 382936554u, +411505255u, 1973395102u, +1825135056u, 2725923798u, +580988377u, 2826990641u, +3474970689u, 1029055034u, +812546227u, 2506885666u, +2584372201u, 1758123094u, +589567754u, 325737734u, +345313518u, 2022370576u, +3886113119u, 3338548567u, +257578986u, 3698087965u, +1776047957u, 1771384107u, +3604937815u, 3198590202u, +2305332220u, 191910725u, +4232136669u, 427759438u, +4244322689u, 542201663u, +3315355162u, 2135941665u, +556609672u, 45845311u, +1175961330u, 3948351189u, +23075771u, 3252374102u, +1634635545u, 4151937410u, +713127376u, 1467786451u, +663013031u, 3444053918u, +2638154051u, 810082938u, +3077742128u, 1062268187u, +2115441882u, 4081398201u, +3735739145u, 2794294783u, +2335576331u, 2560479831u, +1379288194u, 4225182569u, +2442302747u, 3948961926u, +3958366652u, 3067277639u, +3667516477u, 1709989541u, +1516711748u, 2339636583u, +4188504038u, 59581167u, +2725013602u, 3639843023u, +2658147000u, 2643979752u, +3758739543u, 4189944477u, +2470483982u, 877580602u, +2995362413u, 118817200u, +3252925478u, 2062343506u, +3981838403u, 3762572073u, +1231633714u, 4168280671u, +2931588131u, 3284356565u, +1129162571u, 732225574u, +4173605289u, 1407328702u, +1677744031u, 3532596884u, +3232041815u, 1652884780u, +2256541290u, 3459463480u, +3740979556u, 259034107u, +2227121257u, 1426140634u, +3606709555u, 3424793077u, +315836068u, 3200749877u, +1386256573u, 24035717u, +2982018998u, 1811050648u, +234531934u, 1115203611u, +1598686658u, 3146815575u, +1603559457u, 323296368u, +2632963283u, 1778459926u, +739944537u, 579625482u, +3486330348u, 492621815u, +1231665285u, 2457048126u, +3903349120u, 389846205u, +3355404249u, 3275550588u, +1052645068u, 862072556u, +2834153464u, 1481069623u, +2657392572u, 4279236653u, +1688445808u, 701920051u, +3740748788u, 3388062747u, +1873358321u, 2152785640u, +883382081u, 1005815394u, +1020177209u, 734239551u, +2371453141u, 100326520u, +3488500412u, 1279682138u, +2610427744u, 49703572u, +3026361211u, 605900428u, +302392721u, 2509302188u, +1416453607u, 2815915291u, +1862819968u, 519710058u, +2450888314u, 4017598378u, +937074653u, 3035635454u, +1590230729u, 3268013438u, +2710029305u, 12886044u, +3711259084u, 2627383582u, +3895772404u, 648534979u, +260307902u, 855990313u, +3669691805u, 263366740u, +2938543471u, 414331688u, +3080542944u, 3405007814u, +3565059103u, 1190977418u, +390836981u, 1606450012u, +2649808239u, 2514169310u, +2747519432u, 4129538640u, +1721522849u, 492099164u, +792990594u, 3625507637u, +2271095827u, 2993032712u, +2302363854u, 4013112951u, +1111617969u, 2183845740u, +795918276u, 1116991810u, +3110898804u, 3963062126u, +2737064702u, 462795667u, +937372240u, 1343017609u, +1091041189u, 2790555455u, +277024217u, 25485284u, +1166522068u, 1623631848u, +241727183u, 2836158787u, +3112996740u, 573836428u, +2721658101u, 1937681565u, +4175169209u, 3190765433u, +1970000788u, 1668258120u, +114616703u, 954762543u, +199237753u, 4094644498u, +2522281978u, 732086117u, +1756889687u, 2936126607u, +2437031370u, 4103143808u, +3883389541u, 3171090854u, +2483004780u, 1927385370u, +2360538162u, 2740855009u, +4241185118u, 1492209542u, +1672737098u, 2148675559u, +1789864670u, 2434313103u, +2319172611u, 2760941207u, +2636210123u, 1338083267u, +1128080590u, 822806371u, +1199583556u, 314727461u, +1335160250u, 2084630531u, +1156261526u, 316766066u, +112090465u, 3129033323u, +2746885618u, 636616055u, +2582210744u, 1721064910u, +3468394263u, 470463518u, +2076016059u, 408721884u, +2121041886u, 378460278u, +1915948002u, 357324860u, +2301682622u, 2691859523u, +1869756364u, 2429314418u, +2193146527u, 1185564327u, +2614088922u, 1975527044u, +919067651u, 2855948894u, +3662539576u, 1943802836u, +3529473373u, 1490330107u, +366036094u, 3384241033u, +4276268604u, 448403661u, +4271796078u, 1910401882u, +3077107698u, 299427366u, +2035665349u, 3201262636u, +3738454258u, 2554452696u, +3588997135u, 3363895827u, +1267505995u, 1852004679u, +2237827073u, 2803250686u, +3468044908u, 2143572850u, +1728158656u, 1022551180u, +1996680960u, 839529273u, +2400647871u, 2201096054u, +3606433628u, 2597259793u, +3544595875u, 3909443124u, +819278607u, 3447346709u, +806136613u, 2711436388u, +3656063205u, 837475154u, +694525336u, 4070212073u, +4011303412u, 1068395209u, +438095290u, 484603494u, +2673730227u, 737767009u, +642310823u, 3914002299u, +308425103u, 268427550u, +1334387085u, 4069797497u, +4280783219u, 2914011058u, +4243643405u, 2849988118u, +2504230175u, 1817156623u, +2804200483u, 3406991497u, +2948254999u, 2102063419u, +1071272117u, 514889942u, +571972433u, 1246595599u, +1735616066u, 1539151988u, +1230831543u, 277987182u, +4269526481u, 991511607u, +95237878u, 2005032160u, +1291113144u, 626619670u, +3560835907u, 164940926u, +1433635018u, 116647396u, +3039097112u, 2868163232u, +1141645918u, 1764165478u, +881378302u, 2159170082u, +2953647681u, 1011320066u, +184856151u, 1723308975u, +336034862u, 2017579106u, +1476681709u, 147523618u, +3896252223u, 2264728166u, +944743644u, 1694443528u, +2690700128u, 1947321519u, +735478508u, 4058183171u, +260177668u, 505662155u, +2391691262u, 1920739747u, +3216960415u, 1898176786u, +3722741628u, 1511077569u, +449636564u, 983350414u, +2580237367u, 2055059789u, +1103819072u, 2089123665u, +3873755579u, 2718467458u, +3124338704u, 3204250304u, +2475035432u, 1120017626u, +3873758287u, 1982999824u, +2950794582u, 780634378u, +2842141483u, 4029205195u, +1656892865u, 3330993377u, +80890710u, 1953796601u, +3873078673u, 136118734u, +2317676604u, 4199091610u, +1864448181u, 3063437608u, +1699452298u, 1403506686u, +1513069466u, 2348491299u, +4273657745u, 4055855649u, +1805475756u, 2562064338u, +973124563u, 4197091358u, +172861513u, 2858726767u, +4271866024u, 3071338162u, +3590386266u, 2328277259u, +1096050703u, 1189614342u, +459509140u, 771592405u, +817999971u, 3740825152u, +520400189u, 1941874618u, +185232757u, 4032960199u, +3928245258u, 3527721294u, +1301118856u, 752188080u, +3512945009u, 308584855u, +2105373972u, 752872278u, +3823368815u, 3760952096u, +4250142168u, 2565680167u, +3646354146u, 1259957455u, +1085857127u, 3471066607u, +38924274u, 3770488806u, +1083869477u, 3312508103u, +71956383u, 3738784936u, +3099963860u, 1255084262u, +4286969992u, 3621849251u, +1190908967u, 1831557743u, +2363435042u, 54945052u, +4059585566u, 4023974274u, +1788578453u, 3442180039u, +2534883189u, 2432427547u, +3909757989u, 731996369u, +4168347425u, 1356028512u, +2741583197u, 1280920000u, +312887059u, 3259015297u, +3946278527u, 4135481831u, +1281043691u, 1121403845u, +3312292477u, 1819941269u, +1741932545u, 3293015483u, +2127558730u, 713121337u, +2635469238u, 486003418u, +4015067527u, 2976737859u, +2108187161u, 927011680u, +1970188338u, 4177613234u, +1799789551u, 2118505126u, +4134691985u, 1958963937u, +1929210029u, 2555835851u, +2768832862u, 910892050u, +2567532373u, 4075249328u, +86689814u, 3726640307u, +1392137718u, 1240000030u, +4104757832u, 3026358429u, +313797689u, 1435798509u, +3101500919u, 1241665335u, +3573008472u, 3615577014u, +3767659003u, 3134294021u, +4063565523u, 2296824134u, +1541946015u, 3087190425u, +2693152531u, 2199672572u, +2123763822u, 1034244398u, +857839960u, 2515339233u, +2228007483u, 1628096047u, +2116502287u, 2502657424u, +2809830736u, 460237542u, +450205998u, 3646921704u, +3818199357u, 1808504491u, +1950698961u, 2069753399u, +3657033172u, 3734547671u, +4067859590u, 3292597295u, +1106466069u, 356742959u, +2469567432u, 3495418823u, +183440071u, 3248055817u, +3662626864u, 1750561299u, +3926138664u, 4088592524u, +567122118u, 3810297651u, +992181339u, 3384018814u, +3272124369u, 3177596743u, +320086295u, 2316548367u, +100741310u, 451656820u, +4086604273u, 3759628395u, +2553391092u, 1745659881u, +3650357479u, 2390172694u, +330172533u, 767377322u, +526742034u, 4102497288u, +2088767754u, 164402616u, +2482632320u, 2352347393u, +1873658044u, 3861555476u, +2751052984u, 1767810825u, +20037241u, 545143220u, +2594532522u, 472304191u, +3441135892u, 3323383489u, +258785117u, 2977745165u, +2781737565u, 2963590112u, +2756998822u, 207428029u, +2581558559u, 3824717027u, +1258619503u, 3472047571u, +2648427775u, 2360400900u, +2393763818u, 2332399088u, +3932701729u, 884421165u, +1396468647u, 1377764574u, +4061795938u, 1559119087u, +3343596838u, 3604258095u, +1435134775u, 1099809675u, +908163739u, 1418405656u, +368446627u, 3741651161u, +3374512975u, 3542220540u, +3244772570u, 200009340u, +3198975081u, 2521038253u, +4081637863u, 337070226u, +3235259030u, 3897262827u, +736956644u, 641040550u, +644850146u, 1306761320u, +4219448634u, 193750500u, +3293278106u, 1383997679u, +1242645122u, 4109252858u, +450747727u, 3716617561u, +362725793u, 2252520167u, +3377483696u, 1788337208u, +8130777u, 3226734120u, +759239140u, 1012411364u, +1658628529u, 2911512007u, +1002580201u, 1681898320u, +3039016929u, 4294520281u, +367022558u, 3071359622u, +3205848570u, 152989999u, +3839042136u, 2357687350u, +4273132307u, 3898950547u, +1176841812u, 1314157485u, +75443951u, 1027027239u, +1858986613u, 2040551642u, +36574105u, 2603059541u, +3456147251u, 2137668425u, +4077477194u, 3565689036u, +491832241u, 363703593u, +2579177168u, 3589545214u, +265993036u, 1864569342u, +4149035573u, 3189253455u, +1072259310u, 3153745937u, +923017956u, 490608221u, +855846773u, 845706553u, +1018226240u, 1604548872u, +3833372385u, 3287246572u, +2757959551u, 2452872151u, +1553870564u, 1713154780u, +2649450292u, 500120236u, +84251717u, 661869670u, +1444911517u, 2489716881u, +2810524030u, 1561519055u, +3884088359u, 2509890699u, +4247155916u, 1005636939u, +3224066062u, 2774151984u, +2035978240u, 2514910366u, +1478837908u, 3144450144u, +2107011431u, 96459446u, +3587732908u, 2389230590u, +3287635953u, 250533792u, +1235983679u, 4237425634u, +3704645833u, 3882376657u, +2976369049u, 1187061987u, +276949224u, 4100839753u, +1698347543u, 1629662314u, +1556151829u, 3784939568u, +427484362u, 4246879223u, +3155311770u, 4285163791u, +1693376813u, 124492786u, +1858777639u, 3476334357u, +1941442701u, 1121980173u, +3485932087u, 820852908u, +358032121u, 2511026735u, +1873607283u, 2556067450u, +2248275536u, 1528632094u, +1535473864u, 556796152u, +1499201704u, 1472623890u, +1526518503u, 3692729434u, +1476438092u, 2913077464u, +335109599u, 2167614601u, +4121131078u, 3158127917u, +3051522276u, 4046477658u, +2857717851u, 1863977403u, +1341023343u, 692059110u, +1802040304u, 990407433u, +3285847572u, 319814144u, +561105582u, 1540183799u, +4052924496u, 2926590471u, +2244539806u, 439121871u, +3317903224u, 3178387550u, +4265214507u, 82077489u, +1978918971u, 4279668976u, +128732476u, 2853224222u, +464407878u, 4190838199u, +997819001u, 3250520802u, +2330081301u, 4095846095u, +733509243u, 1583801700u, +722314527u, 3552883023u, +1403784280u, 432327540u, +1877837196u, 3912423882u, +505219998u, 696031431u, +908238873u, 4189387259u, +8759461u, 2540185277u, +3385159748u, 381355877u, +2519951681u, 1679786240u, +2019419351u, 4051584612u, +1933923923u, 3768201861u, +1670133081u, 3454981037u, +700836153u, 1675560450u, +371560700u, 338262316u, +847351840u, 2222395828u, +3130433948u, 405251683u, +3037574880u, 184098830u, +453340528u, 1385561439u, +2224044848u, 4071581802u, +1431235296u, 5570097u, +570114376u, 2287305551u, +2272418128u, 803575837u, +3943113491u, 414959787u, +708083137u, 2452657767u, +4019147902u, 3841480082u, +3791794715u, 2965956183u, +2763690963u, 2350937598u, +3424361375u, 779434428u, +1274947212u, 686105485u, +3426668051u, 3692865672u, +3057021940u, 2285701422u, +349809124u, 1379278508u, +3623750518u, 215970497u, +1783152480u, 823305654u, +216118434u, 1787189830u, +3692048450u, 2272612521u, +3032187389u, 4159715581u, +1388133148u, 1611772864u, +2544383526u, 552925303u, +3420960112u, 3198900547u, +3503230228u, 2603352423u, +2318375898u, 4064071435u, +3006227299u, 4194096960u, +1283392422u, 1510460996u, +174272138u, 3671038966u, +1775955687u, 1719108984u, +1763892006u, 1385029063u, +4083790740u, 406757708u, +684087286u, 531310503u, +3329923157u, 3492083607u, +1059031410u, 3037314475u, +3105682208u, 3382290593u, +2292208503u, 426380557u, +97373678u, 3842309471u, +777173623u, 3241407531u, +303065016u, 1477104583u, +4234905200u, 2512514774u, +2649684057u, 1397502982u, +1802596032u, 3973022223u, +2543566442u, 3139578968u, +3193669211u, 811750340u, +4013496209u, 567361887u, +4169410406u, 3622282782u, +3403136990u, 2540585554u, +895210040u, 3862229802u, +1145435213u, 4146963980u, +784952939u, 943914610u, +573034522u, 464420660u, +2356867109u, 3054347639u, +3985088434u, 1911188923u, +583391304u, 176468511u, +2990150068u, 2338031599u, +519948041u, 3181425568u, +496106033u, 4110294665u, +2736756930u, 1196757691u, +1089679033u, 240953857u, +3399092928u, 4040779538u, +2843673626u, 240495962u, +3017658263u, 3828377737u, +4243717901u, 2448373688u, +2759616657u, 2246245780u, +308018483u, 4262383425u, +2731780771u, 328023017u, +2884443148u, 841480070u, +3188015819u, 4051263539u, +2298178908u, 2944209234u, +1372958390u, 4164532914u, +4074952232u, 1683612329u, +2155036654u, 1872815858u, +2041174279u, 2368092311u, +206775997u, 2283918569u, +645945606u, 115406202u, +4206471368u, 3923500892u, +2217060665u, 350160869u, +706531239u, 2824302286u, +509981657u, 1469342315u, +140980u, 1891558063u, +164887091u, 3094962711u, +3437115622u, 13327420u, +422986366u, 330624974u, +3630863408u, 2425505046u, +824008515u, 3543885677u, +918718096u, 376390582u, +3224043675u, 3724791476u, +1837192976u, 2968738516u, +3424344721u, 3187805406u, +1550978788u, 1743089918u, +4251270061u, 645016762u, +3855037968u, 1928519266u, +1373803416u, 2289007286u, +1889218686u, 1610271373u, +3059200728u, 2108753646u, +582042641u, 812347242u, +3188172418u, 191994904u, +1343511943u, 2247006571u, +463291708u, 2697254095u, +1534175504u, 1106275740u, +622521957u, 917121602u, +4095777215u, 3955972648u, +3852234638u, 2845309942u, +3299763344u, 2864033668u, +2554947496u, 799569078u, +2551629074u, 1102873346u, +2661022773u, 2006922227u, +2900438444u, 1448194126u, +1321567432u, 1983773590u, +1237256330u, 3449066284u, +1691553115u, 3274671549u, +4271625619u, 2741371614u, +3285899651u, 786322314u, +1586632825u, 564385522u, +2530557509u, 2974240289u, +1244759631u, 3263135197u, +3592389776u, 3570296884u, +2749873561u, 521432811u, +987586766u, 3206261120u, +1327840078u, 4078716491u, +1753812954u, 976892272u, +1827135136u, 1781944746u, +1328622957u, 1015377974u, +3439601008u, 2209584557u, +2482286699u, 1109175923u, +874877499u, 2036083451u, +483570344u, 1091877599u, +4190721328u, 1129462471u, +640035849u, 1867372700u, +920761165u, 3273688770u, +1623777358u, 3389003793u, +3241132743u, 2734783008u, +696674661u, 2502161880u, +1646071378u, 1164309901u, +350411888u, 1978005963u, +2253937037u, 7371540u, +989577914u, 3626554867u, +3214796883u, 531343826u, +398899695u, 1145247203u, +1516846461u, 3656006011u, +529303412u, 3318455811u, +3062828129u, 1696355359u, +3698796465u, 3155218919u, +1457595996u, 3191404246u, +1395609912u, 2917345728u, +1237411891u, 1854985978u, +1091884675u, 3504488111u, +3109924189u, 1628881950u, +3939149151u, 878608872u, +778235395u, 1052990614u, +903730231u, 2069566979u, +2437686324u, 3163786257u, +2257884264u, 2123173186u, +939764916u, 2933010098u, +1235300371u, 1256485167u, +1950274665u, 2180372319u, +2648400302u, 122035049u, +1883344352u, 2083771672u, +3712110541u, 321199441u, +1896357377u, 508560958u, +3066325351u, 2770847216u, +3177982504u, 296902736u, +1486926688u, 456842861u, +601221482u, 3992583643u, +2794121515u, 1533934172u, +1706465470u, 4281971893u, +2557027816u, 900741486u, +227175484u, 550595824u, +690918144u, 2825943628u, +90375300u, 300318232u, +1985329734u, 1440763373u, +3670603707u, 2533900859u, +3253901179u, 542270815u, +3677388841u, 307706478u, +2570910669u, 3320103693u, +1273768482u, 1216399252u, +1652924805u, 1043647584u, +1120323676u, 639941430u, +325675502u, 3652676161u, +4241680335u, 1545838362u, +1991398008u, 4100211814u, +1097584090u, 3262252593u, +2254324292u, 1765019121u, +4060211241u, 2315856188u, +3704419305u, 411263051u, +238929055u, 3540688404u, +3094544537u, 3250435765u, +3460621305u, 1967599860u, +2016157366u, 847389916u, +1659615591u, 4020453639u, +901109753u, 2682611693u, +1661364280u, 177155177u, +3210561911u, 3802058181u, +797089608u, 3286110054u, +2110358240u, 1353279028u, +2479975820u, 471725410u, +2219863904u, 3623364733u, +3167128228u, 1052188336u, +3656587111u, 721788662u, +3061255808u, 1615375832u, +924941453u, 2547780700u, +3328169224u, 1310964134u, +2701956286u, 4145497671u, +1421461094u, 1221397398u, +1589183618u, 1492533854u, +449740816u, 2686506989u, +3035198924u, 1682886232u, +2529760244u, 3342031659u, +1235084019u, 2151665147u, +2315686577u, 3282027660u, +1140138691u, 2754346599u, +2091754612u, 1178454681u, +4226896579u, 2942520471u, +2122168506u, 3751680858u, +3213794286u, 2601416506u, +4142747914u, 3951404257u, +4243249649u, 748595836u, +4004834921u, 238887261u, +1927321047u, 2217148444u, +205977665u, 1885975275u, +186020771u, 2367569534u, +2941662631u, 2608559272u, +3342096731u, 741809437u, +1962659444u, 3539886328u, +3036596491u, 2282550094u, +2366462727u, 2748286642u, +2144472852u, 1390394371u, +1257385924u, 2205425874u, +2119055686u, 46865323u, +3597555910u, 3188438773u, +2372320753u, 3641116924u, +3116286108u, 2680722658u, +3371014971u, 2058751609u, +2966943726u, 2345078707u, +2330535244u, 4013841927u, +1169588594u, 857915866u, +1875260989u, 3175831309u, +3193475664u, 1955181430u, +923161569u, 4068653043u, +776445899u, 954196929u, +61509556u, 4248237857u, +3808667664u, 581227317u, +2893240187u, 4159497403u, +4212264930u, 3973886195u, +2077539039u, 851579036u, +2957587591u, 772351886u, +1173659554u, 946748363u, +2794103714u, 2094375930u, +4234750213u, 3671645488u, +2614250782u, 2620465358u, +3122317317u, 2365436865u, +3393973390u, 523513960u, +3645735309u, 2766686992u, +2023960931u, 2312244996u, +1875932218u, 3253711056u, +3622416881u, 3274929205u, +612094988u, 1555465129u, +2114270406u, 3553762793u, +1832633644u, 1087551556u, +3306195841u, 1702313921u, +3675066046u, 1735998785u, +1690923980u, 1482649756u, +1171351291u, 2043136409u, +1962596992u, 461214626u, +3278253346u, 1392428048u, +3744621107u, 1028502697u, +3991171462u, 1014064003u, +3642345425u, 3186995039u, +6114625u, 3359104346u, +414856965u, 2814387514u, +3583605071u, 2497896367u, +1024572712u, 1927582962u, +2892797583u, 845302635u, +328548052u, 1523379748u, +3392622118u, 1347167673u, +1012316581u, 37767602u, +2647726017u, 1070326065u, +2075035198u, 4202817168u, +2502924707u, 2612406822u, +2187115553u, 1180137213u, +701024148u, 1481965992u, +3223787553u, 2083541843u, +203230202u, 3876887380u, +1334816273u, 2870251538u, +2186205850u, 3985213979u, +333533378u, 806507642u, +1010064531u, 713520765u, +3084131515u, 2637421459u, +1703168933u, 1517562266u, +4089081247u, 3231042924u, +3079916123u, 3154574447u, +2253948262u, 1725190035u, +2452539325u, 1343734533u, +213706059u, 2519409656u, +108055211u, 2916327746u, +587001593u, 1917607088u, +4202913084u, 926304016u, +469255411u, 4042080256u, +3498936874u, 246692543u, +495780578u, 438717281u, +2259272650u, 4011324645u, +2836854664u, 2317249321u, +946828752u, 1280403658u, +1905648354u, 2034241661u, +774652981u, 1285694082u, +2200307766u, 2158671727u, +1135162148u, 232040752u, +397012087u, 1717527689u, +1720414106u, 918797022u, +2580119304u, 3568069742u, +2904461070u, 3893453420u, +973817938u, 667499332u, +3785870412u, 2088861715u, +1565179401u, 600903026u, +591806775u, 3512242245u, +997964515u, 2339605347u, +1134342772u, 3234226304u, +4084179455u, 302315791u, +2445626811u, 2590372496u, +345572299u, 2274770442u, +3600587867u, 3706939009u, +1430507980u, 2656330434u, +1079209397u, 2122849632u, +1423705223u, 3826321888u, +3683385276u, 1057038163u, +1242840526u, 3987000643u, +2398253089u, 1538190921u, +1295898647u, 3570196893u, +3065138774u, 3111336863u, +2524949549u, 4203895425u, +3025864372u, 968800353u, +1023721001u, 3763083325u, +526350786u, 635552097u, +2308118370u, 2166472723u, +2196937373u, 2643841788u, +3040011470u, 4010301879u, +2782379560u, 3474682856u, +4201389782u, 4223278891u, +1457302296u, 2251842132u, +1090062008u, 3188219189u, +292733931u, 1424229089u, +1590782640u, 1365212370u, +3975957073u, 3982969588u, +2927147928u, 1048291071u, +2766680094u, 884908196u, +35237839u, 2221180633u, +2490333812u, 4098360768u, +4029081103u, 3490831871u, +2392516272u, 3455379186u, +3948800722u, 335456628u, +2105117968u, 4181629008u, +1044201772u, 3335754111u, +540133451u, 3313113759u, +3786107905u, 2627207327u, +3540337875u, 3473113388u, +3430536378u, 2514123129u, +2124531276u, 3872633376u, +3272957388u, 3501994650u, +2418881542u, 487365389u, +3877672368u, 1512866656u, +3486531087u, 2102955203u, +1136054817u, 3004241477u, +1549075351u, 1302002008u, +3936430045u, 2258587644u, +4109233936u, 3679809321u, +3467083076u, 2484463221u, +1594979755u, 529218470u, +3527024461u, 1147434678u, +106799023u, 1823161970u, +1704656738u, 1675883700u, +3308746763u, 1875093248u, +1352868568u, 1898561846u, +2508994984u, 3177750780u, +4217929592u, 400784472u, +80090315u, 3564414786u, +3841585648u, 3379293868u, +160353261u, 2413172925u, +2378499279u, 673436726u, +1505702418u, 1330977363u, +1853298225u, 3201741245u, +2135714208u, 4069554166u, +3715612384u, 3692488887u, +3680311316u, 4274382900u, +914186796u, 2264886523u, +3869634032u, 1254199592u, +1131020455u, 194781179u, +429923922u, 2763792336u, +2052895198u, 3997373194u, +3440090658u, 2165746386u, +1575500242u, 3463310191u, +2064974716u, 3779513671u, +3106421434u, 880320527u, +3281914119u, 286569042u, +3909096631u, 122359727u, +1429837716u, 252230074u, +4111461225u, 762273136u, +93658514u, 2766407143u, +3623657004u, 3869801679u, +3925695921u, 2390397316u, +2499025338u, 2741806539u, +2507199021u, 1659221866u, +361292116u, 4048761557u, +3797133396u, 1517903247u, +3121647246u, 3884308578u, +1697201500u, 1558800262u, +4150812360u, 3161302278u, +2610217849u, 641564641u, +183814518u, 2075245419u, +611996508u, 2223461433u, +329123979u, 121860586u, +860985829u, 1137889144u, +4018949439u, 2904348960u, +947795261u, 1992594155u, +4255427501u, 2281583851u, +2892637604u, 1478186924u, +3050771207u, 2767035539u, +373510582u, 1963520320u, +3763848370u, 3756817798u, +627269409u, 1806905031u, +1814444610u, 3646665053u, +1822693920u, 278515794u, +584050483u, 4142579188u, +2149745808u, 3193071606u, +1179706341u, 2693495182u, +3259749808u, 644172091u, +880509048u, 3340630542u, +3365160815u, 2384445068u, +3053081915u, 2840648309u, +1986990122u, 1084703471u, +2370410550u, 1627743573u, +2244943480u, 4057483496u, +2611595995u, 2470013639u, +4024732359u, 3987190386u, +873421687u, 2447660175u, +3226583022u, 767655877u, +2528024413u, 1962070688u, +1233635843u, 2163464207u, +659054446u, 854207134u, +258410943u, 4197831420u, +2515400215u, 3100476924u, +1961549594u, 2219491151u, +3997658851u, 163850514u, +470325051u, 2598261204u, +3052145580u, 59836528u, +1376188597u, 966733415u, +850667549u, 3622479237u, +1083731990u, 1525777459u, +4005126532u, 1428155540u, +2781907007u, 943739431u, +1493961005u, 2839096988u, +2000057832u, 1941829603u, +1901484772u, 939810041u, +3377407371u, 3090115837u, +3310840540u, 2068409688u, +3261383939u, 2212130277u, +2594774045u, 2912652418u, +4179816101u, 3534504531u, +3349254805u, 2796552902u, +1385421283u, 4259908631u, +3714780837u, 3070073945u, +3372846298u, 3835884044u, +3047965714u, 3009018735u, +744091167u, 1861124263u, +2764936304u, 1338171648u, +4222019554u, 1395200692u, +1371426007u, 3338031581u, +2525665319u, 4196233786u, +2332743921u, 1474702008u, +2274266301u, 4255175517u, +2290169528u, 1793910997u, +2188254024u, 354202001u, +3864458796u, 4280290498u, +1554419340u, 1733094688u, +2010552302u, 1561807039u, +664313606u, 2548990879u, +1084699349u, 3233936866u, +973895284u, 2386881969u, +1831995860u, 2961465052u, +1428704144u, 3269904970u, +231648253u, 2602483763u, +4125013173u, 3319187387u, +3347011944u, 1892898231u, +4019114049u, 868879116u, +4085937045u, 2378411019u, +1072588531u, 3547435717u, +2208070766u, 1069899078u, +3142980597u, 2337088907u, +1593338562u, 919414554u, +688077849u, 3625708135u, +1472447348u, 1947711896u, +3953006207u, 877438080u, +845995820u, 3150361443u, +3053496713u, 2484577841u, +224271045u, 2914958001u, +2682612949u, 806655563u, +2436224507u, 1907729235u, +2920583824u, 1251814062u, +2070814520u, 4034325578u, +497847539u, 2714317144u, +385182008u, 640855184u, +1327075087u, 1062468773u, +1757405994u, 1374270191u, +4263183176u, 3041193150u, +1037871524u, 3633173991u, +4231821821u, 2830131945u, +3505072908u, 2830570613u, +4195208715u, 575398021u, +3992840257u, 3691788221u, +1949847968u, 2999344380u, +3183782163u, 3723754342u, +759716128u, 3284107364u, +1714496583u, 15918244u, +820509475u, 2553936299u, +2201876606u, 4237151697u, +2605688266u, 3253705097u, +1008333207u, 712158730u, +1722280252u, 1933868287u, +4152736859u, 2097020806u, +584426382u, 2836501956u, +2522777566u, 1996172430u, +2122199776u, 1069285218u, +1474209360u, 690831894u, +107482532u, 3695525410u, +670591796u, 768977505u, +2412057331u, 3647886687u, +3110327607u, 1072658422u, +379861934u, 1557579480u, +4124127129u, 2271365865u, +3880613089u, 739218494u, +547346027u, 388559045u, +3147335977u, 176230425u, +3094853730u, 2554321205u, +1495176194u, 4093461535u, +3521297827u, 4108148413u, +1913727929u, 1177947623u, +1911655402u, 1053371241u, +3265708874u, 1266515850u, +1045540427u, 3194420196u, +3717104621u, 1144474110u, +1464392345u, 52070157u, +4144237690u, 3350490823u, +4166253320u, 2747410691u, +}; + +// Return false only if offset is -1 and a spot check of 3 hashes all yield 0. +bool Test(int offset, int len = 0) { +#undef Check +#undef IsAlive + +#define Check(x) do { \ + const uint32_t actual = (x), e = expected[index++]; \ + bool ok = actual == e; \ + if (!ok) { \ + cerr << "expected " << hex << e << " but got " << actual << endl; \ + ++errors; \ + } \ + assert(ok); \ +} while (0) + +#define IsAlive(x) do { alive += IsNonZero(x); } while (0) + + // After the following line is where the uses of "Check" and such will go. + static int index = 0; +if (offset == -1) { int alive = 0; { uint64_t h = farmhashna::Hash64WithSeeds(data, len++, SEED0, SEED1); IsAlive(h >> 32); IsAlive((h << 32) >> 32); } { uint64_t h = farmhashna::Hash64WithSeed(data, len++, SEED); IsAlive(h >> 32); IsAlive((h << 32) >> 32); } { uint64_t h = farmhashna::Hash64(data, len++); IsAlive(h >> 32); IsAlive((h << 32) >> 32); } len -= 3; return alive > 0; } +{ uint64_t h = farmhashna::Hash64WithSeeds(data + offset, len, SEED0, SEED1); Check(h >> 32); Check((h << 32) >> 32); } +{ uint64_t h = farmhashna::Hash64WithSeed(data + offset, len, SEED); Check(h >> 32); Check((h << 32) >> 32); } +{ uint64_t h = farmhashna::Hash64(data + offset, len); Check(h >> 32); Check((h << 32) >> 32); } + + return true; +#undef Check +#undef IsAlive +} + +int RunTest() { + Setup(); + int i = 0; + cout << "Running farmhashnaTest"; + if (!Test(-1)) { + cout << "... Unavailable\n"; + return NoteErrors(); + } + // Good. The function is attempting to hash, so run the full test. + int errors_prior_to_test = errors; + for ( ; i < kTestSize - 1; i++) { + Test(i * i, i); + } + for ( ; i < kDataSize; i += i / 7) { + Test(0, i); + } + Test(0, kDataSize); + cout << (errors == errors_prior_to_test ? "... OK\n" : "... Failed\n"); + return NoteErrors(); +} + +#else + +// After the following line is where the code to print hash codes will go. +void Dump(int offset, int len) { +{ uint64_t h = farmhashna::Hash64WithSeeds(data + offset, len, SEED0, SEED1); cout << (h >> 32) << "u, " << ((h << 32) >> 32) << "u," << endl; } +{ uint64_t h = farmhashna::Hash64WithSeed(data + offset, len, SEED); cout << (h >> 32) << "u, " << ((h << 32) >> 32) << "u," << endl; } +{ uint64_t h = farmhashna::Hash64(data + offset, len); cout << (h >> 32) << "u, " << ((h << 32) >> 32) << "u," << endl; } +} + +#endif + +#undef SEED +#undef SEED1 +#undef SEED0 + +} // namespace farmhashnaTest + +#if !TESTING +int main(int argc, char** argv) { + Setup(); + cout << "uint32_t expected[] = {\n"; + int i = 0; + for ( ; i < kTestSize - 1; i++) { + farmhashnaTest::Dump(i * i, i); + } + for ( ; i < kDataSize; i += i / 7) { + farmhashnaTest::Dump(0, i); + } + farmhashnaTest::Dump(0, kDataSize); + cout << "};\n"; +} +#endif +#ifndef FARMHASH_SELF_TEST_GUARD +#define FARMHASH_SELF_TEST_GUARD +#include +#include +#include + +using std::cout; +using std::cerr; +using std::endl; +using std::hex; + +static const uint64_t kSeed0 = 1234567; +static const uint64_t kSeed1 = k0; +static const int kDataSize = 1 << 20; +static const int kTestSize = 300; +#define kSeed128 Uint128(kSeed0, kSeed1) + +static char data[kDataSize]; + +static int completed_self_tests = 0; +static int errors = 0; + +// Initialize data to pseudorandom values. +void Setup() { + if (completed_self_tests == 0) { + uint64_t a = 9; + uint64_t b = 777; + for (int i = 0; i < kDataSize; i++) { + a += b; + b += a; + a = (a ^ (a >> 41)) * k0; + b = (b ^ (b >> 41)) * k0 + i; + uint8_t u = b >> 37; + memcpy(data + i, &u, 1); // uint8_t -> char + } + } +} + +int NoteErrors() { +#define NUM_SELF_TESTS 9 + if (++completed_self_tests == NUM_SELF_TESTS) + std::exit(errors > 0); + return errors; +} + +template inline bool IsNonZero(T x) { + return x != 0; +} + +template <> inline bool IsNonZero(uint128_t x) { + return x != Uint128(0, 0); +} + +#endif // FARMHASH_SELF_TEST_GUARD + +namespace farmhashntTest { + +uint32_t CreateSeed(int offset, int salt) { + uint32_t h = static_cast(salt & 0xffffffff); + h = h * c1; + h ^= (h >> 17); + h = h * c1; + h ^= (h >> 17); + h = h * c1; + h ^= (h >> 17); + h += static_cast(offset & 0xffffffff); + h = h * c1; + h ^= (h >> 17); + h = h * c1; + h ^= (h >> 17); + h = h * c1; + h ^= (h >> 17); + return h; +} + +#undef SEED +#undef SEED1 +#undef SEED0 +#define SEED CreateSeed(offset, -1) +#define SEED0 CreateSeed(offset, 0) +#define SEED1 CreateSeed(offset, 1) + +#undef TESTING +#define TESTING 1 +#if TESTING +uint32_t expected[] = { +2681724312u, +797982799u, +921001710u, +2134990486u, +2244477846u, +2992121793u, +3943596029u, +452431531u, +2557197665u, +2532580744u, +3099673830u, +3696623795u, +3281581178u, +1882212500u, +275903667u, +3033004529u, +1402319660u, +2699376854u, +4222949502u, +1712034059u, +1330324210u, +2921867846u, +1728752234u, +326029180u, +3349570000u, +1612122221u, +1646032583u, +1432476832u, +3552092450u, +1499109081u, +1554038301u, +3190844552u, +540224401u, +489963606u, +1562872448u, +2128624475u, +1262831810u, +1672724608u, +2077310004u, +1911523866u, +294527927u, +1389770549u, +2026137563u, +629449419u, +2489287368u, +645684964u, +230403464u, +3272648435u, +165370827u, +1230085527u, +3628174014u, +851743255u, +1554380634u, +3667013118u, +2290487377u, +1909203251u, +1498556724u, +4165088768u, +197618179u, +914413116u, +1913303225u, +3117299654u, +1357272220u, +507436733u, +1413396341u, +146044391u, +429095991u, +3056862311u, +366414107u, +2293458109u, +1684583131u, +1170404994u, +520792961u, +1577421232u, +4033596884u, +4229339322u, +3242407770u, +2649785113u, +816692935u, +3555213933u, +517646945u, +2180594090u, +3047062993u, +2391606125u, +382936554u, +788479970u, +2826990641u, +3167748333u, +1758123094u, +389974094u, +3338548567u, +2583576230u, +3198590202u, +4155628142u, +542201663u, +2856634168u, +3948351189u, +4194218315u, +1467786451u, +2743592929u, +1062268187u, +3810665822u, +2560479831u, +997658837u, +3067277639u, +1211737169u, +59581167u, +1389679610u, +4189944477u, +100876854u, +2062343506u, +3088828656u, +3284356565u, +3130054947u, +3532596884u, +3887208531u, +259034107u, +3233195759u, +3200749877u, +760633989u, +1115203611u, +1516407838u, +1778459926u, +2146672889u, +2457048126u, +2217471853u, +862072556u, +3745267835u, +701920051u, +581695350u, +1410111809u, +3326135446u, +2187968410u, +4267859263u, +479241367u, +2868987960u, +704325635u, +1418509533u, +735688735u, +3283299459u, +813690332u, +1439630796u, +3195309868u, +1616408198u, +3254795114u, +2799925823u, +3929484338u, +1798536177u, +4205965408u, +1499475160u, +4247675634u, +3779953975u, +785893184u, +2778575413u, +1160134629u, +823113169u, +4116162021u, +4167766971u, +2487440590u, +4004655503u, +4044418876u, +1462554406u, +2011102035u, +4265993528u, +576405853u, +4038839101u, +2425317635u, +1401013391u, +3062418115u, +3167030094u, +2602636307u, +4264167741u, +4017058800u, +1029665228u, +4036354071u, +2670703363u, +688472265u, +1054670286u, +338058159u, +1539305024u, +146827036u, +4060134777u, +2502815838u, +1603444633u, +2448966429u, +3891353218u, +1082330589u, +201837927u, +2848283092u, +883849006u, +1982110346u, +541496720u, +133643215u, +3847827123u, +4015671361u, +2849988118u, +3452457457u, +2102063419u, +3281002516u, +1539151988u, +1147951686u, +2005032160u, +2415262714u, +116647396u, +1029284767u, +2159170082u, +1919171906u, +2017579106u, +2473524405u, +1694443528u, +3671562289u, +505662155u, +1019936943u, +1511077569u, +773792826u, +2089123665u, +484732447u, +1120017626u, +2809286837u, +4029205195u, +1097806406u, +136118734u, +4017075736u, +1403506686u, +1516736273u, +2562064338u, +2984955003u, +3071338162u, +1923531348u, +771592405u, +2586632018u, +4032960199u, +2687561076u, +308584855u, +1692079268u, +2565680167u, +3674576684u, +3770488806u, +69201295u, +1255084262u, +3593730713u, +54945052u, +1939595371u, +2432427547u, +2295501078u, +1280920000u, +82177963u, +1121403845u, +2889101923u, +713121337u, +1747052377u, +927011680u, +4142246789u, +1958963937u, +1636932722u, +4075249328u, +2025886508u, +3026358429u, +1845587644u, +3615577014u, +1363253259u, +3087190425u, +341851980u, +2515339233u, +1276595523u, +460237542u, +4198897105u, +2069753399u, +4278599955u, +356742959u, +3735275001u, +1750561299u, +668829411u, +3384018814u, +4233785523u, +451656820u, +107312677u, +2390172694u, +1216645846u, +164402616u, +1689811113u, +1767810825u, +1397772514u, +3323383489u, +2986430557u, +207428029u, +2260498180u, +2360400900u, +1263709570u, +1377764574u, +4252610345u, +1099809675u, +2776960536u, +3542220540u, +3752806924u, +337070226u, +3267551635u, +1306761320u, +2220373824u, +4109252858u, +896322512u, +1788337208u, +1336556841u, +2911512007u, +3712582785u, +3071359622u, +2561488770u, +3898950547u, +536047554u, +2040551642u, +3528794619u, +3565689036u, +1197100813u, +1864569342u, +3329594980u, +490608221u, +1174785921u, +3287246572u, +2163330264u, +500120236u, +2520062970u, +1561519055u, +4042710240u, +2774151984u, +3160666939u, +96459446u, +1878067032u, +4237425634u, +2952135524u, +4100839753u, +1265237690u, +4246879223u, +834830418u, +3476334357u, +4277111759u, +2511026735u, +3065234219u, +556796152u, +198182691u, +2913077464u, +1535115487u, +4046477658u, +140762681u, +990407433u, +2198985327u, +2926590471u, +559702706u, +82077489u, +1096697687u, +4190838199u, +3046872820u, +1583801700u, +2185339100u, +3912423882u, +3703603898u, +2540185277u, +1446869792u, +4051584612u, +2719373510u, +1675560450u, +1996164093u, +405251683u, +2864244470u, +4071581802u, +2028708916u, +803575837u, +557660441u, +3841480082u, +255451671u, +779434428u, +3452203069u, +2285701422u, +1568745354u, +823305654u, +3184047862u, +4159715581u, +3160134214u, +3198900547u, +1566527339u, +4194096960u, +1496132623u, +1719108984u, +2584236470u, +531310503u, +3456882941u, +3382290593u, +467441309u, +3241407531u, +2540270567u, +1397502982u, +3348545480u, +811750340u, +1017047954u, +2540585554u, +3531646869u, +943914610u, +1903578924u, +1911188923u, +241574049u, +3181425568u, +3529565564u, +240953857u, +2964595704u, +3828377737u, +4260564140u, +4262383425u, +383233885u, +4051263539u, +919677938u, +1683612329u, +4204155962u, +2283918569u, +4153726847u, +350160869u, +1387233546u, +1891558063u, +740563169u, +330624974u, +2948665536u, +376390582u, +3799363969u, +3187805406u, +2263421398u, +1928519266u, +2746577402u, +2108753646u, +768287270u, +2247006571u, +212490675u, +917121602u, +2549835613u, +2864033668u, +3738062408u, +2006922227u, +2616619070u, +3449066284u, +431292293u, +786322314u, +1415970351u, +3263135197u, +2954777083u, +3206261120u, +2287507921u, +1781944746u, +4081586725u, +1109175923u, +1813855658u, +1129462471u, +1037031473u, +3389003793u, +3122687303u, +1164309901u, +3193251135u, +3626554867u, +3071568023u, +3656006011u, +1167681812u, +3155218919u, +2704165015u, +1854985978u, +1712976649u, +878608872u, +4155949943u, +3163786257u, +1626463554u, +1256485167u, +582664250u, +2083771672u, +804336148u, +2770847216u, +1674051445u, +3992583643u, +2966108111u, +900741486u, +4014551783u, +300318232u, +3517585534u, +542270815u, +760762191u, +1216399252u, +643179562u, +3652676161u, +2990167340u, +3262252593u, +2134299399u, +411263051u, +1342880802u, +1967599860u, +853593042u, +2682611693u, +850464484u, +3286110054u, +3842907484u, +3623364733u, +3693536939u, +1615375832u, +2318423400u, +4145497671u, +1728968857u, +2686506989u, +1502282913u, +2151665147u, +3651607391u, +1178454681u, +4146839064u, +2601416506u, +1448097974u, +238887261u, +4093725287u, +2367569534u, +679517009u, +3539886328u, +3086277222u, +1390394371u, +119173722u, +1766260771u, +751439914u, +215917713u, +2656990891u, +1570750352u, +3533987737u, +3576119563u, +963183826u, +3796810515u, +136547246u, +2592925324u, +427154472u, +1228758574u, +1464255968u, +2984611177u, +2001585786u, +1525438381u, +1348536411u, +2861338018u, +764077711u, +3785343245u, +457568934u, +4104954272u, +2381948487u, +3148473363u, +2180270337u, +1387729170u, +951677556u, +2721005055u, +66786703u, +1149351924u, +1895026827u, +3711056516u, +3638638708u, +2263003308u, +3448840877u, +225333538u, +3797521928u, +3262952567u, +2078619498u, +1178073973u, +3288261538u, +1496966875u, +2481012988u, +114945840u, +1632780103u, +2087949619u, +3787017905u, +2575395164u, +2971726178u, +3642087909u, +3894199764u, +203853421u, +425935223u, +3565833278u, +1748785729u, +580966986u, +2124704694u, +1107045577u, +1067532701u, +1406028344u, +18613994u, +3476683808u, +3762914298u, +1844996900u, +904215228u, +1118521573u, +3657647605u, +3136157065u, +2287683323u, +126005630u, +3555092974u, +49515858u, +1010661841u, +1902040126u, +1400735275u, +2771676666u, +2225229957u, +3454177594u, +2883475137u, +4144472319u, +1051332394u, +542648229u, +1669710469u, +553041029u, +584127807u, +2993670925u, +3587959456u, +1745399498u, +1404723176u, +1334333531u, +3239516985u, +1275954779u, +367320647u, +3684418197u, +4030809053u, +484559105u, +4255931645u, +4271715616u, +3171911678u, +928543347u, +2159512867u, +313902234u, +647086234u, +577214736u, +1130129573u, +995791646u, +1645086060u, +4122335794u, +1064648931u, +2752145076u, +3312498873u, +4238535494u, +1471227427u, +633688562u, +1959779970u, +766642813u, +1380896111u, +3647601207u, +1733961041u, +521947915u, +189164145u, +486382294u, +3770038872u, +3235740744u, +1912506671u, +2276864677u, +1588060152u, +2504457929u, +1471020554u, +3623212998u, +3026631806u, +2342164722u, +1674890530u, +3011542850u, +3549160092u, +4290680005u, +3943068002u, +2273781461u, +2127663659u, +1646681121u, +447810651u, +2366308558u, +970504950u, +2008155560u, +2695940969u, +3444688454u, +1739318893u, +2683090634u, +2774816580u, +437560100u, +512012738u, +3305170944u, +665292744u, +3580039116u, +1579404983u, +3397891494u, +710590371u, +2514565805u, +3624609754u, +3516075816u, +1314000850u, +1935166880u, +3257747610u, +3776931214u, +3183054185u, +675129307u, +3333261712u, +1154611403u, +2759854023u, +1963228038u, +505138315u, +1803966773u, +4032705384u, +798395739u, +3473799845u, +476400898u, +602972493u, +3289878097u, +2520311409u, +3214794876u, +748160407u, +1326769504u, +902775872u, +1372805534u, +1213925114u, +3009384989u, +3781981134u, +2835608783u, +2716786748u, +1669490957u, +1089334066u, +250756920u, +4041016629u, +2495807367u, +2008251381u, +106212622u, +1927268995u, +2251978818u, +3788056262u, +3678660147u, +2656772270u, +1997584981u, +2668998785u, +2954162084u, +845687881u, +776018378u, +2066910012u, +918315064u, +}; + +// Return false only if offset is -1 and a spot check of 3 hashes all yield 0. +bool Test(int offset, int len = 0) { +#undef Check +#undef IsAlive + +#define Check(x) do { \ + const uint32_t actual = (x), e = expected[index++]; \ + bool ok = actual == e; \ + if (!ok) { \ + cerr << "expected " << hex << e << " but got " << actual << endl; \ + ++errors; \ + } \ + assert(ok); \ +} while (0) + +#define IsAlive(x) do { alive += IsNonZero(x); } while (0) + + // After the following line is where the uses of "Check" and such will go. + static int index = 0; +if (offset == -1) { int alive = 0; IsAlive(farmhashnt::Hash32WithSeed(data, len++, SEED)); IsAlive(farmhashnt::Hash32(data, len++)); IsAlive(farmhashnt::Hash32(data, len++)); len -= 3; return alive > 0; } +Check(farmhashnt::Hash32WithSeed(data + offset, len, SEED)); +Check(farmhashnt::Hash32(data + offset, len)); + + return true; +#undef Check +#undef IsAlive +} + +int RunTest() { + Setup(); + int i = 0; + cout << "Running farmhashntTest"; + if (!Test(-1)) { + cout << "... Unavailable\n"; + return NoteErrors(); + } + // Good. The function is attempting to hash, so run the full test. + int errors_prior_to_test = errors; + for ( ; i < kTestSize - 1; i++) { + Test(i * i, i); + } + for ( ; i < kDataSize; i += i / 7) { + Test(0, i); + } + Test(0, kDataSize); + cout << (errors == errors_prior_to_test ? "... OK\n" : "... Failed\n"); + return NoteErrors(); +} + +#else + +// After the following line is where the code to print hash codes will go. +void Dump(int offset, int len) { +cout << farmhashnt::Hash32WithSeed(data + offset, len, SEED) << "u," << endl; +cout << farmhashnt::Hash32(data + offset, len) << "u," << endl; +} + +#endif + +#undef SEED +#undef SEED1 +#undef SEED0 + +} // namespace farmhashntTest + +#if !TESTING +int main(int argc, char** argv) { + Setup(); + cout << "uint32_t expected[] = {\n"; + int i = 0; + for ( ; i < kTestSize - 1; i++) { + farmhashntTest::Dump(i * i, i); + } + for ( ; i < kDataSize; i += i / 7) { + farmhashntTest::Dump(0, i); + } + farmhashntTest::Dump(0, kDataSize); + cout << "};\n"; +} +#endif +#ifndef FARMHASH_SELF_TEST_GUARD +#define FARMHASH_SELF_TEST_GUARD +#include +#include +#include + +using std::cout; +using std::cerr; +using std::endl; +using std::hex; + +static const uint64_t kSeed0 = 1234567; +static const uint64_t kSeed1 = k0; +static const int kDataSize = 1 << 20; +static const int kTestSize = 300; +#define kSeed128 Uint128(kSeed0, kSeed1) + +static char data[kDataSize]; + +static int completed_self_tests = 0; +static int errors = 0; + +// Initialize data to pseudorandom values. +void Setup() { + if (completed_self_tests == 0) { + uint64_t a = 9; + uint64_t b = 777; + for (int i = 0; i < kDataSize; i++) { + a += b; + b += a; + a = (a ^ (a >> 41)) * k0; + b = (b ^ (b >> 41)) * k0 + i; + uint8_t u = b >> 37; + memcpy(data + i, &u, 1); // uint8_t -> char + } + } +} + +int NoteErrors() { +#define NUM_SELF_TESTS 9 + if (++completed_self_tests == NUM_SELF_TESTS) + std::exit(errors > 0); + return errors; +} + +template inline bool IsNonZero(T x) { + return x != 0; +} + +template <> inline bool IsNonZero(uint128_t x) { + return x != Uint128(0, 0); +} + +#endif // FARMHASH_SELF_TEST_GUARD + +namespace farmhashsaTest { + +uint32_t CreateSeed(int offset, int salt) { + uint32_t h = static_cast(salt & 0xffffffff); + h = h * c1; + h ^= (h >> 17); + h = h * c1; + h ^= (h >> 17); + h = h * c1; + h ^= (h >> 17); + h += static_cast(offset & 0xffffffff); + h = h * c1; + h ^= (h >> 17); + h = h * c1; + h ^= (h >> 17); + h = h * c1; + h ^= (h >> 17); + return h; +} + +#undef SEED +#undef SEED1 +#undef SEED0 +#define SEED CreateSeed(offset, -1) +#define SEED0 CreateSeed(offset, 0) +#define SEED1 CreateSeed(offset, 1) + +#undef TESTING +#define TESTING 1 +#if TESTING +uint32_t expected[] = { +4223616069u, +3696677242u, +4081014168u, +2576519988u, +2212771159u, +1112731063u, +1020067935u, +3955445564u, +1451961420u, +653440099u, +31917516u, +2957164615u, +2590087362u, +3879448744u, +176305566u, +2447367541u, +1359016305u, +3363804638u, +1117290165u, +1062549743u, +2437877004u, +1894455839u, +673206794u, +3486923651u, +3269862919u, +2303349487u, +1380660650u, +595525107u, +1525325287u, +2025609358u, +176408838u, +1592885012u, +864896482u, +2101378090u, +3489229104u, +2118965695u, +581644891u, +2718789079u, +631613207u, +4228658372u, +3867875546u, +3531368319u, +3804516756u, +3317755099u, +1619744564u, +2884717286u, +1088213445u, +2667691076u, +3727873235u, +2330406762u, +858590707u, +123802208u, +4150036245u, +182283099u, +1478882570u, +3282617403u, +819171187u, +1172627392u, +4254302102u, +2957028020u, +437030323u, +2452147680u, +2868246750u, +3530169402u, +3154852132u, +215019192u, +357580983u, +1354454461u, +1108813287u, +2324008118u, +2315997713u, +4181601562u, +1360882441u, +92423273u, +3048866755u, +3369188505u, +3664371439u, +2920710428u, +1027891570u, +2653166430u, +3461888315u, +1475780447u, +292769636u, +1737473313u, +4064110516u, +4170160075u, +762850927u, +3630603695u, +2803307356u, +844987665u, +460980967u, +3005635467u, +2802568977u, +588668033u, +2148940781u, +3239099984u, +1266953698u, +3197808789u, +3519942533u, +2511995334u, +2553810188u, +871667697u, +1358675720u, +1499319171u, +2044931270u, +1210355103u, +807152540u, +3262320756u, +2810214575u, +1813386141u, +4089465863u, +903928165u, +1388899322u, +3209183659u, +834536144u, +2733354550u, +2742289921u, +3689042563u, +2655593281u, +4169686303u, +415985561u, +138892376u, +516115393u, +65683883u, +4162865100u, +889944635u, +313566528u, +3346420907u, +1504303591u, +2256809275u, +742243229u, +779775302u, +3140940172u, +2312556111u, +2304095772u, +1151741606u, +2194712422u, +1714084652u, +3272736835u, +1311540658u, +191179665u, +3996605106u, +1657345233u, +4205442903u, +1553339212u, +2351843044u, +1647502006u, +2525516233u, +292202846u, +1498646290u, +1429323381u, +974274898u, +3759331561u, +2881238887u, +826787221u, +1069622448u, +221991032u, +1462969082u, +2799661508u, +364022781u, +2594244377u, +797773898u, +4097839290u, +1529150125u, +2456805570u, +541503425u, +3936326142u, +3112719954u, +775223581u, +3074018423u, +3198488875u, +1772191849u, +2456535211u, +3154686028u, +1520862019u, +4005829426u, +1306433767u, +1943028506u, +2246000782u, +1057766454u, +3761996982u, +3441075333u, +898641979u, +3450209088u, +3941329307u, +3289922449u, +3085075827u, +1814193220u, +690422997u, +2627846676u, +2653520704u, +3739145533u, +3996776010u, +2287072592u, +1346671698u, +3082629900u, +2298811274u, +3639722036u, +1729419228u, +1836765953u, +3708118742u, +213436u, +950223749u, +3734247682u, +2924575678u, +1382024841u, +2431637732u, +3448846682u, +1341301397u, +4206956590u, +1730650902u, +2581075456u, +1542359141u, +707222542u, +2925350541u, +3846303536u, +3579103295u, +3932175763u, +1339615732u, +848825750u, +1070170828u, +1964973818u, +577060344u, +607721296u, +4031023048u, +406883794u, +3991905552u, +1198544082u, +872468460u, +1044847096u, +3159976313u, +3020028266u, +2108700400u, +3373767922u, +264431841u, +2817097007u, +3700061048u, +1733731531u, +3459415893u, +80378591u, +1479875104u, +19735612u, +1382658977u, +3416562245u, +1959852842u, +2384002344u, +124683828u, +3725782174u, +2300301222u, +393852269u, +1302492002u, +3623776492u, +3787086417u, +1730024749u, +1710531361u, +443700716u, +1461987482u, +671998131u, +3018380746u, +2592292305u, +3390799372u, +3945101155u, +3743494852u, +3716045582u, +996005166u, +320698449u, +3420221765u, +1518157951u, +2555810666u, +3381929684u, +2019638523u, +3088262796u, +2072178906u, +3433649364u, +203906916u, +34663784u, +290301305u, +1188021504u, +3754681145u, +3920313139u, +2840496520u, +1656802962u, +2288475489u, +3399185138u, +1296000826u, +2362384746u, +309633360u, +2719851778u, +776035930u, +3200733043u, +365690832u, +3326378243u, +1500331457u, +1625708592u, +4230903462u, +715344888u, +3363777768u, +2243620288u, +2890765789u, +553154234u, +4044100108u, +4056887320u, +1185656496u, +3671476744u, +1064586897u, +1154949698u, +3493481974u, +1294573722u, +1869224012u, +2530084956u, +995321553u, +833419249u, +563815282u, +250258043u, +2970801822u, +441007535u, +42246961u, +2820426655u, +2878882436u, +2363245780u, +2138489282u, +2972360481u, +2312619393u, +3598664848u, +3071556076u, +776990325u, +3220427357u, +2257939577u, +3817305903u, +1502979698u, +3159755934u, +3955997276u, +2423850008u, +1959927572u, +1219782288u, +4119776679u, +1124253854u, +3678052422u, +2620644947u, +1262408666u, +3480072280u, +2627137665u, +807538749u, +3276646337u, +518510128u, +1137828655u, +1498449110u, +3031692317u, +1125635969u, +1130096111u, +780007336u, +3111856399u, +1014917264u, +780877352u, +2909458336u, +4235949214u, +2423879289u, +275888892u, +3891926795u, +3538163953u, +54815161u, +162228302u, +258154068u, +3554455591u, +1801469029u, +2801563220u, +726560058u, +2450221940u, +3677582978u, +440993800u, +424762443u, +2624525253u, +2587715329u, +2292264424u, +1074856749u, +3294752007u, +3164112672u, +2399146799u, +1920182465u, +3858835361u, +193755240u, +3333610311u, +1757504059u, +2576027039u, +2775253365u, +2939191561u, +1046147275u, +235149906u, +4262218222u, +2900542726u, +2260154702u, +1019551635u, +1194720570u, +3519118691u, +3039483153u, +84918216u, +3053381097u, +2572396843u, +3849763371u, +2782686780u, +3710049554u, +3403430713u, +2346080784u, +2496307442u, +1597281872u, +696018239u, +704625714u, +623026921u, +3182413559u, +3794540330u, +305497722u, +1592680199u, +2377854072u, +3060601746u, +3953057908u, +3941551588u, +1033716182u, +2765716854u, +1309699058u, +3519400181u, +3073370877u, +115583008u, +4032909296u, +2944563574u, +3762753718u, +192842727u, +1711348701u, +3086147235u, +1658229443u, +1479783872u, +3839977157u, +225619117u, +1349684817u, +1964813173u, +565753187u, +2530252046u, +840014353u, +1645183704u, +3668429078u, +3438418557u, +639704059u, +360837811u, +2531807958u, +1572353913u, +2116037299u, +1948437512u, +744553393u, +2380697034u, +3775234105u, +3816065157u, +301868653u, +2960939561u, +3306528247u, +2389296549u, +805918610u, +1759358265u, +1760876328u, +2827601706u, +2944594708u, +3313666458u, +2022601495u, +730938791u, +193539397u, +2026103244u, +802928398u, +2630934308u, +782805818u, +3499326016u, +293509489u, +3646131514u, +3182478647u, +854800333u, +2284531628u, +438528022u, +2339298129u, +1692289216u, +2427728723u, +46501288u, +350652353u, +1355971222u, +889682372u, +944799254u, +2763906061u, +2807550612u, +2683762637u, +100870317u, +2449357318u, +2638348436u, +4206088869u, +1788948473u, +3537588549u, +2782490204u, +134406470u, +2409190528u, +2362439849u, +1861661528u, +2101513194u, +1424834765u, +3581765745u, +3185999525u, +2057487100u, +2303941176u, +3639628788u, +1180265315u, +230437935u, +2108319366u, +1131685143u, +1055685292u, +1509007009u, +1258485140u, +560525005u, +3598799040u, +3835680585u, +1851859628u, +332858996u, +641769248u, +4252450037u, +865386707u, +720719117u, +3133612164u, +3833045874u, +3492515435u, +2465970289u, +4234420011u, +573859916u, +252532886u, +870392318u, +4051320920u, +894929092u, +3748361688u, +699355960u, +1885212350u, +1609756949u, +461896870u, +1337065461u, +1775211059u, +1786193749u, +2815154643u, +2128729882u, +969639529u, +3960427545u, +859416958u, +2739758802u, +2698032197u, +2813292418u, +1985467524u, +396604317u, +4122172759u, +1201259789u, +4282051702u, +3270018895u, +961215209u, +961075860u, +4211926998u, +4088374597u, +577510509u, +3058349487u, +4025377754u, +2815478438u, +471023164u, +3947959608u, +4161486934u, +2299888461u, +1103571511u, +2450153872u, +1839939275u, +108299608u, +858086440u, +1030152945u, +3895328530u, +3009080718u, +3690840454u, +3847025277u, +152331362u, +161365689u, +831319961u, +2166017294u, +3945322722u, +4059970216u, +1420824131u, +2770648308u, +1567250186u, +2181067149u, +1939743488u, +3080158120u, +3435218248u, +2495237495u, +3814085102u, +3180983013u, +3199054292u, +2204745908u, +1140337267u, +2213569784u, +1941879842u, +2105562605u, +3618835614u, +2247103645u, +2492473487u, +856414299u, +166022030u, +4080104712u, +3218935344u, +3284220561u, +4261581452u, +1206944836u, +3496705432u, +2215996876u, +3154627465u, +3384005496u, +742170556u, +1333047620u, +802680366u, +156833431u, +2682100354u, +2493654830u, +584848366u, +1691693131u, +2169934170u, +779968026u, +2099545800u, +1423039695u, +4292110968u, +4266576788u, +149142597u, +748501873u, +3865014822u, +1913588198u, +130285614u, +3500768879u, +915458923u, +3071792750u, +1339986633u, +4143929149u, +4048379479u, +725193827u, +1375113643u, +2425277412u, +4144659274u, +465714768u, +226991589u, +2212127704u, +3936145258u, +2891024846u, +3816000225u, +979331165u, +1749907536u, +53847318u, +1462525833u, +2961425455u, +368859113u, +3572721452u, +453048644u, +1628629918u, +3497673923u, +3619079585u, +139870565u, +1518176798u, +3933074281u, +1878623729u, +2074035641u, +3016759257u, +1313053591u, +2557706970u, +2348296582u, +962370022u, +2337285014u, +1618936717u, +1915877085u, +2743743122u, +3250783882u, +1346652536u, +143311109u, +2443788461u, +1048248964u, +2806619339u, +3263266976u, +1668146349u, +3397428868u, +3276188862u, +1774196343u, +1993847813u, +2771079610u, +476672419u, +2119050359u, +2918326659u, +2245402721u, +2692910474u, +2374383269u, +342400227u, +2961437795u, +3899230368u, +337787132u, +3664444935u, +1269451153u, +2971526729u, +1486511182u, +791070133u, +2570319890u, +3482497490u, +2134230518u, +4273391202u, +1825511330u, +3947753714u, +1389755724u, +3995075516u, +2081052615u, +3626343470u, +4213603435u, +2137917278u, +2898987303u, +3059215715u, +3383237881u, +3003674434u, +409174425u, +1911915604u, +2087728055u, +2942005882u, +3386522440u, +714936074u, +261924004u, +3268784033u, +1141188757u, +2413217552u, +1515163433u, +}; + +// Return false only if offset is -1 and a spot check of 3 hashes all yield 0. +bool Test(int offset, int len = 0) { +#undef Check +#undef IsAlive + +#define Check(x) do { \ + const uint32_t actual = (x), e = expected[index++]; \ + bool ok = actual == e; \ + if (!ok) { \ + cerr << "expected " << hex << e << " but got " << actual << endl; \ + ++errors; \ + } \ + assert(ok); \ +} while (0) + +#define IsAlive(x) do { alive += IsNonZero(x); } while (0) + + // After the following line is where the uses of "Check" and such will go. + static int index = 0; +if (offset == -1) { int alive = 0; IsAlive(farmhashsa::Hash32WithSeed(data, len++, SEED)); IsAlive(farmhashsa::Hash32(data, len++)); IsAlive(farmhashsa::Hash32(data, len++)); len -= 3; return alive > 0; } +Check(farmhashsa::Hash32WithSeed(data + offset, len, SEED)); +Check(farmhashsa::Hash32(data + offset, len)); + + return true; +#undef Check +#undef IsAlive +} + +int RunTest() { + Setup(); + int i = 0; + cout << "Running farmhashsaTest"; + if (!Test(-1)) { + cout << "... Unavailable\n"; + return NoteErrors(); + } + // Good. The function is attempting to hash, so run the full test. + int errors_prior_to_test = errors; + for ( ; i < kTestSize - 1; i++) { + Test(i * i, i); + } + for ( ; i < kDataSize; i += i / 7) { + Test(0, i); + } + Test(0, kDataSize); + cout << (errors == errors_prior_to_test ? "... OK\n" : "... Failed\n"); + return NoteErrors(); +} + +#else + +// After the following line is where the code to print hash codes will go. +void Dump(int offset, int len) { +cout << farmhashsa::Hash32WithSeed(data + offset, len, SEED) << "u," << endl; +cout << farmhashsa::Hash32(data + offset, len) << "u," << endl; +} + +#endif + +#undef SEED +#undef SEED1 +#undef SEED0 + +} // namespace farmhashsaTest + +#if !TESTING +int main(int argc, char** argv) { + Setup(); + cout << "uint32_t expected[] = {\n"; + int i = 0; + for ( ; i < kTestSize - 1; i++) { + farmhashsaTest::Dump(i * i, i); + } + for ( ; i < kDataSize; i += i / 7) { + farmhashsaTest::Dump(0, i); + } + farmhashsaTest::Dump(0, kDataSize); + cout << "};\n"; +} +#endif +#ifndef FARMHASH_SELF_TEST_GUARD +#define FARMHASH_SELF_TEST_GUARD +#include +#include +#include + +using std::cout; +using std::cerr; +using std::endl; +using std::hex; + +static const uint64_t kSeed0 = 1234567; +static const uint64_t kSeed1 = k0; +static const int kDataSize = 1 << 20; +static const int kTestSize = 300; +#define kSeed128 Uint128(kSeed0, kSeed1) + +static char data[kDataSize]; + +static int completed_self_tests = 0; +static int errors = 0; + +// Initialize data to pseudorandom values. +void Setup() { + if (completed_self_tests == 0) { + uint64_t a = 9; + uint64_t b = 777; + for (int i = 0; i < kDataSize; i++) { + a += b; + b += a; + a = (a ^ (a >> 41)) * k0; + b = (b ^ (b >> 41)) * k0 + i; + uint8_t u = b >> 37; + memcpy(data + i, &u, 1); // uint8_t -> char + } + } +} + +int NoteErrors() { +#define NUM_SELF_TESTS 9 + if (++completed_self_tests == NUM_SELF_TESTS) + std::exit(errors > 0); + return errors; +} + +template inline bool IsNonZero(T x) { + return x != 0; +} + +template <> inline bool IsNonZero(uint128_t x) { + return x != Uint128(0, 0); +} + +#endif // FARMHASH_SELF_TEST_GUARD + +namespace farmhashsuTest { + +uint32_t CreateSeed(int offset, int salt) { + uint32_t h = static_cast(salt & 0xffffffff); + h = h * c1; + h ^= (h >> 17); + h = h * c1; + h ^= (h >> 17); + h = h * c1; + h ^= (h >> 17); + h += static_cast(offset & 0xffffffff); + h = h * c1; + h ^= (h >> 17); + h = h * c1; + h ^= (h >> 17); + h = h * c1; + h ^= (h >> 17); + return h; +} + +#undef SEED +#undef SEED1 +#undef SEED0 +#define SEED CreateSeed(offset, -1) +#define SEED0 CreateSeed(offset, 0) +#define SEED1 CreateSeed(offset, 1) + +#undef TESTING +#define TESTING 1 +#if TESTING +uint32_t expected[] = { +4223616069u, +3696677242u, +4081014168u, +2576519988u, +2212771159u, +1112731063u, +1020067935u, +3955445564u, +1451961420u, +653440099u, +31917516u, +2957164615u, +2590087362u, +3879448744u, +176305566u, +2447367541u, +1359016305u, +3363804638u, +1117290165u, +1062549743u, +2437877004u, +1894455839u, +673206794u, +3486923651u, +3269862919u, +2303349487u, +1380660650u, +595525107u, +1525325287u, +2025609358u, +176408838u, +1592885012u, +864896482u, +2101378090u, +3489229104u, +2118965695u, +581644891u, +2718789079u, +631613207u, +4228658372u, +3867875546u, +3531368319u, +3804516756u, +3317755099u, +1619744564u, +2884717286u, +1088213445u, +2667691076u, +3727873235u, +2330406762u, +858590707u, +457744844u, +4150036245u, +2000404290u, +1478882570u, +901678172u, +819171187u, +195942998u, +4254302102u, +3967266927u, +437030323u, +4018009204u, +2868246750u, +3540087514u, +3154852132u, +3319116625u, +357580983u, +3177665294u, +1108813287u, +1253366798u, +2315997713u, +510718750u, +1360882441u, +2770216279u, +3048866755u, +3406961221u, +3664371439u, +1151145514u, +1027891570u, +2699067992u, +3461888315u, +198061905u, +292769636u, +1106771795u, +4064110516u, +3258279756u, +762850927u, +1818699721u, +2803307356u, +3919169404u, +460980967u, +3125535078u, +2802568977u, +3582546426u, +2148940781u, +3963274378u, +1266953698u, +204185123u, +1100034381u, +3009193601u, +4200651967u, +274889605u, +2700589508u, +952511689u, +3765324859u, +3465498478u, +4014967037u, +2070988082u, +2972423530u, +3068638223u, +4156773651u, +489509804u, +1323863238u, +3731914806u, +2846098469u, +2728930632u, +346814072u, +848146907u, +551160669u, +4165126521u, +2039095001u, +4179859388u, +2434936359u, +2764414551u, +238491210u, +732483969u, +3366512764u, +478307468u, +4124179572u, +4142733597u, +1953448206u, +4199329278u, +865077060u, +2627662116u, +2802499360u, +3141206831u, +1959218197u, +911371451u, +125987200u, +2821366175u, +2530992747u, +2409206225u, +117991880u, +2133402461u, +895510531u, +428719601u, +3036014536u, +1223783733u, +733793540u, +970650405u, +547701766u, +570764615u, +3224485368u, +3192714940u, +319942831u, +3940200341u, +362056204u, +2832368105u, +1853281226u, +3296434636u, +3752508307u, +604292768u, +2231940616u, +1204094681u, +866194005u, +2405201650u, +2466384396u, +380829379u, +230033818u, +2783417588u, +4249886729u, +829569301u, +2988322580u, +2299983554u, +74748560u, +737514425u, +3153050211u, +652642663u, +1270205115u, +227197032u, +2773091790u, +325849216u, +49998791u, +4043203010u, +3662748068u, +1709364383u, +1179105165u, +1478504366u, +2980456610u, +1167476429u, +1590390732u, +1306256496u, +292008135u, +374690995u, +1809200819u, +1680595904u, +646040226u, +1742445560u, +2435776844u, +3703683804u, +478742495u, +814967947u, +2698190177u, +1003617993u, +1436118705u, +217056304u, +1412287094u, +2738417466u, +2933279339u, +3461877733u, +1203141205u, +2119492857u, +1134895723u, +1560001021u, +3786320122u, +3748116258u, +3486219595u, +702138030u, +1062984182u, +232789133u, +1566523968u, +3885443778u, +1820171888u, +3655858585u, +2316903005u, +2678779620u, +395625433u, +1609107564u, +3108726411u, +2937837224u, +3911907151u, +557272509u, +3893435978u, +1542613576u, +1079886893u, +2624566322u, +1413700616u, +2796974006u, +1922556114u, +562820464u, +2845409784u, +54180312u, +1898782464u, +3681814953u, +2417064617u, +1815464483u, +911626132u, +2964575550u, +1852696128u, +2319647785u, +1998904590u, +619992689u, +3073207513u, +1238163512u, +3199435982u, +828667254u, +3561155502u, +3943095163u, +1045711849u, +2238679131u, +2114975398u, +713808403u, +3871787494u, +2572031161u, +2360934075u, +2337781107u, +262596504u, +693836699u, +2129369850u, +3543189427u, +962205222u, +3685581020u, +692974477u, +725182211u, +646123906u, +2368836544u, +2505872733u, +1999977610u, +1639885802u, +1475058032u, +207023609u, +2773581234u, +3524857793u, +3433371102u, +3243027613u, +1787668353u, +985757946u, +3896012929u, +702356957u, +3559331129u, +884084870u, +4009998120u, +648888720u, +1403349048u, +1624342778u, +1766674171u, +2518582204u, +3251243146u, +792751003u, +1377201813u, +3629686054u, +1583734324u, +3647107626u, +4258564381u, +1469878609u, +1940598241u, +2755003690u, +1907120418u, +109916701u, +775347954u, +2090960874u, +611281803u, +3470490146u, +3301663253u, +1835412158u, +1803066146u, +591872433u, +550703713u, +1495089683u, +826492808u, +817200035u, +4177474571u, +688070143u, +971427632u, +1442499481u, +3568640348u, +2789993738u, +85808128u, +2058346726u, +394058570u, +3466511434u, +318905230u, +4149248030u, +415308316u, +165997598u, +1219639412u, +1648022659u, +2857432523u, +1422508004u, +468095522u, +296968649u, +430250611u, +1775562314u, +2976361671u, +1040036362u, +1372510167u, +292746272u, +3408238954u, +626061886u, +1317637569u, +1237775792u, +1218490455u, +2224234499u, +590942419u, +713995643u, +3541889330u, +4140218960u, +3529791107u, +354462673u, +842607274u, +365048533u, +2638303414u, +3560458014u, +31621379u, +4210854794u, +1273118792u, +2572743762u, +3513175801u, +402066986u, +602524471u, +565029192u, +180576438u, +1288605959u, +2896244423u, +1420543484u, +1329862227u, +1791567324u, +4248690247u, +12917038u, +3483481310u, +2082050731u, +1611921143u, +2443766548u, +2216338811u, +2528006095u, +2984009021u, +674210884u, +2857608106u, +2155534809u, +1023105067u, +2968955846u, +3303624302u, +2502112850u, +245749006u, +3175229091u, +3342796184u, +3613785362u, +1614168851u, +2582149283u, +895403488u, +416205023u, +3792242000u, +529397534u, +299415203u, +4284673348u, +2096851282u, +1864524731u, +2012577738u, +3426363316u, +1387308508u, +1143610148u, +2027467219u, +3772856163u, +3453862623u, +2661437174u, +2047145955u, +2533381447u, +2059534115u, +439426587u, +1537543414u, +2384289877u, +3174229055u, +2658017753u, +2293148474u, +2359450158u, +3930242475u, +1510302397u, +3354288821u, +920095603u, +2415746928u, +2729472638u, +2261143371u, +848667611u, +919157153u, +3322393117u, +4103299943u, +413569608u, +68911216u, +3334990170u, +1228068652u, +1570056373u, +1905477543u, +2622302276u, +2935063895u, +3224810004u, +4211768578u, +828688131u, +3556122839u, +1930935348u, +2605825202u, +1540993970u, +3209115883u, +122847500u, +665638794u, +506571051u, +2691795295u, +3996966556u, +714660621u, +3662432239u, +470651837u, +1807432621u, +3755290953u, +359878860u, +2793081615u, +4065031431u, +904653062u, +2317800777u, +568501094u, +3492871707u, +2738806116u, +2883859610u, +3242080257u, +364246691u, +3601786516u, +3159362524u, +1578272201u, +1283574375u, +2912186103u, +2256279032u, +1540671086u, +2356088973u, +2892277779u, +3441449267u, +2225005503u, +3846428419u, +2014549218u, +2290734767u, +2126684614u, +4235463487u, +3811556204u, +174739661u, +767525888u, +47684458u, +4211168099u, +889063422u, +469864411u, +767407110u, +413337343u, +1618456644u, +2814499820u, +2401124192u, +632089437u, +1234980238u, +1288585402u, +3153169944u, +2917822069u, +1843320264u, +3794359132u, +3074573530u, +258629454u, +3813357060u, +3806887248u, +1665524736u, +3324533324u, +3005091922u, +793108368u, +1529669805u, +2332660395u, +2217730223u, +2634687611u, +442806463u, +1968135266u, +454523002u, +3177866230u, +2808960136u, +4259114138u, +4103264843u, +3103714075u, +2462967542u, +1466891491u, +477973764u, +834565647u, +741089037u, +218837573u, +1710536528u, +2469088212u, +1229072375u, +2828341u, +176923431u, +985763350u, +4095477420u, +1984145538u, +1870791084u, +674956677u, +1978138947u, +1296493993u, +1818183554u, +3443333721u, +2124949983u, +2549590262u, +2700850794u, +2662736367u, +739638109u, +4061447096u, +2960078422u, +2453781158u, +929570940u, +3200328383u, +2406328791u, +1419180666u, +2152455739u, +2805741044u, +3305999074u, +3183816361u, +2303165050u, +4922104u, +63096005u, +936656347u, +3104453886u, +1088673880u, +1113407526u, +1457890086u, +453478383u, +1107686695u, +3626027824u, +1159687359u, +2248467888u, +2004578380u, +3274954621u, +1787958646u, +2628726704u, +1138419798u, +3735442315u, +692385301u, +313807213u, +2329068673u, +59375364u, +3261084359u, +2088644507u, +2471153194u, +788336435u, +4024527246u, +141504460u, +2307553888u, +1930559950u, +48975711u, +2745693338u, +230161982u, +3429230862u, +1335968626u, +609591304u, +57435073u, +4279281136u, +3152151665u, +3984484924u, +3459883943u, +397478330u, +1738762229u, +3033590066u, +3611539498u, +1363463523u, +3319364965u, +2671169141u, +3819548561u, +1691193757u, +2423834608u, +2820147055u, +1378120632u, +1240565187u, +3180720050u, +680831086u, +3309658414u, +1986166490u, +762099827u, +510883662u, +2047373648u, +3606742294u, +3894965352u, +2342078853u, +1091255717u, +776594727u, +3217317445u, +1574468485u, +3844504016u, +2819598918u, +1037401010u, +2550943503u, +3867184001u, +1687911772u, +165313836u, +1679575281u, +2418947263u, +2038774952u, +3913543652u, +3209155736u, +149905221u, +3859604717u, +713919631u, +4069810796u, +1882959164u, +1019939034u, +2379867302u, +3666323035u, +1157389013u, +2422300650u, +3366777340u, +2526452062u, +1313747885u, +1039617868u, +1620553692u, +2032976978u, +578789528u, +1592846839u, +2270630604u, +897850577u, +1603294178u, +3105664807u, +1442670138u, +1728019360u, +79313861u, +1683031101u, +1913067024u, +4070719870u, +708986470u, +2586453359u, +3993348863u, +3358251279u, +3003552537u, +750174793u, +836888956u, +4190747426u, +4251291318u, +4145164938u, +1366883260u, +1912910955u, +510192669u, +1851315039u, +3574241274u, +3220062924u, +2821142039u, +1317082195u, +2274293302u, +1839219569u, +126586168u, +3989293643u, +2680178207u, +347056948u, +799681430u, +2864517481u, +3180404853u, +213140045u, +1956305184u, +1474675286u, +3085723423u, +2841859626u, +308421914u, +3670309263u, +1765052231u, +245459238u, +113434331u, +4079521092u, +2115235526u, +2943408816u, +1055476938u, +1506442339u, +2291296392u, +3267864332u, +1282145528u, +3700108015u, +1932843667u, +2677701670u, +6041177u, +3889648557u, +1461025478u, +}; + +// Return false only if offset is -1 and a spot check of 3 hashes all yield 0. +bool Test(int offset, int len = 0) { +#undef Check +#undef IsAlive + +#define Check(x) do { \ + const uint32_t actual = (x), e = expected[index++]; \ + bool ok = actual == e; \ + if (!ok) { \ + cerr << "expected " << hex << e << " but got " << actual << endl; \ + ++errors; \ + } \ + assert(ok); \ +} while (0) + +#define IsAlive(x) do { alive += IsNonZero(x); } while (0) + + // After the following line is where the uses of "Check" and such will go. + static int index = 0; +if (offset == -1) { int alive = 0; IsAlive(farmhashsu::Hash32WithSeed(data, len++, SEED)); IsAlive(farmhashsu::Hash32(data, len++)); IsAlive(farmhashsu::Hash32(data, len++)); len -= 3; return alive > 0; } +Check(farmhashsu::Hash32WithSeed(data + offset, len, SEED)); +Check(farmhashsu::Hash32(data + offset, len)); + + return true; +#undef Check +#undef IsAlive +} + +int RunTest() { + Setup(); + int i = 0; + cout << "Running farmhashsuTest"; + if (!Test(-1)) { + cout << "... Unavailable\n"; + return NoteErrors(); + } + // Good. The function is attempting to hash, so run the full test. + int errors_prior_to_test = errors; + for ( ; i < kTestSize - 1; i++) { + Test(i * i, i); + } + for ( ; i < kDataSize; i += i / 7) { + Test(0, i); + } + Test(0, kDataSize); + cout << (errors == errors_prior_to_test ? "... OK\n" : "... Failed\n"); + return NoteErrors(); +} + +#else + +// After the following line is where the code to print hash codes will go. +void Dump(int offset, int len) { +cout << farmhashsu::Hash32WithSeed(data + offset, len, SEED) << "u," << endl; +cout << farmhashsu::Hash32(data + offset, len) << "u," << endl; +} + +#endif + +#undef SEED +#undef SEED1 +#undef SEED0 + +} // namespace farmhashsuTest + +#if !TESTING +int main(int argc, char** argv) { + Setup(); + cout << "uint32_t expected[] = {\n"; + int i = 0; + for ( ; i < kTestSize - 1; i++) { + farmhashsuTest::Dump(i * i, i); + } + for ( ; i < kDataSize; i += i / 7) { + farmhashsuTest::Dump(0, i); + } + farmhashsuTest::Dump(0, kDataSize); + cout << "};\n"; +} +#endif +#ifndef FARMHASH_SELF_TEST_GUARD +#define FARMHASH_SELF_TEST_GUARD +#include +#include +#include + +using std::cout; +using std::cerr; +using std::endl; +using std::hex; + +static const uint64_t kSeed0 = 1234567; +static const uint64_t kSeed1 = k0; +static const int kDataSize = 1 << 20; +static const int kTestSize = 300; +#define kSeed128 Uint128(kSeed0, kSeed1) + +static char data[kDataSize]; + +static int completed_self_tests = 0; +static int errors = 0; + +// Initialize data to pseudorandom values. +void Setup() { + if (completed_self_tests == 0) { + uint64_t a = 9; + uint64_t b = 777; + for (int i = 0; i < kDataSize; i++) { + a += b; + b += a; + a = (a ^ (a >> 41)) * k0; + b = (b ^ (b >> 41)) * k0 + i; + uint8_t u = b >> 37; + memcpy(data + i, &u, 1); // uint8_t -> char + } + } +} + +int NoteErrors() { +#define NUM_SELF_TESTS 9 + if (++completed_self_tests == NUM_SELF_TESTS) + std::exit(errors > 0); + return errors; +} + +template inline bool IsNonZero(T x) { + return x != 0; +} + +template <> inline bool IsNonZero(uint128_t x) { + return x != Uint128(0, 0); +} + +#endif // FARMHASH_SELF_TEST_GUARD + +namespace farmhashteTest { + +uint32_t CreateSeed(int offset, int salt) { + uint32_t h = static_cast(salt & 0xffffffff); + h = h * c1; + h ^= (h >> 17); + h = h * c1; + h ^= (h >> 17); + h = h * c1; + h ^= (h >> 17); + h += static_cast(offset & 0xffffffff); + h = h * c1; + h ^= (h >> 17); + h = h * c1; + h ^= (h >> 17); + h = h * c1; + h ^= (h >> 17); + return h; +} + +#undef SEED +#undef SEED1 +#undef SEED0 +#define SEED CreateSeed(offset, -1) +#define SEED0 CreateSeed(offset, 0) +#define SEED1 CreateSeed(offset, 1) + +#undef TESTING +#define TESTING 1 +#if TESTING +uint32_t expected[] = { +1140953930u, 861465670u, +3277735313u, 2681724312u, +2598464059u, 797982799u, +890626835u, 800175912u, +2603993599u, 921001710u, +1410420968u, 2134990486u, +3283896453u, 1867689945u, +2914424215u, 2244477846u, +255297188u, 2992121793u, +1110588164u, 4186314283u, +161451183u, 3943596029u, +4019337850u, 452431531u, +283198166u, 2741341286u, +3379021470u, 2557197665u, +299850021u, 2532580744u, +452473466u, 1706958772u, +1298374911u, 3099673830u, +2199864459u, 3696623795u, +236935126u, 2976578695u, +4055299123u, 3281581178u, +1053458494u, 1882212500u, +2305012065u, 2169731866u, +3456121707u, 275903667u, +458884671u, 3033004529u, +3058973506u, 2379411653u, +1898235244u, 1402319660u, +2700149065u, 2699376854u, +147814787u, 720739346u, +2433714046u, 4222949502u, +4220361840u, 1712034059u, +3425469811u, 3690733394u, +4148372108u, 1330324210u, +594028478u, 2921867846u, +1635026870u, 192883107u, +780716741u, 1728752234u, +3280331829u, 326029180u, +3969463346u, 1436364519u, +393215742u, 3349570000u, +3824583307u, 1612122221u, +2859809759u, 3808705738u, +1379537552u, 1646032583u, +2233466664u, 1432476832u, +4023053163u, 2650381482u, +2052294713u, 3552092450u, +1628777059u, 1499109081u, +3476440786u, 3829307897u, +2960536756u, 1554038301u, +1145519619u, 3190844552u, +2902102606u, 3600725550u, +237495366u, 540224401u, +65721842u, 489963606u, +1448662590u, 397635823u, +1596489240u, 1562872448u, +1790705123u, 2128624475u, +180854224u, 2604346966u, +1435705557u, 1262831810u, +155445229u, 1672724608u, +1669465176u, 1341975128u, +663607706u, 2077310004u, +3610042449u, 1911523866u, +1043692997u, 1454396064u, +2563776023u, 294527927u, +1099072299u, 1389770549u, +703505868u, 678706990u, +2952353448u, 2026137563u, +3603803785u, 629449419u, +1933894405u, 3043213226u, +226132789u, 2489287368u, +1552847036u, 645684964u, +3828089804u, 3632594520u, +187883449u, 230403464u, +3151491850u, 3272648435u, +3729087873u, 1303930448u, +2002861219u, 165370827u, +916494250u, 1230085527u, +3103338579u, 3064290191u, +3807265751u, 3628174014u, +231181488u, 851743255u, +2295806711u, 1781190011u, +2988893883u, 1554380634u, +1142264800u, 3667013118u, +1968445277u, 315203929u, +2638023604u, 2290487377u, +732137533u, 1909203251u, +440398219u, 1891630171u, +1380301172u, 1498556724u, +4072067757u, 4165088768u, +4204318635u, 441430649u, +3931792696u, 197618179u, +956300927u, 914413116u, +3010839769u, 2837339569u, +2148126371u, 1913303225u, +3074915312u, 3117299654u, +4139181436u, 2993479124u, +3178848746u, 1357272220u, +1438494951u, 507436733u, +667183474u, 2084369203u, +3854939912u, 1413396341u, +126024219u, 146044391u, +1016656857u, 3022024459u, +3254014218u, 429095991u, +990500595u, 3056862311u, +985653208u, 1718653828u, +623071693u, 366414107u, +1771289760u, 2293458109u, +3047342438u, 2991127487u, +3120876698u, 1684583131u, +3638043310u, 1170404994u, +863214540u, 1087193030u, +199124911u, 520792961u, +3169775996u, 1577421232u, +3331828431u, 1013201099u, +1716848157u, 4033596884u, +1770708857u, 4229339322u, +1146169032u, 1434258493u, +3824360466u, 3242407770u, +1926419493u, 2649785113u, +872586426u, 762243036u, +2736953692u, 816692935u, +1571283333u, 3555213933u, +2266795890u, 3781899767u, +4290630595u, 517646945u, +3006163611u, 2180594090u, +959214578u, 558910384u, +1283799121u, 3047062993u, +3830962609u, 2391606125u, +3544509313u, 622325861u, +834785312u, 382936554u, +1421463872u, 788479970u, +1825135056u, 2725923798u, +580988377u, 2826990641u, +247825043u, 3167748333u, +812546227u, 2506885666u, +2584372201u, 1758123094u, +1891789696u, 389974094u, +345313518u, 2022370576u, +3886113119u, 3338548567u, +1083486947u, 2583576230u, +1776047957u, 1771384107u, +3604937815u, 3198590202u, +3027522813u, 4155628142u, +4232136669u, 427759438u, +4244322689u, 542201663u, +1549591985u, 2856634168u, +556609672u, 45845311u, +1175961330u, 3948351189u, +4165739882u, 4194218315u, +1634635545u, 4151937410u, +713127376u, 1467786451u, +1327394015u, 2743592929u, +2638154051u, 810082938u, +3077742128u, 1062268187u, +4084325664u, 3810665822u, +3735739145u, 2794294783u, +2335576331u, 2560479831u, +690240711u, 997658837u, +2442302747u, 3948961926u, +3958366652u, 3067277639u, +2059157774u, 1211737169u, +1516711748u, 2339636583u, +4188504038u, 59581167u, +2767897792u, 1389679610u, +2658147000u, 2643979752u, +3758739543u, 4189944477u, +1454470782u, 100876854u, +2995362413u, 118817200u, +3252925478u, 2062343506u, +2804483644u, 3088828656u, +1231633714u, 4168280671u, +2931588131u, 3284356565u, +1255909792u, 3130054947u, +4173605289u, 1407328702u, +1677744031u, 3532596884u, +3162657845u, 3887208531u, +2256541290u, 3459463480u, +3740979556u, 259034107u, +392987633u, 3233195759u, +3606709555u, 3424793077u, +315836068u, 3200749877u, +4065431359u, 760633989u, +2982018998u, 1811050648u, +234531934u, 1115203611u, +3897494162u, 1516407838u, +1603559457u, 323296368u, +2632963283u, 1778459926u, +2879836826u, 2146672889u, +3486330348u, 492621815u, +1231665285u, 2457048126u, +3438440082u, 2217471853u, +3355404249u, 3275550588u, +1052645068u, 862072556u, +4110617119u, 3745267835u, +2657392572u, 4279236653u, +1688445808u, 701920051u, +956734128u, 581695350u, +3157862788u, 2585726058u, +1192588249u, 1410111809u, +1651193125u, 3326135446u, +1073280453u, 97376972u, +2513844237u, 2187968410u, +3976859649u, 4267859263u, +3429034542u, 564493077u, +3000537321u, 479241367u, +3845637831u, 2868987960u, +51544337u, 1029173765u, +393624922u, 704325635u, +2357610553u, 1418509533u, +2007814586u, 3866658271u, +3082385053u, 735688735u, +916110004u, 3283299459u, +1051684175u, 1083796807u, +4074716319u, 813690332u, +144264390u, 1439630796u, +1508556987u, 675582689u, +3748881891u, 3195309868u, +362884708u, 1616408198u, +43233176u, 837301135u, +881504822u, 3254795114u, +1385506591u, 2799925823u, +1469874582u, 3464841997u, +497175391u, 3929484338u, +3975771289u, 1798536177u, +2926265846u, 1374242438u, +3675707838u, 4205965408u, +3153165629u, 1499475160u, +187287713u, 548490821u, +3255259608u, 4247675634u, +1940181471u, 3779953975u, +687167150u, 2319566715u, +1742785722u, 785893184u, +2296977392u, 2778575413u, +1794720651u, 48131484u, +4084891412u, 1160134629u, +3737623280u, 823113169u, +3423207646u, 3803213486u, +710625654u, 4116162021u, +3693420287u, 4167766971u, +1666602807u, 295320990u, +3513255468u, 2487440590u, +234080704u, 4004655503u, +2971762528u, 1479656873u, +4090178629u, 4044418876u, +391947536u, 1462554406u, +3909295855u, 1239580330u, +1515601363u, 2011102035u, +1442068334u, 4265993528u, +1191921695u, 2291355695u, +4257172787u, 576405853u, +314332944u, 4038839101u, +55559918u, 2378985842u, +711098718u, 2425317635u, +1644327317u, 1401013391u, +4193760037u, 2958260436u, +3167371443u, 3062418115u, +3800755475u, 3167030094u, +3489648204u, 1405430357u, +526177822u, 2602636307u, +915406019u, 4264167741u, +1484090483u, 3070944737u, +254529415u, 4017058800u, +1702710265u, 1029665228u, +2000382906u, 3185573940u, +1381258384u, 4036354071u, +2900841028u, 2670703363u, +2921748807u, 2899069938u, +4130543625u, 688472265u, +4186808827u, 1054670286u, +1132985391u, 2840525968u, +4175776103u, 338058159u, +1735964501u, 1539305024u, +3497121710u, 1568260669u, +2227290760u, 146827036u, +3977176001u, 4060134777u, +857488494u, 250055052u, +4284109679u, 2502815838u, +2592281721u, 1603444633u, +1390562014u, 1556658131u, +616327404u, 2448966429u, +3051191726u, 3891353218u, +1213304082u, 762328245u, +2239052397u, 1082330589u, +2455957292u, 201837927u, +405397452u, 3079886794u, +2583939798u, 2848283092u, +3750724631u, 883849006u, +3204198988u, 3341327098u, +1855234968u, 1982110346u, +1485529487u, 541496720u, +4117290321u, 3607433551u, +2168864636u, 133643215u, +1055817409u, 3847827123u, +2960769387u, 4046101649u, +1176127003u, 4015671361u, +4243643405u, 2849988118u, +517111221u, 1796672358u, +2045051700u, 3452457457u, +2948254999u, 2102063419u, +1556410577u, 1536380876u, +3776661467u, 3281002516u, +1735616066u, 1539151988u, +1087795162u, 3332431596u, +685631442u, 1147951686u, +95237878u, 2005032160u, +4012206915u, 4224354805u, +3204999386u, 2415262714u, +1433635018u, 116647396u, +83167836u, 2881562655u, +2729416454u, 1029284767u, +881378302u, 2159170082u, +555057366u, 1169104445u, +3963877000u, 1919171906u, +336034862u, 2017579106u, +4059340529u, 3020819343u, +865146997u, 2473524405u, +944743644u, 1694443528u, +1804513294u, 2904752429u, +617975720u, 3671562289u, +260177668u, 505662155u, +1885941445u, 2504509403u, +2260041112u, 1019936943u, +3722741628u, 1511077569u, +3100701179u, 1379422864u, +1535670711u, 773792826u, +1103819072u, 2089123665u, +1157547425u, 329152940u, +4142587430u, 484732447u, +2475035432u, 1120017626u, +412145504u, 965125959u, +324924679u, 2809286837u, +2842141483u, 4029205195u, +2974306813u, 515627448u, +3791551981u, 1097806406u, +3873078673u, 136118734u, +1872130856u, 3632422367u, +3574135531u, 4017075736u, +1699452298u, 1403506686u, +344414660u, 1189129691u, +3487080616u, 1516736273u, +1805475756u, 2562064338u, +163335594u, 2732147834u, +4077452507u, 2984955003u, +4271866024u, 3071338162u, +2347111903u, 873829983u, +1948409509u, 1923531348u, +459509140u, 771592405u, +1750124750u, 2334938333u, +213811117u, 2586632018u, +185232757u, 4032960199u, +2447383637u, 284777551u, +1654276320u, 2687561076u, +3512945009u, 308584855u, +1861027147u, 4102279334u, +3203802620u, 1692079268u, +4250142168u, 2565680167u, +1507046104u, 841195925u, +520565830u, 3674576684u, +38924274u, 3770488806u, +2414430882u, 3978473838u, +3703994407u, 69201295u, +3099963860u, 1255084262u, +690971838u, 3539996781u, +3696902571u, 3593730713u, +2363435042u, 54945052u, +1785765213u, 184911581u, +1586241476u, 1939595371u, +2534883189u, 2432427547u, +2374171993u, 2039128933u, +2955715987u, 2295501078u, +2741583197u, 1280920000u, +686818699u, 1238742497u, +3843660102u, 82177963u, +1281043691u, 1121403845u, +1697846708u, 284852964u, +278661677u, 2889101923u, +2127558730u, 713121337u, +872502474u, 511142139u, +1261140657u, 1747052377u, +2108187161u, 927011680u, +955328267u, 3821994995u, +2707230761u, 4142246789u, +4134691985u, 1958963937u, +2498463509u, 1977988705u, +1419293714u, 1636932722u, +2567532373u, 4075249328u, +240575705u, 1956681213u, +2598802768u, 2025886508u, +4104757832u, 3026358429u, +3242615202u, 4026813725u, +255108733u, 1845587644u, +3573008472u, 3615577014u, +1222733548u, 1205557630u, +917608574u, 1363253259u, +1541946015u, 3087190425u, +1138008081u, 1444019663u, +109793386u, 341851980u, +857839960u, 2515339233u, +156283211u, 1906768669u, +3886713057u, 1276595523u, +2809830736u, 460237542u, +3420452099u, 142985419u, +205970448u, 4198897105u, +1950698961u, 2069753399u, +1142216925u, 1113051162u, +1033680610u, 4278599955u, +1106466069u, 356742959u, +531521052u, 3494863964u, +225629455u, 3735275001u, +3662626864u, 1750561299u, +1012864651u, 2101846429u, +1074553219u, 668829411u, +992181339u, 3384018814u, +3330664522u, 860966321u, +1885071395u, 4233785523u, +100741310u, 451656820u, +2148187612u, 1063001151u, +360256231u, 107312677u, +3650357479u, 2390172694u, +22452685u, 237319043u, +3600462351u, 1216645846u, +2088767754u, 164402616u, +2418980170u, 926137824u, +94638678u, 1689811113u, +2751052984u, 1767810825u, +271289013u, 3896132233u, +103797041u, 1397772514u, +3441135892u, 3323383489u, +2491268371u, 1662561885u, +1612872497u, 2986430557u, +2756998822u, 207428029u, +937973965u, 2791656726u, +1949717207u, 2260498180u, +2648427775u, 2360400900u, +2080496169u, 486358863u, +1582022990u, 1263709570u, +1396468647u, 1377764574u, +363008508u, 1293502429u, +224580012u, 4252610345u, +1435134775u, 1099809675u, +533671980u, 1533438766u, +1820532305u, 2776960536u, +3374512975u, 3542220540u, +822810075u, 3716663290u, +1157398049u, 3752806924u, +4081637863u, 337070226u, +3866585976u, 359270190u, +2110942730u, 3267551635u, +644850146u, 1306761320u, +746972907u, 934259457u, +2341378668u, 2220373824u, +1242645122u, 4109252858u, +1625266099u, 1173698481u, +383517064u, 896322512u, +3377483696u, 1788337208u, +455496839u, 3194373887u, +1837689083u, 1336556841u, +1658628529u, 2911512007u, +3838343487u, 2757664765u, +1537187340u, 3712582785u, +367022558u, 3071359622u, +3926147070u, 35432879u, +3093195926u, 2561488770u, +4273132307u, 3898950547u, +2838251049u, 2103926083u, +2549435227u, 536047554u, +1858986613u, 2040551642u, +1147412575u, 1972369852u, +4166184983u, 3528794619u, +4077477194u, 3565689036u, +808048238u, 3826350461u, +1359641525u, 1197100813u, +265993036u, 1864569342u, +725164342u, 2264788336u, +1831223342u, 3329594980u, +923017956u, 490608221u, +3818634478u, 258154469u, +1441714797u, 1174785921u, +3833372385u, 3287246572u, +1677395563u, 3569218731u, +868981704u, 2163330264u, +2649450292u, 500120236u, +465161780u, 746438382u, +1145009669u, 2520062970u, +2810524030u, 1561519055u, +1479878006u, 3864969305u, +2686075657u, 4042710240u, +3224066062u, 2774151984u, +2226179547u, 1643626042u, +2328730865u, 3160666939u, +2107011431u, 96459446u, +3920328742u, 3336407558u, +829404209u, 1878067032u, +1235983679u, 4237425634u, +466519055u, 3870676863u, +934312076u, 2952135524u, +276949224u, 4100839753u, +424001484u, 1955120893u, +4015478120u, 1265237690u, +427484362u, 4246879223u, +3452969617u, 1724363362u, +1553513184u, 834830418u, +1858777639u, 3476334357u, +4144030366u, 2450047160u, +2950762705u, 4277111759u, +358032121u, 2511026735u, +167923105u, 2059208280u, +251949572u, 3065234219u, +1535473864u, 556796152u, +1513237478u, 3150857516u, +1103404394u, 198182691u, +1476438092u, 2913077464u, +207119516u, 3963810232u, +2954651680u, 1535115487u, +3051522276u, 4046477658u, +917804636u, 864395565u, +632704095u, 140762681u, +1802040304u, 990407433u, +3771506212u, 4106024923u, +1287729497u, 2198985327u, +4052924496u, 2926590471u, +3084557148u, 1472898694u, +1009870118u, 559702706u, +4265214507u, 82077489u, +3067891003u, 3295678907u, +2402308151u, 1096697687u, +464407878u, 4190838199u, +4269578403u, 3060919438u, +2899950405u, 3046872820u, +733509243u, 1583801700u, +40453902u, 3879773881u, +1993425202u, 2185339100u, +1877837196u, 3912423882u, +3293122640u, 4104318469u, +1679617763u, 3703603898u, +8759461u, 2540185277u, +1152198475u, 2038345882u, +2503579743u, 1446869792u, +2019419351u, 4051584612u, +3178289407u, 3992503830u, +2879018745u, 2719373510u, +700836153u, 1675560450u, +4121245793u, 2064715719u, +343595772u, 1996164093u, +3130433948u, 405251683u, +2804817126u, 1607133689u, +463852893u, 2864244470u, +2224044848u, 4071581802u, +2537107938u, 2246347953u, +3207234525u, 2028708916u, +2272418128u, 803575837u, +38655481u, 2170452091u, +3272166407u, 557660441u, +4019147902u, 3841480082u, +298459606u, 2600943364u, +2440657523u, 255451671u, +3424361375u, 779434428u, +3088526123u, 490671625u, +1322855877u, 3452203069u, +3057021940u, 2285701422u, +2014993457u, 2390431709u, +2002090272u, 1568745354u, +1783152480u, 823305654u, +4053862835u, 2200236540u, +3009412313u, 3184047862u, +3032187389u, 4159715581u, +2966902888u, 252986948u, +1849329144u, 3160134214u, +3420960112u, 3198900547u, +749160960u, 379139040u, +1208883495u, 1566527339u, +3006227299u, 4194096960u, +556075248u, 497404038u, +1717327230u, 1496132623u, +1775955687u, 1719108984u, +1014328900u, 4189966956u, +2108574735u, 2584236470u, +684087286u, 531310503u, +4264509527u, 773405691u, +3088905079u, 3456882941u, +3105682208u, 3382290593u, +2289363624u, 3296306400u, +4168438718u, 467441309u, +777173623u, 3241407531u, +1183994815u, 1132983260u, +1610606159u, 2540270567u, +2649684057u, 1397502982u, +146657385u, 3318434267u, +2109315753u, 3348545480u, +3193669211u, 811750340u, +1073256162u, 3571673088u, +546596661u, 1017047954u, +3403136990u, 2540585554u, +1477047647u, 4145867423u, +2826408201u, 3531646869u, +784952939u, 943914610u, +2717443875u, 3657384638u, +1806867885u, 1903578924u, +3985088434u, 1911188923u, +1764002686u, 3672748083u, +1832925325u, 241574049u, +519948041u, 3181425568u, +2939747257u, 1634174593u, +3429894862u, 3529565564u, +1089679033u, 240953857u, +2025369941u, 2695166650u, +517086873u, 2964595704u, +3017658263u, 3828377737u, +2144895011u, 994799311u, +1184683823u, 4260564140u, +308018483u, 4262383425u, +1374752558u, 3431057723u, +1572637805u, 383233885u, +3188015819u, 4051263539u, +233319221u, 3794788167u, +2017406667u, 919677938u, +4074952232u, 1683612329u, +4213676186u, 327142514u, +3032591014u, 4204155962u, +206775997u, 2283918569u, +2395147154u, 3427505379u, +2211319468u, 4153726847u, +2217060665u, 350160869u, +2493667051u, 1648200185u, +3441709766u, 1387233546u, +140980u, 1891558063u, +760080239u, 2088061981u, +1580964938u, 740563169u, +422986366u, 330624974u, +4264507722u, 150928357u, +2738323042u, 2948665536u, +918718096u, 376390582u, +3966098971u, 717653678u, +3219466255u, 3799363969u, +3424344721u, 3187805406u, +375347278u, 3490350144u, +1992212097u, 2263421398u, +3855037968u, 1928519266u, +3866327955u, 1129127000u, +1782515131u, 2746577402u, +3059200728u, 2108753646u, +2738070963u, 1336849395u, +1705302106u, 768287270u, +1343511943u, 2247006571u, +1956142255u, 1780259453u, +3475618043u, 212490675u, +622521957u, 917121602u, +1852992332u, 1267987847u, +3170016833u, 2549835613u, +3299763344u, 2864033668u, +3378768767u, 1236609378u, +4169365948u, 3738062408u, +2661022773u, 2006922227u, +2760592161u, 3828932355u, +2636387819u, 2616619070u, +1237256330u, 3449066284u, +2871755260u, 3729280948u, +3862686086u, 431292293u, +3285899651u, 786322314u, +2531158535u, 724901242u, +2377363130u, 1415970351u, +1244759631u, 3263135197u, +965248856u, 174024139u, +2297418515u, 2954777083u, +987586766u, 3206261120u, +4059515114u, 3903854066u, +1931934525u, 2287507921u, +1827135136u, 1781944746u, +574617451u, 2299034788u, +2650140034u, 4081586725u, +2482286699u, 1109175923u, +458483596u, 618705848u, +4059852729u, 1813855658u, +4190721328u, 1129462471u, +4089998050u, 3575732749u, +2375584220u, 1037031473u, +1623777358u, 3389003793u, +546597541u, 352770237u, +1383747654u, 3122687303u, +1646071378u, 1164309901u, +290870767u, 830691298u, +929335420u, 3193251135u, +989577914u, 3626554867u, +591974737u, 3996958215u, +3163711272u, 3071568023u, +1516846461u, 3656006011u, +2698625268u, 2510865430u, +340274176u, 1167681812u, +3698796465u, 3155218919u, +4102288238u, 1673474350u, +3069708839u, 2704165015u, +1237411891u, 1854985978u, +3646837503u, 3625406022u, +921552000u, 1712976649u, +3939149151u, 878608872u, +3406359248u, 1068844551u, +1834682077u, 4155949943u, +2437686324u, 3163786257u, +2645117577u, 1988168803u, +747285578u, 1626463554u, +1235300371u, 1256485167u, +1914142538u, 4141546431u, +3838102563u, 582664250u, +1883344352u, 2083771672u, +2611657933u, 2139079047u, +2250573853u, 804336148u, +3066325351u, 2770847216u, +4275641370u, 1455750577u, +3346357270u, 1674051445u, +601221482u, 3992583643u, +1402445097u, 3622527604u, +2509017299u, 2966108111u, +2557027816u, 900741486u, +1790771021u, 2912643797u, +2631381069u, 4014551783u, +90375300u, 300318232u, +3269968032u, 2679371729u, +2664752123u, 3517585534u, +3253901179u, 542270815u, +1188641600u, 365479232u, +2210121140u, 760762191u, +1273768482u, 1216399252u, +3484324231u, 4287337666u, +16322182u, 643179562u, +325675502u, 3652676161u, +3120716054u, 3330259752u, +1011990087u, 2990167340u, +1097584090u, 3262252593u, +1829409951u, 3665087267u, +1214854475u, 2134299399u, +3704419305u, 411263051u, +1625446136u, 549838529u, +4283196353u, 1342880802u, +3460621305u, 1967599860u, +4282843369u, 1275671016u, +2544665755u, 853593042u, +901109753u, 2682611693u, +110631633u, 797487791u, +1472073141u, 850464484u, +797089608u, 3286110054u, +350397471u, 2775631060u, +366448238u, 3842907484u, +2219863904u, 3623364733u, +1850985302u, 4009616991u, +294963924u, 3693536939u, +3061255808u, 1615375832u, +1920066675u, 4113028420u, +4032223840u, 2318423400u, +2701956286u, 4145497671u, +3991532344u, 2536338351u, +1679099863u, 1728968857u, +449740816u, 2686506989u, +685242457u, 97590863u, +3258354115u, 1502282913u, +1235084019u, 2151665147u, +528459289u, 231097464u, +2477280726u, 3651607391u, +2091754612u, 1178454681u, +980597335u, 1604483865u, +1842333726u, 4146839064u, +3213794286u, 2601416506u, +754220096u, 3571436033u, +488595746u, 1448097974u, +4004834921u, 238887261u, +3320337489u, 1416989070u, +2928916831u, 4093725287u, +186020771u, 2367569534u, +3046087671u, 4090084518u, +3548184546u, 679517009u, +1962659444u, 3539886328u, +4192003933u, 1678423485u, +3827951761u, 3086277222u, +2144472852u, 1390394371u, +2976322029u, 1574517163u, +3553313841u, 119173722u, +1702434637u, 1766260771u, +3629581771u, 1407497759u, +895654784u, 751439914u, +4008409498u, 215917713u, +1482103833u, 695551833u, +1288382231u, 2656990891u, +2581779077u, 1570750352u, +3710689053u, 1741390464u, +2666411616u, 3533987737u, +4289478316u, 3576119563u, +4118694920u, 108199666u, +3869794273u, 963183826u, +2081410737u, 3796810515u, +791123882u, 2525792704u, +1036883117u, 136547246u, +875691100u, 2592925324u, +614302599u, 3013176417u, +2689342539u, 427154472u, +532957601u, 1228758574u, +1898117151u, 1181643858u, +1908591042u, 1464255968u, +446980910u, 2984611177u, +58509511u, 1046943619u, +3508927906u, 2001585786u, +2544767379u, 1525438381u, +552181222u, 1959725830u, +879448844u, 1348536411u, +4242243590u, 2861338018u, +1082052441u, 1034351453u, +601175800u, 764077711u, +530635011u, 3785343245u, +2178026726u, 117256687u, +2378297261u, 457568934u, +76438221u, 4104954272u, +956793873u, 3783168634u, +2485968477u, 2381948487u, +4226929450u, 3148473363u, +2518273601u, 3569490233u, +879369091u, 2180270337u, +3674375989u, 1387729170u, +977997984u, 4270646856u, +568650985u, 951677556u, +4213877384u, 2721005055u, +1073364549u, 2563403831u, +1678669911u, 66786703u, +2273631661u, 1149351924u, +3651298990u, 1581883443u, +246723096u, 1895026827u, +3810605772u, 3711056516u, +4058833288u, 2193790614u, +2080120290u, 3638638708u, +2915672708u, 2263003308u, +2361934197u, 4136767460u, +1976115991u, 3448840877u, +2019238520u, 225333538u, +874340815u, 2976159827u, +1555273378u, 3797521928u, +1942347150u, 3262952567u, +435997738u, 340403353u, +2817830907u, 2078619498u, +749534111u, 1178073973u, +894654712u, 3361226032u, +841092198u, 3288261538u, +1696412169u, 1496966875u, +697501571u, 1059158875u, +3739946319u, 2481012988u, +568983526u, 114945840u, +1559249010u, 2218244008u, +2841706923u, 1632780103u, +4020169654u, 2087949619u, +2438736103u, 24032648u, +833416317u, 3787017905u, +2373238993u, 2575395164u, +3434544481u, 3228481067u, +2542976862u, 2971726178u, +2880371864u, 3642087909u, +2407477975u, 2239080836u, +1043714217u, 3894199764u, +2235879182u, 203853421u, +2933669448u, 2504940536u, +834683330u, 425935223u, +3560796393u, 3565833278u, +1668000829u, 3683399154u, +3414330886u, 1748785729u, +1023171602u, 580966986u, +2531038985u, 3227325488u, +2657385925u, 2124704694u, +233442446u, 1107045577u, +3407293834u, 552770757u, +3899097693u, 1067532701u, +115667924u, 1406028344u, +1707768231u, 3724015962u, +2419657149u, 18613994u, +2532882091u, 3476683808u, +1560838678u, 811220224u, +895961699u, 3762914298u, +1328752423u, 1844996900u, +1420427894u, 1848067707u, +1210281744u, 904215228u, +4055325594u, 1118521573u, +2496554183u, 2579259919u, +3996647489u, 3657647605u, +325254059u, 3136157065u, +3951522674u, 4052925250u, +3341068436u, 2287683323u, +1313073005u, 126005630u, +2505120084u, 1194725057u, +853746559u, 3555092974u, +2689238752u, 49515858u, +1244776042u, 1069300695u, +61073168u, 1010661841u, +1269521335u, 1902040126u, +990632502u, 2378708922u, +3858321250u, 1400735275u, +2974699176u, 2771676666u, +170995186u, 2877798589u, +545726212u, 2225229957u, +1086473152u, 3454177594u, +3859483262u, 1499729584u, +2088002891u, 2883475137u, +3222194252u, 4144472319u, +2212229854u, 4146740722u, +567988835u, 1051332394u, +3932046135u, 542648229u, +3017852446u, 1277887997u, +162888005u, 1669710469u, +1492500905u, 553041029u, +1434876932u, 533989516u, +3817492747u, 584127807u, +4147115982u, 2993670925u, +4020312558u, 710021255u, +3509733475u, 3587959456u, +2088550465u, 1745399498u, +2952242967u, 1259815443u, +869648362u, 1404723176u, +3947542735u, 1334333531u, +3873471582u, 229399758u, +59634866u, 3239516985u, +3844250972u, 1275954779u, +492891666u, 1029533080u, +1552951157u, 367320647u, +699480890u, 3684418197u, +3707014310u, 471105777u, +1824587258u, 4030809053u, +3489914436u, 484559105u, +1235750398u, 1428453396u, +4230459084u, 4255931645u, +1848597055u, 4271715616u, +331780381u, 482425775u, +2435323270u, 3171911678u, +3507210587u, 928543347u, +4197807526u, 3680046204u, +2766042024u, 2159512867u, +179373257u, 313902234u, +4024837592u, 294795361u, +1622282562u, 647086234u, +2825039429u, 577214736u, +4043412446u, 2426981244u, +1277736097u, 1130129573u, +2601395338u, 995791646u, +36668922u, 3344746679u, +1521532225u, 1645086060u, +2622763015u, 4122335794u, +2936887705u, 494465807u, +2580840343u, 1064648931u, +1247887787u, 2752145076u, +1277612417u, 1249660507u, +2288678613u, 3312498873u, +2459273912u, 4238535494u, +3117488020u, 2571979978u, +2680188909u, 1471227427u, +1616494033u, 633688562u, +2268653416u, 3268237290u, +3021962815u, 1959779970u, +3321382074u, 766642813u, +204429780u, 1323319858u, +3676032891u, 1380896111u, +4030639049u, 3647601207u, +1830028502u, 2830263774u, +1375962216u, 1733961041u, +939765180u, 521947915u, +3903267364u, 497472767u, +1619700946u, 189164145u, +3115593885u, 486382294u, +1262445920u, 4062496162u, +2464795849u, 3770038872u, +4032121374u, 3235740744u, +3757765258u, 1777199847u, +2167243108u, 1912506671u, +4180515317u, 2276864677u, +536034089u, 2384915026u, +162938278u, 1588060152u, +4018349945u, 2504457929u, +841450426u, 2790120722u, +2719983588u, 1471020554u, +1390856732u, 3623212998u, +2506944218u, 1035080801u, +348812127u, 3026631806u, +746483541u, 2342164722u, +122104390u, 4074122771u, +3986865419u, 1674890530u, +3693306023u, 3011542850u, +1294951725u, 899303190u, +3577146915u, 3549160092u, +1241677652u, 4290680005u, +3193053279u, 2029187390u, +3298063095u, 3943068002u, +3946220635u, 2273781461u, +889053698u, 1376304022u, +1486839612u, 2127663659u, +344127443u, 1646681121u, +2780117810u, 2142045764u, +2694572773u, 447810651u, +2185527146u, 2366308558u, +290335413u, 584901173u, +2012370276u, 970504950u, +3258236042u, 2008155560u, +3945579565u, 614796295u, +24452072u, 2695940969u, +3983727134u, 3444688454u, +1327044473u, 3545633451u, +1875293322u, 1739318893u, +1707527799u, 2683090634u, +2848082386u, 2814622471u, +4111401777u, 2774816580u, +3849839194u, 437560100u, +2238350150u, 2462124836u, +665017710u, 512012738u, +2945294779u, 3305170944u, +819477765u, 59419271u, +155125658u, 665292744u, +444722813u, 3580039116u, +2355675635u, 663735032u, +3247800169u, 1579404983u, +1985115003u, 3397891494u, +358696453u, 1474896279u, +516388613u, 710590371u, +3490497111u, 2514565805u, +2386143445u, 477509654u, +412854590u, 3624609754u, +3214388668u, 3516075816u, +2731288520u, 1369482895u, +4033204378u, 1314000850u, +829769325u, 1935166880u, +1608191643u, 2607067237u, +423820371u, 3257747610u, +1355298041u, 3776931214u, +4105054901u, 2107080812u, +1911521879u, 3183054185u, +3910177801u, 675129307u, +1209358971u, 4205727791u, +1435726287u, 3333261712u, +1400982708u, 1154611403u, +1663501483u, 2837596667u, +3164734053u, 2759854023u, +4012043629u, 1963228038u, +3981675284u, 2677557877u, +520119591u, 505138315u, +897271356u, 1803966773u, +1016663294u, 616691903u, +2254742522u, 4032705384u, +2468470796u, 798395739u, +3025169002u, 3570037122u, +1461093710u, 3473799845u, +3702624858u, 476400898u, +1043039728u, 2304070437u, +181576948u, 602972493u, +3996616030u, 3289878097u, +2068516226u, 3922247304u, +1299968266u, 2520311409u, +1968824721u, 3214794876u, +1581813122u, 2668800905u, +3297613974u, 748160407u, +1145536484u, 1326769504u, +2973323521u, 3775262814u, +3218653169u, 902775872u, +3498603433u, 1372805534u, +704686363u, 3626542352u, +2271580579u, 1213925114u, +46329775u, 3009384989u, +1330254048u, 1194824134u, +514204310u, 3781981134u, +442526164u, 2835608783u, +3460471867u, 510634034u, +546406434u, 2716786748u, +2840500021u, 1669490957u, +2536189149u, 3251421224u, +1358736072u, 1089334066u, +3260749330u, 250756920u, +2974806681u, 1513718866u, +82635635u, 4041016629u, +3391765744u, 2495807367u, +3962674316u, 2822889695u, +753413337u, 2008251381u, +3123390177u, 106212622u, +490570565u, 1684884205u, +793892547u, 1927268995u, +2344148164u, 2251978818u, +437424236u, 2774023200u, +2674940754u, 3788056262u, +2597882666u, 3678660147u, +3797434193u, 3838215866u, +279687080u, 2656772270u, +2190204787u, 1997584981u, +3384401882u, 3160208845u, +3629379425u, 2668998785u, +1050036757u, 2954162084u, +917091826u, 1744374041u, +1454282570u, 845687881u, +2997173625u, 776018378u, +1137560602u, 1938378389u, +1748082354u, 2066910012u, +2677675207u, 918315064u, +}; + +// Return false only if offset is -1 and a spot check of 3 hashes all yield 0. +bool Test(int offset, int len = 0) { +#undef Check +#undef IsAlive + +#define Check(x) do { \ + const uint32_t actual = (x), e = expected[index++]; \ + bool ok = actual == e; \ + if (!ok) { \ + cerr << "expected " << hex << e << " but got " << actual << endl; \ + ++errors; \ + } \ + assert(ok); \ +} while (0) + +#define IsAlive(x) do { alive += IsNonZero(x); } while (0) + + // After the following line is where the uses of "Check" and such will go. + static int index = 0; +if (offset == -1) { int alive = 0; { uint64_t h = farmhashte::Hash64WithSeeds(data, len++, SEED0, SEED1); IsAlive(h >> 32); IsAlive((h << 32) >> 32); } { uint64_t h = farmhashte::Hash64WithSeed(data, len++, SEED); IsAlive(h >> 32); IsAlive((h << 32) >> 32); } { uint64_t h = farmhashte::Hash64(data, len++); IsAlive(h >> 32); IsAlive((h << 32) >> 32); } len -= 3; return alive > 0; } +{ uint64_t h = farmhashte::Hash64WithSeeds(data + offset, len, SEED0, SEED1); Check(h >> 32); Check((h << 32) >> 32); } +{ uint64_t h = farmhashte::Hash64WithSeed(data + offset, len, SEED); Check(h >> 32); Check((h << 32) >> 32); } +{ uint64_t h = farmhashte::Hash64(data + offset, len); Check(h >> 32); Check((h << 32) >> 32); } + + return true; +#undef Check +#undef IsAlive +} + +int RunTest() { + Setup(); + int i = 0; + cout << "Running farmhashteTest"; + if (!Test(-1)) { + cout << "... Unavailable\n"; + return NoteErrors(); + } + // Good. The function is attempting to hash, so run the full test. + int errors_prior_to_test = errors; + for ( ; i < kTestSize - 1; i++) { + Test(i * i, i); + } + for ( ; i < kDataSize; i += i / 7) { + Test(0, i); + } + Test(0, kDataSize); + cout << (errors == errors_prior_to_test ? "... OK\n" : "... Failed\n"); + return NoteErrors(); +} + +#else + +// After the following line is where the code to print hash codes will go. +void Dump(int offset, int len) { +{ uint64_t h = farmhashte::Hash64WithSeeds(data + offset, len, SEED0, SEED1); cout << (h >> 32) << "u, " << ((h << 32) >> 32) << "u," << endl; } +{ uint64_t h = farmhashte::Hash64WithSeed(data + offset, len, SEED); cout << (h >> 32) << "u, " << ((h << 32) >> 32) << "u," << endl; } +{ uint64_t h = farmhashte::Hash64(data + offset, len); cout << (h >> 32) << "u, " << ((h << 32) >> 32) << "u," << endl; } +} + +#endif + +#undef SEED +#undef SEED1 +#undef SEED0 + +} // namespace farmhashteTest + +#if !TESTING +int main(int argc, char** argv) { + Setup(); + cout << "uint32_t expected[] = {\n"; + int i = 0; + for ( ; i < kTestSize - 1; i++) { + farmhashteTest::Dump(i * i, i); + } + for ( ; i < kDataSize; i += i / 7) { + farmhashteTest::Dump(0, i); + } + farmhashteTest::Dump(0, kDataSize); + cout << "};\n"; +} +#endif +#ifndef FARMHASH_SELF_TEST_GUARD +#define FARMHASH_SELF_TEST_GUARD +#include +#include +#include + +using std::cout; +using std::cerr; +using std::endl; +using std::hex; + +static const uint64_t kSeed0 = 1234567; +static const uint64_t kSeed1 = k0; +static const int kDataSize = 1 << 20; +static const int kTestSize = 300; +#define kSeed128 Uint128(kSeed0, kSeed1) + +static char data[kDataSize]; + +static int completed_self_tests = 0; +static int errors = 0; + +// Initialize data to pseudorandom values. +void Setup() { + if (completed_self_tests == 0) { + uint64_t a = 9; + uint64_t b = 777; + for (int i = 0; i < kDataSize; i++) { + a += b; + b += a; + a = (a ^ (a >> 41)) * k0; + b = (b ^ (b >> 41)) * k0 + i; + uint8_t u = b >> 37; + memcpy(data + i, &u, 1); // uint8_t -> char + } + } +} + +int NoteErrors() { +#define NUM_SELF_TESTS 9 + if (++completed_self_tests == NUM_SELF_TESTS) + std::exit(errors > 0); + return errors; +} + +template inline bool IsNonZero(T x) { + return x != 0; +} + +template <> inline bool IsNonZero(uint128_t x) { + return x != Uint128(0, 0); +} + +#endif // FARMHASH_SELF_TEST_GUARD + +namespace farmhashuoTest { + +uint32_t CreateSeed(int offset, int salt) { + uint32_t h = static_cast(salt & 0xffffffff); + h = h * c1; + h ^= (h >> 17); + h = h * c1; + h ^= (h >> 17); + h = h * c1; + h ^= (h >> 17); + h += static_cast(offset & 0xffffffff); + h = h * c1; + h ^= (h >> 17); + h = h * c1; + h ^= (h >> 17); + h = h * c1; + h ^= (h >> 17); + return h; +} + +#undef SEED +#undef SEED1 +#undef SEED0 +#define SEED CreateSeed(offset, -1) +#define SEED0 CreateSeed(offset, 0) +#define SEED1 CreateSeed(offset, 1) + +#undef TESTING +#define TESTING 1 +#if TESTING +uint32_t expected[] = { +3277735313u, 2681724312u, +2598464059u, 797982799u, +2603993599u, 921001710u, +1410420968u, 2134990486u, +2914424215u, 2244477846u, +255297188u, 2992121793u, +161451183u, 3943596029u, +4019337850u, 452431531u, +3379021470u, 2557197665u, +299850021u, 2532580744u, +1298374911u, 3099673830u, +2199864459u, 3696623795u, +4055299123u, 3281581178u, +1053458494u, 1882212500u, +3456121707u, 275903667u, +458884671u, 3033004529u, +1898235244u, 1402319660u, +2700149065u, 2699376854u, +2433714046u, 4222949502u, +4220361840u, 1712034059u, +4148372108u, 1330324210u, +594028478u, 2921867846u, +780716741u, 1728752234u, +3280331829u, 326029180u, +393215742u, 3349570000u, +3824583307u, 1612122221u, +1379537552u, 1646032583u, +2233466664u, 1432476832u, +2052294713u, 3552092450u, +1628777059u, 1499109081u, +2960536756u, 1554038301u, +1145519619u, 3190844552u, +237495366u, 540224401u, +65721842u, 489963606u, +1596489240u, 1562872448u, +1790705123u, 2128624475u, +1435705557u, 1262831810u, +155445229u, 1672724608u, +663607706u, 2077310004u, +3610042449u, 1911523866u, +2563776023u, 294527927u, +1099072299u, 1389770549u, +2952353448u, 2026137563u, +3603803785u, 629449419u, +226132789u, 2489287368u, +1552847036u, 645684964u, +187883449u, 230403464u, +3151491850u, 3272648435u, +2002861219u, 165370827u, +916494250u, 1230085527u, +3807265751u, 3628174014u, +231181488u, 851743255u, +2988893883u, 1554380634u, +1142264800u, 3667013118u, +2638023604u, 2290487377u, +732137533u, 1909203251u, +1380301172u, 1498556724u, +4072067757u, 4165088768u, +3931792696u, 197618179u, +956300927u, 914413116u, +2148126371u, 1913303225u, +3074915312u, 3117299654u, +3178848746u, 1357272220u, +1438494951u, 507436733u, +3854939912u, 1413396341u, +126024219u, 146044391u, +3254014218u, 429095991u, +165589978u, 1578546616u, +623071693u, 366414107u, +249776086u, 1207522198u, +3120876698u, 1684583131u, +46987739u, 1157614300u, +199124911u, 520792961u, +3614377032u, 586863115u, +1716848157u, 4033596884u, +1164298657u, 4140791139u, +3824360466u, 3242407770u, +3725511003u, 232064808u, +2736953692u, 816692935u, +512845449u, 3748861010u, +4290630595u, 517646945u, +22638523u, 648000590u, +1283799121u, 3047062993u, +1024246061u, 4027776454u, +834785312u, 382936554u, +411505255u, 1973395102u, +580988377u, 2826990641u, +3474970689u, 1029055034u, +2584372201u, 1758123094u, +589567754u, 325737734u, +3886113119u, 3338548567u, +257578986u, 3698087965u, +3604937815u, 3198590202u, +2305332220u, 191910725u, +4244322689u, 542201663u, +3315355162u, 2135941665u, +1175961330u, 3948351189u, +23075771u, 3252374102u, +713127376u, 1467786451u, +663013031u, 3444053918u, +3077742128u, 1062268187u, +2115441882u, 4081398201u, +2335576331u, 2560479831u, +1379288194u, 4225182569u, +3958366652u, 3067277639u, +3667516477u, 1709989541u, +4188504038u, 59581167u, +2725013602u, 3639843023u, +3758739543u, 4189944477u, +2470483982u, 877580602u, +3252925478u, 2062343506u, +3981838403u, 3762572073u, +2931588131u, 3284356565u, +1129162571u, 732225574u, +1677744031u, 3532596884u, +3232041815u, 1652884780u, +3740979556u, 259034107u, +2227121257u, 1426140634u, +315836068u, 3200749877u, +1386256573u, 24035717u, +234531934u, 1115203611u, +1598686658u, 3146815575u, +2632963283u, 1778459926u, +739944537u, 579625482u, +1231665285u, 2457048126u, +3903349120u, 389846205u, +1052645068u, 862072556u, +2834153464u, 1481069623u, +1688445808u, 701920051u, +3740748788u, 3388062747u, +1192588249u, 1410111809u, +2633463887u, 4050419847u, +2513844237u, 2187968410u, +2951683019u, 3015806005u, +3000537321u, 479241367u, +252167538u, 1231057113u, +393624922u, 704325635u, +1467197045u, 2066433573u, +3082385053u, 735688735u, +956434529u, 4028590195u, +4074716319u, 813690332u, +2124740535u, 804073145u, +3748881891u, 3195309868u, +841856605u, 2585865274u, +881504822u, 3254795114u, +1241815736u, 970796142u, +497175391u, 3929484338u, +4264993211u, 1835322201u, +3675707838u, 4205965408u, +300298607u, 3858319990u, +3255259608u, 4247675634u, +1095823272u, 1197245408u, +1742785722u, 785893184u, +1702965674u, 850401405u, +4084891412u, 1160134629u, +2555998391u, 1972759056u, +710625654u, 4116162021u, +3352753742u, 85121177u, +3513255468u, 2487440590u, +2480032715u, 2287747045u, +4090178629u, 4044418876u, +1703944517u, 486290428u, +1515601363u, 2011102035u, +573985957u, 3536053779u, +4257172787u, 576405853u, +1523550693u, 1014952061u, +711098718u, 2425317635u, +3460807169u, 3688987163u, +3167371443u, 3062418115u, +3330028292u, 1713171303u, +526177822u, 2602636307u, +1245357025u, 3346699703u, +254529415u, 4017058800u, +1829738451u, 2164236533u, +1381258384u, 4036354071u, +1749181924u, 4118435443u, +4130543625u, 688472265u, +2731071299u, 2547657502u, +4175776103u, 338058159u, +3729582129u, 4181845558u, +2227290760u, 146827036u, +2459178427u, 1025353883u, +4284109679u, 2502815838u, +825124804u, 2533140036u, +616327404u, 2448966429u, +413992636u, 2334782461u, +2239052397u, 1082330589u, +3381164715u, 199381437u, +2583939798u, 2848283092u, +2300168091u, 2156336315u, +1855234968u, 1982110346u, +2482046810u, 3158163887u, +2168864636u, 133643215u, +3904021624u, 3646514568u, +1176127003u, 4015671361u, +100525019u, 3534706803u, +2045051700u, 3452457457u, +1492267772u, 2308393828u, +3776661467u, 3281002516u, +4246334524u, 743955039u, +685631442u, 1147951686u, +2040912376u, 2911148054u, +3204999386u, 2415262714u, +313209105u, 777065474u, +2729416454u, 1029284767u, +1632078298u, 1817552554u, +3963877000u, 1919171906u, +3843219958u, 3073580867u, +865146997u, 2473524405u, +2593817617u, 3643076308u, +617975720u, 3671562289u, +121812599u, 2902367378u, +2260041112u, 1019936943u, +320945955u, 2337845588u, +1535670711u, 773792826u, +3152195900u, 4090794518u, +4142587430u, 484732447u, +419191319u, 3377973345u, +324924679u, 2809286837u, +1562277603u, 1378362199u, +3791551981u, 1097806406u, +1386297408u, 2304900033u, +3574135531u, 4017075736u, +1161238398u, 1358056883u, +3487080616u, 1516736273u, +851615042u, 2927899494u, +4077452507u, 2984955003u, +3907754394u, 3578173844u, +1948409509u, 1923531348u, +3578472493u, 3710074193u, +213811117u, 2586632018u, +1922589216u, 274958014u, +1654276320u, 2687561076u, +2569061755u, 3122046057u, +3203802620u, 1692079268u, +477806878u, 140587742u, +520565830u, 3674576684u, +91246882u, 1010215946u, +3703994407u, 69201295u, +776213083u, 3677771507u, +3696902571u, 3593730713u, +2907901228u, 3239753796u, +1586241476u, 1939595371u, +2268396558u, 3468719670u, +2955715987u, 2295501078u, +2775848696u, 1358532390u, +3843660102u, 82177963u, +4094477877u, 191727221u, +278661677u, 2889101923u, +1352525614u, 2844977667u, +1261140657u, 1747052377u, +2334120653u, 645125282u, +2707230761u, 4142246789u, +1068639717u, 2288162940u, +1419293714u, 1636932722u, +3252686293u, 318543902u, +2598802768u, 2025886508u, +2250788464u, 2711763065u, +255108733u, 1845587644u, +3719270134u, 3940707863u, +917608574u, 1363253259u, +788659330u, 673256220u, +109793386u, 341851980u, +2698465479u, 3011229884u, +3886713057u, 1276595523u, +2439962760u, 2700515456u, +205970448u, 4198897105u, +875511891u, 371715572u, +1033680610u, 4278599955u, +3120038721u, 1256300069u, +225629455u, 3735275001u, +3961944123u, 1769389163u, +1074553219u, 668829411u, +1098679359u, 2573697509u, +1885071395u, 4233785523u, +2513878053u, 2030193788u, +360256231u, 107312677u, +310517502u, 2618936366u, +3600462351u, 1216645846u, +2970730323u, 4278812598u, +94638678u, 1689811113u, +4125738800u, 3103759730u, +103797041u, 1397772514u, +1669653333u, 572567964u, +1612872497u, 2986430557u, +214990655u, 3117607990u, +1949717207u, 2260498180u, +1493936866u, 3554860960u, +1582022990u, 1263709570u, +1244120487u, 3416600761u, +224580012u, 4252610345u, +286306391u, 814956796u, +1820532305u, 2776960536u, +3082703465u, 1659265982u, +1157398049u, 3752806924u, +3508246460u, 2902716664u, +2110942730u, 3267551635u, +902835431u, 405228165u, +2341378668u, 2220373824u, +3303626294u, 1175118221u, +383517064u, 896322512u, +1697257567u, 2202820683u, +1837689083u, 1336556841u, +914535232u, 3634083711u, +1537187340u, 3712582785u, +1088201893u, 3270984620u, +3093195926u, 2561488770u, +1962968100u, 236189500u, +2549435227u, 536047554u, +422609195u, 2958815818u, +4166184983u, 3528794619u, +1042329086u, 3914176886u, +1359641525u, 1197100813u, +1269739674u, 3301844628u, +1831223342u, 3329594980u, +2433669782u, 494908536u, +1441714797u, 1174785921u, +1933050423u, 958901065u, +868981704u, 2163330264u, +3243110680u, 1443133429u, +1145009669u, 2520062970u, +3851564853u, 2664619323u, +2686075657u, 4042710240u, +2125408249u, 4165697916u, +2328730865u, 3160666939u, +588683409u, 2126275847u, +829404209u, 1878067032u, +2567792910u, 897670516u, +934312076u, 2952135524u, +504832490u, 3312698056u, +4015478120u, 1265237690u, +3376133707u, 967674402u, +1553513184u, 834830418u, +2396504772u, 3278582098u, +2950762705u, 4277111759u, +4159211303u, 1290097509u, +251949572u, 3065234219u, +1832020534u, 312136369u, +1103404394u, 198182691u, +1369599600u, 3906710870u, +2954651680u, 1535115487u, +2389327507u, 1813520230u, +632704095u, 140762681u, +3123202913u, 3336005523u, +1287729497u, 2198985327u, +2470730783u, 3821758006u, +1009870118u, 559702706u, +4274686257u, 3187546567u, +2402308151u, 1096697687u, +678932329u, 3716363135u, +2899950405u, 3046872820u, +3754655641u, 2021741414u, +1993425202u, 2185339100u, +2838253700u, 3099212100u, +1679617763u, 3703603898u, +1135665833u, 3559875668u, +2503579743u, 1446869792u, +879818611u, 3788305533u, +2879018745u, 2719373510u, +3606051203u, 2166567748u, +343595772u, 1996164093u, +1577656121u, 475248376u, +463852893u, 2864244470u, +1332049663u, 3326459767u, +3207234525u, 2028708916u, +938916154u, 3115246264u, +3272166407u, 557660441u, +1265684026u, 245033807u, +2440657523u, 255451671u, +3811885130u, 1399880284u, +1322855877u, 3452203069u, +1324994449u, 3796404024u, +2002090272u, 1568745354u, +3700047753u, 31799506u, +3009412313u, 3184047862u, +728680761u, 3848624873u, +1849329144u, 3160134214u, +1272923193u, 1474278816u, +1208883495u, 1566527339u, +4136466541u, 630825649u, +1717327230u, 1496132623u, +2449386742u, 128106940u, +2108574735u, 2584236470u, +2872246579u, 397338552u, +3088905079u, 3456882941u, +1715915153u, 2940716269u, +4168438718u, 467441309u, +872996731u, 3206901319u, +1610606159u, 2540270567u, +1301658081u, 2379410194u, +2109315753u, 3348545480u, +2041927873u, 2644077493u, +546596661u, 1017047954u, +2596792972u, 2783958892u, +2826408201u, 3531646869u, +2219352672u, 4217451852u, +1806867885u, 1903578924u, +2076465705u, 2373061493u, +1832925325u, 241574049u, +1509517110u, 3703614272u, +3429894862u, 3529565564u, +4010000614u, 2256197939u, +517086873u, 2964595704u, +3501035294u, 4079457298u, +1184683823u, 4260564140u, +2339268412u, 3871564102u, +1572637805u, 383233885u, +3351411126u, 3419328182u, +2017406667u, 919677938u, +29804156u, 46276077u, +3032591014u, 4204155962u, +1172319502u, 969309871u, +2211319468u, 4153726847u, +3094193193u, 4240669441u, +3441709766u, 1387233546u, +4048882438u, 1217896566u, +1580964938u, 740563169u, +3691850348u, 3176426539u, +2738323042u, 2948665536u, +1474029445u, 3513354882u, +3219466255u, 3799363969u, +3961796122u, 1055550923u, +1992212097u, 2263421398u, +4289759174u, 2516844140u, +1782515131u, 2746577402u, +721928440u, 3529570984u, +1705302106u, 768287270u, +3474902815u, 4000011125u, +3475618043u, 212490675u, +549130471u, 2970128275u, +3170016833u, 2549835613u, +3691104824u, 2694324482u, +4169365948u, 3738062408u, +602930397u, 2148954730u, +2636387819u, 2616619070u, +301617872u, 374657036u, +3862686086u, 431292293u, +4225245165u, 1358580562u, +2377363130u, 1415970351u, +3885060756u, 1438379807u, +2297418515u, 2954777083u, +3970368221u, 1229801760u, +1931934525u, 2287507921u, +1713471510u, 2145608111u, +2650140034u, 4081586725u, +4196863572u, 1896558394u, +4059852729u, 1813855658u, +2618400836u, 1396056469u, +2375584220u, 1037031473u, +249284003u, 2450077637u, +1383747654u, 3122687303u, +2664431743u, 3855028730u, +929335420u, 3193251135u, +137313762u, 1850894384u, +3163711272u, 3071568023u, +418541677u, 3621223039u, +340274176u, 1167681812u, +4106647531u, 4022465625u, +3069708839u, 2704165015u, +2332023349u, 641449034u, +921552000u, 1712976649u, +1876484273u, 2343049860u, +1834682077u, 4155949943u, +2061821157u, 4240649383u, +747285578u, 1626463554u, +165503115u, 359629739u, +3838102563u, 582664250u, +3878924635u, 4117237498u, +2250573853u, 804336148u, +331393443u, 4242530387u, +3346357270u, 1674051445u, +3348019777u, 1722242971u, +2509017299u, 2966108111u, +4189102509u, 3323592310u, +2631381069u, 4014551783u, +4250787412u, 3448394212u, +2664752123u, 3517585534u, +3605365141u, 1669471183u, +2210121140u, 760762191u, +249697459u, 3416920106u, +16322182u, 643179562u, +1564226597u, 2134630675u, +1011990087u, 2990167340u, +2349550842u, 1642428946u, +1214854475u, 2134299399u, +2704221532u, 2104175211u, +4283196353u, 1342880802u, +198529755u, 2004468390u, +2544665755u, 853593042u, +2090611294u, 2970943872u, +1472073141u, 850464484u, +1407609278u, 3062461105u, +366448238u, 3842907484u, +488797416u, 1432670231u, +294963924u, 3693536939u, +3390549825u, 1583234720u, +4032223840u, 2318423400u, +2965642867u, 930822729u, +1679099863u, 1728968857u, +900822335u, 702309817u, +3258354115u, 1502282913u, +2811888503u, 3924947660u, +2477280726u, 3651607391u, +3788310204u, 1300369123u, +1842333726u, 4146839064u, +2468893861u, 4091095953u, +488595746u, 1448097974u, +1159634090u, 1738834113u, +2928916831u, 4093725287u, +530850094u, 291657799u, +3548184546u, 679517009u, +399175380u, 2658337143u, +3827951761u, 3086277222u, +2067718397u, 3632376023u, +3553313841u, 119173722u, +1702434637u, 1766260771u, +895654784u, 751439914u, +4008409498u, 215917713u, +1288382231u, 2656990891u, +2581779077u, 1570750352u, +2666411616u, 3533987737u, +4289478316u, 3576119563u, +3869794273u, 963183826u, +2081410737u, 3796810515u, +1036883117u, 136547246u, +875691100u, 2592925324u, +2689342539u, 427154472u, +532957601u, 1228758574u, +1908591042u, 1464255968u, +446980910u, 2984611177u, +3508927906u, 2001585786u, +2544767379u, 1525438381u, +879448844u, 1348536411u, +4242243590u, 2861338018u, +601175800u, 764077711u, +530635011u, 3785343245u, +2378297261u, 457568934u, +76438221u, 4104954272u, +2485968477u, 2381948487u, +4226929450u, 3148473363u, +879369091u, 2180270337u, +3674375989u, 1387729170u, +568650985u, 951677556u, +4213877384u, 2721005055u, +1678669911u, 66786703u, +2273631661u, 1149351924u, +246723096u, 1895026827u, +3810605772u, 3711056516u, +2080120290u, 3638638708u, +2915672708u, 2263003308u, +1976115991u, 3448840877u, +2019238520u, 225333538u, +1555273378u, 3797521928u, +1942347150u, 3262952567u, +2817830907u, 2078619498u, +749534111u, 1178073973u, +841092198u, 3288261538u, +1696412169u, 1496966875u, +3739946319u, 2481012988u, +568983526u, 114945840u, +2841706923u, 1632780103u, +4020169654u, 2087949619u, +833416317u, 3787017905u, +2373238993u, 2575395164u, +2542976862u, 2971726178u, +2880371864u, 3642087909u, +1043714217u, 3894199764u, +2235879182u, 203853421u, +834683330u, 425935223u, +3560796393u, 3565833278u, +3414330886u, 1748785729u, +1023171602u, 580966986u, +2657385925u, 2124704694u, +233442446u, 1107045577u, +3899097693u, 1067532701u, +115667924u, 1406028344u, +2419657149u, 18613994u, +2532882091u, 3476683808u, +895961699u, 3762914298u, +1328752423u, 1844996900u, +1210281744u, 904215228u, +4055325594u, 1118521573u, +3996647489u, 3657647605u, +325254059u, 3136157065u, +3341068436u, 2287683323u, +1313073005u, 126005630u, +853746559u, 3555092974u, +2689238752u, 49515858u, +61073168u, 1010661841u, +1269521335u, 1902040126u, +3858321250u, 1400735275u, +2974699176u, 2771676666u, +545726212u, 2225229957u, +1086473152u, 3454177594u, +2088002891u, 2883475137u, +3222194252u, 4144472319u, +567988835u, 1051332394u, +3932046135u, 542648229u, +162888005u, 1669710469u, +1492500905u, 553041029u, +3817492747u, 584127807u, +4147115982u, 2993670925u, +3509733475u, 3587959456u, +2088550465u, 1745399498u, +869648362u, 1404723176u, +3947542735u, 1334333531u, +59634866u, 3239516985u, +3844250972u, 1275954779u, +2512155003u, 1685649437u, +639306006u, 2524620206u, +576786501u, 655707039u, +2864351838u, 3736264674u, +1200907897u, 2384379464u, +15823708u, 206117476u, +1193310960u, 1093099415u, +3696538026u, 4112584792u, +2069527017u, 547588820u, +4178147211u, 2827259351u, +940846775u, 1054995047u, +2976960697u, 1934305529u, +2199137382u, 1005722394u, +1875867180u, 2064356511u, +4019734130u, 3096333006u, +2069509024u, 2906358341u, +2232866485u, 1456016086u, +1422674894u, 867282151u, +1612503136u, 1739843072u, +134947567u, 2978775774u, +1284167756u, 1090844589u, +831688783u, 2079216362u, +1626991196u, 3644714163u, +3678110059u, 898470030u, +3916646913u, 3182422972u, +3630426828u, 969847973u, +3427164640u, 3463937250u, +3044785046u, 897322257u, +3443872170u, 4185408854u, +2557463241u, 4080940424u, +2048168570u, 2429169982u, +3174690447u, 2513494106u, +1213061732u, 3143736628u, +3482268149u, 1250714337u, +31648125u, 3872383625u, +1565760579u, 36665130u, +751041229u, 2257179590u, +2915361862u, 280819225u, +2907818413u, 4254297769u, +3493178615u, 3755944354u, +4043533423u, 1134196225u, +4177134659u, 127246419u, +2442615581u, 923049607u, +1004426206u, 782768297u, +2410586681u, 1430106871u, +4103323427u, 3168399477u, +3716682375u, 3616334719u, +3413209549u, 656672786u, +2876965944u, 182894450u, +456581318u, 2683752067u, +3877875910u, 3190666241u, +3240336907u, 4024807233u, +1681224377u, 1576191191u, +3599250276u, 2381111980u, +3495321877u, 3956024585u, +1611608524u, 3815677453u, +2062334396u, 1656117707u, +5457134u, 3234118251u, +470187419u, 2688566989u, +3259870297u, 660100446u, +442236198u, 2542452448u, +493137955u, 392411099u, +947967568u, 1234595917u, +4230082284u, 2762976773u, +2870085764u, 1455086530u, +2762099647u, 4011882747u, +1215981925u, 3227517889u, +3269061963u, 4037515364u, +3168911474u, 4255057396u, +2026092260u, 1736192508u, +3909727042u, 3114708966u, +1938800693u, 680793595u, +1525265867u, 2808224480u, +2122290603u, 1211197714u, +3520488321u, 3979192396u, +3540779343u, 4192918639u, +2736030448u, 1120335563u, +1698949078u, 3993310631u, +1966048551u, 2228221363u, +597941119u, 3498018399u, +393987327u, 454500547u, +1222959566u, 567151340u, +3774764786u, 1492844524u, +3308300614u, 805568076u, +868414882u, 177406999u, +1608110313u, 642061169u, +1027515771u, 3131251981u, +2851936150u, 4272755262u, +1532845092u, 709643652u, +682573592u, 1244104217u, +796769556u, 2500467040u, +3002618826u, 1112998535u, +1780193104u, 1243644607u, +3691719535u, 2958853053u, +466635014u, 2277292580u, +4082276003u, 1030800045u, +1750863246u, 379050598u, +3576413281u, 731493104u, +132259176u, 4115195437u, +1769890695u, 2715470335u, +1819263183u, 2028531518u, +2154809766u, 3672399742u, +76727603u, 4198182186u, +2304993586u, 1666387627u, +284366017u, 3359785538u, +3469807328u, 2926494787u, +3829072836u, 2493478921u, +3738499303u, 3311304980u, +932916545u, 2235559063u, +2909742396u, 1765719309u, +1456588655u, 508290328u, +1490719640u, 3356513470u, +2908490783u, 251085588u, +830410677u, 3172220325u, +3897208579u, 1940535730u, +151909546u, 2384458112u, +}; + +// Return false only if offset is -1 and a spot check of 3 hashes all yield 0. +bool Test(int offset, int len = 0) { +#undef Check +#undef IsAlive + +#define Check(x) do { \ + const uint32_t actual = (x), e = expected[index++]; \ + bool ok = actual == e; \ + if (!ok) { \ + cerr << "expected " << hex << e << " but got " << actual << endl; \ + ++errors; \ + } \ + assert(ok); \ +} while (0) + +#define IsAlive(x) do { alive += IsNonZero(x); } while (0) + + // After the following line is where the uses of "Check" and such will go. + static int index = 0; +if (offset == -1) { int alive = 0; { uint64_t h = farmhashuo::Hash64WithSeed(data, len++, SEED); IsAlive(h >> 32); IsAlive((h << 32) >> 32); } { uint64_t h = farmhashuo::Hash64(data, len++); IsAlive(h >> 32); IsAlive((h << 32) >> 32); } { uint64_t h = farmhashuo::Hash64(data, len++); IsAlive(h >> 32); IsAlive((h << 32) >> 32); } len -= 3; return alive > 0; } +{ uint64_t h = farmhashuo::Hash64WithSeed(data + offset, len, SEED); Check(h >> 32); Check((h << 32) >> 32); } +{ uint64_t h = farmhashuo::Hash64(data + offset, len); Check(h >> 32); Check((h << 32) >> 32); } + + return true; +#undef Check +#undef IsAlive +} + +int RunTest() { + Setup(); + int i = 0; + cout << "Running farmhashuoTest"; + if (!Test(-1)) { + cout << "... Unavailable\n"; + return NoteErrors(); + } + // Good. The function is attempting to hash, so run the full test. + int errors_prior_to_test = errors; + for ( ; i < kTestSize - 1; i++) { + Test(i * i, i); + } + for ( ; i < kDataSize; i += i / 7) { + Test(0, i); + } + Test(0, kDataSize); + cout << (errors == errors_prior_to_test ? "... OK\n" : "... Failed\n"); + return NoteErrors(); +} + +#else + +// After the following line is where the code to print hash codes will go. +void Dump(int offset, int len) { +{ uint64_t h = farmhashuo::Hash64WithSeed(data + offset, len, SEED); cout << (h >> 32) << "u, " << ((h << 32) >> 32) << "u," << endl; } +{ uint64_t h = farmhashuo::Hash64(data + offset, len); cout << (h >> 32) << "u, " << ((h << 32) >> 32) << "u," << endl; } +} + +#endif + +#undef SEED +#undef SEED1 +#undef SEED0 + +} // namespace farmhashuoTest + +#if !TESTING +int main(int argc, char** argv) { + Setup(); + cout << "uint32_t expected[] = {\n"; + int i = 0; + for ( ; i < kTestSize - 1; i++) { + farmhashuoTest::Dump(i * i, i); + } + for ( ; i < kDataSize; i += i / 7) { + farmhashuoTest::Dump(0, i); + } + farmhashuoTest::Dump(0, kDataSize); + cout << "};\n"; +} +#endif +#ifndef FARMHASH_SELF_TEST_GUARD +#define FARMHASH_SELF_TEST_GUARD +#include +#include +#include + +using std::cout; +using std::cerr; +using std::endl; +using std::hex; + +static const uint64_t kSeed0 = 1234567; +static const uint64_t kSeed1 = k0; +static const int kDataSize = 1 << 20; +static const int kTestSize = 300; +#define kSeed128 Uint128(kSeed0, kSeed1) + +static char data[kDataSize]; + +static int completed_self_tests = 0; +static int errors = 0; + +// Initialize data to pseudorandom values. +void Setup() { + if (completed_self_tests == 0) { + uint64_t a = 9; + uint64_t b = 777; + for (int i = 0; i < kDataSize; i++) { + a += b; + b += a; + a = (a ^ (a >> 41)) * k0; + b = (b ^ (b >> 41)) * k0 + i; + uint8_t u = b >> 37; + memcpy(data + i, &u, 1); // uint8_t -> char + } + } +} + +int NoteErrors() { +#define NUM_SELF_TESTS 9 + if (++completed_self_tests == NUM_SELF_TESTS) + std::exit(errors > 0); + return errors; +} + +template inline bool IsNonZero(T x) { + return x != 0; +} + +template <> inline bool IsNonZero(uint128_t x) { + return x != Uint128(0, 0); +} + +#endif // FARMHASH_SELF_TEST_GUARD + +namespace farmhashxoTest { + +uint32_t CreateSeed(int offset, int salt) { + uint32_t h = static_cast(salt & 0xffffffff); + h = h * c1; + h ^= (h >> 17); + h = h * c1; + h ^= (h >> 17); + h = h * c1; + h ^= (h >> 17); + h += static_cast(offset & 0xffffffff); + h = h * c1; + h ^= (h >> 17); + h = h * c1; + h ^= (h >> 17); + h = h * c1; + h ^= (h >> 17); + return h; +} + +#undef SEED +#undef SEED1 +#undef SEED0 +#define SEED CreateSeed(offset, -1) +#define SEED0 CreateSeed(offset, 0) +#define SEED1 CreateSeed(offset, 1) + +#undef TESTING +#define TESTING 1 +#if TESTING +uint32_t expected[] = { +1140953930u, 861465670u, +3277735313u, 2681724312u, +2598464059u, 797982799u, +890626835u, 800175912u, +2603993599u, 921001710u, +1410420968u, 2134990486u, +3283896453u, 1867689945u, +2914424215u, 2244477846u, +255297188u, 2992121793u, +1110588164u, 4186314283u, +161451183u, 3943596029u, +4019337850u, 452431531u, +283198166u, 2741341286u, +3379021470u, 2557197665u, +299850021u, 2532580744u, +452473466u, 1706958772u, +1298374911u, 3099673830u, +2199864459u, 3696623795u, +236935126u, 2976578695u, +4055299123u, 3281581178u, +1053458494u, 1882212500u, +2305012065u, 2169731866u, +3456121707u, 275903667u, +458884671u, 3033004529u, +3058973506u, 2379411653u, +1898235244u, 1402319660u, +2700149065u, 2699376854u, +147814787u, 720739346u, +2433714046u, 4222949502u, +4220361840u, 1712034059u, +3425469811u, 3690733394u, +4148372108u, 1330324210u, +594028478u, 2921867846u, +1635026870u, 192883107u, +780716741u, 1728752234u, +3280331829u, 326029180u, +3969463346u, 1436364519u, +393215742u, 3349570000u, +3824583307u, 1612122221u, +2859809759u, 3808705738u, +1379537552u, 1646032583u, +2233466664u, 1432476832u, +4023053163u, 2650381482u, +2052294713u, 3552092450u, +1628777059u, 1499109081u, +3476440786u, 3829307897u, +2960536756u, 1554038301u, +1145519619u, 3190844552u, +2902102606u, 3600725550u, +237495366u, 540224401u, +65721842u, 489963606u, +1448662590u, 397635823u, +1596489240u, 1562872448u, +1790705123u, 2128624475u, +180854224u, 2604346966u, +1435705557u, 1262831810u, +155445229u, 1672724608u, +1669465176u, 1341975128u, +663607706u, 2077310004u, +3610042449u, 1911523866u, +1043692997u, 1454396064u, +2563776023u, 294527927u, +1099072299u, 1389770549u, +703505868u, 678706990u, +2952353448u, 2026137563u, +3603803785u, 629449419u, +1933894405u, 3043213226u, +226132789u, 2489287368u, +1552847036u, 645684964u, +3828089804u, 3632594520u, +187883449u, 230403464u, +3151491850u, 3272648435u, +3729087873u, 1303930448u, +2002861219u, 165370827u, +916494250u, 1230085527u, +3103338579u, 3064290191u, +3807265751u, 3628174014u, +231181488u, 851743255u, +2295806711u, 1781190011u, +2988893883u, 1554380634u, +1142264800u, 3667013118u, +1968445277u, 315203929u, +2638023604u, 2290487377u, +732137533u, 1909203251u, +440398219u, 1891630171u, +1380301172u, 1498556724u, +4072067757u, 4165088768u, +4204318635u, 441430649u, +3931792696u, 197618179u, +956300927u, 914413116u, +3010839769u, 2837339569u, +2148126371u, 1913303225u, +3074915312u, 3117299654u, +4139181436u, 2993479124u, +3178848746u, 1357272220u, +1438494951u, 507436733u, +667183474u, 2084369203u, +3854939912u, 1413396341u, +126024219u, 146044391u, +1016656857u, 3022024459u, +3254014218u, 429095991u, +990500595u, 3056862311u, +985653208u, 1718653828u, +623071693u, 366414107u, +1771289760u, 2293458109u, +3047342438u, 2991127487u, +3120876698u, 1684583131u, +3638043310u, 1170404994u, +863214540u, 1087193030u, +199124911u, 520792961u, +3169775996u, 1577421232u, +3331828431u, 1013201099u, +1716848157u, 4033596884u, +1770708857u, 4229339322u, +1146169032u, 1434258493u, +3824360466u, 3242407770u, +1926419493u, 2649785113u, +872586426u, 762243036u, +2736953692u, 816692935u, +1571283333u, 3555213933u, +2266795890u, 3781899767u, +4290630595u, 517646945u, +3006163611u, 2180594090u, +959214578u, 558910384u, +1283799121u, 3047062993u, +3830962609u, 2391606125u, +3544509313u, 622325861u, +834785312u, 382936554u, +1421463872u, 788479970u, +1825135056u, 2725923798u, +580988377u, 2826990641u, +247825043u, 3167748333u, +812546227u, 2506885666u, +2584372201u, 1758123094u, +1891789696u, 389974094u, +345313518u, 2022370576u, +3886113119u, 3338548567u, +1083486947u, 2583576230u, +1776047957u, 1771384107u, +3604937815u, 3198590202u, +3027522813u, 4155628142u, +4232136669u, 427759438u, +4244322689u, 542201663u, +1549591985u, 2856634168u, +556609672u, 45845311u, +1175961330u, 3948351189u, +4165739882u, 4194218315u, +1634635545u, 4151937410u, +713127376u, 1467786451u, +1327394015u, 2743592929u, +2638154051u, 810082938u, +3077742128u, 1062268187u, +4084325664u, 3810665822u, +3735739145u, 2794294783u, +2335576331u, 2560479831u, +690240711u, 997658837u, +2442302747u, 3948961926u, +3958366652u, 3067277639u, +2059157774u, 1211737169u, +1516711748u, 2339636583u, +4188504038u, 59581167u, +2767897792u, 1389679610u, +2658147000u, 2643979752u, +3758739543u, 4189944477u, +1454470782u, 100876854u, +2995362413u, 118817200u, +3252925478u, 2062343506u, +2804483644u, 3088828656u, +1231633714u, 4168280671u, +2931588131u, 3284356565u, +1255909792u, 3130054947u, +4173605289u, 1407328702u, +1677744031u, 3532596884u, +3162657845u, 3887208531u, +2256541290u, 3459463480u, +3740979556u, 259034107u, +392987633u, 3233195759u, +3606709555u, 3424793077u, +315836068u, 3200749877u, +4065431359u, 760633989u, +2982018998u, 1811050648u, +234531934u, 1115203611u, +3897494162u, 1516407838u, +1603559457u, 323296368u, +2632963283u, 1778459926u, +2879836826u, 2146672889u, +3486330348u, 492621815u, +1231665285u, 2457048126u, +3438440082u, 2217471853u, +3355404249u, 3275550588u, +1052645068u, 862072556u, +4110617119u, 3745267835u, +2657392572u, 4279236653u, +1688445808u, 701920051u, +956734128u, 581695350u, +3157862788u, 2585726058u, +1192588249u, 1410111809u, +1651193125u, 3326135446u, +1073280453u, 97376972u, +2513844237u, 2187968410u, +3976859649u, 4267859263u, +3429034542u, 564493077u, +3000537321u, 479241367u, +3845637831u, 2868987960u, +51544337u, 1029173765u, +393624922u, 704325635u, +2357610553u, 1418509533u, +2007814586u, 3866658271u, +3082385053u, 735688735u, +916110004u, 3283299459u, +1051684175u, 1083796807u, +4074716319u, 813690332u, +144264390u, 1439630796u, +1508556987u, 675582689u, +3748881891u, 3195309868u, +362884708u, 1616408198u, +43233176u, 837301135u, +881504822u, 3254795114u, +1385506591u, 2799925823u, +1469874582u, 3464841997u, +497175391u, 3929484338u, +3975771289u, 1798536177u, +2926265846u, 1374242438u, +3675707838u, 4205965408u, +3153165629u, 1499475160u, +187287713u, 548490821u, +3255259608u, 4247675634u, +1940181471u, 3779953975u, +687167150u, 2319566715u, +1742785722u, 785893184u, +2296977392u, 2778575413u, +1794720651u, 48131484u, +4084891412u, 1160134629u, +3737623280u, 823113169u, +3423207646u, 3803213486u, +710625654u, 4116162021u, +3693420287u, 4167766971u, +1666602807u, 295320990u, +3513255468u, 2487440590u, +234080704u, 4004655503u, +2971762528u, 1479656873u, +4090178629u, 4044418876u, +391947536u, 1462554406u, +3909295855u, 1239580330u, +1515601363u, 2011102035u, +1442068334u, 4265993528u, +1191921695u, 2291355695u, +4257172787u, 576405853u, +314332944u, 4038839101u, +55559918u, 2378985842u, +711098718u, 2425317635u, +1644327317u, 1401013391u, +4193760037u, 2958260436u, +3167371443u, 3062418115u, +3800755475u, 3167030094u, +3489648204u, 1405430357u, +526177822u, 2602636307u, +915406019u, 4264167741u, +1484090483u, 3070944737u, +254529415u, 4017058800u, +1702710265u, 1029665228u, +2000382906u, 3185573940u, +1381258384u, 4036354071u, +2900841028u, 2670703363u, +2921748807u, 2899069938u, +4130543625u, 688472265u, +4186808827u, 1054670286u, +1132985391u, 2840525968u, +4175776103u, 338058159u, +1735964501u, 1539305024u, +3497121710u, 1568260669u, +2227290760u, 146827036u, +3977176001u, 4060134777u, +857488494u, 250055052u, +4284109679u, 2502815838u, +2592281721u, 1603444633u, +1390562014u, 1556658131u, +616327404u, 2448966429u, +3051191726u, 3891353218u, +1213304082u, 762328245u, +2239052397u, 1082330589u, +2455957292u, 201837927u, +405397452u, 3079886794u, +2583939798u, 2848283092u, +3750724631u, 883849006u, +3204198988u, 3341327098u, +1855234968u, 1982110346u, +1485529487u, 541496720u, +4117290321u, 3607433551u, +2168864636u, 133643215u, +1055817409u, 3847827123u, +2960769387u, 4046101649u, +1176127003u, 4015671361u, +4243643405u, 2849988118u, +517111221u, 1796672358u, +2045051700u, 3452457457u, +2948254999u, 2102063419u, +1556410577u, 1536380876u, +3776661467u, 3281002516u, +1735616066u, 1539151988u, +1087795162u, 3332431596u, +685631442u, 1147951686u, +95237878u, 2005032160u, +4012206915u, 4224354805u, +3204999386u, 2415262714u, +1433635018u, 116647396u, +83167836u, 2881562655u, +2729416454u, 1029284767u, +881378302u, 2159170082u, +555057366u, 1169104445u, +3963877000u, 1919171906u, +336034862u, 2017579106u, +4059340529u, 3020819343u, +865146997u, 2473524405u, +944743644u, 1694443528u, +1804513294u, 2904752429u, +617975720u, 3671562289u, +260177668u, 505662155u, +1885941445u, 2504509403u, +2260041112u, 1019936943u, +3722741628u, 1511077569u, +3100701179u, 1379422864u, +1535670711u, 773792826u, +1103819072u, 2089123665u, +1157547425u, 329152940u, +4142587430u, 484732447u, +2475035432u, 1120017626u, +412145504u, 965125959u, +324924679u, 2809286837u, +2842141483u, 4029205195u, +2974306813u, 515627448u, +3791551981u, 1097806406u, +3873078673u, 136118734u, +1872130856u, 3632422367u, +3574135531u, 4017075736u, +1699452298u, 1403506686u, +344414660u, 1189129691u, +3487080616u, 1516736273u, +1805475756u, 2562064338u, +163335594u, 2732147834u, +4077452507u, 2984955003u, +4271866024u, 3071338162u, +2347111903u, 873829983u, +1948409509u, 1923531348u, +459509140u, 771592405u, +1750124750u, 2334938333u, +213811117u, 2586632018u, +185232757u, 4032960199u, +2447383637u, 284777551u, +1654276320u, 2687561076u, +3512945009u, 308584855u, +1861027147u, 4102279334u, +3203802620u, 1692079268u, +4250142168u, 2565680167u, +1507046104u, 841195925u, +520565830u, 3674576684u, +38924274u, 3770488806u, +2414430882u, 3978473838u, +3703994407u, 69201295u, +3099963860u, 1255084262u, +690971838u, 3539996781u, +3696902571u, 3593730713u, +2363435042u, 54945052u, +1785765213u, 184911581u, +1586241476u, 1939595371u, +2534883189u, 2432427547u, +2374171993u, 2039128933u, +2955715987u, 2295501078u, +2741583197u, 1280920000u, +686818699u, 1238742497u, +3843660102u, 82177963u, +1281043691u, 1121403845u, +1697846708u, 284852964u, +278661677u, 2889101923u, +2127558730u, 713121337u, +872502474u, 511142139u, +1261140657u, 1747052377u, +2108187161u, 927011680u, +955328267u, 3821994995u, +2707230761u, 4142246789u, +4134691985u, 1958963937u, +2498463509u, 1977988705u, +1419293714u, 1636932722u, +2567532373u, 4075249328u, +240575705u, 1956681213u, +2598802768u, 2025886508u, +4104757832u, 3026358429u, +3242615202u, 4026813725u, +255108733u, 1845587644u, +3573008472u, 3615577014u, +1222733548u, 1205557630u, +917608574u, 1363253259u, +1541946015u, 3087190425u, +1138008081u, 1444019663u, +109793386u, 341851980u, +857839960u, 2515339233u, +156283211u, 1906768669u, +3886713057u, 1276595523u, +2809830736u, 460237542u, +3420452099u, 142985419u, +205970448u, 4198897105u, +1950698961u, 2069753399u, +1142216925u, 1113051162u, +1033680610u, 4278599955u, +1106466069u, 356742959u, +531521052u, 3494863964u, +225629455u, 3735275001u, +3662626864u, 1750561299u, +1012864651u, 2101846429u, +1074553219u, 668829411u, +992181339u, 3384018814u, +3330664522u, 860966321u, +1885071395u, 4233785523u, +100741310u, 451656820u, +2148187612u, 1063001151u, +360256231u, 107312677u, +3650357479u, 2390172694u, +22452685u, 237319043u, +3600462351u, 1216645846u, +2088767754u, 164402616u, +2418980170u, 926137824u, +94638678u, 1689811113u, +2751052984u, 1767810825u, +271289013u, 3896132233u, +103797041u, 1397772514u, +3441135892u, 3323383489u, +2491268371u, 1662561885u, +1612872497u, 2986430557u, +2756998822u, 207428029u, +937973965u, 2791656726u, +1949717207u, 2260498180u, +2648427775u, 2360400900u, +2080496169u, 486358863u, +1582022990u, 1263709570u, +1396468647u, 1377764574u, +363008508u, 1293502429u, +224580012u, 4252610345u, +1435134775u, 1099809675u, +533671980u, 1533438766u, +1820532305u, 2776960536u, +3374512975u, 3542220540u, +822810075u, 3716663290u, +1157398049u, 3752806924u, +4081637863u, 337070226u, +3866585976u, 359270190u, +2110942730u, 3267551635u, +644850146u, 1306761320u, +746972907u, 934259457u, +2341378668u, 2220373824u, +1242645122u, 4109252858u, +1625266099u, 1173698481u, +383517064u, 896322512u, +3377483696u, 1788337208u, +455496839u, 3194373887u, +1837689083u, 1336556841u, +1658628529u, 2911512007u, +3838343487u, 2757664765u, +1537187340u, 3712582785u, +367022558u, 3071359622u, +3926147070u, 35432879u, +3093195926u, 2561488770u, +4273132307u, 3898950547u, +2838251049u, 2103926083u, +2549435227u, 536047554u, +1858986613u, 2040551642u, +1147412575u, 1972369852u, +4166184983u, 3528794619u, +4077477194u, 3565689036u, +808048238u, 3826350461u, +1359641525u, 1197100813u, +265993036u, 1864569342u, +725164342u, 2264788336u, +1831223342u, 3329594980u, +923017956u, 490608221u, +3818634478u, 258154469u, +1441714797u, 1174785921u, +3833372385u, 3287246572u, +1677395563u, 3569218731u, +868981704u, 2163330264u, +2649450292u, 500120236u, +465161780u, 746438382u, +1145009669u, 2520062970u, +2810524030u, 1561519055u, +1479878006u, 3864969305u, +2686075657u, 4042710240u, +3224066062u, 2774151984u, +2226179547u, 1643626042u, +2328730865u, 3160666939u, +2107011431u, 96459446u, +3920328742u, 3336407558u, +829404209u, 1878067032u, +1235983679u, 4237425634u, +466519055u, 3870676863u, +934312076u, 2952135524u, +276949224u, 4100839753u, +424001484u, 1955120893u, +4015478120u, 1265237690u, +427484362u, 4246879223u, +3452969617u, 1724363362u, +1553513184u, 834830418u, +1858777639u, 3476334357u, +4144030366u, 2450047160u, +2950762705u, 4277111759u, +358032121u, 2511026735u, +167923105u, 2059208280u, +251949572u, 3065234219u, +1535473864u, 556796152u, +1513237478u, 3150857516u, +1103404394u, 198182691u, +1476438092u, 2913077464u, +207119516u, 3963810232u, +2954651680u, 1535115487u, +3051522276u, 4046477658u, +917804636u, 864395565u, +632704095u, 140762681u, +1802040304u, 990407433u, +3771506212u, 4106024923u, +1287729497u, 2198985327u, +4052924496u, 2926590471u, +3084557148u, 1472898694u, +1009870118u, 559702706u, +4265214507u, 82077489u, +3067891003u, 3295678907u, +2402308151u, 1096697687u, +464407878u, 4190838199u, +4269578403u, 3060919438u, +2899950405u, 3046872820u, +733509243u, 1583801700u, +40453902u, 3879773881u, +1993425202u, 2185339100u, +1877837196u, 3912423882u, +3293122640u, 4104318469u, +1679617763u, 3703603898u, +8759461u, 2540185277u, +1152198475u, 2038345882u, +2503579743u, 1446869792u, +2019419351u, 4051584612u, +3178289407u, 3992503830u, +2879018745u, 2719373510u, +700836153u, 1675560450u, +4121245793u, 2064715719u, +343595772u, 1996164093u, +3130433948u, 405251683u, +2804817126u, 1607133689u, +463852893u, 2864244470u, +2224044848u, 4071581802u, +2537107938u, 2246347953u, +3207234525u, 2028708916u, +2272418128u, 803575837u, +38655481u, 2170452091u, +3272166407u, 557660441u, +4019147902u, 3841480082u, +298459606u, 2600943364u, +2440657523u, 255451671u, +3424361375u, 779434428u, +3088526123u, 490671625u, +1322855877u, 3452203069u, +3057021940u, 2285701422u, +2014993457u, 2390431709u, +2002090272u, 1568745354u, +1783152480u, 823305654u, +4053862835u, 2200236540u, +3009412313u, 3184047862u, +3032187389u, 4159715581u, +2966902888u, 252986948u, +1849329144u, 3160134214u, +3420960112u, 3198900547u, +749160960u, 379139040u, +1208883495u, 1566527339u, +3006227299u, 4194096960u, +556075248u, 497404038u, +1717327230u, 1496132623u, +1775955687u, 1719108984u, +1014328900u, 4189966956u, +2108574735u, 2584236470u, +684087286u, 531310503u, +4264509527u, 773405691u, +3088905079u, 3456882941u, +3105682208u, 3382290593u, +2289363624u, 3296306400u, +4168438718u, 467441309u, +777173623u, 3241407531u, +1183994815u, 1132983260u, +1610606159u, 2540270567u, +2649684057u, 1397502982u, +146657385u, 3318434267u, +2109315753u, 3348545480u, +3193669211u, 811750340u, +1073256162u, 3571673088u, +546596661u, 1017047954u, +3403136990u, 2540585554u, +1477047647u, 4145867423u, +2826408201u, 3531646869u, +784952939u, 943914610u, +2717443875u, 3657384638u, +1806867885u, 1903578924u, +3985088434u, 1911188923u, +1764002686u, 3672748083u, +1832925325u, 241574049u, +519948041u, 3181425568u, +2939747257u, 1634174593u, +3429894862u, 3529565564u, +1089679033u, 240953857u, +2025369941u, 2695166650u, +517086873u, 2964595704u, +3017658263u, 3828377737u, +2144895011u, 994799311u, +1184683823u, 4260564140u, +308018483u, 4262383425u, +1374752558u, 3431057723u, +1572637805u, 383233885u, +3188015819u, 4051263539u, +233319221u, 3794788167u, +2017406667u, 919677938u, +4074952232u, 1683612329u, +4213676186u, 327142514u, +3032591014u, 4204155962u, +206775997u, 2283918569u, +2395147154u, 3427505379u, +2211319468u, 4153726847u, +2217060665u, 350160869u, +2493667051u, 1648200185u, +3441709766u, 1387233546u, +140980u, 1891558063u, +760080239u, 2088061981u, +1580964938u, 740563169u, +422986366u, 330624974u, +4264507722u, 150928357u, +2738323042u, 2948665536u, +918718096u, 376390582u, +3966098971u, 717653678u, +3219466255u, 3799363969u, +3424344721u, 3187805406u, +375347278u, 3490350144u, +1992212097u, 2263421398u, +3855037968u, 1928519266u, +3866327955u, 1129127000u, +1782515131u, 2746577402u, +3059200728u, 2108753646u, +2738070963u, 1336849395u, +1705302106u, 768287270u, +1343511943u, 2247006571u, +1956142255u, 1780259453u, +3475618043u, 212490675u, +622521957u, 917121602u, +1852992332u, 1267987847u, +3170016833u, 2549835613u, +3299763344u, 2864033668u, +3378768767u, 1236609378u, +4169365948u, 3738062408u, +2661022773u, 2006922227u, +2760592161u, 3828932355u, +2636387819u, 2616619070u, +1237256330u, 3449066284u, +2871755260u, 3729280948u, +3862686086u, 431292293u, +3285899651u, 786322314u, +2531158535u, 724901242u, +2377363130u, 1415970351u, +1244759631u, 3263135197u, +965248856u, 174024139u, +2297418515u, 2954777083u, +987586766u, 3206261120u, +4059515114u, 3903854066u, +1931934525u, 2287507921u, +1827135136u, 1781944746u, +574617451u, 2299034788u, +2650140034u, 4081586725u, +2482286699u, 1109175923u, +458483596u, 618705848u, +4059852729u, 1813855658u, +4190721328u, 1129462471u, +4089998050u, 3575732749u, +2375584220u, 1037031473u, +1623777358u, 3389003793u, +546597541u, 352770237u, +1383747654u, 3122687303u, +1646071378u, 1164309901u, +290870767u, 830691298u, +929335420u, 3193251135u, +989577914u, 3626554867u, +591974737u, 3996958215u, +3163711272u, 3071568023u, +1516846461u, 3656006011u, +2698625268u, 2510865430u, +340274176u, 1167681812u, +3698796465u, 3155218919u, +4102288238u, 1673474350u, +3069708839u, 2704165015u, +1237411891u, 1854985978u, +3646837503u, 3625406022u, +921552000u, 1712976649u, +3939149151u, 878608872u, +3406359248u, 1068844551u, +1834682077u, 4155949943u, +2437686324u, 3163786257u, +2645117577u, 1988168803u, +747285578u, 1626463554u, +1235300371u, 1256485167u, +1914142538u, 4141546431u, +3838102563u, 582664250u, +1883344352u, 2083771672u, +2611657933u, 2139079047u, +2250573853u, 804336148u, +3066325351u, 2770847216u, +4275641370u, 1455750577u, +3346357270u, 1674051445u, +601221482u, 3992583643u, +1402445097u, 3622527604u, +2509017299u, 2966108111u, +2557027816u, 900741486u, +1790771021u, 2912643797u, +2631381069u, 4014551783u, +90375300u, 300318232u, +3269968032u, 2679371729u, +2664752123u, 3517585534u, +3253901179u, 542270815u, +1188641600u, 365479232u, +2210121140u, 760762191u, +1273768482u, 1216399252u, +3484324231u, 4287337666u, +16322182u, 643179562u, +325675502u, 3652676161u, +3120716054u, 3330259752u, +1011990087u, 2990167340u, +1097584090u, 3262252593u, +1829409951u, 3665087267u, +1214854475u, 2134299399u, +3704419305u, 411263051u, +1625446136u, 549838529u, +4283196353u, 1342880802u, +3460621305u, 1967599860u, +4282843369u, 1275671016u, +2544665755u, 853593042u, +901109753u, 2682611693u, +110631633u, 797487791u, +1472073141u, 850464484u, +797089608u, 3286110054u, +350397471u, 2775631060u, +366448238u, 3842907484u, +2219863904u, 3623364733u, +1850985302u, 4009616991u, +294963924u, 3693536939u, +3061255808u, 1615375832u, +1920066675u, 4113028420u, +4032223840u, 2318423400u, +2701956286u, 4145497671u, +3991532344u, 2536338351u, +1679099863u, 1728968857u, +449740816u, 2686506989u, +685242457u, 97590863u, +3258354115u, 1502282913u, +1235084019u, 2151665147u, +528459289u, 231097464u, +2477280726u, 3651607391u, +2091754612u, 1178454681u, +980597335u, 1604483865u, +1842333726u, 4146839064u, +3213794286u, 2601416506u, +754220096u, 3571436033u, +488595746u, 1448097974u, +4004834921u, 238887261u, +3320337489u, 1416989070u, +2928916831u, 4093725287u, +186020771u, 2367569534u, +3046087671u, 4090084518u, +3548184546u, 679517009u, +1962659444u, 3539886328u, +4192003933u, 1678423485u, +3827951761u, 3086277222u, +2144472852u, 1390394371u, +2976322029u, 1574517163u, +3553313841u, 119173722u, +1702434637u, 1766260771u, +3629581771u, 1407497759u, +895654784u, 751439914u, +4008409498u, 215917713u, +1482103833u, 695551833u, +1288382231u, 2656990891u, +2581779077u, 1570750352u, +3710689053u, 1741390464u, +2666411616u, 3533987737u, +4289478316u, 3576119563u, +4118694920u, 108199666u, +3869794273u, 963183826u, +2081410737u, 3796810515u, +791123882u, 2525792704u, +1036883117u, 136547246u, +875691100u, 2592925324u, +614302599u, 3013176417u, +2689342539u, 427154472u, +532957601u, 1228758574u, +1898117151u, 1181643858u, +1908591042u, 1464255968u, +446980910u, 2984611177u, +58509511u, 1046943619u, +3508927906u, 2001585786u, +2544767379u, 1525438381u, +552181222u, 1959725830u, +879448844u, 1348536411u, +4242243590u, 2861338018u, +1082052441u, 1034351453u, +601175800u, 764077711u, +530635011u, 3785343245u, +2178026726u, 117256687u, +2378297261u, 457568934u, +76438221u, 4104954272u, +956793873u, 3783168634u, +2485968477u, 2381948487u, +4226929450u, 3148473363u, +2518273601u, 3569490233u, +879369091u, 2180270337u, +3674375989u, 1387729170u, +977997984u, 4270646856u, +568650985u, 951677556u, +4213877384u, 2721005055u, +1073364549u, 2563403831u, +1678669911u, 66786703u, +2273631661u, 1149351924u, +3651298990u, 1581883443u, +246723096u, 1895026827u, +3810605772u, 3711056516u, +4058833288u, 2193790614u, +2080120290u, 3638638708u, +2915672708u, 2263003308u, +2361934197u, 4136767460u, +1976115991u, 3448840877u, +2019238520u, 225333538u, +874340815u, 2976159827u, +1555273378u, 3797521928u, +1942347150u, 3262952567u, +435997738u, 340403353u, +2817830907u, 2078619498u, +749534111u, 1178073973u, +894654712u, 3361226032u, +841092198u, 3288261538u, +1696412169u, 1496966875u, +697501571u, 1059158875u, +3739946319u, 2481012988u, +568983526u, 114945840u, +1559249010u, 2218244008u, +2841706923u, 1632780103u, +4020169654u, 2087949619u, +2438736103u, 24032648u, +833416317u, 3787017905u, +2373238993u, 2575395164u, +3434544481u, 3228481067u, +2542976862u, 2971726178u, +2880371864u, 3642087909u, +2407477975u, 2239080836u, +1043714217u, 3894199764u, +2235879182u, 203853421u, +2933669448u, 2504940536u, +834683330u, 425935223u, +3560796393u, 3565833278u, +1668000829u, 3683399154u, +3414330886u, 1748785729u, +1023171602u, 580966986u, +2531038985u, 3227325488u, +2657385925u, 2124704694u, +233442446u, 1107045577u, +3407293834u, 552770757u, +3899097693u, 1067532701u, +115667924u, 1406028344u, +1707768231u, 3724015962u, +2419657149u, 18613994u, +2532882091u, 3476683808u, +1560838678u, 811220224u, +895961699u, 3762914298u, +1328752423u, 1844996900u, +1420427894u, 1848067707u, +1210281744u, 904215228u, +4055325594u, 1118521573u, +2496554183u, 2579259919u, +3996647489u, 3657647605u, +325254059u, 3136157065u, +3951522674u, 4052925250u, +3341068436u, 2287683323u, +1313073005u, 126005630u, +2505120084u, 1194725057u, +853746559u, 3555092974u, +2689238752u, 49515858u, +1244776042u, 1069300695u, +61073168u, 1010661841u, +1269521335u, 1902040126u, +990632502u, 2378708922u, +3858321250u, 1400735275u, +2974699176u, 2771676666u, +170995186u, 2877798589u, +545726212u, 2225229957u, +1086473152u, 3454177594u, +3859483262u, 1499729584u, +2088002891u, 2883475137u, +3222194252u, 4144472319u, +2212229854u, 4146740722u, +567988835u, 1051332394u, +3932046135u, 542648229u, +3017852446u, 1277887997u, +162888005u, 1669710469u, +1492500905u, 553041029u, +1434876932u, 533989516u, +3817492747u, 584127807u, +4147115982u, 2993670925u, +4020312558u, 710021255u, +3509733475u, 3587959456u, +2088550465u, 1745399498u, +2952242967u, 1259815443u, +869648362u, 1404723176u, +3947542735u, 1334333531u, +3873471582u, 229399758u, +59634866u, 3239516985u, +3844250972u, 1275954779u, +1385684948u, 2243700741u, +2512155003u, 1685649437u, +639306006u, 2524620206u, +955360345u, 1646776457u, +576786501u, 655707039u, +2864351838u, 3736264674u, +655621239u, 362070173u, +1200907897u, 2384379464u, +15823708u, 206117476u, +3652870937u, 122927134u, +1193310960u, 1093099415u, +3696538026u, 4112584792u, +1834541277u, 845639252u, +2069527017u, 547588820u, +4178147211u, 2827259351u, +1764455305u, 3312003602u, +940846775u, 1054995047u, +2976960697u, 1934305529u, +3095615046u, 3354962706u, +2199137382u, 1005722394u, +1875867180u, 2064356511u, +3363633633u, 2688499147u, +4019734130u, 3096333006u, +2069509024u, 2906358341u, +3247463123u, 4191788132u, +2232866485u, 1456016086u, +1422674894u, 867282151u, +1851386407u, 1268304058u, +1612503136u, 1739843072u, +134947567u, 2978775774u, +2051592101u, 1017127033u, +1284167756u, 1090844589u, +831688783u, 2079216362u, +2079309682u, 1950585801u, +1626991196u, 3644714163u, +3678110059u, 898470030u, +1117570988u, 2517572125u, +3916646913u, 3182422972u, +3630426828u, 969847973u, +2835126238u, 53541366u, +3427164640u, 3463937250u, +3044785046u, 897322257u, +103038235u, 3804506837u, +3443872170u, 4185408854u, +2557463241u, 4080940424u, +3669923099u, 2789619871u, +2048168570u, 2429169982u, +3174690447u, 2513494106u, +3099587829u, 2627855577u, +1213061732u, 3143736628u, +3482268149u, 1250714337u, +3553412672u, 2689632914u, +31648125u, 3872383625u, +1565760579u, 36665130u, +1282106920u, 359361724u, +751041229u, 2257179590u, +2915361862u, 280819225u, +954406473u, 4101682199u, +2907818413u, 4254297769u, +3493178615u, 3755944354u, +3539557658u, 3330196096u, +4043533423u, 1134196225u, +4177134659u, 127246419u, +4213770762u, 1978302978u, +2442615581u, 923049607u, +1004426206u, 782768297u, +2702745496u, 1880389457u, +2410586681u, 1430106871u, +4103323427u, 3168399477u, +201787012u, 3105353527u, +3716682375u, 3616334719u, +3413209549u, 656672786u, +526032790u, 2895072131u, +2876965944u, 182894450u, +456581318u, 2683752067u, +1287916294u, 1270745752u, +3877875910u, 3190666241u, +3240336907u, 4024807233u, +4227999465u, 2389301430u, +1681224377u, 1576191191u, +3599250276u, 2381111980u, +3995044500u, 995595530u, +3495321877u, 3956024585u, +1611608524u, 3815677453u, +1520987487u, 3669102590u, +2062334396u, 1656117707u, +5457134u, 3234118251u, +4242065111u, 596879987u, +470187419u, 2688566989u, +3259870297u, 660100446u, +1042378442u, 2206034096u, +442236198u, 2542452448u, +493137955u, 392411099u, +3111186954u, 438250493u, +947967568u, 1234595917u, +4230082284u, 2762976773u, +421203727u, 3728409592u, +2870085764u, 1455086530u, +2762099647u, 4011882747u, +1785430706u, 3684427488u, +1215981925u, 3227517889u, +3269061963u, 4037515364u, +1749401388u, 2167451566u, +3168911474u, 4255057396u, +2026092260u, 1736192508u, +4123254745u, 2319366806u, +3909727042u, 3114708966u, +1938800693u, 680793595u, +3933041672u, 616863613u, +1525265867u, 2808224480u, +2122290603u, 1211197714u, +1186177814u, 2395325006u, +3520488321u, 3979192396u, +3540779343u, 4192918639u, +1763872074u, 3402419930u, +2736030448u, 1120335563u, +1698949078u, 3993310631u, +2947659998u, 1461045789u, +1966048551u, 2228221363u, +597941119u, 3498018399u, +1441110751u, 2229999711u, +393987327u, 454500547u, +1222959566u, 567151340u, +2496952483u, 1708770195u, +3774764786u, 1492844524u, +3308300614u, 805568076u, +4068812294u, 3404648243u, +868414882u, 177406999u, +1608110313u, 642061169u, +2093999089u, 222470301u, +1027515771u, 3131251981u, +2851936150u, 4272755262u, +2763002551u, 1881527822u, +1532845092u, 709643652u, +682573592u, 1244104217u, +440905170u, 1111321746u, +796769556u, 2500467040u, +3002618826u, 1112998535u, +1188525643u, 4212674512u, +1780193104u, 1243644607u, +3691719535u, 2958853053u, +2813437721u, 4036584207u, +466635014u, 2277292580u, +4082276003u, 1030800045u, +1899531424u, 609466946u, +1750863246u, 379050598u, +3576413281u, 731493104u, +2707384133u, 2289193651u, +132259176u, 4115195437u, +1769890695u, 2715470335u, +3348954692u, 2166575624u, +1819263183u, 2028531518u, +2154809766u, 3672399742u, +1142139448u, 88299682u, +76727603u, 4198182186u, +2304993586u, 1666387627u, +2488475423u, 3832777692u, +284366017u, 3359785538u, +3469807328u, 2926494787u, +1914195188u, 1134129972u, +3829072836u, 2493478921u, +3738499303u, 3311304980u, +726951526u, 911080963u, +932916545u, 2235559063u, +2909742396u, 1765719309u, +465269850u, 3803621553u, +1456588655u, 508290328u, +1490719640u, 3356513470u, +2262196163u, 1451774941u, +2908490783u, 251085588u, +830410677u, 3172220325u, +4039692645u, 1383603170u, +3897208579u, 1940535730u, +151909546u, 2384458112u, +}; + +// Return false only if offset is -1 and a spot check of 3 hashes all yield 0. +bool Test(int offset, int len = 0) { +#undef Check +#undef IsAlive + +#define Check(x) do { \ + const uint32_t actual = (x), e = expected[index++]; \ + bool ok = actual == e; \ + if (!ok) { \ + cerr << "expected " << hex << e << " but got " << actual << endl; \ + ++errors; \ + } \ + assert(ok); \ +} while (0) + +#define IsAlive(x) do { alive += IsNonZero(x); } while (0) + + // After the following line is where the uses of "Check" and such will go. + static int index = 0; +if (offset == -1) { int alive = 0; { uint64_t h = farmhashxo::Hash64WithSeeds(data, len++, SEED0, SEED1); IsAlive(h >> 32); IsAlive((h << 32) >> 32); } { uint64_t h = farmhashxo::Hash64WithSeed(data, len++, SEED); IsAlive(h >> 32); IsAlive((h << 32) >> 32); } { uint64_t h = farmhashxo::Hash64(data, len++); IsAlive(h >> 32); IsAlive((h << 32) >> 32); } len -= 3; return alive > 0; } +{ uint64_t h = farmhashxo::Hash64WithSeeds(data + offset, len, SEED0, SEED1); Check(h >> 32); Check((h << 32) >> 32); } +{ uint64_t h = farmhashxo::Hash64WithSeed(data + offset, len, SEED); Check(h >> 32); Check((h << 32) >> 32); } +{ uint64_t h = farmhashxo::Hash64(data + offset, len); Check(h >> 32); Check((h << 32) >> 32); } + + return true; +#undef Check +#undef IsAlive +} + +int RunTest() { + Setup(); + int i = 0; + cout << "Running farmhashxoTest"; + if (!Test(-1)) { + cout << "... Unavailable\n"; + return NoteErrors(); + } + // Good. The function is attempting to hash, so run the full test. + int errors_prior_to_test = errors; + for ( ; i < kTestSize - 1; i++) { + Test(i * i, i); + } + for ( ; i < kDataSize; i += i / 7) { + Test(0, i); + } + Test(0, kDataSize); + cout << (errors == errors_prior_to_test ? "... OK\n" : "... Failed\n"); + return NoteErrors(); +} + +#else + +// After the following line is where the code to print hash codes will go. +void Dump(int offset, int len) { +{ uint64_t h = farmhashxo::Hash64WithSeeds(data + offset, len, SEED0, SEED1); cout << (h >> 32) << "u, " << ((h << 32) >> 32) << "u," << endl; } +{ uint64_t h = farmhashxo::Hash64WithSeed(data + offset, len, SEED); cout << (h >> 32) << "u, " << ((h << 32) >> 32) << "u," << endl; } +{ uint64_t h = farmhashxo::Hash64(data + offset, len); cout << (h >> 32) << "u, " << ((h << 32) >> 32) << "u," << endl; } +} + +#endif + +#undef SEED +#undef SEED1 +#undef SEED0 + +} // namespace farmhashxoTest + +#if !TESTING +int main(int argc, char** argv) { + Setup(); + cout << "uint32_t expected[] = {\n"; + int i = 0; + for ( ; i < kTestSize - 1; i++) { + farmhashxoTest::Dump(i * i, i); + } + for ( ; i < kDataSize; i += i / 7) { + farmhashxoTest::Dump(0, i); + } + farmhashxoTest::Dump(0, kDataSize); + cout << "};\n"; +} +#endif + +int main() { + farmhashccTest::RunTest(); + farmhashmkTest::RunTest(); + farmhashnaTest::RunTest(); + farmhashntTest::RunTest(); + farmhashsaTest::RunTest(); + farmhashsuTest::RunTest(); + farmhashteTest::RunTest(); + farmhashuoTest::RunTest(); + farmhashxoTest::RunTest(); + __builtin_unreachable(); +} + +#endif // FARMHASHSELFTEST diff --git a/ApplicationCode/Commands/HoloLensCommands/farmhash/farmhash.h b/ApplicationCode/Commands/HoloLensCommands/farmhash/farmhash.h new file mode 100644 index 0000000000..f90ca17e14 --- /dev/null +++ b/ApplicationCode/Commands/HoloLensCommands/farmhash/farmhash.h @@ -0,0 +1,328 @@ +// Copyright (c) 2014 Google, Inc. +// +// 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. +// +// FarmHash, by Geoff Pike + +// +// http://code.google.com/p/farmhash/ +// +// This file provides a few functions for hashing strings and other +// data. All of them are high-quality functions in the sense that +// they do well on standard tests such as Austin Appleby's SMHasher. +// They're also fast. FarmHash is the successor to CityHash. +// +// Functions in the FarmHash family are not suitable for cryptography. +// +// WARNING: This code has been only lightly tested on big-endian platforms! +// It is known to work well on little-endian platforms that have a small penalty +// for unaligned reads, such as current Intel and AMD moderate-to-high-end CPUs. +// It should work on all 32-bit and 64-bit platforms that allow unaligned reads; +// bug reports are welcome. +// +// By the way, for some hash functions, given strings a and b, the hash +// of a+b is easily derived from the hashes of a and b. This property +// doesn't hold for any hash functions in this file. + +#ifndef FARM_HASH_H_ +#define FARM_HASH_H_ + +#include +#include +#include +#include // for memcpy and memset +#include + +#ifndef NAMESPACE_FOR_HASH_FUNCTIONS +#define NAMESPACE_FOR_HASH_FUNCTIONS util +#endif + +namespace NAMESPACE_FOR_HASH_FUNCTIONS { + +#if defined(FARMHASH_UINT128_T_DEFINED) +#if defined(__clang__) +#if !defined(uint128_t) +#define uint128_t __uint128_t +#endif +#endif +inline uint64_t Uint128Low64(const uint128_t x) { + return static_cast(x); +} +inline uint64_t Uint128High64(const uint128_t x) { + return static_cast(x >> 64); +} +inline uint128_t Uint128(uint64_t lo, uint64_t hi) { + return lo + (((uint128_t)hi) << 64); +} +#else +typedef std::pair uint128_t; +inline uint64_t Uint128Low64(const uint128_t x) { return x.first; } +inline uint64_t Uint128High64(const uint128_t x) { return x.second; } +inline uint128_t Uint128(uint64_t lo, uint64_t hi) { return uint128_t(lo, hi); } +#endif + + +// BASIC STRING HASHING + +// Hash function for a byte array. +// May change from time to time, may differ on different platforms, may differ +// depending on NDEBUG. +size_t Hash(const char* s, size_t len); + +// Hash function for a byte array. Most useful in 32-bit binaries. +// May change from time to time, may differ on different platforms, may differ +// depending on NDEBUG. +uint32_t Hash32(const char* s, size_t len); + +// Hash function for a byte array. For convenience, a 32-bit seed is also +// hashed into the result. +// May change from time to time, may differ on different platforms, may differ +// depending on NDEBUG. +uint32_t Hash32WithSeed(const char* s, size_t len, uint32_t seed); + +// Hash function for a byte array. +// May change from time to time, may differ on different platforms, may differ +// depending on NDEBUG. +uint64_t Hash64(const char* s, size_t len); + +// Hash function for a byte array. For convenience, a 64-bit seed is also +// hashed into the result. +// May change from time to time, may differ on different platforms, may differ +// depending on NDEBUG. +uint64_t Hash64WithSeed(const char* s, size_t len, uint64_t seed); + +// Hash function for a byte array. For convenience, two seeds are also +// hashed into the result. +// May change from time to time, may differ on different platforms, may differ +// depending on NDEBUG. +uint64_t Hash64WithSeeds(const char* s, size_t len, + uint64_t seed0, uint64_t seed1); + +// Hash function for a byte array. +// May change from time to time, may differ on different platforms, may differ +// depending on NDEBUG. +uint128_t Hash128(const char* s, size_t len); + +// Hash function for a byte array. For convenience, a 128-bit seed is also +// hashed into the result. +// May change from time to time, may differ on different platforms, may differ +// depending on NDEBUG. +uint128_t Hash128WithSeed(const char* s, size_t len, uint128_t seed); + +// BASIC NON-STRING HASHING + +// Hash 128 input bits down to 64 bits of output. +// This is intended to be a reasonably good hash function. +// May change from time to time, may differ on different platforms, may differ +// depending on NDEBUG. +inline uint64_t Hash128to64(uint128_t x) { + // Murmur-inspired hashing. + const uint64_t kMul = 0x9ddfea08eb382d69ULL; + uint64_t a = (Uint128Low64(x) ^ Uint128High64(x)) * kMul; + a ^= (a >> 47); + uint64_t b = (Uint128High64(x) ^ a) * kMul; + b ^= (b >> 47); + b *= kMul; + return b; +} + +// FINGERPRINTING (i.e., good, portable, forever-fixed hash functions) + +// Fingerprint function for a byte array. Most useful in 32-bit binaries. +uint32_t Fingerprint32(const char* s, size_t len); + +// Fingerprint function for a byte array. +uint64_t Fingerprint64(const char* s, size_t len); + +// Fingerprint function for a byte array. +uint128_t Fingerprint128(const char* s, size_t len); + +// This is intended to be a good fingerprinting primitive. +// See below for more overloads. +inline uint64_t Fingerprint(uint128_t x) { + // Murmur-inspired hashing. + const uint64_t kMul = 0x9ddfea08eb382d69ULL; + uint64_t a = (Uint128Low64(x) ^ Uint128High64(x)) * kMul; + a ^= (a >> 47); + uint64_t b = (Uint128High64(x) ^ a) * kMul; + b ^= (b >> 44); + b *= kMul; + b ^= (b >> 41); + b *= kMul; + return b; +} + +// This is intended to be a good fingerprinting primitive. +inline uint64_t Fingerprint(uint64_t x) { + // Murmur-inspired hashing. + const uint64_t kMul = 0x9ddfea08eb382d69ULL; + uint64_t b = x * kMul; + b ^= (b >> 44); + b *= kMul; + b ^= (b >> 41); + b *= kMul; + return b; +} + +#ifndef FARMHASH_NO_CXX_STRING + +// Convenience functions to hash or fingerprint C++ strings. +// These require that Str::data() return a pointer to the first char +// (as a const char*) and that Str::length() return the string's length; +// they work with std::string, for example. + +// Hash function for a byte array. +// May change from time to time, may differ on different platforms, may differ +// depending on NDEBUG. +template +inline size_t Hash(const Str& s) { + assert(sizeof(s[0]) == 1); + return Hash(s.data(), s.length()); +} + +// Hash function for a byte array. Most useful in 32-bit binaries. +// May change from time to time, may differ on different platforms, may differ +// depending on NDEBUG. +template +inline uint32_t Hash32(const Str& s) { + assert(sizeof(s[0]) == 1); + return Hash32(s.data(), s.length()); +} + +// Hash function for a byte array. For convenience, a 32-bit seed is also +// hashed into the result. +// May change from time to time, may differ on different platforms, may differ +// depending on NDEBUG. +template +inline uint32_t Hash32WithSeed(const Str& s, uint32_t seed) { + assert(sizeof(s[0]) == 1); + return Hash32WithSeed(s.data(), s.length(), seed); +} + +// Hash 128 input bits down to 64 bits of output. +// Hash function for a byte array. +// May change from time to time, may differ on different platforms, may differ +// depending on NDEBUG. +template +inline uint64_t Hash64(const Str& s) { + assert(sizeof(s[0]) == 1); + return Hash64(s.data(), s.length()); +} + +// Hash function for a byte array. For convenience, a 64-bit seed is also +// hashed into the result. +// May change from time to time, may differ on different platforms, may differ +// depending on NDEBUG. +template +inline uint64_t Hash64WithSeed(const Str& s, uint64_t seed) { + assert(sizeof(s[0]) == 1); + return Hash64WithSeed(s.data(), s.length(), seed); +} + +// Hash function for a byte array. For convenience, two seeds are also +// hashed into the result. +// May change from time to time, may differ on different platforms, may differ +// depending on NDEBUG. +template +inline uint64_t Hash64WithSeeds(const Str& s, uint64_t seed0, uint64_t seed1) { + assert(sizeof(s[0]) == 1); + return Hash64WithSeeds(s.data(), s.length(), seed0, seed1); +} + +// Hash function for a byte array. +// May change from time to time, may differ on different platforms, may differ +// depending on NDEBUG. +template +inline uint128_t Hash128(const Str& s) { + assert(sizeof(s[0]) == 1); + return Hash128(s.data(), s.length()); +} + +// Hash function for a byte array. For convenience, a 128-bit seed is also +// hashed into the result. +// May change from time to time, may differ on different platforms, may differ +// depending on NDEBUG. +template +inline uint128_t Hash128WithSeed(const Str& s, uint128_t seed) { + assert(sizeof(s[0]) == 1); + return Hash128(s.data(), s.length(), seed); +} + +// FINGERPRINTING (i.e., good, portable, forever-fixed hash functions) + +// Fingerprint function for a byte array. Most useful in 32-bit binaries. +template +inline uint32_t Fingerprint32(const Str& s) { + assert(sizeof(s[0]) == 1); + return Fingerprint32(s.data(), s.length()); +} + +// Fingerprint 128 input bits down to 64 bits of output. +// Fingerprint function for a byte array. +template +inline uint64_t Fingerprint64(const Str& s) { + assert(sizeof(s[0]) == 1); + return Fingerprint64(s.data(), s.length()); +} + +// Fingerprint function for a byte array. +template +inline uint128_t Fingerprint128(const Str& s) { + assert(sizeof(s[0]) == 1); + return Fingerprint128(s.data(), s.length()); +} + +#endif + +} // namespace NAMESPACE_FOR_HASH_FUNCTIONS + +/* gently define FARMHASH_BIG_ENDIAN when detected big-endian machine */ +#if defined(__BIG_ENDIAN__) + #if !defined(FARMHASH_BIG_ENDIAN) + #define FARMHASH_BIG_ENDIAN + #endif +#elif defined(__LITTLE_ENDIAN__) + // nothing for little-endian +#elif defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && (__BYTE_ORDER == __ORDER_LITTLE_ENDIAN__) + // nothing for little-endian +#elif defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && (__BYTE_ORDER == __ORDER_BIG_ENDIAN__) + #if !defined(FARMHASH_BIG_ENDIAN) + #define FARMHASH_BIG_ENDIAN + #endif +#elif defined(__linux__) || defined(__CYGWIN__) || defined( __GNUC__ ) || defined( __GNU_LIBRARY__ ) + #include // libc6-dev, GLIBC + #if BYTE_ORDER == BIG_ENDIAN + #if !defined(FARMHASH_BIG_ENDIAN) + #define FARMHASH_BIG_ENDIAN + #endif + #endif +#elif defined(__OpenBSD__) || defined(__NetBSD__) || defined(__FreeBSD__) || defined(__DragonFly__) || defined(__s390x__) + #include + #if BYTE_ORDER == BIG_ENDIAN + #if !defined(FARMHASH_BIG_ENDIAN) + #define FARMHASH_BIG_ENDIAN + #endif + #endif +#elif defined(_WIN32) + // Windows is (currently) little-endian +#else + #error "Unable to determine endianness!" +#endif /* __BIG_ENDIAN__ */ + +#endif // FARM_HASH_H_ diff --git a/ApplicationCode/Commands/IntersectionViewCommands/RicNewIntersectionViewFeature.cpp b/ApplicationCode/Commands/IntersectionViewCommands/RicNewIntersectionViewFeature.cpp index 42d8e45ab0..92d81bdd5a 100644 --- a/ApplicationCode/Commands/IntersectionViewCommands/RicNewIntersectionViewFeature.cpp +++ b/ApplicationCode/Commands/IntersectionViewCommands/RicNewIntersectionViewFeature.cpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018- Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -23,7 +23,7 @@ #include "RimIntersection.h" #include "Riu3DMainWindowTools.h" -#include "RiuSelectionManager.h" +#include "Riu3dSelectionManager.h" #include "cafSelectionManagerTools.h" @@ -102,8 +102,8 @@ std::set RicNewIntersectionViewFeature::selectedIntersections( { std::set objects; - RiuSelectionManager* riuSelManager = RiuSelectionManager::instance(); - RiuSelectionItem* selItem = riuSelManager->selectedItem(RiuSelectionManager::RUI_TEMPORARY); + Riu3dSelectionManager* riuSelManager = Riu3dSelectionManager::instance(); + RiuSelectionItem* selItem = riuSelManager->selectedItem(Riu3dSelectionManager::RUI_TEMPORARY); RiuGeneralSelectionItem* generalSelectionItem = static_cast(selItem); if (generalSelectionItem) diff --git a/ApplicationCode/Commands/IntersectionViewCommands/RicNewIntersectionViewFeature.h b/ApplicationCode/Commands/IntersectionViewCommands/RicNewIntersectionViewFeature.h index 7f7a1af9d6..e6be38a77d 100644 --- a/ApplicationCode/Commands/IntersectionViewCommands/RicNewIntersectionViewFeature.h +++ b/ApplicationCode/Commands/IntersectionViewCommands/RicNewIntersectionViewFeature.h @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018- Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by diff --git a/ApplicationCode/Commands/MeasurementCommands/CMakeLists_files.cmake b/ApplicationCode/Commands/MeasurementCommands/CMakeLists_files.cmake new file mode 100644 index 0000000000..ce64437e6c --- /dev/null +++ b/ApplicationCode/Commands/MeasurementCommands/CMakeLists_files.cmake @@ -0,0 +1,23 @@ + +set (SOURCE_GROUP_HEADER_FILES +${CMAKE_CURRENT_LIST_DIR}/RicToggleMeasurementModeFeature.h +${CMAKE_CURRENT_LIST_DIR}/RicMeasurementPickEventHandler.h +) + +set (SOURCE_GROUP_SOURCE_FILES +${CMAKE_CURRENT_LIST_DIR}/RicToggleMeasurementModeFeature.cpp +${CMAKE_CURRENT_LIST_DIR}/RicMeasurementPickEventHandler.cpp +) + +list(APPEND CODE_HEADER_FILES +${SOURCE_GROUP_HEADER_FILES} +) + +list(APPEND CODE_SOURCE_FILES +${SOURCE_GROUP_SOURCE_FILES} +) + +list(APPEND QT_MOC_HEADERS +) + +source_group( "CommandFeature\\Measurement" FILES ${SOURCE_GROUP_HEADER_FILES} ${SOURCE_GROUP_SOURCE_FILES} ${CMAKE_CURRENT_LIST_DIR}/CMakeLists_files.cmake ) diff --git a/ApplicationCode/Commands/MeasurementCommands/RicMeasurementPickEventHandler.cpp b/ApplicationCode/Commands/MeasurementCommands/RicMeasurementPickEventHandler.cpp new file mode 100644 index 0000000000..305bb8b109 --- /dev/null +++ b/ApplicationCode/Commands/MeasurementCommands/RicMeasurementPickEventHandler.cpp @@ -0,0 +1,134 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2018- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "RicMeasurementPickEventHandler.h" + +#include "RiaApplication.h" +#include "RiuViewer.h" +#include "RiuViewerCommands.h" + +#include "Rim3dView.h" +#include "RimIntersection.h" +#include "RimMeasurement.h" +#include "RimProject.h" + +#include "cafDisplayCoordTransform.h" +#include "cafSelectionManager.h" + +#include "RivPartPriority.h" + +#include "cvfPart.h" + +#include + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RicMeasurementPickEventHandler* RicMeasurementPickEventHandler::instance() +{ + static RicMeasurementPickEventHandler* singleton = new RicMeasurementPickEventHandler; + return singleton; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicMeasurementPickEventHandler::registerAsPickEventHandler() +{ + RiuViewer::setHoverCursor(Qt::CrossCursor); + RiuViewerCommands::setPickEventHandler(RicMeasurementPickEventHandler::instance()); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicMeasurementPickEventHandler::unregisterAsPickEventHandler() +{ + RiuViewer::clearHoverCursor(); + RiuViewerCommands::removePickEventHandlerIfActive(RicMeasurementPickEventHandler::instance()); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RicMeasurementPickEventHandler::RicMeasurementPickEventHandler() + : m_polyLineModeEnabled(false) +{ +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicMeasurementPickEventHandler::enablePolyLineMode(bool polyLineModeEnabled) +{ + m_polyLineModeEnabled = polyLineModeEnabled; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RicMeasurementPickEventHandler::handle3dPickEvent(const Ric3dPickEvent& eventObject) +{ + auto measurement = RiaApplication::instance()->project()->measurement(); + + if (measurement && measurement->measurementMode()) + { + const RiuPickItemInfo* firstGeometryPickInfo = nullptr; + for (const auto& info : eventObject.m_pickItemInfos) + { + auto partCandidate = info.pickedPart(); + if (!firstGeometryPickInfo && partCandidate->priority() != RivPartPriority::PartType::Text) + { + firstGeometryPickInfo = &info; + } + } + + Rim3dView* rimView = RiaApplication::instance()->activeReservoirView(); + + if (firstGeometryPickInfo && rimView) + { + cvf::ref transForm = rimView->displayCoordTransform(); + + cvf::Vec3d domainCoord = transForm->transformToDomainCoord(firstGeometryPickInfo->globalPickedPoint()); + + bool isControlButtonDown = QApplication::keyboardModifiers() & Qt::ControlModifier; + + bool isPolyLineMode = m_polyLineModeEnabled != isControlButtonDown; + + if (!isPolyLineMode) + { + if (measurement->pointsInDomainCoords().size() > 1) + { + measurement->removeAllPoints(); + } + } + + measurement->addPointInDomainCoords(domainCoord); + } + + // Further Ui processing is stopped when true is returned + return true; + } + + return false; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicMeasurementPickEventHandler::notifyUnregistered() {} diff --git a/ApplicationCode/Commands/MeasurementCommands/RicMeasurementPickEventHandler.h b/ApplicationCode/Commands/MeasurementCommands/RicMeasurementPickEventHandler.h new file mode 100644 index 0000000000..f62057cf18 --- /dev/null +++ b/ApplicationCode/Commands/MeasurementCommands/RicMeasurementPickEventHandler.h @@ -0,0 +1,44 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2018- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "Ric3dViewPickEventHandler.h" + +//================================================================================================== +/// +//================================================================================================== +class RicMeasurementPickEventHandler : public Ric3dViewPickEventHandler +{ +public: + static RicMeasurementPickEventHandler* instance(); + + void registerAsPickEventHandler() override; + void unregisterAsPickEventHandler() override; + + void enablePolyLineMode(bool polyLineModeEnabled); + +protected: + RicMeasurementPickEventHandler(); + bool handle3dPickEvent(const Ric3dPickEvent& eventObject) override; + void notifyUnregistered() override; + +private: + bool m_polyLineModeEnabled; +}; + diff --git a/ApplicationCode/Commands/MeasurementCommands/RicToggleMeasurementModeFeature.cpp b/ApplicationCode/Commands/MeasurementCommands/RicToggleMeasurementModeFeature.cpp new file mode 100644 index 0000000000..07074bc241 --- /dev/null +++ b/ApplicationCode/Commands/MeasurementCommands/RicToggleMeasurementModeFeature.cpp @@ -0,0 +1,196 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2018- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "RicToggleMeasurementModeFeature.h" + +#include "RiaApplication.h" + +#include "Rim3dView.h" +#include "RimMeasurement.h" +#include "RimProject.h" + +#include "cafCmdFeatureManager.h" +#include "cafPdmUiPropertyViewDialog.h" +#include "cafSelectionManager.h" +#include "cvfAssert.h" + +#include + +CAF_CMD_SOURCE_INIT(RicToggleMeasurementModeFeature, "RicToggleMeasurementModeFeature"); +CAF_CMD_SOURCE_INIT(RicTogglePolyMeasurementModeFeature, "RicTogglePolyMeasurementModeFeature"); + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicToggleMeasurementModeFeature::refreshActionLook() +{ + setupActionLook(action()); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RicToggleMeasurementModeFeature::isCommandEnabled() +{ + return activeView() != nullptr; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicToggleMeasurementModeFeature::onActionTriggered(bool isChecked) +{ + auto meas = measurement(); + if (meas->measurementMode() == RimMeasurement::MEASURE_REGULAR) + { + meas->setMeasurementMode(RimMeasurement::MEASURE_DISABLED); + } + else + { + meas->setMeasurementMode(RimMeasurement::MEASURE_REGULAR); + } + + refreshActionLook(); + refreshPolyMeasuremeantActionLook(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicToggleMeasurementModeFeature::setupActionLook(QAction* actionToSetup) +{ + actionToSetup->setText("Measurement"); + actionToSetup->setToolTip("Single Line Measurement (Ctrl+M)"); + actionToSetup->setIcon(QIcon(":/Ruler24x24.png")); + actionToSetup->setCheckable(true); + + auto* meas = measurement(); + if (meas && meas->measurementMode() == RimMeasurement::MEASURE_REGULAR) + { + applyShortcutWithHintToAction(actionToSetup, QKeySequence(Qt::Key_Escape)); + applyShortcutWithHintToAction(actionToSetup, QKeySequence(tr("Ctrl+M"))); + } + else + { + applyShortcutWithHintToAction(actionToSetup, QKeySequence(tr("Ctrl+M"))); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RicToggleMeasurementModeFeature::isCommandChecked() +{ + auto meas = measurement(); + if (meas) + { + return meas->measurementMode() == RimMeasurement::MEASURE_REGULAR; + } + + return false; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimMeasurement* RicToggleMeasurementModeFeature::measurement() const +{ + return RiaApplication::instance()->project()->measurement(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +Rim3dView* RicToggleMeasurementModeFeature::activeView() const +{ + auto view = RiaApplication::instance()->activeReservoirView(); + return view; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicToggleMeasurementModeFeature::refreshPolyMeasuremeantActionLook() +{ + auto cmdFeature = caf::CmdFeatureManager::instance()->getCommandFeature("RicTogglePolyMeasurementModeFeature"); + static_cast(cmdFeature)->refreshActionLook(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicTogglePolyMeasurementModeFeature::onActionTriggered(bool isChecked) +{ + auto meas = measurement(); + if (meas->measurementMode() == RimMeasurement::MEASURE_POLYLINE) + { + meas->setMeasurementMode(RimMeasurement::MEASURE_DISABLED); + } + else + { + meas->setMeasurementMode(RimMeasurement::MEASURE_POLYLINE); + } + + refreshActionLook(); + refreshMeasurementActionLook(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicTogglePolyMeasurementModeFeature::setupActionLook(QAction* actionToSetup) +{ + actionToSetup->setText("Poly Line Measurement"); + actionToSetup->setToolTip("Poly Line Measurement (Ctrl+Shift+M)"); + actionToSetup->setIcon(QIcon(":/RulerPoly24x24.png")); + actionToSetup->setCheckable(true); + + auto* meas = measurement(); + if (meas && meas->measurementMode() == RimMeasurement::MEASURE_POLYLINE) + { + applyShortcutWithHintToAction(actionToSetup, QKeySequence(Qt::Key_Escape)); + applyShortcutWithHintToAction(actionToSetup, QKeySequence(tr("Ctrl+Shift+M"))); + } + else + { + applyShortcutWithHintToAction(actionToSetup, QKeySequence(tr("Ctrl+Shift+M"))); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RicTogglePolyMeasurementModeFeature::isCommandChecked() +{ + auto meas = measurement(); + if (meas) + { + return meas->measurementMode() == RimMeasurement::MEASURE_POLYLINE; + } + + return false; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicTogglePolyMeasurementModeFeature::refreshMeasurementActionLook() +{ + auto cmdFeature = caf::CmdFeatureManager::instance()->getCommandFeature("RicToggleMeasurementModeFeature"); + static_cast(cmdFeature)->refreshActionLook(); +} diff --git a/ApplicationCode/Commands/MeasurementCommands/RicToggleMeasurementModeFeature.h b/ApplicationCode/Commands/MeasurementCommands/RicToggleMeasurementModeFeature.h new file mode 100644 index 0000000000..87c448d935 --- /dev/null +++ b/ApplicationCode/Commands/MeasurementCommands/RicToggleMeasurementModeFeature.h @@ -0,0 +1,67 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2018- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "cafCmdFeature.h" + +class RimMeasurement; +class Rim3dView; +class QObject; +class RiuMeasurementViewEventFilter; + + +//================================================================================================== +/// +//================================================================================================== +class RicToggleMeasurementModeFeature : public caf::CmdFeature +{ + CAF_CMD_HEADER_INIT; + + void refreshActionLook(); + +protected: + bool isCommandEnabled() override; + void onActionTriggered( bool isChecked ) override; + void setupActionLook(QAction* actionToSetup) override; + bool isCommandChecked() override; + +protected: + RimMeasurement* measurement() const; + Rim3dView* activeView() const; + +private: + void refreshPolyMeasuremeantActionLook(); +}; + +//================================================================================================== +/// +//================================================================================================== +class RicTogglePolyMeasurementModeFeature : public RicToggleMeasurementModeFeature +{ + CAF_CMD_HEADER_INIT; + +protected: + void onActionTriggered(bool isChecked) override; + void setupActionLook(QAction* actionToSetup) override; + bool isCommandChecked() override; + +private: + void refreshMeasurementActionLook(); + +}; diff --git a/ApplicationCode/Commands/OctaveScriptCommands/RicDeleteScriptPathFeature.cpp b/ApplicationCode/Commands/OctaveScriptCommands/RicDeleteScriptPathFeature.cpp index a1d1ba84aa..fe5e2c6323 100644 --- a/ApplicationCode/Commands/OctaveScriptCommands/RicDeleteScriptPathFeature.cpp +++ b/ApplicationCode/Commands/OctaveScriptCommands/RicDeleteScriptPathFeature.cpp @@ -82,4 +82,5 @@ void RicDeleteScriptPathFeature::setupActionLook(QAction* actionToSetup) { actionToSetup->setText("Delete Script Path"); actionToSetup->setIcon(QIcon(":/Erase.png")); + applyShortcutWithHintToAction(actionToSetup, QKeySequence::Delete); } diff --git a/ApplicationCode/Commands/OctaveScriptCommands/RicEditScriptFeature.cpp b/ApplicationCode/Commands/OctaveScriptCommands/RicEditScriptFeature.cpp index fa21027efe..1244ef4ef1 100644 --- a/ApplicationCode/Commands/OctaveScriptCommands/RicEditScriptFeature.cpp +++ b/ApplicationCode/Commands/OctaveScriptCommands/RicEditScriptFeature.cpp @@ -58,7 +58,7 @@ void RicEditScriptFeature::onActionTriggered(bool isChecked) if (!scriptEditor.isEmpty()) { QStringList arguments; - arguments << calcScript->absolutePath; + arguments << calcScript->absoluteFileName; QProcess* myProcess = new QProcess(this); myProcess->start(scriptEditor, arguments); diff --git a/ApplicationCode/Commands/OctaveScriptCommands/RicExecuteScriptFeature.cpp b/ApplicationCode/Commands/OctaveScriptCommands/RicExecuteScriptFeature.cpp index a0658ec706..e52539aa29 100644 --- a/ApplicationCode/Commands/OctaveScriptCommands/RicExecuteScriptFeature.cpp +++ b/ApplicationCode/Commands/OctaveScriptCommands/RicExecuteScriptFeature.cpp @@ -59,15 +59,7 @@ void RicExecuteScriptFeature::onActionTriggered(bool isChecked) QString octavePath = app->octavePath(); if (!octavePath.isEmpty()) { - // TODO: Must rename RimCalcScript::absolutePath to absoluteFileName, as the code below is confusing - // absolutePath() is a function in QFileInfo - QFileInfo fi(calcScript->absolutePath()); - QString octaveFunctionSearchPath = fi.absolutePath(); - - QStringList arguments = app->octaveArguments(); - arguments.append("--path"); - arguments << octaveFunctionSearchPath; - arguments << calcScript->absolutePath(); + QStringList arguments = RimCalcScript::createCommandLineArguments(calcScript->absoluteFileName()); RiaApplication::instance()->launchProcess(octavePath, arguments); } diff --git a/ApplicationCode/Commands/OctaveScriptCommands/RicExecuteScriptForCasesFeature.cpp b/ApplicationCode/Commands/OctaveScriptCommands/RicExecuteScriptForCasesFeature.cpp index c86253283a..9c3f0e1192 100644 --- a/ApplicationCode/Commands/OctaveScriptCommands/RicExecuteScriptForCasesFeature.cpp +++ b/ApplicationCode/Commands/OctaveScriptCommands/RicExecuteScriptForCasesFeature.cpp @@ -19,8 +19,11 @@ #include "RicExecuteScriptForCasesFeature.h" -#include "RimCase.h" #include "RiaApplication.h" + +#include "RimCase.h" +#include "RimCalcScript.h" + #include "RiuMainWindow.h" #include "cafSelectionManager.h" @@ -62,16 +65,7 @@ void RicExecuteScriptForCasesFeature::onActionTriggered(bool isChecked) QString octavePath = app->octavePath(); if (!octavePath.isEmpty()) { - // TODO: Must rename RimCalcScript::absolutePath to absoluteFileName, as the code below is confusing - // absolutePath() is a function in QFileInfo - - QFileInfo fi(scriptAbsolutePath); - QString octaveFunctionSearchPath = fi.absolutePath(); - - QStringList arguments = app->octaveArguments(); - arguments.append("--path"); - arguments << octaveFunctionSearchPath; - arguments << scriptAbsolutePath; + QStringList arguments = RimCalcScript::createCommandLineArguments(scriptAbsolutePath); std::vector selection; caf::SelectionManager::instance()->objectsByType(&selection); diff --git a/ApplicationCode/Commands/OctaveScriptCommands/RicNewScriptFeature.cpp b/ApplicationCode/Commands/OctaveScriptCommands/RicNewScriptFeature.cpp index 47df7d2f4b..7864db945d 100644 --- a/ApplicationCode/Commands/OctaveScriptCommands/RicNewScriptFeature.cpp +++ b/ApplicationCode/Commands/OctaveScriptCommands/RicNewScriptFeature.cpp @@ -63,7 +63,7 @@ void RicNewScriptFeature::onActionTriggered(bool isChecked) if (calcScript) { - QFileInfo existingScriptFileInfo(calcScript->absolutePath()); + QFileInfo existingScriptFileInfo(calcScript->absoluteFileName()); fullPathNewScript = existingScriptFileInfo.absolutePath(); } else if (scriptColl) diff --git a/ApplicationCode/Commands/OperationsUsingObjReferences/RicCopyReferencesToClipboardFeature.cpp b/ApplicationCode/Commands/OperationsUsingObjReferences/RicCopyReferencesToClipboardFeature.cpp index a09af8470a..9d773ed26f 100644 --- a/ApplicationCode/Commands/OperationsUsingObjReferences/RicCopyReferencesToClipboardFeature.cpp +++ b/ApplicationCode/Commands/OperationsUsingObjReferences/RicCopyReferencesToClipboardFeature.cpp @@ -2,17 +2,17 @@ // // Copyright (C) 2015- Statoil ASA // Copyright (C) 2015- Ceetron Solutions AS -// +// // ResInsight 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 3 of the License, or // (at your option) any later version. -// +// // ResInsight 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 at +// +// See the GNU General Public License at // for more details. // ///////////////////////////////////////////////////////////////////////////////// @@ -24,6 +24,8 @@ #include "RimEnsembleCurveSet.h" #include "RimFractureTemplate.h" #include "RimGeoMechView.h" +#include "RimGridCrossPlotCurve.h" +#include "RimGridCrossPlotDataSet.h" #include "RimIntersection.h" #include "RimIntersectionBox.h" #include "RimMimeData.h" @@ -42,13 +44,10 @@ #include #include - - CAF_CMD_SOURCE_INIT(RicCopyReferencesToClipboardFeature, "RicCopyReferencesToClipboardFeature"); - //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- bool RicCopyReferencesToClipboardFeature::isCommandEnabled() { @@ -56,7 +55,7 @@ bool RicCopyReferencesToClipboardFeature::isCommandEnabled() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RicCopyReferencesToClipboardFeature::onActionTriggered(bool isChecked) { @@ -73,8 +72,9 @@ void RicCopyReferencesToClipboardFeature::onActionTriggered(bool isChecked) { if (RicCopyReferencesToClipboardFeature::isCopyOfObjectSupported(pdmObject)) { - QString itemRef = caf::PdmReferenceHelper::referenceFromRootToObject(caf::SelectionManager::instance()->pdmRootObject(), pdmObject); - + QString itemRef = + caf::PdmReferenceHelper::referenceFromRootToObject(caf::SelectionManager::instance()->pdmRootObject(), pdmObject); + referenceList.push_back(itemRef); } } @@ -90,17 +90,17 @@ void RicCopyReferencesToClipboardFeature::onActionTriggered(bool isChecked) } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RicCopyReferencesToClipboardFeature::setupActionLook(QAction* actionToSetup) { actionToSetup->setText("Copy"); actionToSetup->setIcon(QIcon(":/Copy.png")); - actionToSetup->setShortcuts(QKeySequence::Copy); + applyShortcutWithHintToAction(actionToSetup, QKeySequence::Copy); } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- bool RicCopyReferencesToClipboardFeature::isAnyCopyableObjectSelected() { @@ -119,12 +119,12 @@ bool RicCopyReferencesToClipboardFeature::isAnyCopyableObjectSelected() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- bool RicCopyReferencesToClipboardFeature::isCopyOfObjectSupported(caf::PdmObject* pdmObject) { RimWellAllocationPlot* wellAllocPlot = nullptr; - RimWellRftPlot* rftPlot = nullptr; + RimWellRftPlot* rftPlot = nullptr; pdmObject->firstAncestorOrThisOfType(wellAllocPlot); pdmObject->firstAncestorOrThisOfType(rftPlot); @@ -152,9 +152,9 @@ bool RicCopyReferencesToClipboardFeature::isCopyOfObjectSupported(caf::PdmObject { return true; } - else if (dynamic_cast(pdmObject)) + else if (dynamic_cast(pdmObject) && !dynamic_cast(pdmObject)) { - if(!rftPlot) return true; + if (!rftPlot) return true; } else if (dynamic_cast(pdmObject)) { @@ -172,6 +172,10 @@ bool RicCopyReferencesToClipboardFeature::isCopyOfObjectSupported(caf::PdmObject { return true; } + else if (dynamic_cast(pdmObject)) + { + return true; + } return false; } diff --git a/ApplicationCode/Commands/OperationsUsingObjReferences/RicCutReferencesToClipboardFeature.cpp b/ApplicationCode/Commands/OperationsUsingObjReferences/RicCutReferencesToClipboardFeature.cpp index f84687c035..efbb0fffc9 100644 --- a/ApplicationCode/Commands/OperationsUsingObjReferences/RicCutReferencesToClipboardFeature.cpp +++ b/ApplicationCode/Commands/OperationsUsingObjReferences/RicCutReferencesToClipboardFeature.cpp @@ -82,7 +82,7 @@ void RicCutReferencesToClipboardFeature::setupActionLook(QAction* actionToSetup) { actionToSetup->setText("Cut"); actionToSetup->setIcon(QIcon(":/Clipboard.png")); - actionToSetup->setShortcut(QKeySequence::Cut); + applyShortcutWithHintToAction(actionToSetup, QKeySequence::Cut); } //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/Commands/OperationsUsingObjReferences/RicPasteFeatureImpl.cpp b/ApplicationCode/Commands/OperationsUsingObjReferences/RicPasteFeatureImpl.cpp index 07e9b605ea..e53d85a0f4 100644 --- a/ApplicationCode/Commands/OperationsUsingObjReferences/RicPasteFeatureImpl.cpp +++ b/ApplicationCode/Commands/OperationsUsingObjReferences/RicPasteFeatureImpl.cpp @@ -30,6 +30,7 @@ #include "RimMimeData.h" #include "RimProject.h" +#include "cafCmdFeature.h" #include "cafPdmObjectGroup.h" #include "cafPdmObjectHandle.h" @@ -146,7 +147,7 @@ void RicPasteFeatureImpl::setIconAndShortcuts(QAction* action) if (action) { action->setIcon(QIcon(":/clipboard.png")); - action->setShortcuts(QKeySequence::Paste); + caf::CmdFeature::applyShortcutWithHintToAction(action, QKeySequence::Paste); } } diff --git a/ApplicationCode/Commands/OperationsUsingObjReferences/RicPasteIntersectionsFeature.cpp b/ApplicationCode/Commands/OperationsUsingObjReferences/RicPasteIntersectionsFeature.cpp index b7ed0e8e1c..0a863c5870 100644 --- a/ApplicationCode/Commands/OperationsUsingObjReferences/RicPasteIntersectionsFeature.cpp +++ b/ApplicationCode/Commands/OperationsUsingObjReferences/RicPasteIntersectionsFeature.cpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018- Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by diff --git a/ApplicationCode/Commands/OperationsUsingObjReferences/RicPasteIntersectionsFeature.h b/ApplicationCode/Commands/OperationsUsingObjReferences/RicPasteIntersectionsFeature.h index 47b749c38b..25051d38b3 100644 --- a/ApplicationCode/Commands/OperationsUsingObjReferences/RicPasteIntersectionsFeature.h +++ b/ApplicationCode/Commands/OperationsUsingObjReferences/RicPasteIntersectionsFeature.h @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018- Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by diff --git a/ApplicationCode/Commands/Ric3dViewPickEventHandler.cpp b/ApplicationCode/Commands/Ric3dViewPickEventHandler.cpp new file mode 100644 index 0000000000..1185847025 --- /dev/null +++ b/ApplicationCode/Commands/Ric3dViewPickEventHandler.cpp @@ -0,0 +1,50 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2019- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// +#include "Ric3dViewPickEventHandler.h" +#include "RiuViewerCommands.h" + +#include + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void Ric3dViewPickEventHandler::registerAsPickEventHandler() +{ + RiuViewerCommands::setPickEventHandler(this); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void Ric3dViewPickEventHandler::unregisterAsPickEventHandler() +{ + RiuViewerCommands::removePickEventHandlerIfActive(this); +} + +//-------------------------------------------------------------------------------------------------- +/// Override from caf::PickEventHandler. Translates to a 3d Pick event. +//-------------------------------------------------------------------------------------------------- +bool Ric3dViewPickEventHandler::handlePickEvent(const caf::PickEvent& eventObject) +{ + const Ric3dPickEvent* eventObject3d = dynamic_cast(&eventObject); + if (eventObject3d != nullptr) + { + return handle3dPickEvent(*eventObject3d); + } + return false; +} diff --git a/ApplicationCode/Commands/Ric3dViewPickEventHandler.h b/ApplicationCode/Commands/Ric3dViewPickEventHandler.h new file mode 100644 index 0000000000..2e2ce8da46 --- /dev/null +++ b/ApplicationCode/Commands/Ric3dViewPickEventHandler.h @@ -0,0 +1,40 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2019- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// +#pragma once + +#include "RicPickEventHandler.h" + +#include "cafPdmField.h" +#include "cafPdmObjectHandle.h" + +//================================================================================================== +/// A temporary, dynamic pick handler that overrides the default ones +//================================================================================================== +class Ric3dViewPickEventHandler : public caf::PickEventHandler +{ +public: + // Override from caf + void registerAsPickEventHandler() override; + void unregisterAsPickEventHandler() override; + bool handlePickEvent(const caf::PickEvent& eventObject) override; + virtual bool handle3dPickEvent(const Ric3dPickEvent& eventObject) = 0; + +}; + + + diff --git a/ApplicationCode/Commands/RicCloseCaseFeature.cpp b/ApplicationCode/Commands/RicCloseCaseFeature.cpp index c95cced44f..50c15e2805 100644 --- a/ApplicationCode/Commands/RicCloseCaseFeature.cpp +++ b/ApplicationCode/Commands/RicCloseCaseFeature.cpp @@ -2,17 +2,17 @@ // // Copyright (C) 2015- Statoil ASA // Copyright (C) 2015- Ceetron Solutions AS -// +// // ResInsight 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 3 of the License, or // (at your option) any later version. -// +// // ResInsight 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 at +// +// See the GNU General Public License at // for more details. // ///////////////////////////////////////////////////////////////////////////////// @@ -21,18 +21,19 @@ #include "RiaApplication.h" +#include "RimAdvancedSnapshotExportDefinition.h" #include "RimCaseCollection.h" #include "RimEclipseCase.h" -#include "RimEclipseResultCase.h" #include "RimEclipseCaseCollection.h" +#include "RimEclipseResultCase.h" #include "RimEclipseStatisticsCase.h" #include "RimGeoMechCase.h" #include "RimGeoMechModels.h" +#include "RimGridSummaryCase.h" #include "RimIdenticalGridCaseGroup.h" +#include "RimMainPlotCollection.h" #include "RimOilField.h" #include "RimProject.h" -#include "RimMainPlotCollection.h" -#include "RimGridSummaryCase.h" #include "RimSummaryCaseMainCollection.h" #include "RimWellLogPlotCollection.h" @@ -48,7 +49,7 @@ CAF_CMD_SOURCE_INIT(RicCloseCaseFeature, "RicCloseCaseFeature"); //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- bool RicCloseCaseFeature::isCommandEnabled() { @@ -56,7 +57,7 @@ bool RicCloseCaseFeature::isCommandEnabled() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RicCloseCaseFeature::onActionTriggered(bool isChecked) { @@ -90,7 +91,7 @@ void RicCloseCaseFeature::onActionTriggered(bool isChecked) RiuMainWindow::instance()->cleanupGuiCaseClose(); } } - + if (!geoMechCases.empty()) { for (RimGeoMechCase* geoMechCase : geoMechCases) @@ -102,17 +103,17 @@ void RicCloseCaseFeature::onActionTriggered(bool isChecked) } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RicCloseCaseFeature::setupActionLook(QAction* actionToSetup) { actionToSetup->setText("Close"); actionToSetup->setIcon(QIcon(":/Erase.png")); + applyShortcutWithHintToAction(actionToSetup, QKeySequence::Delete); } - //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- std::vector RicCloseCaseFeature::selectedCases() const { @@ -122,14 +123,14 @@ std::vector RicCloseCaseFeature::selectedCases() const } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RicCloseCaseFeature::removeCaseFromAllGroups(RimEclipseCase* eclipseCase) { CVF_ASSERT(eclipseCase); - RimProject* proj = RiaApplication::instance()->project(); - RimOilField* activeOilField = proj ? proj->activeOilField() : nullptr; + RimProject* proj = RiaApplication::instance()->project(); + RimOilField* activeOilField = proj ? proj->activeOilField() : nullptr; RimEclipseCaseCollection* analysisModels = (activeOilField) ? activeOilField->analysisModels() : nullptr; if (analysisModels) { @@ -139,7 +140,7 @@ void RicCloseCaseFeature::removeCaseFromAllGroups(RimEclipseCase* eclipseCase) } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RicCloseCaseFeature::deleteEclipseCase(RimEclipseCase* eclipseCase) { @@ -189,8 +190,9 @@ void RicCloseCaseFeature::deleteEclipseCase(RimEclipseCase* eclipseCase) RimEclipseResultCase* resultCase = dynamic_cast(eclipseCase); if (resultCase) { - RimProject* project = RiaApplication::instance()->project(); - RimSummaryCaseMainCollection* sumCaseColl = project->activeOilField() ? project->activeOilField()->summaryCaseMainCollection() : nullptr; + RimProject* project = RiaApplication::instance()->project(); + RimSummaryCaseMainCollection* sumCaseColl = + project->activeOilField() ? project->activeOilField()->summaryCaseMainCollection() : nullptr; if (sumCaseColl) { RimSummaryCase* summaryCase = sumCaseColl->findSummaryCaseFromEclipseResultCase(resultCase); @@ -203,18 +205,37 @@ void RicCloseCaseFeature::deleteEclipseCase(RimEclipseCase* eclipseCase) } delete eclipseCase; + + { + RimProject* project = RiaApplication::instance()->project(); + + std::vector cases; + project->allCases(cases); + + if (cases.empty()) + { + project->multiSnapshotDefinitions.deleteAllChildObjects(); + } + else + { + for (RimAdvancedSnapshotExportDefinition* msd : project->multiSnapshotDefinitions()) + { + msd->additionalCases.removePtr(nullptr); + } + } + } } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RicCloseCaseFeature::deleteGeoMechCase(RimGeoMechCase* geoMechCase) { CVF_ASSERT(geoMechCase); - RimProject* proj = RiaApplication::instance()->project(); - RimOilField* activeOilField = proj ? proj->activeOilField() : nullptr; - RimGeoMechModels* models = (activeOilField) ? activeOilField->geoMechModels() : nullptr; + RimProject* proj = RiaApplication::instance()->project(); + RimOilField* activeOilField = proj ? proj->activeOilField() : nullptr; + RimGeoMechModels* models = (activeOilField) ? activeOilField->geoMechModels() : nullptr; if (models) { models->cases.removeChildObject(geoMechCase); @@ -225,7 +246,7 @@ void RicCloseCaseFeature::deleteGeoMechCase(RimGeoMechCase* geoMechCase) } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- bool RicCloseCaseFeature::hasAnyStatisticsResults(RimIdenticalGridCaseGroup* gridCaseGroup) { @@ -233,7 +254,8 @@ bool RicCloseCaseFeature::hasAnyStatisticsResults(RimIdenticalGridCaseGroup* gri for (size_t i = 0; i < gridCaseGroup->statisticsCaseCollection()->reservoirs().size(); i++) { - RimEclipseStatisticsCase* rimStaticsCase = dynamic_cast(gridCaseGroup->statisticsCaseCollection()->reservoirs[i]); + RimEclipseStatisticsCase* rimStaticsCase = + dynamic_cast(gridCaseGroup->statisticsCaseCollection()->reservoirs[i]); if (rimStaticsCase) { if (rimStaticsCase->hasComputedStatistics()) @@ -246,18 +268,17 @@ bool RicCloseCaseFeature::hasAnyStatisticsResults(RimIdenticalGridCaseGroup* gri return false; } - //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- bool RicCloseCaseFeature::userConfirmedGridCaseGroupChange(const std::vector& casesToBeDeleted) { std::vector gridCaseGroups; - for (size_t i = 0; i < casesToBeDeleted.size(); i++) + for (auto caseToDelete : casesToBeDeleted) { RimIdenticalGridCaseGroup* gridCaseGroup = nullptr; - casesToBeDeleted[i]->firstAncestorOrThisOfType(gridCaseGroup); + caseToDelete->firstAncestorOrThisOfType(gridCaseGroup); if (gridCaseGroup && hasAnyStatisticsResults(gridCaseGroup)) { @@ -265,7 +286,7 @@ bool RicCloseCaseFeature::userConfirmedGridCaseGroupChange(const std::vector 0) + if (!gridCaseGroups.empty()) { RiuMainWindow* mainWnd = RiuMainWindow::instance(); @@ -275,15 +296,16 @@ bool RicCloseCaseFeature::userConfirmedGridCaseGroupChange(const std::vectorname()); + questionText = QString("This operation will invalidate statistics results in grid case group\n\"%1\".\n") + .arg(gridCaseGroups[0]->name()); questionText += "Computed results in this group will be deleted if you continue."; } else { questionText = "This operation will invalidate statistics results in grid case groups\n"; - for (size_t i = 0; i < gridCaseGroups.size(); i++) + for (auto& gridCaseGroup : gridCaseGroups) { - questionText += QString("\"%1\"\n").arg(gridCaseGroups[i]->name()); + questionText += QString("\"%1\"\n").arg(gridCaseGroup->name()); } questionText += "Computed results in these groups will be deleted if you continue."; diff --git a/ApplicationCode/Commands/RicCloseCaseFeature.h b/ApplicationCode/Commands/RicCloseCaseFeature.h index e7d370e8f5..ad048f7a08 100644 --- a/ApplicationCode/Commands/RicCloseCaseFeature.h +++ b/ApplicationCode/Commands/RicCloseCaseFeature.h @@ -2,17 +2,17 @@ // // Copyright (C) 2015- Statoil ASA // Copyright (C) 2015- Ceetron Solutions AS -// +// // ResInsight 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 3 of the License, or // (at your option) any later version. -// +// // ResInsight 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 at +// +// See the GNU General Public License at // for more details. // ///////////////////////////////////////////////////////////////////////////////// @@ -29,7 +29,7 @@ class RimCase; class RimIdenticalGridCaseGroup; //================================================================================================== -/// +/// //================================================================================================== class RicCloseCaseFeature : public caf::CmdFeature { @@ -42,16 +42,14 @@ class RicCloseCaseFeature : public caf::CmdFeature protected: // Overrides bool isCommandEnabled() override; - void onActionTriggered( bool isChecked ) override; - void setupActionLook( QAction* actionToSetup ) override; + void onActionTriggered(bool isChecked) override; + void setupActionLook(QAction* actionToSetup) override; private: std::vector selectedCases() const; void deleteGeoMechCase(RimGeoMechCase* geoMechCase); - + static bool hasAnyStatisticsResults(RimIdenticalGridCaseGroup* gridCaseGroup); static void removeCaseFromAllGroups(RimEclipseCase* eclipseCase); }; - - diff --git a/ApplicationCode/Commands/RicCloseSummaryCaseFeature.cpp b/ApplicationCode/Commands/RicCloseSummaryCaseFeature.cpp index 7ac41e2ea1..9766037dd6 100644 --- a/ApplicationCode/Commands/RicCloseSummaryCaseFeature.cpp +++ b/ApplicationCode/Commands/RicCloseSummaryCaseFeature.cpp @@ -46,6 +46,7 @@ void RicCloseSummaryCaseFeature::setupActionLook(QAction* actionToSetup) { actionToSetup->setText("Close Summary Case"); actionToSetup->setIcon(QIcon(":/Erase.png")); + applyShortcutWithHintToAction(actionToSetup, QKeySequence::Delete); } //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/Commands/RicContourMapPickEventHandler.cpp b/ApplicationCode/Commands/RicContourMapPickEventHandler.cpp index de6b22eedf..6f6706b196 100644 --- a/ApplicationCode/Commands/RicContourMapPickEventHandler.cpp +++ b/ApplicationCode/Commands/RicContourMapPickEventHandler.cpp @@ -18,8 +18,8 @@ #include "RicContourMapPickEventHandler.h" #include "RimContourMapProjection.h" -#include "RimContourMapView.h" -#include "RimEclipseCellColors.h" +#include "RimGeoMechContourMapView.h" +#include "RimEclipseContourMapView.h" #include "Rim3dView.h" #include "RiuMainWindow.h" @@ -43,7 +43,7 @@ RicContourMapPickEventHandler* RicContourMapPickEventHandler::instance() //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -bool RicContourMapPickEventHandler::handlePickEvent(const Ric3DPickEvent& eventObject) +bool RicContourMapPickEventHandler::handle3dPickEvent(const Ric3dPickEvent& eventObject) { if (eventObject.m_pickItemInfos.empty()) return false; @@ -58,25 +58,33 @@ bool RicContourMapPickEventHandler::handlePickEvent(const Ric3DPickEvent& eventO { RiuMainWindow::instance()->selectAsCurrentItem(contourMap); - RimContourMapView* view = nullptr; + RimGridView* view = nullptr; contourMap->firstAncestorOrThisOfTypeAsserted(view); cvf::Vec2d pickedPoint; - cvf::Vec2ui pickedCell; double valueAtPoint = 0.0; - if (contourMap->checkForMapIntersection(firstPickedItem.globalPickedPoint(), &pickedPoint, &pickedCell, &valueAtPoint)) + if (contourMap->checkForMapIntersection(firstPickedItem.globalPickedPoint(), &pickedPoint, &valueAtPoint)) { QString curveText; curveText += QString("%1\n").arg(view->createAutoName()); curveText += QString("Picked Point X, Y: %1, %2\n").arg(pickedPoint.x(), 5, 'f', 0).arg(pickedPoint.y(), 5, 'f', 0); - curveText += QString("Picked Cell I, J: %1, %2\n").arg(pickedCell.x()).arg(pickedCell.y()); curveText += QString("Result Type: %1\n").arg(contourMap->resultDescriptionText()); curveText += QString("Aggregated Value: %1\n").arg(valueAtPoint); RiuMainWindow::instance()->setResultInfo(curveText); contourMap->setPickPoint(pickedPoint); - view->updateCurrentTimeStepAndRedraw(); + + RimGeoMechContourMapView* geoMechContourView = dynamic_cast(view); + RimEclipseContourMapView* eclipseContourView = dynamic_cast(view); + if (geoMechContourView) + { + geoMechContourView->updatePickPointAndRedraw(); + } + else + { + eclipseContourView->updatePickPointAndRedraw(); + } return true; } contourMap->setPickPoint(cvf::Vec2d::UNDEFINED); diff --git a/ApplicationCode/Commands/RicContourMapPickEventHandler.h b/ApplicationCode/Commands/RicContourMapPickEventHandler.h index cb9c1e6457..6a5bc1673f 100644 --- a/ApplicationCode/Commands/RicContourMapPickEventHandler.h +++ b/ApplicationCode/Commands/RicContourMapPickEventHandler.h @@ -29,6 +29,6 @@ class RicContourMapPickEventHandler : public RicDefaultPickEventHandler static RicContourMapPickEventHandler* instance(); protected: - bool handlePickEvent(const Ric3DPickEvent& eventObject) override; + bool handle3dPickEvent(const Ric3dPickEvent& eventObject) override; }; diff --git a/ApplicationCode/Commands/RicCreateTemporaryLgrFeature.cpp b/ApplicationCode/Commands/RicCreateTemporaryLgrFeature.cpp index 080d6c3c69..d13090c4f7 100644 --- a/ApplicationCode/Commands/RicCreateTemporaryLgrFeature.cpp +++ b/ApplicationCode/Commands/RicCreateTemporaryLgrFeature.cpp @@ -51,7 +51,7 @@ #include "RimWellPathCompletions.h" #include "RiuPlotMainWindow.h" -#include "RiuSelectionManager.h" +#include "Riu3dSelectionManager.h" #include #include @@ -344,12 +344,3 @@ void RicCreateTemporaryLgrFeature::computeCachedData(RimEclipseCase* eclipseCase } } -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -bool RicCreateTemporaryLgrFeature::containsAnyNonMainGridCells(const std::vector& cells) -{ - return std::find_if(cells.begin(), cells.end(), [](const RigCompletionDataGridCell& cell) { - return !cell.isMainGridCell(); - }) != cells.end(); -} diff --git a/ApplicationCode/Commands/RicCreateTemporaryLgrFeature.h b/ApplicationCode/Commands/RicCreateTemporaryLgrFeature.h index 0d3864cebd..86bd89da2f 100644 --- a/ApplicationCode/Commands/RicCreateTemporaryLgrFeature.h +++ b/ApplicationCode/Commands/RicCreateTemporaryLgrFeature.h @@ -65,5 +65,4 @@ class RicCreateTemporaryLgrFeature : public caf::CmdFeature void createLgr(const LgrInfo& lgrInfo, RigMainGrid* mainGrid); void computeCachedData(RimEclipseCase* eclipseCase); void deleteAllCachedData(RimEclipseCase* eclipseCase); - bool containsAnyNonMainGridCells(const std::vector& cells); }; diff --git a/ApplicationCode/Commands/RicCreateUserDefinedPolylinesAnnotationFeature.cpp b/ApplicationCode/Commands/RicCreateUserDefinedPolylinesAnnotationFeature.cpp new file mode 100644 index 0000000000..5fd6c0e6b3 --- /dev/null +++ b/ApplicationCode/Commands/RicCreateUserDefinedPolylinesAnnotationFeature.cpp @@ -0,0 +1,82 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2016- Statoil ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "RicCreateUserDefinedPolylinesAnnotationFeature.h" + +#include "RiaApplication.h" + +#include "RimTextAnnotation.h" +#include "RimReachCircleAnnotation.h" +#include "RimPolylinesAnnotation.h" +#include "RimAnnotationCollection.h" +#include "RimAnnotationInViewCollection.h" +#include "RimProject.h" +#include "RimOilField.h" + +#include "RiuMainWindow.h" + +#include + +#include + + +CAF_CMD_SOURCE_INIT(RicCreateUserDefinedPolylinesAnnotationFeature, "RicCreateUserDefinedPolylinesAnnotationFeature"); + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RicCreateUserDefinedPolylinesAnnotationFeature::isCommandEnabled() +{ + auto selObjs = caf::selectedObjectsByTypeStrict(); + return selObjs.size() == 1; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicCreateUserDefinedPolylinesAnnotationFeature::onActionTriggered(bool isChecked) +{ + auto coll = annotationCollection(); + if (coll) + { + auto newAnnotation = new RimUserDefinedPolylinesAnnotation(); + coll->addAnnotation(newAnnotation); + coll->updateConnectedEditors(); + RiuMainWindow::instance()->selectAsCurrentItem(newAnnotation); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicCreateUserDefinedPolylinesAnnotationFeature::setupActionLook(QAction* actionToSetup) +{ + actionToSetup->setIcon(QIcon(":/Plus.png")); + actionToSetup->setText("Create User Defined Polyline Annotation"); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- + RimAnnotationCollection* RicCreateUserDefinedPolylinesAnnotationFeature::annotationCollection() const +{ + auto project = RiaApplication::instance()->project(); + auto oilField = project->activeOilField(); + return oilField ? oilField->annotationCollection() : nullptr; +} diff --git a/ApplicationCode/Commands/RicDeleteItemExec.cpp b/ApplicationCode/Commands/RicDeleteItemExec.cpp index 9c16e4f55f..a4f10ee4bb 100644 --- a/ApplicationCode/Commands/RicDeleteItemExec.cpp +++ b/ApplicationCode/Commands/RicDeleteItemExec.cpp @@ -24,6 +24,8 @@ #include "RiaApplication.h" #include "Rim3dView.h" +#include "RimAnnotationCollection.h" +#include "RimAnnotationInViewCollection.h" #include "RimCase.h" #include "RimCellRangeFilterCollection.h" #include "RimEclipsePropertyFilterCollection.h" @@ -50,7 +52,6 @@ #include "RimFractureTemplateCollection.h" - #include "cafNotificationCenter.h" #include "cafPdmChildArrayField.h" #include "cafPdmDocument.h" @@ -152,6 +153,7 @@ void RicDeleteItemExec::redo() view->scheduleCreateDisplayModelAndRedraw(); } + RimFractureTemplateCollection* fracTemplateColl; parentObj->firstAncestorOrThisOfType(fracTemplateColl); if (fracTemplateColl) @@ -300,6 +302,24 @@ void RicDeleteItemExec::redo() ensembleCurveFilterColl->firstAncestorOrThisOfType(plot); if (plot) plot->loadDataAndUpdate(); } + + { + RimAnnotationCollection* annotationColl = nullptr; + parentObj->firstAncestorOrThisOfType(annotationColl); + if (annotationColl) + { + annotationColl->onAnnotationDeleted(); + } + } + + { + RimAnnotationInViewCollection* annotationColl = nullptr; + parentObj->firstAncestorOrThisOfType(annotationColl); + if (annotationColl) + { + annotationColl->onAnnotationDeleted(); + } + } } } diff --git a/ApplicationCode/Commands/RicDeleteItemFeature.cpp b/ApplicationCode/Commands/RicDeleteItemFeature.cpp index 911ca76857..f30550687a 100644 --- a/ApplicationCode/Commands/RicDeleteItemFeature.cpp +++ b/ApplicationCode/Commands/RicDeleteItemFeature.cpp @@ -34,6 +34,8 @@ #include "RimGeoMechPropertyFilter.h" #include "RimGeoMechView.h" #include "RimGridTimeHistoryCurve.h" +#include "RimGridCrossPlot.h" +#include "RimGridCrossPlotDataSet.h" #include "RimIdenticalGridCaseGroup.h" #include "RimIntersection.h" #include "RimIntersectionBox.h" @@ -53,7 +55,9 @@ #include "RimWellLogRftCurve.h" #include "RimWellRftPlot.h" #include "RimWellPathValve.h" - +#include "RimTextAnnotation.h" +#include "RimReachCircleAnnotation.h" +#include "RimPolylinesAnnotation.h" #include "RimEllipseFractureTemplate.h" #include "RimSimWellFracture.h" #include "RimSimWellFractureCollection.h" @@ -62,6 +66,7 @@ #include "RimWellPathFractureCollection.h" + #include "cafCmdExecCommandManager.h" #include "cafCmdSelectionHelper.h" #include "cafPdmChildArrayField.h" @@ -125,7 +130,11 @@ bool isDeletable(caf::PdmUiItem* uiItem) if (dynamic_cast(uiItem)) return true; if (dynamic_cast(uiItem)) return true; if (dynamic_cast(uiItem)) return true; - + if (dynamic_cast(uiItem)) return true; + if (dynamic_cast(uiItem)) return true; + if (dynamic_cast(uiItem)) return true; + if (dynamic_cast(uiItem)) return true; + if (dynamic_cast(uiItem)) return true; return false; } @@ -207,4 +216,5 @@ void RicDeleteItemFeature::setupActionLook(QAction* actionToSetup) { actionToSetup->setText("Delete"); actionToSetup->setIcon(QIcon(":/Erase.png")); + applyShortcutWithHintToAction(actionToSetup, QKeySequence::Delete); } diff --git a/ApplicationCode/Commands/RicDeleteSubItemsFeature.cpp b/ApplicationCode/Commands/RicDeleteSubItemsFeature.cpp index 217c4085c7..2b580080be 100644 --- a/ApplicationCode/Commands/RicDeleteSubItemsFeature.cpp +++ b/ApplicationCode/Commands/RicDeleteSubItemsFeature.cpp @@ -106,6 +106,7 @@ void RicDeleteSubItemsFeature::setupActionLook(QAction* actionToSetup) { actionToSetup->setText("Delete Sub Items"); actionToSetup->setIcon(QIcon(":/Erase.png")); + applyShortcutWithHintToAction(actionToSetup, QKeySequence::Delete); } //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/Commands/RicDeleteSummaryCaseCollectionFeature.cpp b/ApplicationCode/Commands/RicDeleteSummaryCaseCollectionFeature.cpp index 22451728ae..2a103ae015 100644 --- a/ApplicationCode/Commands/RicDeleteSummaryCaseCollectionFeature.cpp +++ b/ApplicationCode/Commands/RicDeleteSummaryCaseCollectionFeature.cpp @@ -133,6 +133,7 @@ void RicDeleteSummaryCaseCollectionFeature::setupActionLook(QAction* actionToSet { actionToSetup->setText("Delete Summary Case Group/Ensemble"); actionToSetup->setIcon(QIcon(":/Erase.png")); + applyShortcutWithHintToAction(actionToSetup, QKeySequence::Delete); } //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/Commands/RicDeleteTemporaryLgrsFeature.cpp b/ApplicationCode/Commands/RicDeleteTemporaryLgrsFeature.cpp index 93c4c0bfa3..14630fe89f 100644 --- a/ApplicationCode/Commands/RicDeleteTemporaryLgrsFeature.cpp +++ b/ApplicationCode/Commands/RicDeleteTemporaryLgrsFeature.cpp @@ -2,17 +2,17 @@ // // Copyright (C) 2015- Statoil ASA // Copyright (C) 2015- Ceetron Solutions AS -// +// // ResInsight 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 3 of the License, or // (at your option) any later version. -// +// // ResInsight 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 at +// +// See the GNU General Public License at // for more details. // ///////////////////////////////////////////////////////////////////////////////// @@ -23,6 +23,7 @@ #include "RimEclipseCase.h" #include "RimGridCollection.h" +#include "RimReloadCaseTools.h" #include "cafPdmObject.h" #include "cafSelectionManagerTools.h" @@ -38,11 +39,14 @@ void RicDeleteTemporaryLgrsFeature::deleteAllTemporaryLgrs(RimEclipseCase* eclip { RiaApplication::clearAllSelections(); - if (eclipseCase) eclipseCase->reloadDataAndUpdate(); + if (eclipseCase) + { + RimReloadCaseTools::reloadAllEclipseGridData(eclipseCase); + } } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- bool RicDeleteTemporaryLgrsFeature::isCommandEnabled() { @@ -56,7 +60,7 @@ bool RicDeleteTemporaryLgrsFeature::isCommandEnabled() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RicDeleteTemporaryLgrsFeature::onActionTriggered(bool isChecked) { @@ -71,10 +75,11 @@ void RicDeleteTemporaryLgrsFeature::onActionTriggered(bool isChecked) } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RicDeleteTemporaryLgrsFeature::setupActionLook(QAction* actionToSetup) { actionToSetup->setText("Delete Temporary LGRs"); actionToSetup->setIcon(QIcon(":/Erase.png")); + applyShortcutWithHintToAction(actionToSetup, QKeySequence::Delete); } diff --git a/ApplicationCode/Commands/RicExportFeatureImpl.cpp b/ApplicationCode/Commands/RicExportFeatureImpl.cpp index e5b151b6fd..776fd41d05 100644 --- a/ApplicationCode/Commands/RicExportFeatureImpl.cpp +++ b/ApplicationCode/Commands/RicExportFeatureImpl.cpp @@ -18,17 +18,13 @@ #include "RicExportFeatureImpl.h" -#include "cafPdmUiPropertyViewDialog.h" - #include //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RicExportFeatureImpl::configureForExport(caf::PdmUiPropertyViewDialog* propertyViewDialog) +void RicExportFeatureImpl::configureForExport(QDialogButtonBox* dialogButtonBox) { - QDialogButtonBox* dialogButtonBox = propertyViewDialog->dialogButtonBox(); - dialogButtonBox->clear(); dialogButtonBox->addButton("Export", QDialogButtonBox::AcceptRole); diff --git a/ApplicationCode/Commands/RicExportFeatureImpl.h b/ApplicationCode/Commands/RicExportFeatureImpl.h index 9288cb72ea..6f9fe5ac65 100644 --- a/ApplicationCode/Commands/RicExportFeatureImpl.h +++ b/ApplicationCode/Commands/RicExportFeatureImpl.h @@ -18,9 +18,7 @@ #pragma once -namespace caf { - class PdmUiPropertyViewDialog; -} +class QDialogButtonBox; //================================================================================================== /// @@ -28,5 +26,5 @@ namespace caf { class RicExportFeatureImpl { public: - static void configureForExport(caf::PdmUiPropertyViewDialog* propertyViewDialog); + static void configureForExport(QDialogButtonBox* propertyViewDialog); }; diff --git a/ApplicationCode/Commands/RicFileHierarchyDialog.cpp b/ApplicationCode/Commands/RicFileHierarchyDialog.cpp index e5ca5b34c8..1b3f8bc671 100644 --- a/ApplicationCode/Commands/RicFileHierarchyDialog.cpp +++ b/ApplicationCode/Commands/RicFileHierarchyDialog.cpp @@ -28,7 +28,6 @@ #include "Rim3dOverlayInfoConfig.h" #include "RiuPlotMainWindow.h" -#include "RiuSummaryQwtPlot.h" #include "RiuTools.h" #include @@ -48,7 +47,7 @@ #include #include -#include +#include #include #define DEFAULT_DIALOG_WIDTH 750 diff --git a/ApplicationCode/Commands/RicGeoMechPropertyFilterFeatureImpl.cpp b/ApplicationCode/Commands/RicGeoMechPropertyFilterFeatureImpl.cpp index 5e01fee6c9..f10d2a329b 100644 --- a/ApplicationCode/Commands/RicGeoMechPropertyFilterFeatureImpl.cpp +++ b/ApplicationCode/Commands/RicGeoMechPropertyFilterFeatureImpl.cpp @@ -20,6 +20,8 @@ #include "RicGeoMechPropertyFilterFeatureImpl.h" #include "RicEclipsePropertyFilterFeatureImpl.h" +#include "RigFemResultAddress.h" + #include "RimGeoMechPropertyFilter.h" #include "RimGeoMechPropertyFilterCollection.h" #include "RimGeoMechView.h" diff --git a/ApplicationCode/Commands/RicGridStatisticsDialog.cpp b/ApplicationCode/Commands/RicGridStatisticsDialog.cpp index 3fe3f8beb6..58d43282e4 100644 --- a/ApplicationCode/Commands/RicGridStatisticsDialog.cpp +++ b/ApplicationCode/Commands/RicGridStatisticsDialog.cpp @@ -28,6 +28,7 @@ #include "RiuPlotMainWindow.h" #include "RiuSummaryQwtPlot.h" +#include "RiuQwtPlotTools.h" #include "RiuTools.h" #include @@ -69,8 +70,8 @@ RicGridStatisticsDialog::RicGridStatisticsDialog(QWidget* parent) // Set widget properties m_textEdit->setReadOnly(true); - RiuSummaryQwtPlot::setCommonPlotBehaviour(m_historgramPlot); - RiuSummaryQwtPlot::setCommonPlotBehaviour(m_aggregatedPlot); + RiuQwtPlotTools::setCommonPlotBehaviour(m_historgramPlot); + RiuQwtPlotTools::setCommonPlotBehaviour(m_aggregatedPlot); // Define layout QVBoxLayout* dialogLayout = new QVBoxLayout(); diff --git a/ApplicationCode/Commands/RicHideIntersectionBoxFeature.cpp b/ApplicationCode/Commands/RicHideIntersectionBoxFeature.cpp index 266c8376e6..a54cefbefa 100644 --- a/ApplicationCode/Commands/RicHideIntersectionBoxFeature.cpp +++ b/ApplicationCode/Commands/RicHideIntersectionBoxFeature.cpp @@ -23,7 +23,7 @@ #include "RimIntersectionBox.h" #include "Rim3dView.h" -#include "RiuSelectionManager.h" +#include "Riu3dSelectionManager.h" #include @@ -37,8 +37,8 @@ bool RicHideIntersectionBoxFeature::isCommandEnabled() Rim3dView* activeView = RiaApplication::instance()->activeReservoirView(); if (!activeView) return false; - RiuSelectionManager* riuSelManager = RiuSelectionManager::instance(); - RiuSelectionItem* selItem = riuSelManager->selectedItem(RiuSelectionManager::RUI_TEMPORARY); + Riu3dSelectionManager* riuSelManager = Riu3dSelectionManager::instance(); + RiuSelectionItem* selItem = riuSelManager->selectedItem(Riu3dSelectionManager::RUI_TEMPORARY); RiuGeneralSelectionItem* generalSelectionItem = static_cast(selItem); if (!generalSelectionItem) return false; @@ -59,8 +59,8 @@ void RicHideIntersectionBoxFeature::onActionTriggered(bool isChecked) Rim3dView* activeView = RiaApplication::instance()->activeReservoirView(); if (!activeView) return; - RiuSelectionManager* riuSelManager = RiuSelectionManager::instance(); - RiuSelectionItem* selItem = riuSelManager->selectedItem(RiuSelectionManager::RUI_TEMPORARY); + Riu3dSelectionManager* riuSelManager = Riu3dSelectionManager::instance(); + RiuSelectionItem* selItem = riuSelManager->selectedItem(Riu3dSelectionManager::RUI_TEMPORARY); RiuGeneralSelectionItem* generalSelectionItem = static_cast(selItem); if (!generalSelectionItem) return; diff --git a/ApplicationCode/Commands/RicHideIntersectionFeature.cpp b/ApplicationCode/Commands/RicHideIntersectionFeature.cpp index 845432a9f9..2e0344f75c 100644 --- a/ApplicationCode/Commands/RicHideIntersectionFeature.cpp +++ b/ApplicationCode/Commands/RicHideIntersectionFeature.cpp @@ -23,7 +23,7 @@ #include "RimIntersection.h" #include "Rim3dView.h" -#include "RiuSelectionManager.h" +#include "Riu3dSelectionManager.h" #include @@ -37,8 +37,8 @@ bool RicHideIntersectionFeature::isCommandEnabled() Rim3dView* activeView = RiaApplication::instance()->activeReservoirView(); if (!activeView) return false; - RiuSelectionManager* riuSelManager = RiuSelectionManager::instance(); - RiuSelectionItem* selItem = riuSelManager->selectedItem(RiuSelectionManager::RUI_TEMPORARY); + Riu3dSelectionManager* riuSelManager = Riu3dSelectionManager::instance(); + RiuSelectionItem* selItem = riuSelManager->selectedItem(Riu3dSelectionManager::RUI_TEMPORARY); RiuGeneralSelectionItem* generalSelectionItem = static_cast(selItem); if (!generalSelectionItem) return false; @@ -59,8 +59,8 @@ void RicHideIntersectionFeature::onActionTriggered(bool isChecked) Rim3dView* activeView = RiaApplication::instance()->activeReservoirView(); if (!activeView) return; - RiuSelectionManager* riuSelManager = RiuSelectionManager::instance(); - RiuSelectionItem* selItem = riuSelManager->selectedItem(RiuSelectionManager::RUI_TEMPORARY); + Riu3dSelectionManager* riuSelManager = Riu3dSelectionManager::instance(); + RiuSelectionItem* selItem = riuSelManager->selectedItem(Riu3dSelectionManager::RUI_TEMPORARY); RiuGeneralSelectionItem* generalSelectionItem = static_cast(selItem); if (!generalSelectionItem) return; diff --git a/ApplicationCode/Commands/RicImportElementPropertyFeature.cpp b/ApplicationCode/Commands/RicImportElementPropertyFeature.cpp index 6f33931e88..381b6b51a9 100644 --- a/ApplicationCode/Commands/RicImportElementPropertyFeature.cpp +++ b/ApplicationCode/Commands/RicImportElementPropertyFeature.cpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018- Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -80,6 +80,6 @@ void RicImportElementPropertyFeature::onActionTriggered(bool isChecked) //-------------------------------------------------------------------------------------------------- void RicImportElementPropertyFeature::setupActionLook(QAction* actionToSetup) { - actionToSetup->setIcon(QIcon(":/GeoMechCase48x48.png")); + actionToSetup->setIcon(QIcon(":/GeoMechCasePropTable24x24.png")); actionToSetup->setText("Import &Element Property Table"); } diff --git a/ApplicationCode/Commands/RicImportElementPropertyFeature.h b/ApplicationCode/Commands/RicImportElementPropertyFeature.h index 848dda6a1d..9bc55fd9b3 100644 --- a/ApplicationCode/Commands/RicImportElementPropertyFeature.h +++ b/ApplicationCode/Commands/RicImportElementPropertyFeature.h @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018- Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by diff --git a/ApplicationCode/Commands/RicImportEnsembleFeature.cpp b/ApplicationCode/Commands/RicImportEnsembleFeature.cpp index dcdcd89b53..731c551fb0 100644 --- a/ApplicationCode/Commands/RicImportEnsembleFeature.cpp +++ b/ApplicationCode/Commands/RicImportEnsembleFeature.cpp @@ -1,17 +1,17 @@ ///////////////////////////////////////////////////////////////////////////////// // // Copyright (C) 2016- Statoil ASA -// +// // ResInsight 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 3 of the License, or // (at your option) any later version. -// +// // ResInsight 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 at +// +// See the GNU General Public License at // for more details. // ///////////////////////////////////////////////////////////////////////////////// @@ -21,11 +21,12 @@ #include "RiaApplication.h" #include "RiaPreferences.h" -#include "RicImportSummaryCasesFeature.h" #include "RicCreateSummaryCaseCollectionFeature.h" +#include "RicImportSummaryCasesFeature.h" #include "RifSummaryCaseRestartSelector.h" +#include "RimEnsembleCurveSet.h" #include "RimGridSummaryCase.h" #include "RimMainPlotCollection.h" #include "RimOilField.h" @@ -33,24 +34,24 @@ #include "RimSummaryCase.h" #include "RimSummaryCaseCollection.h" #include "RimSummaryCaseMainCollection.h" +#include "RimSummaryPlot.h" #include "RimSummaryPlotCollection.h" -#include "RiuPlotMainWindow.h" #include "RiuMainWindow.h" +#include "RiuPlotMainWindow.h" +#include "SummaryPlotCommands/RicNewSummaryEnsembleCurveSetFeature.h" #include "SummaryPlotCommands/RicNewSummaryPlotFeature.h" #include #include -#include #include - +#include CAF_CMD_SOURCE_INIT(RicImportEnsembleFeature, "RicImportEnsembleFeature"); - //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- bool RicImportEnsembleFeature::isCommandEnabled() { @@ -58,14 +59,15 @@ bool RicImportEnsembleFeature::isCommandEnabled() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RicImportEnsembleFeature::onActionTriggered(bool isChecked) { - RiaApplication* app = RiaApplication::instance(); - QString pathCacheName = "ENSEMBLE_FILES"; - QStringList fileNames = RicImportSummaryCasesFeature::runRecursiveSummaryCaseFileSearchDialog("Import Ensemble", pathCacheName); - + RiaApplication* app = RiaApplication::instance(); + QString pathCacheName = "ENSEMBLE_FILES"; + QStringList fileNames = + RicImportSummaryCasesFeature::runRecursiveSummaryCaseFileSearchDialog("Import Ensemble", pathCacheName); + if (fileNames.isEmpty()) return; QString ensembleName = askForEnsembleName(); @@ -75,13 +77,11 @@ void RicImportEnsembleFeature::onActionTriggered(bool isChecked) RicImportSummaryCasesFeature::createSummaryCasesFromFiles(fileNames, &cases, true); RicImportSummaryCasesFeature::addSummaryCases(cases); - auto newGroup = RicCreateSummaryCaseCollectionFeature::groupSummaryCases(cases, ensembleName, true); + RimSummaryCaseCollection* ensemble = RicCreateSummaryCaseCollectionFeature::groupSummaryCases(cases, ensembleName, true); - RiuPlotMainWindow* mainPlotWindow = app->getOrCreateAndShowMainPlotWindow(); - if (mainPlotWindow && newGroup) + if (ensemble) { - mainPlotWindow->selectAsCurrentItem(newGroup); - mainPlotWindow->updateSummaryPlotToolBar(); + RicNewSummaryEnsembleCurveSetFeature::createPlotForCurveSetAndUpdate(ensemble); } std::vector allCases; @@ -94,22 +94,23 @@ void RicImportEnsembleFeature::onActionTriggered(bool isChecked) } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RicImportEnsembleFeature::setupActionLook(QAction* actionToSetup) { - actionToSetup->setIcon(QIcon(":/SummaryEnsemble16x16.png")); + actionToSetup->setIcon(QIcon(":/SummaryEnsemble24x24.png")); actionToSetup->setText("Import Ensemble"); } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- QString RicImportEnsembleFeature::askForEnsembleName() { - RimProject* project = RiaApplication::instance()->project(); - std::vector groups = project->summaryGroups(); - int ensembleCount = std::count_if(groups.begin(), groups.end(), [](RimSummaryCaseCollection* group) { return group->isEnsemble(); }); + RimProject* project = RiaApplication::instance()->project(); + std::vector groups = project->summaryGroups(); + int ensembleCount = + std::count_if(groups.begin(), groups.end(), [](RimSummaryCaseCollection* group) { return group->isEnsemble(); }); ensembleCount += 1; QInputDialog dialog; diff --git a/ApplicationCode/Commands/RicImportFormationNamesFeature.cpp b/ApplicationCode/Commands/RicImportFormationNamesFeature.cpp index 90aae06f40..3eab4c5c49 100644 --- a/ApplicationCode/Commands/RicImportFormationNamesFeature.cpp +++ b/ApplicationCode/Commands/RicImportFormationNamesFeature.cpp @@ -90,11 +90,12 @@ void RicImportFormationNamesFeature::onActionTriggered(bool isChecked) if (ownerCase) { ownerCase->setFormationNames(formationName); + ownerCase->updateConnectedEditors(); } } } - proj->updateConnectedEditors(); + fomNameColl->updateConnectedEditors(); if (formationName) { diff --git a/ApplicationCode/Commands/RicImportGeneralDataFeature.cpp b/ApplicationCode/Commands/RicImportGeneralDataFeature.cpp new file mode 100644 index 0000000000..2e1a485996 --- /dev/null +++ b/ApplicationCode/Commands/RicImportGeneralDataFeature.cpp @@ -0,0 +1,217 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2019- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// +#include "RicImportGeneralDataFeature.h" + +#include "RiaApplication.h" +#include "RiaDefines.h" +#include "RiaImportEclipseCaseTools.h" +#include "RiaLogging.h" + +#include "RicImportSummaryCasesFeature.h" + +#include "RimSummaryCase.h" + +#include "Riu3DMainWindowTools.h" + +#include +#include +#include +#include + +using namespace RiaDefines; + +CAF_CMD_SOURCE_INIT(RicImportGeneralDataFeature, "RicImportGeneralDataFeature"); + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RicImportGeneralDataFeature::openEclipseFilesFromFileNames(const QStringList& fileNames) +{ + CVF_ASSERT(!fileNames.empty()); + + QString defaultDir = QFileInfo(fileNames.last()).absolutePath(); + + QStringList eclipseCaseFiles; + QStringList eclipseInputFiles; + QStringList eclipseSummaryFiles; + + for (const QString& fileName : fileNames) + { + if (obtainFileTypeFromFileName(fileName) & (ECLIPSE_GRID_FILE | ECLIPSE_EGRID_FILE)) + { + eclipseCaseFiles.push_back(fileName); + } + else if (obtainFileTypeFromFileName(fileName) & ECLIPSE_INPUT_FILE) + { + eclipseInputFiles.push_back(fileName); + } + else if (obtainFileTypeFromFileName(fileName) & ECLIPSE_SUMMARY_FILE) + { + eclipseSummaryFiles.push_back(fileName); + } + } + + bool allSucceeded = true; + if (!eclipseCaseFiles.empty()) + { + allSucceeded = allSucceeded && openEclipseCaseFromFileNames(eclipseCaseFiles); + RiaApplication::instance()->setLastUsedDialogDirectory(defaultDirectoryLabel(ECLIPSE_EGRID_FILE), defaultDir); + } + if (!eclipseInputFiles.empty()) + { + allSucceeded = allSucceeded && openInputEclipseCaseFromFileNames(eclipseInputFiles); + RiaApplication::instance()->setLastUsedDialogDirectory(defaultDirectoryLabel(ECLIPSE_INPUT_FILE), defaultDir); + } + if (!eclipseSummaryFiles.empty()) + { + allSucceeded = allSucceeded && openSummaryCaseFromFileNames(eclipseSummaryFiles); + RiaApplication::instance()->setLastUsedDialogDirectory(defaultDirectoryLabel(ECLIPSE_SUMMARY_FILE), defaultDir); + } + return allSucceeded; +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RicImportGeneralDataFeature::isCommandEnabled() +{ + return true; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicImportGeneralDataFeature::onActionTriggered(bool isChecked) +{ + openFileDialog(ANY_ECLIPSE_FILE); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicImportGeneralDataFeature::setupActionLook(QAction* actionToSetup) +{ + actionToSetup->setIcon(QIcon(":/Case48x48.png")); + actionToSetup->setText("Import Eclipse Files"); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicImportGeneralDataFeature::openFileDialog(ImportFileType fileTypes) +{ + QString eclipseGridFilePattern("*.GRID"); + QString eclipseEGridFilePattern("*.EGRID"); + QString eclipseInputFilePattern("*.GRDECL"); + QString eclipseSummaryFilePattern("*.SMSPEC"); + + QStringList filePatternTexts; + if (fileTypes == ANY_ECLIPSE_FILE) + { + filePatternTexts += QString("Eclipse Files (%1 %2 %3 %4)") + .arg(eclipseGridFilePattern) + .arg(eclipseEGridFilePattern) + .arg(eclipseInputFilePattern) + .arg(eclipseSummaryFilePattern); + } + if (fileTypes & ECLIPSE_GRID_FILE) + { + filePatternTexts += QString("Eclipse Grid Files (%1)").arg(eclipseGridFilePattern); + } + if (fileTypes & ECLIPSE_EGRID_FILE) + { + filePatternTexts += QString("Eclipse EGrid Files (%1)").arg(eclipseEGridFilePattern); + } + if (fileTypes & ECLIPSE_INPUT_FILE) + { + filePatternTexts += QString("Eclipse Input Files and Input Properties (%1)").arg(eclipseInputFilePattern); + } + if (fileTypes & ECLIPSE_SUMMARY_FILE) + { + filePatternTexts += QString("Eclipse Summary File (%1)").arg(eclipseSummaryFilePattern); + } + + QString fullPattern = filePatternTexts.join(";;"); + + QString defaultDir = RiaApplication::instance()->lastUsedDialogDirectory(defaultDirectoryLabel(fileTypes)); + + QStringList fileNames = + QFileDialog::getOpenFileNames(Riu3DMainWindowTools::mainWindowWidget(), "Import Data File", defaultDir, fullPattern); + + if (fileNames.empty()) return; + + if (fileTypes == ANY_ECLIPSE_FILE) + { + RiaApplication::instance()->setLastUsedDialogDirectory(defaultDirectoryLabel(ANY_ECLIPSE_FILE), fileNames.front()); + } + + if (!openEclipseFilesFromFileNames(fileNames)) + { + RiaLogging::error(QString("Failed to open file names: %1").arg(fileNames.join(", "))); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RicImportGeneralDataFeature::openEclipseCaseFromFileNames(const QStringList& fileNames) +{ + QStringList newCaseFiles; + if (RiaImportEclipseCaseTools::openEclipseCasesFromFile(fileNames, &newCaseFiles)) + { + for (const auto newCaseFile : newCaseFiles) + { + RiaApplication::instance()->addToRecentFiles(newCaseFile); + } + return true; + } + return false; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RicImportGeneralDataFeature::openInputEclipseCaseFromFileNames(const QStringList& fileNames) +{ + QString fileContainingGrid; + if (RiaImportEclipseCaseTools::openEclipseInputCaseFromFileNames(fileNames, &fileContainingGrid)) + { + RiaApplication::instance()->addToRecentFiles(fileContainingGrid); + return true; + } + return false; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RicImportGeneralDataFeature::openSummaryCaseFromFileNames(const QStringList& fileNames) +{ + std::vector newCases; + if (RicImportSummaryCasesFeature::createAndAddSummaryCasesFromFiles(fileNames, &newCases)) + { + RicImportSummaryCasesFeature::addCasesToGroupIfRelevant(newCases); + for (const RimSummaryCase* newCase : newCases) + { + RiaApplication::instance()->addToRecentFiles(newCase->summaryHeaderFilename()); + } + return true; + } + return false; +} diff --git a/ApplicationCode/Commands/RicImportGeneralDataFeature.h b/ApplicationCode/Commands/RicImportGeneralDataFeature.h new file mode 100644 index 0000000000..3cfc15a085 --- /dev/null +++ b/ApplicationCode/Commands/RicImportGeneralDataFeature.h @@ -0,0 +1,50 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2019- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "RiaDefines.h" + +#include "cafCmdFeature.h" + +#include + +//================================================================================================== +/// +//================================================================================================== +class RicImportGeneralDataFeature : public caf::CmdFeature +{ + CAF_CMD_HEADER_INIT; + +public: + static bool openEclipseFilesFromFileNames(const QStringList& fileNames); + +protected: + + // Overrides + bool isCommandEnabled() override; + void onActionTriggered(bool isChecked) override; + void setupActionLook(QAction* actionToSetup) override; + + static void openFileDialog(RiaDefines::ImportFileType fileTypes); + + static bool openEclipseCaseFromFileNames(const QStringList& fileNames); + static bool openInputEclipseCaseFromFileNames(const QStringList& fileNames); + static bool openSummaryCaseFromFileNames(const QStringList& fileNames); + +}; diff --git a/ApplicationCode/Commands/RicImportGeoMechCaseFeature.cpp b/ApplicationCode/Commands/RicImportGeoMechCaseFeature.cpp index 11ac6cd35a..656d887079 100644 --- a/ApplicationCode/Commands/RicImportGeoMechCaseFeature.cpp +++ b/ApplicationCode/Commands/RicImportGeoMechCaseFeature.cpp @@ -45,11 +45,9 @@ void RicImportGeoMechCaseFeature::onActionTriggered(bool isChecked) if (fileNames.size()) defaultDir = QFileInfo(fileNames.last()).absolutePath(); app->setLastUsedDialogDirectory("GEOMECH_MODEL", defaultDir); - for (int i = 0; i < fileNames.size(); i++) + for (const auto& fileName : fileNames) { - QString fileName = fileNames[i]; - - if (!fileNames.isEmpty()) + if (!fileName.isEmpty()) { if (app->openOdbCaseFromFile(fileName)) { @@ -64,6 +62,6 @@ void RicImportGeoMechCaseFeature::onActionTriggered(bool isChecked) //-------------------------------------------------------------------------------------------------- void RicImportGeoMechCaseFeature::setupActionLook(QAction* actionToSetup) { - actionToSetup->setIcon(QIcon(":/GeoMechCase48x48.png")); + actionToSetup->setIcon(QIcon(":/GeoMechCase24x24.png")); actionToSetup->setText("Import &Geo Mechanical Model"); } diff --git a/ApplicationCode/Commands/RicImportGeoMechCaseTimeStepFilterFeature.cpp b/ApplicationCode/Commands/RicImportGeoMechCaseTimeStepFilterFeature.cpp index a29077cc76..8d723fdaa5 100644 --- a/ApplicationCode/Commands/RicImportGeoMechCaseTimeStepFilterFeature.cpp +++ b/ApplicationCode/Commands/RicImportGeoMechCaseTimeStepFilterFeature.cpp @@ -59,7 +59,7 @@ void RicImportGeoMechCaseTimeStepFilterFeature::onActionTriggered(bool isChecked //-------------------------------------------------------------------------------------------------- void RicImportGeoMechCaseTimeStepFilterFeature::setupActionLook(QAction* actionToSetup) { - actionToSetup->setIcon(QIcon(":/GeoMechCase48x48.png")); + actionToSetup->setIcon(QIcon(":/GeoMechCaseTime24x24.png")); actionToSetup->setText("Import Geo Mechanical Model (Time Step Filtered)"); } diff --git a/ApplicationCode/Commands/RicImportObservedDataFeature.cpp b/ApplicationCode/Commands/RicImportObservedDataFeature.cpp index 3679c2c5b3..990755ac1b 100644 --- a/ApplicationCode/Commands/RicImportObservedDataFeature.cpp +++ b/ApplicationCode/Commands/RicImportObservedDataFeature.cpp @@ -51,7 +51,7 @@ void RicImportObservedDataFeature::selectObservedDataFileInDialog() { RiaApplication* app = RiaApplication::instance(); QString defaultDir = app->lastUsedDialogDirectory("INPUT_FILES"); - QStringList fileNames = QFileDialog::getOpenFileNames(nullptr, "Import Observed Time History Data", defaultDir, "Observed Data (*.RSM *.txt *.csv);;All Files (*.*)"); + QStringList fileNames = QFileDialog::getOpenFileNames(nullptr, "Import Observed Data", defaultDir, "Observed Data (*.RSM *.txt *.csv);;All Files (*.*)"); if (fileNames.isEmpty()) return; @@ -132,5 +132,5 @@ void RicImportObservedDataFeature::onActionTriggered(bool isChecked) void RicImportObservedDataFeature::setupActionLook(QAction* actionToSetup) { actionToSetup->setIcon(QIcon(":/ObservedDataFile16x16.png")); - actionToSetup->setText("Import Observed Time History Data"); + actionToSetup->setText("Import Observed Data"); } diff --git a/ApplicationCode/Commands/RicImportObservedDataInMenuFeature.cpp b/ApplicationCode/Commands/RicImportObservedDataInMenuFeature.cpp index 2c55ca6726..5fb9be56bd 100644 --- a/ApplicationCode/Commands/RicImportObservedDataInMenuFeature.cpp +++ b/ApplicationCode/Commands/RicImportObservedDataInMenuFeature.cpp @@ -62,6 +62,6 @@ void RicImportObservedDataInMenuFeature::onActionTriggered(bool isChecked) void RicImportObservedDataInMenuFeature::setupActionLook(QAction* actionToSetup) { actionToSetup->setIcon(QIcon(":/ObservedDataFile16x16.png")); - actionToSetup->setText("Import Observed Time History Data"); + actionToSetup->setText("Import Observed Data"); } diff --git a/ApplicationCode/Commands/RicImportSummaryCaseFeature.cpp b/ApplicationCode/Commands/RicImportSummaryCaseFeature.cpp index 50726cbb97..f48a42216a 100644 --- a/ApplicationCode/Commands/RicImportSummaryCaseFeature.cpp +++ b/ApplicationCode/Commands/RicImportSummaryCaseFeature.cpp @@ -22,8 +22,6 @@ #include "RiaPreferences.h" #include "RiaFilePathTools.h" -#include "RicImportSummaryCasesFeature.h" - #include "RimGridSummaryCase.h" #include "RimMainPlotCollection.h" #include "RimOilField.h" @@ -53,34 +51,7 @@ bool RicImportSummaryCaseFeature::isCommandEnabled() //-------------------------------------------------------------------------------------------------- void RicImportSummaryCaseFeature::onActionTriggered(bool isChecked) { - RiaApplication* app = RiaApplication::instance(); - QString defaultDir = app->lastUsedDialogDirectory("INPUT_FILES"); - QStringList fileNames_ = QFileDialog::getOpenFileNames(nullptr, "Import Summary Case", defaultDir, "Eclipse Summary File (*.SMSPEC);;All Files (*.*)"); - - if (fileNames_.isEmpty()) return; - - QStringList fileNames; - - // Convert to internal path separator - for (QString s : fileNames_) - { - fileNames.push_back(RiaFilePathTools::toInternalSeparator(s)); - } - - // Remember the path to next time - app->setLastUsedDialogDirectory("INPUT_FILES", QFileInfo(fileNames.last()).absolutePath()); - - if (fileNames.isEmpty()) return; - - std::vector newCases; - if (RicImportSummaryCasesFeature::createAndAddSummaryCasesFromFiles(fileNames, &newCases)) - { - RicImportSummaryCasesFeature::addCasesToGroupIfRelevant(newCases); - for (const RimSummaryCase* newCase : newCases) - { - RiaApplication::instance()->addToRecentFiles(newCase->summaryHeaderFilename()); - } - } + RicImportGeneralDataFeature::openFileDialog(RiaDefines::ECLIPSE_SUMMARY_FILE); } //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/Commands/RicImportSummaryCaseFeature.h b/ApplicationCode/Commands/RicImportSummaryCaseFeature.h index f24f7405e5..d9e5a33d87 100644 --- a/ApplicationCode/Commands/RicImportSummaryCaseFeature.h +++ b/ApplicationCode/Commands/RicImportSummaryCaseFeature.h @@ -18,6 +18,8 @@ #pragma once +#include "RicImportGeneralDataFeature.h" + #include "cafCmdFeature.h" #include @@ -25,10 +27,10 @@ //================================================================================================== /// //================================================================================================== -class RicImportSummaryCaseFeature : public caf::CmdFeature +class RicImportSummaryCaseFeature : public RicImportGeneralDataFeature { CAF_CMD_HEADER_INIT; - + protected: // Overrides bool isCommandEnabled() override; diff --git a/ApplicationCode/Commands/RicImportSummaryCasesFeature.cpp b/ApplicationCode/Commands/RicImportSummaryCasesFeature.cpp index 9c159d48ea..f7ea9c8141 100644 --- a/ApplicationCode/Commands/RicImportSummaryCasesFeature.cpp +++ b/ApplicationCode/Commands/RicImportSummaryCasesFeature.cpp @@ -1,17 +1,17 @@ ///////////////////////////////////////////////////////////////////////////////// // // Copyright (C) 2016- Statoil ASA -// +// // ResInsight 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 3 of the License, or // (at your option) any later version. -// +// // ResInsight 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 at +// +// See the GNU General Public License at // for more details. // ///////////////////////////////////////////////////////////////////////////////// @@ -28,6 +28,7 @@ #include "RifSummaryCaseRestartSelector.h" +#include "RimEnsembleCurveSet.h" #include "RimGridSummaryCase.h" #include "RimMainPlotCollection.h" #include "RimOilField.h" @@ -35,11 +36,13 @@ #include "RimSummaryCase.h" #include "RimSummaryCaseCollection.h" #include "RimSummaryCaseMainCollection.h" +#include "RimSummaryPlot.h" #include "RimSummaryPlotCollection.h" -#include "RiuPlotMainWindow.h" #include "RiuMainWindow.h" +#include "RiuPlotMainWindow.h" +#include "SummaryPlotCommands/RicNewSummaryEnsembleCurveSetFeature.h" #include "SummaryPlotCommands/RicNewSummaryPlotFeature.h" #include "cafProgressInfo.h" @@ -51,15 +54,14 @@ CAF_CMD_SOURCE_INIT(RicImportSummaryCasesFeature, "RicImportSummaryCasesFeature"); - //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- -QString RicImportSummaryCasesFeature::m_pathFilter = "*"; +QString RicImportSummaryCasesFeature::m_pathFilter = "*"; QString RicImportSummaryCasesFeature::m_fileNameFilter = "*"; //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- bool RicImportSummaryCasesFeature::isCommandEnabled() { @@ -67,22 +69,27 @@ bool RicImportSummaryCasesFeature::isCommandEnabled() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RicImportSummaryCasesFeature::onActionTriggered(bool isChecked) { - RiaApplication* app = RiaApplication::instance(); - QString pathCacheName = "INPUT_FILES"; - QStringList fileNames = runRecursiveSummaryCaseFileSearchDialog("Import Summary Cases", pathCacheName); - + RiaApplication* app = RiaApplication::instance(); + QString pathCacheName = "INPUT_FILES"; + QStringList fileNames = runRecursiveSummaryCaseFileSearchDialog("Import Summary Cases", pathCacheName); + std::vector cases; if (!fileNames.isEmpty()) createSummaryCasesFromFiles(fileNames, &cases); addSummaryCases(cases); + if (!cases.empty()) + { + createNewPlot(cases.front()); + } addCasesToGroupIfRelevant(cases); - for (const auto& rimCase : cases) RiaApplication::instance()->addToRecentFiles(rimCase->summaryHeaderFilename()); + for (const auto& rimCase : cases) + RiaApplication::instance()->addToRecentFiles(rimCase->summaryHeaderFilename()); RiuPlotMainWindow* mainPlotWindow = app->getOrCreateAndShowMainPlotWindow(); if (mainPlotWindow && !cases.empty()) @@ -102,7 +109,7 @@ void RicImportSummaryCasesFeature::onActionTriggered(bool isChecked) } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RicImportSummaryCasesFeature::setupActionLook(QAction* actionToSetup) { @@ -111,17 +118,22 @@ void RicImportSummaryCasesFeature::setupActionLook(QAction* actionToSetup) } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- -bool RicImportSummaryCasesFeature::createAndAddSummaryCasesFromFiles(const QStringList& fileNames, std::vector* newCases) +bool RicImportSummaryCasesFeature::createAndAddSummaryCasesFromFiles(const QStringList& fileNames, + std::vector* newCases) { RiaApplication* app = RiaApplication::instance(); - std::vector temp; + std::vector temp; std::vector* cases = newCases ? newCases : &temp; if (createSummaryCasesFromFiles(fileNames, cases)) { addSummaryCases(*cases); + if (!cases->empty()) + { + createNewPlot(cases->back()); + } RiuPlotMainWindow* mainPlotWindow = app->getOrCreateAndShowMainPlotWindow(); if (mainPlotWindow && !cases->empty()) @@ -145,20 +157,21 @@ bool RicImportSummaryCasesFeature::createAndAddSummaryCasesFromFiles(const QStri } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- -bool RicImportSummaryCasesFeature::createSummaryCasesFromFiles(const QStringList& fileNames, +bool RicImportSummaryCasesFeature::createSummaryCasesFromFiles(const QStringList& fileNames, std::vector* newCases, - bool ensembleOrGroup) + bool ensembleOrGroup) { - RiaApplication* app = RiaApplication::instance(); - RimProject* proj = app->project(); - RimSummaryCaseMainCollection* sumCaseColl = proj->activeOilField() ? proj->activeOilField()->summaryCaseMainCollection() : nullptr; + RiaApplication* app = RiaApplication::instance(); + RimProject* proj = app->project(); + RimSummaryCaseMainCollection* sumCaseColl = + proj->activeOilField() ? proj->activeOilField()->summaryCaseMainCollection() : nullptr; if (newCases) newCases->clear(); if (!sumCaseColl) return false; - RifSummaryCaseRestartSelector fileSelector; + RifSummaryCaseRestartSelector fileSelector; fileSelector.setEnsembleOrGroupMode(ensembleOrGroup); fileSelector.determineFilesToImportFromSummaryFiles(fileNames); @@ -181,25 +194,21 @@ bool RicImportSummaryCasesFeature::createSummaryCasesFromFiles(const QStringList } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RicImportSummaryCasesFeature::addSummaryCases(const std::vector cases) { - RiaApplication* app = RiaApplication::instance(); - RimProject* proj = app->project(); - RimSummaryCaseMainCollection* sumCaseColl = proj->activeOilField() ? proj->activeOilField()->summaryCaseMainCollection() : nullptr; + RiaApplication* app = RiaApplication::instance(); + RimProject* proj = app->project(); + RimSummaryCaseMainCollection* sumCaseColl = + proj->activeOilField() ? proj->activeOilField()->summaryCaseMainCollection() : nullptr; sumCaseColl->addCases(cases); - if (!cases.empty()) - { - RicNewSummaryCurveFeature::createNewPlot(proj->mainPlotCollection->summaryPlotCollection(), cases.front()); - } - sumCaseColl->updateAllRequiredEditors(); } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RicImportSummaryCasesFeature::addCasesToGroupIfRelevant(const std::vector cases) { @@ -207,8 +216,8 @@ void RicImportSummaryCasesFeature::addCasesToGroupIfRelevant(const std::vectorfirstAncestorOrThisOfType(mainColl); if (mainColl) @@ -224,23 +233,30 @@ void RicImportSummaryCasesFeature::addCasesToGroupIfRelevant(const std::vectorproject(); + + RicNewSummaryCurveFeature::createNewPlot(proj->mainPlotCollection->summaryPlotCollection(), summaryCase); +} + +//-------------------------------------------------------------------------------------------------- +/// //-------------------------------------------------------------------------------------------------- QStringList RicImportSummaryCasesFeature::runRecursiveSummaryCaseFileSearchDialog(const QString& dialogTitle, const QString& pathCacheName) { - RiaApplication* app = RiaApplication::instance(); - QString defaultDir = app->lastUsedDialogDirectory(pathCacheName); + RiaApplication* app = RiaApplication::instance(); + QString defaultDir = app->lastUsedDialogDirectory(pathCacheName); - RicFileHierarchyDialogResult result = RicFileHierarchyDialog::runRecursiveSearchDialog(nullptr, - dialogTitle, - defaultDir, - m_pathFilter, - m_fileNameFilter, - QStringList(".SMSPEC")); + RicFileHierarchyDialogResult result = RicFileHierarchyDialog::runRecursiveSearchDialog( + nullptr, dialogTitle, defaultDir, m_pathFilter, m_fileNameFilter, QStringList(".SMSPEC")); // Remember filters - m_pathFilter = result.pathFilter; + m_pathFilter = result.pathFilter; m_fileNameFilter = result.fileNameFilter; if (!result.ok) return QStringList(); diff --git a/ApplicationCode/Commands/RicImportSummaryCasesFeature.h b/ApplicationCode/Commands/RicImportSummaryCasesFeature.h index 14afbad64a..0a1635390b 100644 --- a/ApplicationCode/Commands/RicImportSummaryCasesFeature.h +++ b/ApplicationCode/Commands/RicImportSummaryCasesFeature.h @@ -42,6 +42,7 @@ class RicImportSummaryCasesFeature : public caf::CmdFeature static bool createSummaryCasesFromFiles(const QStringList& fileName, std::vector* newCases, bool ensembleOrGroup = false); static void addSummaryCases(const std::vector cases); static void addCasesToGroupIfRelevant(const std::vector cases); + static void createNewPlot(RimSummaryCase* summaryCase); static QStringList runRecursiveSummaryCaseFileSearchDialog(const QString& dialogTitle, const QString& pathCacheName); diff --git a/ApplicationCode/Commands/RicNewAnnotationFeature.cpp b/ApplicationCode/Commands/RicNewAnnotationFeature.cpp new file mode 100644 index 0000000000..3f000ef61f --- /dev/null +++ b/ApplicationCode/Commands/RicNewAnnotationFeature.cpp @@ -0,0 +1,149 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2016- Statoil ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "RicNewAnnotationFeature.h" + +#include "RiaApplication.h" + +#include "RimTextAnnotation.h" +#include "RimReachCircleAnnotation.h" +#include "RimPolylinesAnnotation.h" +#include "RimAnnotationCollection.h" +#include "RimProject.h" +#include "RimOilField.h" + +#include "RiuMainWindow.h" + +#include + +#include + + +CAF_CMD_SOURCE_INIT(RicNewAnnotationFeature, "RicNewAnnotationFeature"); +CAF_CMD_SOURCE_INIT(RicNewTextAnnotationFeature, "RicNewTextAnnotationFeature"); +CAF_CMD_SOURCE_INIT(RicNewReachCircleAnnotationFeature, "RicNewReachCircleAnnotationFeature"); +CAF_CMD_SOURCE_INIT(RicNewPolylineAnnotationFeature, "RicNewPolygonAnnotationFeature"); + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RicNewAnnotationFeature::isCommandEnabled() +{ + auto selObjs = caf::selectedObjectsByTypeStrict(); + return selObjs.size() == 1; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicNewAnnotationFeature::onActionTriggered(bool isChecked) +{ +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicNewAnnotationFeature::setupActionLook(QAction* actionToSetup) +{ + actionToSetup->setIcon(QIcon(":/Plus.png")); + actionToSetup->setText("(Not valid)"); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimAnnotationCollection* RicNewAnnotationFeature::annotationCollection() const +{ + auto project = RiaApplication::instance()->project(); + auto oilField = project->activeOilField(); + return oilField ? oilField->annotationCollection() : nullptr; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicNewTextAnnotationFeature::onActionTriggered(bool isChecked) +{ + auto coll = annotationCollection(); + if (coll) + { + auto newAnnotation = new RimTextAnnotation(); + coll->addAnnotation(newAnnotation); + coll->updateConnectedEditors(); + RiuMainWindow::instance()->selectAsCurrentItem(newAnnotation); + } + +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicNewTextAnnotationFeature::setupActionLook(QAction* actionToSetup) +{ + actionToSetup->setIcon(QIcon(":/Plus.png")); + actionToSetup->setText("New Text Annotation"); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicNewReachCircleAnnotationFeature::onActionTriggered(bool isChecked) +{ + auto coll = annotationCollection(); + if (coll) + { + auto newAnnotation = new RimReachCircleAnnotation(); + coll->addAnnotation(newAnnotation); + coll->updateConnectedEditors(); + RiuMainWindow::instance()->selectAsCurrentItem(newAnnotation); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicNewReachCircleAnnotationFeature::setupActionLook(QAction* actionToSetup) +{ + actionToSetup->setIcon(QIcon(":/Plus.png")); + actionToSetup->setText("New Reach Circle Annotation"); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicNewPolylineAnnotationFeature::onActionTriggered(bool isChecked) +{ + auto coll = annotationCollection(); + if (coll) + { + auto newAnnotation = new RimUserDefinedPolyLinesAnnotation(); + coll->addAnnotation(newAnnotation); + coll->updateConnectedEditors(); + RiuMainWindow::instance()->selectAsCurrentItem(newAnnotation); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicNewPolylineAnnotationFeature::setupActionLook(QAction* actionToSetup) +{ + actionToSetup->setIcon(QIcon(":/Plus.png")); + actionToSetup->setText("New Polyline Annotation"); +} diff --git a/ApplicationCode/Commands/RicNewContourMapViewFeature.cpp b/ApplicationCode/Commands/RicNewContourMapViewFeature.cpp index 8f579cd1e6..75d202934b 100644 --- a/ApplicationCode/Commands/RicNewContourMapViewFeature.cpp +++ b/ApplicationCode/Commands/RicNewContourMapViewFeature.cpp @@ -1,30 +1,38 @@ ///////////////////////////////////////////////////////////////////////////////// // // Copyright (C) 2018- Equinor ASA -// +// // ResInsight 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 3 of the License, or // (at your option) any later version. -// +// // ResInsight 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 at +// +// See the GNU General Public License at // for more details. // ///////////////////////////////////////////////////////////////////////////////// #include "RicNewContourMapViewFeature.h" -#include "RimContourMapView.h" -#include "RimContourMapViewCollection.h" +#include "Rim3dView.h" #include "RimCellEdgeColors.h" -#include "RimEclipseView.h" +#include "RimEclipseContourMapView.h" +#include "RimEclipseContourMapViewCollection.h" #include "RimEclipseCase.h" #include "RimEclipseCellColors.h" -#include "Rim3dView.h" +#include "RimEclipseView.h" +#include "RimGeoMechContourMapView.h" +#include "RimGeoMechContourMapViewCollection.h" +#include "RimGeoMechCase.h" +#include "RimGeoMechCellColors.h" +#include "RimGeoMechView.h" + +#include "RimFaultInViewCollection.h" +#include "RimSimWellInViewCollection.h" #include "Riu3DMainWindowTools.h" @@ -40,70 +48,106 @@ CAF_CMD_SOURCE_INIT(RicNewContourMapViewFeature, "RicNewContourMapViewFeature"); //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- bool RicNewContourMapViewFeature::isCommandEnabled() { - bool selectedView = caf::SelectionManager::instance()->selectedItemOfType() != nullptr; - bool selectedCase = caf::SelectionManager::instance()->selectedItemOfType() != nullptr; - bool selectedMapCollection = caf::SelectionManager::instance()->selectedItemOfType(); - return selectedView || selectedCase || selectedMapCollection; + bool selectedView = caf::SelectionManager::instance()->selectedItemOfType() != nullptr; + bool selectedCase = caf::SelectionManager::instance()->selectedItemOfType() != nullptr; + bool selectedEclipseContourMapCollection = caf::SelectionManager::instance()->selectedItemOfType(); + bool selectedGeoMechContourMapCollection = caf::SelectionManager::instance()->selectedItemOfType(); + return selectedView || selectedCase || selectedEclipseContourMapCollection || selectedGeoMechContourMapCollection; } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RicNewContourMapViewFeature::onActionTriggered(bool isChecked) { - RimEclipseView* reservoirView = caf::SelectionManager::instance()->selectedItemOfType(); - RimContourMapView* existingContourMap = caf::SelectionManager::instance()->selectedItemOfType(); - RimEclipseCase* eclipseCase = caf::SelectionManager::instance()->selectedItemAncestorOfType(); - RimContourMapView* contourMap = nullptr; + RimEclipseView* reservoirView = caf::SelectionManager::instance()->selectedItemOfType(); + RimEclipseContourMapView* existingEclipseContourMap = + caf::SelectionManager::instance()->selectedItemOfType(); + RimEclipseCase* eclipseCase = caf::SelectionManager::instance()->selectedItemAncestorOfType(); + RimEclipseContourMapView* eclipseContourMap = nullptr; + + RimGeoMechView* geoMechView = caf::SelectionManager::instance()->selectedItemOfType(); + RimGeoMechContourMapView* existingGeoMechContourMap = + caf::SelectionManager::instance()->selectedItemOfType(); + RimGeoMechCase* geoMechCase = caf::SelectionManager::instance()->selectedItemAncestorOfType(); + RimGeoMechContourMapView* geoMechContourMap = nullptr; // Find case to insert into - if (existingContourMap) + if (existingEclipseContourMap) { - contourMap = create2dContourMapFromExistingContourMap(eclipseCase, existingContourMap); + eclipseContourMap = createEclipseContourMapFromExistingContourMap(eclipseCase, existingEclipseContourMap); } else if (reservoirView) { - contourMap = create2dContourMapFrom3dView(eclipseCase, reservoirView); + eclipseContourMap = createEclipseContourMapFrom3dView(eclipseCase, reservoirView); } else if (eclipseCase) { - contourMap = create2dContourMap(eclipseCase); + eclipseContourMap = createEclipseContourMap(eclipseCase); + } + else if (existingGeoMechContourMap) + { + geoMechContourMap = createGeoMechContourMapFromExistingContourMap(geoMechCase, existingGeoMechContourMap); + } + else if (geoMechView) + { + geoMechContourMap = createGeoMechContourMapFrom3dView(geoMechCase, geoMechView); + } + else if (geoMechCase) + { + geoMechContourMap = createGeoMechContourMap(geoMechCase); } - if (contourMap) + if (eclipseContourMap) { // Must be run before buildViewItems, as wells are created in this function - contourMap->loadDataAndUpdate(); + eclipseContourMap->loadDataAndUpdate(); if (eclipseCase) { eclipseCase->updateConnectedEditors(); } - caf::SelectionManager::instance()->setSelectedItem(contourMap); + caf::SelectionManager::instance()->setSelectedItem(eclipseContourMap); - contourMap->createDisplayModelAndRedraw(); - contourMap->zoomAll(); + eclipseContourMap->createDisplayModelAndRedraw(); + eclipseContourMap->zoomAll(); - Riu3DMainWindowTools::setExpanded(contourMap); + Riu3DMainWindowTools::setExpanded(eclipseContourMap); + } + else if (geoMechContourMap) + { + geoMechContourMap->loadDataAndUpdate(); + if (geoMechCase) + { + geoMechCase->updateConnectedEditors(); + caf::SelectionManager::instance()->setSelectedItem(geoMechContourMap); + geoMechContourMap->createDisplayModelAndRedraw(); + geoMechContourMap->zoomAll(); + Riu3DMainWindowTools::setExpanded(geoMechContourMap); + } } } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RicNewContourMapViewFeature::setupActionLook(QAction* actionToSetup) { - RimContourMapView* contourMap = caf::SelectionManager::instance()->selectedItemOfType(); - RimEclipseView* eclipseView = caf::SelectionManager::instance()->selectedItemOfType(); - if (contourMap) + bool contourMapSelected = caf::SelectionManager::instance()->selectedItemOfType() != nullptr || + caf::SelectionManager::instance()->selectedItemOfType() != nullptr; + + bool viewSelected = caf::SelectionManager::instance()->selectedItemOfType() != nullptr || + caf::SelectionManager::instance()->selectedItemOfType() != nullptr; + + if (contourMapSelected) { actionToSetup->setText("Duplicate Contour Map"); } - else if (eclipseView) + else if (viewSelected) { actionToSetup->setText("New Contour Map From 3d View"); } @@ -112,15 +156,16 @@ void RicNewContourMapViewFeature::setupActionLook(QAction* actionToSetup) actionToSetup->setText("New Contour Map"); } actionToSetup->setIcon(QIcon(":/2DMap16x16.png")); -} +} //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -RimContourMapView* RicNewContourMapViewFeature::create2dContourMapFromExistingContourMap(RimEclipseCase* eclipseCase, RimContourMapView* existingContourMap) +RimEclipseContourMapView* RicNewContourMapViewFeature::createEclipseContourMapFromExistingContourMap(RimEclipseCase* eclipseCase, + RimEclipseContourMapView* existingContourMap) { - RimContourMapView* contourMap = - dynamic_cast(existingContourMap->xmlCapability()->copyByXmlSerialization(caf::PdmDefaultObjectFactory::instance())); + RimEclipseContourMapView* contourMap = dynamic_cast( + existingContourMap->xmlCapability()->copyByXmlSerialization(caf::PdmDefaultObjectFactory::instance())); CVF_ASSERT(contourMap); contourMap->setEclipseCase(eclipseCase); @@ -142,23 +187,33 @@ RimContourMapView* RicNewContourMapViewFeature::create2dContourMapFromExistingCo //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -RimContourMapView* RicNewContourMapViewFeature::create2dContourMapFrom3dView(RimEclipseCase* eclipseCase, const RimEclipseView* sourceView) +RimEclipseContourMapView* RicNewContourMapViewFeature::createEclipseContourMapFrom3dView(RimEclipseCase* eclipseCase, + const RimEclipseView* sourceView) { - RimContourMapView* contourMap = dynamic_cast(sourceView->xmlCapability()->copyAndCastByXmlSerialization( - RimContourMapView::classKeywordStatic(), sourceView->classKeyword(), caf::PdmDefaultObjectFactory::instance())); + RimEclipseContourMapView* contourMap = dynamic_cast(sourceView->xmlCapability()->copyAndCastByXmlSerialization( + RimEclipseContourMapView::classKeywordStatic(), sourceView->classKeyword(), caf::PdmDefaultObjectFactory::instance())); CVF_ASSERT(contourMap); contourMap->setEclipseCase(eclipseCase); contourMap->setBackgroundColor(cvf::Color3f(1.0f, 1.0f, 0.98f)); // Ignore original view background + contourMap->setDefaultCustomName(); + contourMap->faultCollection()->showFaultCollection = false; + contourMap->wellCollection()->isActive = false; caf::PdmDocument::updateUiIconStateRecursively(contourMap); - size_t i = eclipseCase->contourMapCollection()->views().size(); - contourMap->setName(QString("Contour Map %1").arg(i + 1)); eclipseCase->contourMapCollection()->push_back(contourMap); + contourMap->syncronizeLocalAnnotationsFromGlobal(); + // Resolve references after contour map has been inserted into Rim structures - contourMap->resolveReferencesRecursively(); + std::vector fieldsWithFailingResolve; + contourMap->resolveReferencesRecursively(&fieldsWithFailingResolve); + + // TODO: Introduce the assert when code is stable + // If we have intersections on well paths, the resolving is now failing + // CVF_ASSERT(fieldsWithFailingResolve.empty()); + contourMap->initAfterReadRecursively(); return contourMap; @@ -167,9 +222,9 @@ RimContourMapView* RicNewContourMapViewFeature::create2dContourMapFrom3dView(Rim //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -RimContourMapView* RicNewContourMapViewFeature::create2dContourMap(RimEclipseCase* eclipseCase) +RimEclipseContourMapView* RicNewContourMapViewFeature::createEclipseContourMap(RimEclipseCase* eclipseCase) { - RimContourMapView* contourMap = new RimContourMapView(); + RimEclipseContourMapView* contourMap = new RimEclipseContourMapView(); contourMap->setEclipseCase(eclipseCase); // Set default values @@ -179,7 +234,7 @@ RimContourMapView* RicNewContourMapViewFeature::create2dContourMap(RimEclipseCas if (RiaApplication::instance()->preferences()->loadAndShowSoil) { contourMap->cellResult()->setResultVariable("SOIL"); - } + } } caf::PdmDocument::updateUiIconStateRecursively(contourMap); @@ -194,3 +249,79 @@ RimContourMapView* RicNewContourMapViewFeature::create2dContourMap(RimEclipseCas return contourMap; } + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimGeoMechContourMapView* + RicNewContourMapViewFeature::createGeoMechContourMapFromExistingContourMap(RimGeoMechCase* geoMechCase, + RimGeoMechContourMapView* existingContourMap) +{ + RimGeoMechContourMapView* contourMap = dynamic_cast( + existingContourMap->xmlCapability()->copyByXmlSerialization(caf::PdmDefaultObjectFactory::instance())); + CVF_ASSERT(contourMap); + + contourMap->setGeoMechCase(geoMechCase); + contourMap->setBackgroundColor(cvf::Color3f(1.0f, 1.0f, 0.98f)); // Ignore original view background + + caf::PdmDocument::updateUiIconStateRecursively(contourMap); + + size_t i = geoMechCase->contourMapCollection()->views().size(); + contourMap->setName(QString("Contour Map %1").arg(i + 1)); + geoMechCase->contourMapCollection()->push_back(contourMap); + + // Resolve references after contour map has been inserted into Rim structures + contourMap->resolveReferencesRecursively(); + contourMap->initAfterReadRecursively(); + + return contourMap; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimGeoMechContourMapView* RicNewContourMapViewFeature::createGeoMechContourMapFrom3dView(RimGeoMechCase* geoMechCase, + const RimGeoMechView* sourceView) +{ + RimGeoMechContourMapView* contourMap = dynamic_cast( + sourceView->xmlCapability()->copyAndCastByXmlSerialization(RimGeoMechContourMapView::classKeywordStatic(), + sourceView->classKeyword(), + caf::PdmDefaultObjectFactory::instance())); + CVF_ASSERT(contourMap); + + contourMap->setGeoMechCase(geoMechCase); + contourMap->setBackgroundColor(cvf::Color3f(1.0f, 1.0f, 0.98f)); // Ignore original view background + contourMap->setDefaultCustomName(); + + caf::PdmDocument::updateUiIconStateRecursively(contourMap); + + geoMechCase->contourMapCollection()->push_back(contourMap); + + // Resolve references after contour map has been inserted into Rim structures + std::vector fieldsWithFailingResolve; + contourMap->resolveReferencesRecursively(&fieldsWithFailingResolve); + contourMap->initAfterReadRecursively(); + + return contourMap; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimGeoMechContourMapView* RicNewContourMapViewFeature::createGeoMechContourMap(RimGeoMechCase* geoMechCase) +{ + RimGeoMechContourMapView* contourMap = new RimGeoMechContourMapView(); + contourMap->setGeoMechCase(geoMechCase); + + caf::PdmDocument::updateUiIconStateRecursively(contourMap); + + size_t i = geoMechCase->contourMapCollection()->views().size(); + contourMap->setName(QString("Contour Map %1").arg(i + 1)); + geoMechCase->contourMapCollection()->push_back(contourMap); + + contourMap->hasUserRequestedAnimation = true; + contourMap->setBackgroundColor(cvf::Color3f(1.0f, 1.0f, 0.98f)); + contourMap->initAfterReadRecursively(); + + return contourMap; +} diff --git a/ApplicationCode/Commands/RicNewContourMapViewFeature.h b/ApplicationCode/Commands/RicNewContourMapViewFeature.h index 9338249b4d..fca36520f4 100644 --- a/ApplicationCode/Commands/RicNewContourMapViewFeature.h +++ b/ApplicationCode/Commands/RicNewContourMapViewFeature.h @@ -22,8 +22,11 @@ #include "cafCmdFeature.h" class RimEclipseCase; -class RimContourMapView; +class RimGeoMechCase; +class RimEclipseContourMapView; +class RimGeoMechContourMapView; class RimEclipseView; +class RimGeoMechView; //================================================================================================== /// @@ -38,8 +41,12 @@ class RicNewContourMapViewFeature : public caf::CmdFeature void onActionTriggered( bool isChecked ) override; void setupActionLook( QAction* actionToSetup ) override; - static RimContourMapView* create2dContourMapFromExistingContourMap(RimEclipseCase* eclipseCase, RimContourMapView* existingContourMap); - static RimContourMapView* create2dContourMapFrom3dView(RimEclipseCase* eclipseCase, const RimEclipseView* reservoirView); - static RimContourMapView* create2dContourMap(RimEclipseCase* eclipseCase); + static RimEclipseContourMapView* createEclipseContourMapFromExistingContourMap(RimEclipseCase* eclipseCase, RimEclipseContourMapView* existingContourMap); + static RimEclipseContourMapView* createEclipseContourMapFrom3dView(RimEclipseCase* eclipseCase, const RimEclipseView* sourceView); + static RimEclipseContourMapView* createEclipseContourMap(RimEclipseCase* eclipseCase); + + static RimGeoMechContourMapView* createGeoMechContourMapFromExistingContourMap(RimGeoMechCase* geoMechCase, RimGeoMechContourMapView* existingContourMap); + static RimGeoMechContourMapView* createGeoMechContourMapFrom3dView(RimGeoMechCase* geoMechCase, const RimGeoMechView* sourceView); + static RimGeoMechContourMapView* createGeoMechContourMap(RimGeoMechCase* geoMechCase); }; diff --git a/ApplicationCode/Commands/RicNewViewFeature.cpp b/ApplicationCode/Commands/RicNewViewFeature.cpp index 775ec094ea..f3700f7226 100644 --- a/ApplicationCode/Commands/RicNewViewFeature.cpp +++ b/ApplicationCode/Commands/RicNewViewFeature.cpp @@ -19,7 +19,7 @@ #include "RicNewViewFeature.h" -#include "RimContourMapView.h" +#include "RimEclipseContourMapView.h" #include "RimEclipseCase.h" #include "RimEclipseView.h" #include "RimGeoMechCase.h" @@ -161,7 +161,7 @@ RimEclipseView* RicNewViewFeature::selectedEclipseView() for (RimEclipseView* view : selection) { - if (dynamic_cast(view) == nullptr) + if (dynamic_cast(view) == nullptr) { return view; } diff --git a/ApplicationCode/Commands/RicPickEventHandler.h b/ApplicationCode/Commands/RicPickEventHandler.h index 34f828df79..46fa57ec06 100644 --- a/ApplicationCode/Commands/RicPickEventHandler.h +++ b/ApplicationCode/Commands/RicPickEventHandler.h @@ -1,6 +1,7 @@ ///////////////////////////////////////////////////////////////////////////////// // // Copyright (C) 2015- Statoil ASA +// Copyright (C) 2019- Equinor ASA // Copyright (C) 2015- Ceetron Solutions AS // // ResInsight is free software: you can redistribute it and/or modify @@ -19,12 +20,14 @@ #pragma once +#include "RiuPickItemInfo.h" + #include "cafCmdFeature.h" +#include "cafPickEventHandler.h" #include "cvfBase.h" #include "cvfObject.h" #include "cvfVector3.h" -#include "RiuPickItemInfo.h" namespace cvf { class Part; @@ -35,10 +38,10 @@ class Rim3dView; //================================================================================================== /// //================================================================================================== -class Ric3DPickEvent +class Ric3dPickEvent : public caf::PickEvent { public: - Ric3DPickEvent(const std::vector& pickItemInfos, + Ric3dPickEvent(const std::vector& pickItemInfos, Rim3dView* view) : m_pickItemInfos(pickItemInfos) , m_view(view) @@ -56,16 +59,6 @@ class Ric3DPickEvent class RicDefaultPickEventHandler { public: - virtual bool handlePickEvent(const Ric3DPickEvent& eventObject) = 0; -}; - -//================================================================================================== -/// A temporary, dynamic pick handler that overrides the default ones -//================================================================================================== -class RicPickEventHandler -{ -public: - virtual bool handlePickEvent(const Ric3DPickEvent& eventObject) = 0; - virtual void notifyUnregistered() = 0; + virtual bool handle3dPickEvent(const Ric3dPickEvent& eventObject) = 0; }; diff --git a/ApplicationCode/Commands/RicReloadCaseFeature.cpp b/ApplicationCode/Commands/RicReloadCaseFeature.cpp index 1c9ae9328c..42d5afaaba 100644 --- a/ApplicationCode/Commands/RicReloadCaseFeature.cpp +++ b/ApplicationCode/Commands/RicReloadCaseFeature.cpp @@ -22,8 +22,10 @@ #include "RiaApplication.h" #include "RimEclipseCase.h" +#include "RimReloadCaseTools.h" +#include "RimTimeStepFilter.h" -#include "RiuSelectionManager.h" +#include "Riu3dSelectionManager.h" #include "cafPdmObject.h" #include "cafSelectionManager.h" @@ -62,7 +64,15 @@ void RicReloadCaseFeature::onActionTriggered(bool isChecked) for (RimEclipseCase* selectedCase : selectedEclipseCases) { - selectedCase->reloadDataAndUpdate(); + std::vector timeStepFilter; + selectedCase->descendantsIncludingThisOfType(timeStepFilter); + if (timeStepFilter.size() == 1) + { + timeStepFilter[0]->clearFilteredTimeSteps(); + } + + RimReloadCaseTools::reloadAllEclipseData(selectedCase); + selectedCase->updateConnectedEditors(); } } diff --git a/ApplicationCode/Commands/RicReloadSummaryCaseFeature.cpp b/ApplicationCode/Commands/RicReloadSummaryCaseFeature.cpp index 5fa0185ca0..4796ae6218 100644 --- a/ApplicationCode/Commands/RicReloadSummaryCaseFeature.cpp +++ b/ApplicationCode/Commands/RicReloadSummaryCaseFeature.cpp @@ -1,17 +1,17 @@ ///////////////////////////////////////////////////////////////////////////////// // // Copyright (C) 2017- Statoil ASA -// +// // ResInsight 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 3 of the License, or // (at your option) any later version. -// +// // ResInsight 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 at +// +// See the GNU General Public License at // for more details. // ///////////////////////////////////////////////////////////////////////////////// @@ -23,6 +23,8 @@ #include "RiaSummaryTools.h" #include "RimMainPlotCollection.h" +#include "RimObservedData.h" +#include "RimObservedDataCollection.h" #include "RimProject.h" #include "RimSummaryCase.h" #include "RimSummaryCaseCollection.h" @@ -38,30 +40,17 @@ CAF_CMD_SOURCE_INIT(RicReloadSummaryCaseFeature, "RicReloadSummaryCaseFeature"); //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- bool RicReloadSummaryCaseFeature::isCommandEnabled() { std::vector caseSelection = selectedSummaryCases(); - if (caseSelection.size() == 0) - { - return false; - } - - for (RimSummaryCase* summaryCase : caseSelection) - { - if (summaryCase->isObservedData()) - { - return false; - } - } - return true; - + return !caseSelection.empty(); } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RicReloadSummaryCaseFeature::onActionTriggered(bool isChecked) { @@ -82,7 +71,7 @@ void RicReloadSummaryCaseFeature::onActionTriggered(bool isChecked) } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RicReloadSummaryCaseFeature::setupActionLook(QAction* actionToSetup) { @@ -91,7 +80,7 @@ void RicReloadSummaryCaseFeature::setupActionLook(QAction* actionToSetup) } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- std::vector RicReloadSummaryCaseFeature::selectedSummaryCases() { @@ -106,13 +95,26 @@ std::vector RicReloadSummaryCaseFeature::selectedSummaryCases() std::vector caseSelection; caf::SelectionManager::instance()->objectsByType(&caseSelection); - std::vector collectionSelection; - caf::SelectionManager::instance()->objectsByType(&collectionSelection); + { + std::vector collectionSelection; + caf::SelectionManager::instance()->objectsByType(&collectionSelection); + + for (auto collection : collectionSelection) + { + std::vector summaryCaseCollection = collection->allSummaryCases(); + caseSelection.insert(caseSelection.end(), summaryCaseCollection.begin(), summaryCaseCollection.end()); + } + } - for (auto collection : collectionSelection) { - std::vector summaryCaseCollection = collection->allSummaryCases(); - caseSelection.insert(caseSelection.end(), summaryCaseCollection.begin(), summaryCaseCollection.end()); + std::vector collectionSelection; + caf::SelectionManager::instance()->objectsByType(&collectionSelection); + + for (auto collection : collectionSelection) + { + std::vector observedCases = collection->allObservedData(); + caseSelection.insert(caseSelection.end(), observedCases.begin(), observedCases.end()); + } } return caseSelection; diff --git a/ApplicationCode/Commands/RicReloadSummaryCaseFeature.h b/ApplicationCode/Commands/RicReloadSummaryCaseFeature.h index 8d751621bd..8343072236 100644 --- a/ApplicationCode/Commands/RicReloadSummaryCaseFeature.h +++ b/ApplicationCode/Commands/RicReloadSummaryCaseFeature.h @@ -1,17 +1,17 @@ ///////////////////////////////////////////////////////////////////////////////// // // Copyright (C) 2017- Statoil ASA -// +// // ResInsight 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 3 of the License, or // (at your option) any later version. -// +// // ResInsight 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 at +// +// See the GNU General Public License at // for more details. // ///////////////////////////////////////////////////////////////////////////////// diff --git a/ApplicationCode/Commands/RicSelectColorResult.cpp b/ApplicationCode/Commands/RicSelectColorResult.cpp index 891d4e0719..dfad27c8be 100644 --- a/ApplicationCode/Commands/RicSelectColorResult.cpp +++ b/ApplicationCode/Commands/RicSelectColorResult.cpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018- Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by diff --git a/ApplicationCode/Commands/RicSelectColorResult.h b/ApplicationCode/Commands/RicSelectColorResult.h index 94954ab9e1..a319981724 100644 --- a/ApplicationCode/Commands/RicSelectColorResult.h +++ b/ApplicationCode/Commands/RicSelectColorResult.h @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018- Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by diff --git a/ApplicationCode/Commands/RicSelectOrCreateViewFeatureImpl.cpp b/ApplicationCode/Commands/RicSelectOrCreateViewFeatureImpl.cpp index a63eff9d59..43e7800caa 100644 --- a/ApplicationCode/Commands/RicSelectOrCreateViewFeatureImpl.cpp +++ b/ApplicationCode/Commands/RicSelectOrCreateViewFeatureImpl.cpp @@ -1,17 +1,17 @@ ///////////////////////////////////////////////////////////////////////////////// // // Copyright (C) 2017 Statoil ASA -// +// // ResInsight 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 3 of the License, or // (at your option) any later version. -// +// // ResInsight 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 at +// +// See the GNU General Public License at // for more details. // ///////////////////////////////////////////////////////////////////////////////// @@ -22,22 +22,26 @@ #include "RiaApplication.h" -#include "RimProject.h" -#include "RimEclipseView.h" #include "RimEclipseResultCase.h" +#include "RimEclipseView.h" +#include "RimProject.h" #include "RiuMainWindow.h" #include "cafPdmUiPropertyViewDialog.h" //================================================================================================== -/// +/// //================================================================================================== -RimEclipseView* RicSelectOrCreateViewFeatureImpl::showViewSelection(RimEclipseResultCase* resultCase, const QString& lastUsedViewKey, const QString& dialogTitle) +RimEclipseView* RicSelectOrCreateViewFeatureImpl::showViewSelection(RimEclipseResultCase* resultCase, + const QString& lastUsedViewKey, + const QString& newViewName, + const QString& dialogTitle) { RimEclipseView* defaultSelectedView = getDefaultSelectedView(resultCase, lastUsedViewKey); RicSelectViewUI featureUi; + featureUi.setNewViewName(newViewName); if (defaultSelectedView) { featureUi.setView(defaultSelectedView); @@ -69,14 +73,15 @@ RimEclipseView* RicSelectOrCreateViewFeatureImpl::showViewSelection(RimEclipseRe viewToManipulate = featureUi.selectedView(); } - QString refFromProjectToView = caf::PdmReferenceHelper::referenceFromRootToObject(RiaApplication::instance()->project(), viewToManipulate); + QString refFromProjectToView = + caf::PdmReferenceHelper::referenceFromRootToObject(RiaApplication::instance()->project(), viewToManipulate); RiaApplication::instance()->setCacheDataObject(lastUsedViewKey, refFromProjectToView); return viewToManipulate; } //================================================================================================== -/// +/// //================================================================================================== void RicSelectOrCreateViewFeatureImpl::focusView(RimEclipseView* view) { @@ -86,14 +91,16 @@ void RicSelectOrCreateViewFeatureImpl::focusView(RimEclipseView* view) } //================================================================================================== -/// +/// //================================================================================================== -RimEclipseView* RicSelectOrCreateViewFeatureImpl::getDefaultSelectedView(RimEclipseResultCase* resultCase, const QString& lastUsedViewKey) +RimEclipseView* RicSelectOrCreateViewFeatureImpl::getDefaultSelectedView(RimEclipseResultCase* resultCase, + const QString& lastUsedViewKey) { RimEclipseView* defaultSelectedView = nullptr; - QString lastUsedViewRef = RiaApplication::instance()->cacheDataObject(lastUsedViewKey).toString(); - RimEclipseView* lastUsedView = dynamic_cast(caf::PdmReferenceHelper::objectFromReference(RiaApplication::instance()->project(), lastUsedViewRef)); + QString lastUsedViewRef = RiaApplication::instance()->cacheDataObject(lastUsedViewKey).toString(); + RimEclipseView* lastUsedView = dynamic_cast( + caf::PdmReferenceHelper::objectFromReference(RiaApplication::instance()->project(), lastUsedViewRef)); if (lastUsedView) { RimEclipseResultCase* lastUsedViewResultCase = nullptr; diff --git a/ApplicationCode/Commands/RicSelectOrCreateViewFeatureImpl.h b/ApplicationCode/Commands/RicSelectOrCreateViewFeatureImpl.h index 7399d59cf8..ddc9ac4fd0 100644 --- a/ApplicationCode/Commands/RicSelectOrCreateViewFeatureImpl.h +++ b/ApplicationCode/Commands/RicSelectOrCreateViewFeatureImpl.h @@ -1,17 +1,17 @@ ///////////////////////////////////////////////////////////////////////////////// // // Copyright (C) 2017 Statoil ASA -// +// // ResInsight 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 3 of the License, or // (at your option) any later version. -// +// // ResInsight 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 at +// +// See the GNU General Public License at // for more details. // ///////////////////////////////////////////////////////////////////////////////// @@ -24,16 +24,17 @@ class RimEclipseView; class RimEclipseResultCase; //================================================================================================== -/// +/// //================================================================================================== class RicSelectOrCreateViewFeatureImpl { public: - static RimEclipseView* showViewSelection(RimEclipseResultCase* resultCase, const QString& lastUsedViewKey, const QString& dialogTitle); - static void focusView(RimEclipseView* view); + static RimEclipseView* showViewSelection(RimEclipseResultCase* resultCase, + const QString& lastUsedViewKey, + const QString& newViewName, + const QString& dialogTitle); + static void focusView(RimEclipseView* view); private: static RimEclipseView* getDefaultSelectedView(RimEclipseResultCase* resultCase, const QString& lastUsedViewKey); }; - - diff --git a/ApplicationCode/Commands/RicSummaryCaseRestartDialog.cpp b/ApplicationCode/Commands/RicSummaryCaseRestartDialog.cpp index 5a227b6eee..8d71986717 100644 --- a/ApplicationCode/Commands/RicSummaryCaseRestartDialog.cpp +++ b/ApplicationCode/Commands/RicSummaryCaseRestartDialog.cpp @@ -24,16 +24,15 @@ #include "RiaApplication.h" #include "RiaFilePathTools.h" #include "RiaLogging.h" +#include "RiaQDateTimeTools.h" #include "RifReaderEclipseSummary.h" #include "RifEclipseSummaryTools.h" #include "RimEclipseView.h" #include "Rim3dOverlayInfoConfig.h" -#include "RimTools.h" #include "RiuPlotMainWindow.h" -#include "RiuSummaryQwtPlot.h" #include "RiuTools.h" #include @@ -57,7 +56,7 @@ #include #include -#include +#include #include #define DEFAULT_DIALOG_WIDTH 550 @@ -485,9 +484,9 @@ void RicSummaryCaseRestartDialog::appendFileInfoToGridLayout(QGridLayout* gridLa CVF_ASSERT(gridLayout); QDateTime startDate = QDateTime::fromTime_t(fileInfo.startDate); - QString startDateString = startDate.toString(RimTools::dateFormatString()); + QString startDateString = startDate.toString(RiaQDateTimeTools::dateFormatString()); QDateTime endDate = QDateTime::fromTime_t(fileInfo.endDate); - QString endDateString = endDate.toString(RimTools::dateFormatString()); + QString endDateString = endDate.toString(RiaQDateTimeTools::dateFormatString()); int rowCount = gridLayout->rowCount(); QLabel* fileNameLabel = new QLabel(); diff --git a/ApplicationCode/Commands/RicTogglePerspectiveViewFeature.cpp b/ApplicationCode/Commands/RicTogglePerspectiveViewFeature.cpp index 2058516e33..88588132c9 100644 --- a/ApplicationCode/Commands/RicTogglePerspectiveViewFeature.cpp +++ b/ApplicationCode/Commands/RicTogglePerspectiveViewFeature.cpp @@ -20,7 +20,7 @@ #include "RicTogglePerspectiveViewFeature.h" #include "RiuViewer.h" -#include "RimContourMapView.h" +#include "RimEclipseContourMapView.h" #include "Rim3dView.h" #include "RimGridView.h" #include "RiuMainWindow.h" @@ -37,7 +37,7 @@ bool RicTogglePerspectiveViewFeature::isCommandEnabled() { this->action(); // Retrieve the action to update the looks RimGridView* activeGridView = RiaApplication::instance()->activeGridView(); - RimContourMapView* view2d = dynamic_cast(activeGridView); + RimEclipseContourMapView* view2d = dynamic_cast(activeGridView); return !view2d && activeGridView && RiaApplication::instance()->activeReservoirView()->viewer(); } diff --git a/ApplicationCode/Commands/RicVec3dPickEventHandler.cpp b/ApplicationCode/Commands/RicVec3dPickEventHandler.cpp new file mode 100644 index 0000000000..6a94c835ee --- /dev/null +++ b/ApplicationCode/Commands/RicVec3dPickEventHandler.cpp @@ -0,0 +1,78 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2019- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// +#include "RicVec3dPickEventHandler.h" + +#include "RiaApplication.h" +#include "Rim3dView.h" +#include "RimCase.h" +#include "RiuViewer.h" + +#include "cafDisplayCoordTransform.h" +#include "cafSelectionManager.h" + +//-------------------------------------------------------------------------------------------------- +/// zOffsetFactor will be multiplied by characteristic length to yield a z-offset +//-------------------------------------------------------------------------------------------------- +RicVec3dPickEventHandler::RicVec3dPickEventHandler(caf::PdmField* vectorField, double zOffsetFactor) + : m_vectorField(vectorField) + , m_zOffsetFactor(zOffsetFactor) +{ +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RicVec3dPickEventHandler::handle3dPickEvent(const Ric3dPickEvent& eventObject) +{ + const Rim3dView* rimView = eventObject.m_view; + + cvf::Vec3d pickedPosition = eventObject.m_pickItemInfos.front().globalPickedPoint(); + + RimCase* ownerCase = nullptr; + rimView->firstAncestorOrThisOfType(ownerCase); + if (ownerCase) + { + double zPickOffset = ownerCase->characteristicCellSize() * m_zOffsetFactor; + pickedPosition.z() += zPickOffset; + } + + cvf::ref transForm = rimView->displayCoordTransform(); + cvf::Vec3d pickedPositionInUTM = transForm->transformToDomainCoord(pickedPosition); + + pickedPositionInUTM.z() *= -1.0; + + m_vectorField->setValueWithFieldChanged(pickedPositionInUTM); + return true; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicVec3dPickEventHandler::registerAsPickEventHandler() +{ + Ric3dViewPickEventHandler::registerAsPickEventHandler(); + RiuViewer::setHoverCursor(Qt::CrossCursor); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicVec3dPickEventHandler::notifyUnregistered() +{ + RiuViewer::clearHoverCursor(); +} diff --git a/ApplicationCode/Commands/RicVec3dPickEventHandler.h b/ApplicationCode/Commands/RicVec3dPickEventHandler.h new file mode 100644 index 0000000000..31a4ef876c --- /dev/null +++ b/ApplicationCode/Commands/RicVec3dPickEventHandler.h @@ -0,0 +1,43 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2019- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// +#pragma once + +#include "Ric3dViewPickEventHandler.h" + +#include "cafPdmUiCoreVec3d.h" + +class Rim3dView; + +//================================================================================================== +/// A 3d view pick handler for Vec3d fields +//================================================================================================== +class RicVec3dPickEventHandler : public Ric3dViewPickEventHandler +{ +public: + RicVec3dPickEventHandler(caf::PdmField* vectorField, double zOffsetFactor = 0.0); + bool handle3dPickEvent(const Ric3dPickEvent& eventObject) override; + + void registerAsPickEventHandler() override; + void notifyUnregistered() override; + +private: + caf::PdmField* m_vectorField; + double m_zOffsetFactor; +}; + + diff --git a/ApplicationCode/Commands/RicWellLogTools.cpp b/ApplicationCode/Commands/RicWellLogTools.cpp index 242af85174..007303aa6d 100644 --- a/ApplicationCode/Commands/RicWellLogTools.cpp +++ b/ApplicationCode/Commands/RicWellLogTools.cpp @@ -36,7 +36,7 @@ #include "RifReaderEclipseRft.h" #include "RiuPlotMainWindowTools.h" -#include "RiuSelectionManager.h" +#include "Riu3dSelectionManager.h" #include "WellLogCommands/RicWellLogPlotCurveFeatureImpl.h" @@ -47,7 +47,7 @@ //-------------------------------------------------------------------------------------------------- RimSimWellInView* RicWellLogTools::selectedSimulationWell(int *branchIndex) { - RiuSelectionItem* selItem = RiuSelectionManager::instance()->selectedItem(RiuSelectionManager::RUI_TEMPORARY); + RiuSelectionItem* selItem = Riu3dSelectionManager::instance()->selectedItem(Riu3dSelectionManager::RUI_TEMPORARY); RiuSimWellSelectionItem* simWellSelItem = dynamic_cast(selItem); if (simWellSelItem) { @@ -93,8 +93,8 @@ bool RicWellLogTools::wellHasRftData(const QString& wellName) //-------------------------------------------------------------------------------------------------- bool RicWellLogTools::isWellPathOrSimWellSelectedInView() { - RiuSelectionManager* riuSelManager = RiuSelectionManager::instance(); - RiuSelectionItem* selItem = riuSelManager->selectedItem(RiuSelectionManager::RUI_TEMPORARY); + Riu3dSelectionManager* riuSelManager = Riu3dSelectionManager::instance(); + RiuSelectionItem* selItem = riuSelManager->selectedItem(Riu3dSelectionManager::RUI_TEMPORARY); RiuSimWellSelectionItem* simWellSelectionItem = dynamic_cast(selItem); if (simWellSelectionItem) return true; diff --git a/ApplicationCode/Commands/SummaryPlotCommands/RicNewGridTimeHistoryCurveFeature.cpp b/ApplicationCode/Commands/SummaryPlotCommands/RicNewGridTimeHistoryCurveFeature.cpp index 32ea6a52a3..605c2ce330 100644 --- a/ApplicationCode/Commands/SummaryPlotCommands/RicNewGridTimeHistoryCurveFeature.cpp +++ b/ApplicationCode/Commands/SummaryPlotCommands/RicNewGridTimeHistoryCurveFeature.cpp @@ -21,6 +21,8 @@ #include "RiaApplication.h" #include "RiaSummaryTools.h" +#include "RigFemResultAddress.h" + #include "RicNewSummaryCurveFeature.h" #include "RicSelectSummaryPlotUI.h" #include "RicWellLogTools.h" @@ -37,7 +39,7 @@ #include "RimSummaryPlotCollection.h" #include "RiuPlotMainWindowTools.h" -#include "RiuSelectionManager.h" +#include "Riu3dSelectionManager.h" #include "cafPdmReferenceHelper.h" #include "cafPdmUiPropertyViewDialog.h" @@ -206,7 +208,7 @@ bool RicNewGridTimeHistoryCurveFeature::isCommandEnabled() if (RicWellLogTools::isWellPathOrSimWellSelectedInView()) return false; std::vector items; - RiuSelectionManager::instance()->selectedItems(items); + Riu3dSelectionManager::instance()->selectedItems(items); if (items.size() > 0) { @@ -234,7 +236,7 @@ void RicNewGridTimeHistoryCurveFeature::onActionTriggered(bool isChecked) if (!summaryPlot) return; std::vector items; - RiuSelectionManager::instance()->selectedItems(items); + Riu3dSelectionManager::instance()->selectedItems(items); CVF_ASSERT(items.size() > 0); for (auto item : items) diff --git a/ApplicationCode/Commands/SummaryPlotCommands/RicNewSummaryCurveFeature.cpp b/ApplicationCode/Commands/SummaryPlotCommands/RicNewSummaryCurveFeature.cpp index 2836e28918..5f418670d1 100644 --- a/ApplicationCode/Commands/SummaryPlotCommands/RicNewSummaryCurveFeature.cpp +++ b/ApplicationCode/Commands/SummaryPlotCommands/RicNewSummaryCurveFeature.cpp @@ -61,7 +61,7 @@ RimSummaryCurve* RicNewSummaryCurveFeature::addCurveToPlot(RimSummaryPlot* plot, newCurve->setSummaryCaseY(summaryCase); } - newCurve->setSummaryAddressY(RifEclipseSummaryAddress::fieldAddress("FOPT")); + newCurve->setSummaryAddressYAndApplyInterpolation(RifEclipseSummaryAddress::fieldAddress("FOPT")); newCurve->loadDataAndUpdate(true); diff --git a/ApplicationCode/Commands/SummaryPlotCommands/RicNewSummaryEnsembleCurveSetFeature.cpp b/ApplicationCode/Commands/SummaryPlotCommands/RicNewSummaryEnsembleCurveSetFeature.cpp index 606faf578d..503fbc9a30 100644 --- a/ApplicationCode/Commands/SummaryPlotCommands/RicNewSummaryEnsembleCurveSetFeature.cpp +++ b/ApplicationCode/Commands/SummaryPlotCommands/RicNewSummaryEnsembleCurveSetFeature.cpp @@ -1,17 +1,17 @@ ///////////////////////////////////////////////////////////////////////////////// // // Copyright (C) 2016- Statoil ASA -// +// // ResInsight 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 3 of the License, or // (at your option) any later version. -// +// // ResInsight 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 at +// +// See the GNU General Public License at // for more details. // ///////////////////////////////////////////////////////////////////////////////// @@ -21,17 +21,17 @@ #include "RiaApplication.h" #include "RiaColorTables.h" +#include "RiaSummaryTools.h" +#include "RimEnsembleCurveSet.h" +#include "RimEnsembleCurveSetCollection.h" +#include "RimEnsembleCurveSetColorManager.h" #include "RimMainPlotCollection.h" #include "RimOilField.h" #include "RimProject.h" -#include "RiaSummaryTools.h" #include "RimSummaryCaseMainCollection.h" #include "RimSummaryCurve.h" #include "RimSummaryPlot.h" #include "RimSummaryPlotCollection.h" -#include "RimEnsembleCurveSet.h" -#include "RimEnsembleCurveSetCollection.h" -#include "RimEnsembleCurveSetColorManager.h" #include "RiuPlotMainWindow.h" @@ -43,11 +43,60 @@ #include - CAF_CMD_SOURCE_INIT(RicNewSummaryEnsembleCurveSetFeature, "RicNewSummaryEnsembleCurveSetFeature"); //-------------------------------------------------------------------------------------------------- -/// +/// +//-------------------------------------------------------------------------------------------------- +RimEnsembleCurveSet* RicNewSummaryEnsembleCurveSetFeature::addDefaultCurveSet(RimSummaryPlot* plot, + RimSummaryCaseCollection* ensemble) +{ + CVF_ASSERT(plot && ensemble); + + RimProject* project = RiaApplication::instance()->project(); + CVF_ASSERT(project); + + RimEnsembleCurveSet* curveSet = new RimEnsembleCurveSet(); + + // Use same counting as RicNewSummaryCurveFeature::onActionTriggered + auto colorIndex = plot->singleColorCurveCount(); + curveSet->setColor(RiaColorTables::summaryCurveDefaultPaletteColors().cycledColor3f(colorIndex)); + curveSet->legendConfig()->setColorRange( + RimEnsembleCurveSetColorManager::cycledEnsembleColorRange(static_cast(colorIndex))); + + curveSet->setSummaryCaseCollection(ensemble); + curveSet->setSummaryAddress(RifEclipseSummaryAddress::fieldAddress("FOPT")); + + plot->ensembleCurveSetCollection()->addCurveSet(curveSet); + + return curveSet; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicNewSummaryEnsembleCurveSetFeature::createPlotForCurveSetAndUpdate(RimSummaryCaseCollection* ensemble) +{ + RiaApplication* app = RiaApplication::instance(); + RimProject* proj = app->project(); + + RimSummaryPlotCollection* summaryPlotCollection = proj->mainPlotCollection->summaryPlotCollection(); + RimSummaryPlot* plot = summaryPlotCollection->createSummaryPlotWithAutoTitle(); + + RimEnsembleCurveSet* curveSet = RicNewSummaryEnsembleCurveSetFeature::addDefaultCurveSet(plot, ensemble); + plot->loadDataAndUpdate(); + summaryPlotCollection->updateConnectedEditors(); + + RiuPlotMainWindow* mainPlotWindow = app->getOrCreateAndShowMainPlotWindow(); + if (mainPlotWindow) + { + mainPlotWindow->selectAsCurrentItem(curveSet); + mainPlotWindow->updateSummaryPlotToolBar(); + } +} + +//-------------------------------------------------------------------------------------------------- +/// //-------------------------------------------------------------------------------------------------- bool RicNewSummaryEnsembleCurveSetFeature::isCommandEnabled() { @@ -55,7 +104,7 @@ bool RicNewSummaryEnsembleCurveSetFeature::isCommandEnabled() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RicNewSummaryEnsembleCurveSetFeature::onActionTriggered(bool isChecked) { @@ -65,30 +114,14 @@ void RicNewSummaryEnsembleCurveSetFeature::onActionTriggered(bool isChecked) RimSummaryPlot* plot = selectedSummaryPlot(); if (plot) { - RimEnsembleCurveSet* curveSet = new RimEnsembleCurveSet(); + auto ensemble = project->summaryGroups().back(); - // Use same counting as RicNewSummaryCurveFeature::onActionTriggered - auto colorIndex = plot->singleColorCurveCount(); - curveSet->setColor(RiaColorTables::summaryCurveDefaultPaletteColors().cycledColor3f(colorIndex)); - curveSet->legendConfig()->setColorRange(RimEnsembleCurveSetColorManager::cycledEnsembleColorRange(static_cast(colorIndex))); - - if (!project->summaryGroups().empty()) - { - curveSet->setSummaryCaseCollection(project->summaryGroups().back()); - } - - plot->ensembleCurveSetCollection()->addCurveSet(curveSet); - plot->updateConnectedEditors(); - - RiaApplication::instance()->getOrCreateAndShowMainPlotWindow()->selectAsCurrentItem(curveSet); - - RiuPlotMainWindow* mainPlotWindow = RiaApplication::instance()->mainPlotWindow(); - mainPlotWindow->updateSummaryPlotToolBar(); + RicNewSummaryEnsembleCurveSetFeature::createPlotForCurveSetAndUpdate(ensemble); } } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RicNewSummaryEnsembleCurveSetFeature::setupActionLook(QAction* actionToSetup) { @@ -97,13 +130,13 @@ void RicNewSummaryEnsembleCurveSetFeature::setupActionLook(QAction* actionToSetu } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- RimSummaryPlot* RicNewSummaryEnsembleCurveSetFeature::selectedSummaryPlot() const { RimSummaryPlot* sumPlot = nullptr; - caf::PdmObject* selObj = dynamic_cast(caf::SelectionManager::instance()->selectedItem()); + caf::PdmObject* selObj = dynamic_cast(caf::SelectionManager::instance()->selectedItem()); if (selObj) { sumPlot = RiaSummaryTools::parentSummaryPlot(selObj); diff --git a/ApplicationCode/Commands/SummaryPlotCommands/RicNewSummaryEnsembleCurveSetFeature.h b/ApplicationCode/Commands/SummaryPlotCommands/RicNewSummaryEnsembleCurveSetFeature.h index 9460b44534..15879846d1 100644 --- a/ApplicationCode/Commands/SummaryPlotCommands/RicNewSummaryEnsembleCurveSetFeature.h +++ b/ApplicationCode/Commands/SummaryPlotCommands/RicNewSummaryEnsembleCurveSetFeature.h @@ -1,17 +1,17 @@ ///////////////////////////////////////////////////////////////////////////////// // // Copyright (C) 2016- Statoil ASA -// +// // ResInsight 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 3 of the License, or // (at your option) any later version. -// +// // ResInsight 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 at +// +// See the GNU General Public License at // for more details. // ///////////////////////////////////////////////////////////////////////////////// @@ -23,18 +23,27 @@ #include class RimSummaryPlot; +class RimEnsembleCurveSet; +class RimSummaryCaseCollection; //================================================================================================== -/// +/// //================================================================================================== class RicNewSummaryEnsembleCurveSetFeature : public caf::CmdFeature { CAF_CMD_HEADER_INIT; + +public: + static void createPlotForCurveSetAndUpdate(RimSummaryCaseCollection* ensemble); + protected: // Overrides bool isCommandEnabled() override; - void onActionTriggered( bool isChecked ) override; - void setupActionLook( QAction* actionToSetup ) override; + void onActionTriggered(bool isChecked) override; + void setupActionLook(QAction* actionToSetup) override; + +private: + static RimEnsembleCurveSet* addDefaultCurveSet(RimSummaryPlot* plot, RimSummaryCaseCollection* ensemble); private: RimSummaryPlot* selectedSummaryPlot() const; diff --git a/ApplicationCode/Commands/SummaryPlotCommands/RicPasteAsciiDataToSummaryPlotFeatureUi.cpp b/ApplicationCode/Commands/SummaryPlotCommands/RicPasteAsciiDataToSummaryPlotFeatureUi.cpp index ff79605f53..a6c4cbf908 100644 --- a/ApplicationCode/Commands/SummaryPlotCommands/RicPasteAsciiDataToSummaryPlotFeatureUi.cpp +++ b/ApplicationCode/Commands/SummaryPlotCommands/RicPasteAsciiDataToSummaryPlotFeatureUi.cpp @@ -288,6 +288,75 @@ void RicPasteAsciiDataToSummaryPlotFeatureUi::createNewPlot() m_createNewPlot = true; } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RicPasteAsciiDataToSummaryPlotFeatureUi::DateFormat + RicPasteAsciiDataToSummaryPlotFeatureUi::dateFormatFromString(const QString& dateString) +{ + std::vector values; + + { + QStringList split = dateString.split(".", QString::SkipEmptyParts); + if (split.size() == 3) + { + values.push_back(split.at(0).toInt()); + values.push_back(split.at(1).toInt()); + values.push_back(split.at(2).toInt()); + + if (values[0] > 31) return DATE_YYYYMMDD_DOT_SEPARATED; + if (values[2] > 31) return DATE_DDMMYYYY_DOT_SEPARATED; + } + } + + { + QStringList split = dateString.split("-", QString::SkipEmptyParts); + if (split.size() == 3) + { + values.push_back(split.at(0).toInt()); + values.push_back(split.at(1).toInt()); + values.push_back(split.at(2).toInt()); + + if (values[0] > 31) return DATE_YYYYMMDD_DASH_SEPARATED; + if (values[2] > 31) return DATE_DDMMYYYY_DASH_SEPARATED; + } + } + + { + QStringList split = dateString.split("/", QString::SkipEmptyParts); + if (split.size() == 3) + { + values.push_back(split.at(0).toInt()); + values.push_back(split.at(1).toInt()); + values.push_back(split.at(2).toInt()); + + if (split.at(0).size() == 2 && split.at(1).size() == 2 && split.at(2).size() == 2) return DATE_MMDDYY_SLASH_SEPARATED; + + if (values[0] > 31) + { + return DATE_YYYYMMDD_SLASH_SEPARATED; + } + else if (values[2] > 31) + { + if (values[0] > 12) + { + return DATE_DDMMYYYY_SLASH_SEPARATED; + } + + if (values[1] > 12) + { + return DATE_MMDDYYYY_SLASH_SEPARATED; + } + + return DATE_DDMMYYYY_SLASH_SEPARATED; + } + } + } + + return DATE_DDMMYYYY_DOT_SEPARATED; +} + + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -395,7 +464,7 @@ void RicPasteAsciiDataToSummaryPlotFeatureUi::fieldChangedByUi(const caf::PdmFie { if (changedField == &m_cellSeparator || changedField == &m_timeSeriesColumnName) { - m_previewText = m_parser->previewText(PREVIEW_TEXT_LINE_COUNT, parseOptions()); + updatePreviewTextAndDateFormat(); } } @@ -424,5 +493,23 @@ void RicPasteAsciiDataToSummaryPlotFeatureUi::initialize(RifCsvUserDataParser* p m_timeSeriesColumnName = QString::fromStdString(parser->tableData().columnInfos()[0].columnName()); } - m_previewText = parser->previewText(PREVIEW_TEXT_LINE_COUNT, parseOptions()); + updatePreviewTextAndDateFormat(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicPasteAsciiDataToSummaryPlotFeatureUi::updatePreviewTextAndDateFormat() +{ + m_previewText = m_parser->previewText(PREVIEW_TEXT_LINE_COUNT, parseOptions()); + + QStringList timeStrings = m_parser->timeColumnPreviewData(PREVIEW_TEXT_LINE_COUNT, parseOptions()); + + DateFormat df = DATE_DDMMYYYY_DOT_SEPARATED; + for (auto& s : timeStrings) + { + df = dateFormatFromString(s); + } + + m_dateFormat = df; } diff --git a/ApplicationCode/Commands/SummaryPlotCommands/RicPasteAsciiDataToSummaryPlotFeatureUi.h b/ApplicationCode/Commands/SummaryPlotCommands/RicPasteAsciiDataToSummaryPlotFeatureUi.h index bae4818f80..7580f96490 100644 --- a/ApplicationCode/Commands/SummaryPlotCommands/RicPasteAsciiDataToSummaryPlotFeatureUi.h +++ b/ApplicationCode/Commands/SummaryPlotCommands/RicPasteAsciiDataToSummaryPlotFeatureUi.h @@ -38,7 +38,12 @@ class AsciiDataParseOptions { public: - AsciiDataParseOptions() : useCustomDateTimeFormat(false), assumeNumericDataColumns(false) { } + AsciiDataParseOptions() + : useCustomDateTimeFormat(false) + , assumeNumericDataColumns(false) + , curveSymbolSkipDistance(0.0f) + { + } QString plotTitle; QString curvePrefix; @@ -128,6 +133,8 @@ class RicPasteAsciiDataToSummaryPlotFeatureUi : public caf::PdmObject const AsciiDataParseOptions parseOptions() const; void createNewPlot(); + static DateFormat dateFormatFromString(const QString& dateString); + protected: void defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering) override; QList calculateValueOptions(const caf::PdmFieldHandle* fieldNeedingOptions, bool* useOptionsOnly) override; @@ -136,6 +143,7 @@ class RicPasteAsciiDataToSummaryPlotFeatureUi : public caf::PdmObject private: void initialize(RifCsvUserDataParser* parser); + void updatePreviewTextAndDateFormat(); private: UiMode m_uiMode; diff --git a/ApplicationCode/Commands/SummaryPlotCommands/RicPasteSummaryCaseFeature.cpp b/ApplicationCode/Commands/SummaryPlotCommands/RicPasteSummaryCaseFeature.cpp index 0ca62db9f9..fb0d8b1384 100644 --- a/ApplicationCode/Commands/SummaryPlotCommands/RicPasteSummaryCaseFeature.cpp +++ b/ApplicationCode/Commands/SummaryPlotCommands/RicPasteSummaryCaseFeature.cpp @@ -116,11 +116,11 @@ void RicPasteSummaryCaseFeature::onActionTriggered(bool isChecked) //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RicPasteSummaryCaseFeature::setupActionLook(QAction* action) +void RicPasteSummaryCaseFeature::setupActionLook(QAction* actionToSetup) { - action->setText("Paste Summary Case"); - action->setIcon(QIcon(":/clipboard.png")); - action->setShortcut(QKeySequence::Paste); + actionToSetup->setText("Paste Summary Case"); + actionToSetup->setIcon(QIcon(":/clipboard.png")); + applyShortcutWithHintToAction(actionToSetup, QKeySequence::Paste); } //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/Commands/SummaryPlotCommands/RicSummaryCurveCalculatorEditor.cpp b/ApplicationCode/Commands/SummaryPlotCommands/RicSummaryCurveCalculatorEditor.cpp index 82ea501134..f7b336e108 100644 --- a/ApplicationCode/Commands/SummaryPlotCommands/RicSummaryCurveCalculatorEditor.cpp +++ b/ApplicationCode/Commands/SummaryPlotCommands/RicSummaryCurveCalculatorEditor.cpp @@ -123,7 +123,11 @@ QWidget* RicSummaryCurveCalculatorEditor::createWidget(QWidget* parent) m_pdmTableView->enableHeaderText(false); QHeaderView* verticalHeader = m_pdmTableView->tableView()->verticalHeader(); +#if QT_VERSION >= 0x050000 + verticalHeader->setSectionResizeMode(QHeaderView::Interactive); +#else verticalHeader->setResizeMode(QHeaderView::Interactive); +#endif m_pdmTableView->tableView()->resizeColumnsToContents(); @@ -187,7 +191,7 @@ QMinimizePanel* RicSummaryCurveCalculatorEditor::updateGroupBoxWithContent(caf:: { QMinimizePanel* groupBox = findOrCreateGroupBox(this->widget(), group, uiConfigName); - recursivelyConfigureAndUpdateUiOrderingInGridLayoutColumn(*group, groupBox->contentFrame(), uiConfigName); + recursivelyConfigureAndUpdateUiOrderingInGridLayout(*group, groupBox->contentFrame(), uiConfigName); return groupBox; } diff --git a/ApplicationCode/Commands/SummaryPlotCommands/RicSummaryCurveCreator.cpp b/ApplicationCode/Commands/SummaryPlotCommands/RicSummaryCurveCreator.cpp index 29c674d2fe..c587144e89 100644 --- a/ApplicationCode/Commands/SummaryPlotCommands/RicSummaryCurveCreator.cpp +++ b/ApplicationCode/Commands/SummaryPlotCommands/RicSummaryCurveCreator.cpp @@ -463,7 +463,7 @@ void RicSummaryCurveCreator::updatePreviewCurvesFromCurveDefinitions( RimSummaryCase* currentCase = curveDef.summaryCase(); RimSummaryCurve* curve = new RimSummaryCurve(); curve->setSummaryCaseY(currentCase); - curve->setSummaryAddressY(curveDef.summaryAddress()); + curve->setSummaryAddressYAndApplyInterpolation(curveDef.summaryAddress()); curve->applyCurveAutoNameSettings(*m_curveNameConfig()); if (currentCase->isObservedData()) curve->setSymbolSkipDistance(0); diff --git a/ApplicationCode/Commands/SummaryPlotCommands/RicSummaryCurveCreatorSplitterUi.cpp b/ApplicationCode/Commands/SummaryPlotCommands/RicSummaryCurveCreatorSplitterUi.cpp index c3e429fea8..c16f6d062f 100644 --- a/ApplicationCode/Commands/SummaryPlotCommands/RicSummaryCurveCreatorSplitterUi.cpp +++ b/ApplicationCode/Commands/SummaryPlotCommands/RicSummaryCurveCreatorSplitterUi.cpp @@ -102,10 +102,11 @@ void RicSummaryCurveCreatorSplitterUi::recursivelyConfigureAndUpdateTopLevelUiOr auto nameConfigGroupBox = createGroupBoxWithContent(nameConfigGroup, uiConfigName); m_lowerLeftLayout->insertWidget(1, nameConfigGroupBox); - m_lowerLeftLayout->insertWidget(2, getOrCreateCurveTreeWidget(), 1); - + QMinimizePanel* curveGroup = getOrCreateCurveTreeGroup(); + m_lowerLeftLayout->insertWidget(2, curveGroup, 1); + m_lowerLeftLayout->addStretch(0); m_secondRowLayout->insertWidget(1, getOrCreatePlotWidget()); - + // Fields at bottom of dialog configureAndUpdateFields(1, m_bottomFieldLayout, topLevelUiItems, uiConfigName); } @@ -128,7 +129,7 @@ QWidget* RicSummaryCurveCreatorSplitterUi::createWidget(QWidget* parent) QFrame* secondRowFrame = new QFrame(widget); m_secondRowLayout = new QHBoxLayout; - m_secondRowLayout->setContentsMargins(0, 0, 0, 0); + m_secondRowLayout->setContentsMargins(0, 4, 0, 0); secondRowFrame->setLayout(m_secondRowLayout); m_lowerLeftLayout = new QVBoxLayout; @@ -148,7 +149,7 @@ QWidget* RicSummaryCurveCreatorSplitterUi::createWidget(QWidget* parent) m_layout->addWidget(m_firstColumnSplitter); m_bottomFieldLayout = new QHBoxLayout; - m_bottomFieldLayout->setContentsMargins(0, 0, 0, 0); + m_bottomFieldLayout->setContentsMargins(0, 2, 0, 0); m_layout->addLayout(m_bottomFieldLayout); m_bottomFieldLayout->insertStretch(0, 1); @@ -180,7 +181,7 @@ caf::PdmUiGroup* RicSummaryCurveCreatorSplitterUi::findGroupByKeyword(const std: //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -QWidget* RicSummaryCurveCreatorSplitterUi::getOrCreateCurveTreeWidget() +QMinimizePanel* RicSummaryCurveCreatorSplitterUi::getOrCreateCurveTreeGroup() { if (!m_curvesPanel) { @@ -189,6 +190,8 @@ QWidget* RicSummaryCurveCreatorSplitterUi::getOrCreateCurveTreeWidget() QVBoxLayout* curvesLayout = new QVBoxLayout(m_curvesPanel->contentFrame()); m_curveTreeView = new caf::PdmUiTreeView(m_curvesPanel->contentFrame()); + curvesLayout->setStretchFactor(m_curveTreeView, 1); + curvesLayout->addWidget(m_curveTreeView); m_curveTreeView->treeView()->setHeaderHidden(true); @@ -299,6 +302,6 @@ QMinimizePanel* RicSummaryCurveCreatorSplitterUi::createGroupBoxWithContent(caf: { QMinimizePanel* groupBox = findOrCreateGroupBox(this->widget(), group, uiConfigName); - recursivelyConfigureAndUpdateUiOrderingInGridLayoutColumn(*group, groupBox->contentFrame(), uiConfigName); + recursivelyConfigureAndUpdateUiOrderingInGridLayout(*group, groupBox->contentFrame(), uiConfigName); return groupBox; } diff --git a/ApplicationCode/Commands/SummaryPlotCommands/RicSummaryCurveCreatorSplitterUi.h b/ApplicationCode/Commands/SummaryPlotCommands/RicSummaryCurveCreatorSplitterUi.h index 856fc38881..77f71b60ef 100644 --- a/ApplicationCode/Commands/SummaryPlotCommands/RicSummaryCurveCreatorSplitterUi.h +++ b/ApplicationCode/Commands/SummaryPlotCommands/RicSummaryCurveCreatorSplitterUi.h @@ -62,7 +62,7 @@ class RicSummaryCurveCreatorSplitterUi : public caf::PdmUiFormLayoutObjectEditor QWidget* createWidget(QWidget* parent) override; - QWidget* getOrCreateCurveTreeWidget(); + QMinimizePanel* getOrCreateCurveTreeGroup(); QWidget* getOrCreatePlotWidget(); static caf::PdmUiGroup* findGroupByKeyword(const std::vector& topLevelUiItems, diff --git a/ApplicationCode/Commands/SummaryPlotCommands/RicViewZoomAllFeature.cpp b/ApplicationCode/Commands/SummaryPlotCommands/RicViewZoomAllFeature.cpp index 5ec633e894..eb04c5f3f1 100644 --- a/ApplicationCode/Commands/SummaryPlotCommands/RicViewZoomAllFeature.cpp +++ b/ApplicationCode/Commands/SummaryPlotCommands/RicViewZoomAllFeature.cpp @@ -79,5 +79,7 @@ void RicViewZoomAllFeature::onActionTriggered(bool isChecked) void RicViewZoomAllFeature::setupActionLook(QAction* actionToSetup) { actionToSetup->setText("Zoom All"); + actionToSetup->setToolTip("Zoom All (Ctrl+Alt+A)"); actionToSetup->setIcon(QIcon(":/ZoomAll16x16.png")); + applyShortcutWithHintToAction(actionToSetup, QKeySequence(tr("Ctrl+Alt+A"))); } diff --git a/ApplicationCode/Commands/ViewLink/RicDeleteAllLinkedViewsFeature.cpp b/ApplicationCode/Commands/ViewLink/RicDeleteAllLinkedViewsFeature.cpp index 318e096985..9668be3b30 100644 --- a/ApplicationCode/Commands/ViewLink/RicDeleteAllLinkedViewsFeature.cpp +++ b/ApplicationCode/Commands/ViewLink/RicDeleteAllLinkedViewsFeature.cpp @@ -24,6 +24,8 @@ #include "RimViewLinker.h" #include "RimViewLinkerCollection.h" +#include "cafSelectionManager.h" + #include CAF_CMD_SOURCE_INIT(RicDeleteAllLinkedViewsFeature, "RicDeleteAllLinkedViewsFeature"); @@ -33,7 +35,7 @@ CAF_CMD_SOURCE_INIT(RicDeleteAllLinkedViewsFeature, "RicDeleteAllLinkedViewsFeat //-------------------------------------------------------------------------------------------------- bool RicDeleteAllLinkedViewsFeature::isCommandEnabled() { - return true; + return caf::SelectionManager::instance()->selectedItemAncestorOfType() != nullptr; } //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/Commands/ViewLink/RicLinkViewFeature.cpp b/ApplicationCode/Commands/ViewLink/RicLinkViewFeature.cpp index e304e812b1..2c0dc87ac9 100644 --- a/ApplicationCode/Commands/ViewLink/RicLinkViewFeature.cpp +++ b/ApplicationCode/Commands/ViewLink/RicLinkViewFeature.cpp @@ -24,7 +24,7 @@ #include "RicLinkVisibleViewsFeature.h" #include "Rim3dView.h" -#include "RimContourMapView.h" +#include "RimEclipseContourMapView.h" #include "RimGridView.h" #include "RimProject.h" #include "RimViewLinkerCollection.h" @@ -43,7 +43,7 @@ bool RicLinkViewFeature::isCommandEnabled() { std::vector allSelectedItems; std::vector selectedGridViews; - std::vector selectedContourMaps; + std::vector selectedContourMaps; caf::SelectionManager::instance()->selectedItems(allSelectedItems); caf::SelectionManager::instance()->objectsByType(&selectedGridViews); diff --git a/ApplicationCode/Commands/ViewLink/RicLinkVisibleViewsFeature.cpp b/ApplicationCode/Commands/ViewLink/RicLinkVisibleViewsFeature.cpp index ee891554a2..aea12bb551 100644 --- a/ApplicationCode/Commands/ViewLink/RicLinkVisibleViewsFeature.cpp +++ b/ApplicationCode/Commands/ViewLink/RicLinkVisibleViewsFeature.cpp @@ -23,7 +23,7 @@ #include "RicLinkVisibleViewsFeatureUi.h" -#include "RimContourMapView.h" +#include "RimEclipseContourMapView.h" #include "RimGridView.h" #include "RimProject.h" #include "RimViewController.h" @@ -151,7 +151,7 @@ void RicLinkVisibleViewsFeature::linkViews(std::vector& views) std::vector masterCandidates; for (RimGridView* view : views) { - if (dynamic_cast(view) == nullptr) + if (dynamic_cast(view) == nullptr) { masterCandidates.push_back(view); } diff --git a/ApplicationCode/Commands/ViewLink/RicLinkVisibleViewsFeatureUi.cpp b/ApplicationCode/Commands/ViewLink/RicLinkVisibleViewsFeatureUi.cpp index f5abbfd666..0cf755734e 100644 --- a/ApplicationCode/Commands/ViewLink/RicLinkVisibleViewsFeatureUi.cpp +++ b/ApplicationCode/Commands/ViewLink/RicLinkVisibleViewsFeatureUi.cpp @@ -22,7 +22,7 @@ #include "RiaApplication.h" #include "RiaOptionItemFactory.h" -#include "RimContourMapView.h" +#include "RimEclipseContourMapView.h" #include "RimCase.h" #include "RimGridView.h" #include "RimViewLinker.h" @@ -83,7 +83,7 @@ std::vector RicLinkVisibleViewsFeatureUi::masterViewCandidates() c // Set Active view as master view if the active view isn't a contour map. for (size_t i = 0; i < m_allViews.size(); i++) { - RimContourMapView* contourMap = dynamic_cast(m_allViews[i]); + RimEclipseContourMapView* contourMap = dynamic_cast(m_allViews[i]); if (contourMap == nullptr) { masterCandidates.push_back(m_allViews[i]); diff --git a/ApplicationCode/Commands/ViewLink/RicSetMasterViewFeature.cpp b/ApplicationCode/Commands/ViewLink/RicSetMasterViewFeature.cpp index a6643c3cd9..1b219def9d 100644 --- a/ApplicationCode/Commands/ViewLink/RicSetMasterViewFeature.cpp +++ b/ApplicationCode/Commands/ViewLink/RicSetMasterViewFeature.cpp @@ -21,7 +21,7 @@ #include "RiaApplication.h" -#include "RimContourMapView.h" +#include "RimEclipseContourMapView.h" #include "RimGridView.h" #include "RimProject.h" #include "RimViewController.h" @@ -55,7 +55,7 @@ bool RicSetMasterViewFeature::isCommandEnabled() return false; } - if (dynamic_cast(activeView) != nullptr) + if (dynamic_cast(activeView) != nullptr) { return false; } diff --git a/ApplicationCode/Commands/ViewLink/RicShowAllLinkedViewsFeature.cpp b/ApplicationCode/Commands/ViewLink/RicShowAllLinkedViewsFeature.cpp index 4d13a95255..751dee2afb 100644 --- a/ApplicationCode/Commands/ViewLink/RicShowAllLinkedViewsFeature.cpp +++ b/ApplicationCode/Commands/ViewLink/RicShowAllLinkedViewsFeature.cpp @@ -22,7 +22,7 @@ #include "RimViewController.h" #include "RimGridView.h" #include "RimViewLinker.h" - +#include "RimViewLinkerCollection.h" #include "cafSelectionManager.h" #include @@ -34,7 +34,7 @@ CAF_CMD_SOURCE_INIT(RicShowAllLinkedViewsFeature, "RicShowAllLinkedViewsFeature" //-------------------------------------------------------------------------------------------------- bool RicShowAllLinkedViewsFeature::isCommandEnabled() { - return true; + return caf::SelectionManager::instance()->selectedItemAncestorOfType() != nullptr; } //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/Commands/WellLogCommands/Ric3dWellLogCurveDeleteFeature.cpp b/ApplicationCode/Commands/WellLogCommands/Ric3dWellLogCurveDeleteFeature.cpp index 866aceb212..24d1180b6a 100644 --- a/ApplicationCode/Commands/WellLogCommands/Ric3dWellLogCurveDeleteFeature.cpp +++ b/ApplicationCode/Commands/WellLogCommands/Ric3dWellLogCurveDeleteFeature.cpp @@ -78,4 +78,5 @@ void Ric3dWellLogCurveDeleteFeature::setupActionLook(QAction* actionToSetup) { actionToSetup->setText("Delete 3D Well Log Curve(s)"); actionToSetup->setIcon(QIcon(":/Erase.png")); + applyShortcutWithHintToAction(actionToSetup, QKeySequence::Delete); } diff --git a/ApplicationCode/Commands/WellLogCommands/Ric3dWellLogCurvePickEventHandler.cpp b/ApplicationCode/Commands/WellLogCommands/Ric3dWellLogCurvePickEventHandler.cpp index e43983be88..3a5ef63f01 100644 --- a/ApplicationCode/Commands/WellLogCommands/Ric3dWellLogCurvePickEventHandler.cpp +++ b/ApplicationCode/Commands/WellLogCommands/Ric3dWellLogCurvePickEventHandler.cpp @@ -39,7 +39,7 @@ Ric3dWellLogCurvePickEventHandler* Ric3dWellLogCurvePickEventHandler::instance() //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -bool Ric3dWellLogCurvePickEventHandler::handlePickEvent(const Ric3DPickEvent& eventObject) +bool Ric3dWellLogCurvePickEventHandler::handle3dPickEvent(const Ric3dPickEvent& eventObject) { if (eventObject.m_pickItemInfos.empty()) return false; diff --git a/ApplicationCode/Commands/WellLogCommands/Ric3dWellLogCurvePickEventHandler.h b/ApplicationCode/Commands/WellLogCommands/Ric3dWellLogCurvePickEventHandler.h index b7d5a3717c..6afa1bb14c 100644 --- a/ApplicationCode/Commands/WellLogCommands/Ric3dWellLogCurvePickEventHandler.h +++ b/ApplicationCode/Commands/WellLogCommands/Ric3dWellLogCurvePickEventHandler.h @@ -29,5 +29,5 @@ class Ric3dWellLogCurvePickEventHandler : public RicDefaultPickEventHandler public: static Ric3dWellLogCurvePickEventHandler* instance(); - bool handlePickEvent(const Ric3DPickEvent& eventObject) override; + bool handle3dPickEvent(const Ric3dPickEvent& eventObject) override; }; diff --git a/ApplicationCode/Commands/WellLogCommands/RicAdd3dWellLogCurveFeature.cpp b/ApplicationCode/Commands/WellLogCommands/RicAdd3dWellLogCurveFeature.cpp index 8adb77b6c3..0f8992a122 100644 --- a/ApplicationCode/Commands/WellLogCommands/RicAdd3dWellLogCurveFeature.cpp +++ b/ApplicationCode/Commands/WellLogCommands/RicAdd3dWellLogCurveFeature.cpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018- Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -81,5 +81,5 @@ void RicAdd3dWellLogCurveFeature::onActionTriggered(bool isChecked) void RicAdd3dWellLogCurveFeature::setupActionLook(QAction* actionToSetup) { actionToSetup->setIcon(QIcon(":/WellLogCurve16x16.png")); - actionToSetup->setText("Add 3D Well Log Curve"); + actionToSetup->setText("Create 3D Well Log Curve"); } diff --git a/ApplicationCode/Commands/WellLogCommands/RicAdd3dWellLogCurveFeature.h b/ApplicationCode/Commands/WellLogCommands/RicAdd3dWellLogCurveFeature.h index 81f6e8b54f..15f3a2a431 100644 --- a/ApplicationCode/Commands/WellLogCommands/RicAdd3dWellLogCurveFeature.h +++ b/ApplicationCode/Commands/WellLogCommands/RicAdd3dWellLogCurveFeature.h @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018- Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by diff --git a/ApplicationCode/Commands/WellLogCommands/RicAdd3dWellLogFileCurveFeature.cpp b/ApplicationCode/Commands/WellLogCommands/RicAdd3dWellLogFileCurveFeature.cpp index 4aa0d890e0..d0352cc747 100644 --- a/ApplicationCode/Commands/WellLogCommands/RicAdd3dWellLogFileCurveFeature.cpp +++ b/ApplicationCode/Commands/WellLogCommands/RicAdd3dWellLogFileCurveFeature.cpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018- Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -72,5 +72,5 @@ void RicAdd3dWellLogFileCurveFeature::onActionTriggered(bool isChecked) void RicAdd3dWellLogFileCurveFeature::setupActionLook(QAction* actionToSetup) { actionToSetup->setIcon(QIcon(":/WellLogCurve16x16.png")); - actionToSetup->setText("Add 3D Well Log LAS Curve"); + actionToSetup->setText("Create 3D Well Log LAS Curve"); } diff --git a/ApplicationCode/Commands/WellLogCommands/RicAdd3dWellLogFileCurveFeature.h b/ApplicationCode/Commands/WellLogCommands/RicAdd3dWellLogFileCurveFeature.h index 6126a99cf9..36e6a7ec51 100644 --- a/ApplicationCode/Commands/WellLogCommands/RicAdd3dWellLogFileCurveFeature.h +++ b/ApplicationCode/Commands/WellLogCommands/RicAdd3dWellLogFileCurveFeature.h @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018- Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by diff --git a/ApplicationCode/Commands/WellLogCommands/RicAdd3dWellLogRftCurveFeature.cpp b/ApplicationCode/Commands/WellLogCommands/RicAdd3dWellLogRftCurveFeature.cpp index 190cf5486e..1ed0a1251e 100644 --- a/ApplicationCode/Commands/WellLogCommands/RicAdd3dWellLogRftCurveFeature.cpp +++ b/ApplicationCode/Commands/WellLogCommands/RicAdd3dWellLogRftCurveFeature.cpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018- Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -77,5 +77,5 @@ void RicAdd3dWellLogRftCurveFeature::onActionTriggered(bool isChecked) void RicAdd3dWellLogRftCurveFeature::setupActionLook(QAction* actionToSetup) { actionToSetup->setIcon(QIcon(":/WellLogCurve16x16.png")); - actionToSetup->setText("Add 3D Well Log RFT Curve"); + actionToSetup->setText("Create 3D Well Log RFT Curve"); } diff --git a/ApplicationCode/Commands/WellLogCommands/RicAdd3dWellLogRftCurveFeature.h b/ApplicationCode/Commands/WellLogCommands/RicAdd3dWellLogRftCurveFeature.h index e60ffd406b..28bc9f6428 100644 --- a/ApplicationCode/Commands/WellLogCommands/RicAdd3dWellLogRftCurveFeature.h +++ b/ApplicationCode/Commands/WellLogCommands/RicAdd3dWellLogRftCurveFeature.h @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018- Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by diff --git a/ApplicationCode/Commands/WellLogCommands/RicDeleteRftPlotFeature.cpp b/ApplicationCode/Commands/WellLogCommands/RicDeleteRftPlotFeature.cpp index 7a02146e2d..47cd69a7e3 100644 --- a/ApplicationCode/Commands/WellLogCommands/RicDeleteRftPlotFeature.cpp +++ b/ApplicationCode/Commands/WellLogCommands/RicDeleteRftPlotFeature.cpp @@ -76,4 +76,5 @@ void RicDeleteRftPlotFeature::setupActionLook(QAction* actionToSetup) { actionToSetup->setText("Delete RFT Plot"); actionToSetup->setIcon(QIcon(":/Erase.png")); + applyShortcutWithHintToAction(actionToSetup, QKeySequence::Delete); } diff --git a/ApplicationCode/Commands/WellLogCommands/RicDeleteWellLogPlotTrackFeature.cpp b/ApplicationCode/Commands/WellLogCommands/RicDeleteWellLogPlotTrackFeature.cpp index 26ea915fe4..a93e145ed1 100644 --- a/ApplicationCode/Commands/WellLogCommands/RicDeleteWellLogPlotTrackFeature.cpp +++ b/ApplicationCode/Commands/WellLogCommands/RicDeleteWellLogPlotTrackFeature.cpp @@ -104,4 +104,5 @@ void RicDeleteWellLogPlotTrackFeature::setupActionLook(QAction* actionToSetup) { actionToSetup->setText("Delete Track"); actionToSetup->setIcon(QIcon(":/Erase.png")); + applyShortcutWithHintToAction(actionToSetup, QKeySequence::Delete); } diff --git a/ApplicationCode/Commands/WellLogCommands/RicNewPltPlotFeature.cpp b/ApplicationCode/Commands/WellLogCommands/RicNewPltPlotFeature.cpp index 31f57f0475..0aee07182e 100644 --- a/ApplicationCode/Commands/WellLogCommands/RicNewPltPlotFeature.cpp +++ b/ApplicationCode/Commands/WellLogCommands/RicNewPltPlotFeature.cpp @@ -39,7 +39,7 @@ #include "RimEclipseResultCase.h" #include "RiuPlotMainWindowTools.h" -#include "RiuSelectionManager.h" +#include "Riu3dSelectionManager.h" #include "cafSelectionManagerTools.h" @@ -152,7 +152,7 @@ RimWellPath* RicNewPltPlotFeature::selectedWellPath() const //-------------------------------------------------------------------------------------------------- RimSimWellInView* RicNewPltPlotFeature::selectedSimulationWell(int * branchIndex) const { - RiuSelectionItem* selItem = RiuSelectionManager::instance()->selectedItem(RiuSelectionManager::RUI_TEMPORARY); + RiuSelectionItem* selItem = Riu3dSelectionManager::instance()->selectedItem(Riu3dSelectionManager::RUI_TEMPORARY); RiuSimWellSelectionItem* simWellSelItem = dynamic_cast(selItem); if (simWellSelItem) { diff --git a/ApplicationCode/Commands/WellLogCommands/RicNewWellBoreStabilityPlotFeature.cpp b/ApplicationCode/Commands/WellLogCommands/RicNewWellBoreStabilityPlotFeature.cpp index f9f78f7856..682cede2d7 100644 --- a/ApplicationCode/Commands/WellLogCommands/RicNewWellBoreStabilityPlotFeature.cpp +++ b/ApplicationCode/Commands/WellLogCommands/RicNewWellBoreStabilityPlotFeature.cpp @@ -102,29 +102,42 @@ void RicNewWellBoreStabilityPlotFeature::onActionTriggered(bool isChecked) if (!geoMechView) return; caf::ProgressInfo progInfo(100, "Creating Well Bore Stability Plot"); - progInfo.setProgressDescription("Creating plot and formation track"); - progInfo.setNextProgressIncrement(2); + RimGeoMechCase* geoMechCase = geoMechView->geoMechCase(); + RimWellLogPlot* plot = RicNewWellLogPlotFeatureImpl::createWellLogPlot(false, "Well Bore Stability"); - QString plotName("Well Bore Stability"); - RimWellLogPlot* plot = RicNewWellLogPlotFeatureImpl::createWellLogPlot(false, plotName); - createFormationTrack(plot, wellPath, geoMechCase); - progInfo.incrementProgressAndUpdateNextStep(3, "Creating well design track"); - createCasingShoeTrack(plot, wellPath, geoMechCase); - progInfo.incrementProgressAndUpdateNextStep(75, "Creating stability curves track"); - createStabilityCurvesTrack(plot, wellPath, geoMechView); - progInfo.incrementProgressAndUpdateNextStep(15, "Creating angles track"); - createAnglesTrack(plot, wellPath, geoMechView); - progInfo.incrementProgressAndUpdateNextStep(5, "Updating all tracks"); - plot->enableAllAutoNameTags(true); - plot->setPlotTitleVisible(true); - plot->setTrackLegendsVisible(true); - plot->setTrackLegendsHorizontal(true); - plot->setDepthType(RimWellLogPlot::TRUE_VERTICAL_DEPTH); - plot->setDepthAutoZoom(true); - - RicNewWellLogPlotFeatureImpl::updateAfterCreation(plot); - progInfo.incrementProgress(); + { + auto task = progInfo.task("Creating formation track", 2); + createFormationTrack(plot, wellPath, geoMechCase); + } + + { + auto task = progInfo.task("Creating well design track", 3); + createCasingShoeTrack(plot, wellPath, geoMechCase); + } + + { + auto task = progInfo.task("Creating stability curves track", 75); + createStabilityCurvesTrack(plot, wellPath, geoMechView); + } + + { + auto task = progInfo.task("Creating angles track", 15); + createAnglesTrack(plot, wellPath, geoMechView); + } + + { + auto task = progInfo.task("Updating all tracks", 5); + + plot->enableAllAutoNameTags(true); + plot->setPlotTitleVisible(true); + plot->setTrackLegendsVisible(true); + plot->setTrackLegendsHorizontal(true); + plot->setDepthType(RimWellLogPlot::TRUE_VERTICAL_DEPTH); + plot->setDepthAutoZoom(true); + + RicNewWellLogPlotFeatureImpl::updateAfterCreation(plot); + } RiuPlotMainWindowTools::selectAsCurrentItem(plot); diff --git a/ApplicationCode/Commands/WellLogCommands/RicNewWellLogCurveExtractionFeature.cpp b/ApplicationCode/Commands/WellLogCommands/RicNewWellLogCurveExtractionFeature.cpp index e4700459ed..ac23136346 100644 --- a/ApplicationCode/Commands/WellLogCommands/RicNewWellLogCurveExtractionFeature.cpp +++ b/ApplicationCode/Commands/WellLogCommands/RicNewWellLogCurveExtractionFeature.cpp @@ -38,7 +38,7 @@ #include "RimWellPathCollection.h" #include "RiuPlotMainWindow.h" -#include "RiuSelectionManager.h" +#include "Riu3dSelectionManager.h" #include "cafSelectionManager.h" diff --git a/ApplicationCode/Commands/WellPathCommands/CMakeLists_files.cmake b/ApplicationCode/Commands/WellPathCommands/CMakeLists_files.cmake index 7af02e103f..316f3f892e 100644 --- a/ApplicationCode/Commands/WellPathCommands/CMakeLists_files.cmake +++ b/ApplicationCode/Commands/WellPathCommands/CMakeLists_files.cmake @@ -15,7 +15,15 @@ ${CMAKE_CURRENT_LIST_DIR}/RicWellPathPickEventHandler.h ${CMAKE_CURRENT_LIST_DIR}/RicCreateWellTargetsPickEventHandler.h ${CMAKE_CURRENT_LIST_DIR}/RicIntersectionPickEventHandler.h ${CMAKE_CURRENT_LIST_DIR}/RicWellPathFormationsImportFileFeature.h +${CMAKE_CURRENT_LIST_DIR}/RicPolylineTargetsPickEventHandler.h +${CMAKE_CURRENT_LIST_DIR}/RicNewPolylineTargetFeature.h +${CMAKE_CURRENT_LIST_DIR}/RicDeletePolylineTargetFeature.h ${CMAKE_CURRENT_LIST_DIR}/PointTangentManipulator/RicPointTangentManipulator.h +${CMAKE_CURRENT_LIST_DIR}/PointTangentManipulator/RicWellTarget3dEditor.h +${CMAKE_CURRENT_LIST_DIR}/PointTangentManipulator/RicWellPathGeometry3dEditor.h +${CMAKE_CURRENT_LIST_DIR}/PointTangentManipulator/RicPointTangentManipulatorPartMgr.h +${CMAKE_CURRENT_LIST_DIR}/PointTangentManipulator/RicPolyline3dEditor.h +${CMAKE_CURRENT_LIST_DIR}/PointTangentManipulator/RicPolylineTarget3dEditor.h ) set (SOURCE_GROUP_SOURCE_FILES @@ -34,7 +42,15 @@ ${CMAKE_CURRENT_LIST_DIR}/RicWellPathPickEventHandler.cpp ${CMAKE_CURRENT_LIST_DIR}/RicCreateWellTargetsPickEventHandler.cpp ${CMAKE_CURRENT_LIST_DIR}/RicIntersectionPickEventHandler.cpp ${CMAKE_CURRENT_LIST_DIR}/RicWellPathFormationsImportFileFeature.cpp +${CMAKE_CURRENT_LIST_DIR}/RicPolylineTargetsPickEventHandler.cpp +${CMAKE_CURRENT_LIST_DIR}/RicNewPolylineTargetFeature.cpp +${CMAKE_CURRENT_LIST_DIR}/RicDeletePolylineTargetFeature.cpp ${CMAKE_CURRENT_LIST_DIR}/PointTangentManipulator/RicPointTangentManipulator.cpp +${CMAKE_CURRENT_LIST_DIR}/PointTangentManipulator/RicWellTarget3dEditor.cpp +${CMAKE_CURRENT_LIST_DIR}/PointTangentManipulator/RicWellPathGeometry3dEditor.cpp +${CMAKE_CURRENT_LIST_DIR}/PointTangentManipulator/RicPointTangentManipulatorPartMgr.cpp +${CMAKE_CURRENT_LIST_DIR}/PointTangentManipulator/RicPolyline3dEditor.cpp +${CMAKE_CURRENT_LIST_DIR}/PointTangentManipulator/RicPolylineTarget3dEditor.cpp ) list(APPEND CODE_HEADER_FILES @@ -47,6 +63,10 @@ ${SOURCE_GROUP_SOURCE_FILES} list(APPEND QT_MOC_HEADERS ${CMAKE_CURRENT_LIST_DIR}/PointTangentManipulator/RicPointTangentManipulator.h +${CMAKE_CURRENT_LIST_DIR}/PointTangentManipulator/RicWellTarget3dEditor.h +${CMAKE_CURRENT_LIST_DIR}/PointTangentManipulator/RicWellPathGeometry3dEditor.h +${CMAKE_CURRENT_LIST_DIR}/PointTangentManipulator/RicPolyline3dEditor.h +${CMAKE_CURRENT_LIST_DIR}/PointTangentManipulator/RicPolylineTarget3dEditor.h ) source_group( "CommandFeature\\WellPath" FILES ${SOURCE_GROUP_HEADER_FILES} ${SOURCE_GROUP_SOURCE_FILES} ${CMAKE_CURRENT_LIST_DIR}/CMakeLists_files.cmake ) diff --git a/ApplicationCode/Commands/WellPathCommands/PointTangentManipulator/RicPointTangentManipulator.cpp b/ApplicationCode/Commands/WellPathCommands/PointTangentManipulator/RicPointTangentManipulator.cpp index 10a8fa81f0..612717857f 100644 --- a/ApplicationCode/Commands/WellPathCommands/PointTangentManipulator/RicPointTangentManipulator.cpp +++ b/ApplicationCode/Commands/WellPathCommands/PointTangentManipulator/RicPointTangentManipulator.cpp @@ -19,7 +19,11 @@ #include "RicPointTangentManipulator.h" +#include "RicPointTangentManipulatorPartMgr.h" +#include "RivPartPriority.h" + #include "cafViewer.h" +#include "cafPdmUiCommandSystemProxy.h" #include "cvfCamera.h" #include "cvfDrawableGeo.h" @@ -30,9 +34,6 @@ #include #include -#include "RivPartPriority.h" -#include "cafPdmUiCommandSystemProxy.h" -#include "RimModeledWellPath.h" //-------------------------------------------------------------------------------------------------- /// @@ -158,757 +159,3 @@ bool RicPointTangentManipulator::eventFilter(QObject *obj, QEvent* inputEvent) } - -//================================================================================================== -/// -/// -//================================================================================================== - - - -#include "RicPointTangentManipulator.h" - -#include "cafBoxManipulatorGeometryGenerator.h" -#include "cafEffectGenerator.h" -#include "cafLine.h" -#include "cafSelectionManager.h" - -#include "cvfBoxGenerator.h" -#include "cvfDrawableGeo.h" -#include "cvfGeometryBuilderFaceList.h" -#include "cvfModelBasicList.h" -#include "cvfPart.h" -#include "cvfPrimitiveSetIndexedUInt.h" -#include "cvfPrimitiveSetIndexedUShort.h" -#include "cvfRay.h" -#include "cvfPrimitiveSetDirect.h" -#include "cvfHitItem.h" -#include - -#include "cvfGeometryBuilderTriangles.h" -#include "cvfGeometryUtils.h" -// - - - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -RicPointTangentManipulatorPartMgr::RicPointTangentManipulatorPartMgr() - : m_tangentOnStartManipulation(cvf::Vec3d::UNDEFINED), - m_originOnStartManipulation(cvf::Vec3d::UNDEFINED), - m_currentHandleIndex(cvf::UNDEFINED_SIZE_T), - m_handleSize(1.0) -{ -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -RicPointTangentManipulatorPartMgr::~RicPointTangentManipulatorPartMgr() -{ -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RicPointTangentManipulatorPartMgr::setOrigin(const cvf::Vec3d& origin) -{ - if (isManipulatorActive()) return; - - m_origin = origin; - if (m_originOnStartManipulation.isUndefined()) m_originOnStartManipulation = origin; - - clearAllGeometryAndParts(); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RicPointTangentManipulatorPartMgr::setTangent(const cvf::Vec3d& tangent) -{ - if(isManipulatorActive()) return; - - m_tangent = tangent; - if (m_tangentOnStartManipulation.isUndefined()) m_tangentOnStartManipulation = m_tangent; - - clearAllGeometryAndParts(); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RicPointTangentManipulatorPartMgr::setHandleSize(double handleSize) -{ - m_handleSize = handleSize; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RicPointTangentManipulatorPartMgr::originAndTangent(cvf::Vec3d* origin, cvf::Vec3d* tangent) -{ - *origin = m_origin; - *tangent = m_tangent; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -bool RicPointTangentManipulatorPartMgr::isManipulatorActive() const -{ - return m_currentHandleIndex != cvf::UNDEFINED_SIZE_T; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RicPointTangentManipulatorPartMgr::appendPartsToModel(cvf::ModelBasicList* model) -{ - if (!m_handleParts.size()) - { - recreateAllGeometryAndParts(); - } - - for (size_t i = 0; i < m_handleParts.size(); i++) - { - model->addPart(m_handleParts.at(i)); - } - - for (auto activeModePart: m_activeDragModeParts) - { - model->addPart(activeModePart.p()); - } -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RicPointTangentManipulatorPartMgr::tryToActivateManipulator(const cvf::HitItem* hitItem) -{ - endManipulator(); - - if (!hitItem) return; - - const cvf::Part* pickedPart = hitItem->part(); - const cvf::Vec3d intersectionPoint = hitItem->intersectionPoint(); - - if (!pickedPart) return; - - for (size_t i = 0; i < m_handleParts.size(); i++) - { - if (pickedPart == m_handleParts.at(i)) - { - m_initialPickPoint = intersectionPoint; - m_tangentOnStartManipulation = m_tangent; - m_originOnStartManipulation = m_origin; - m_currentHandleIndex = i; - } - } - -} - - -//-------------------------------------------------------------------------------------------------- -/// Calculate new origin and tangent based on the new ray position -/// Clear geometry to trigger regeneration -//-------------------------------------------------------------------------------------------------- -void RicPointTangentManipulatorPartMgr::updateManipulatorFromRay(const cvf::Ray* newMouseRay) -{ - if (!isManipulatorActive()) return; - - if ( m_handleIds[m_currentHandleIndex] == HORIZONTAL_PLANE ) - { - cvf::Plane plane; - plane.setFromPointAndNormal(m_origin, cvf::Vec3d::Z_AXIS); - cvf::Vec3d newIntersection; - newMouseRay->planeIntersect(plane, &newIntersection); - - cvf::Vec3d newOrigin = m_originOnStartManipulation + (newIntersection - m_initialPickPoint); - - m_origin = newOrigin; - } - else if ( m_handleIds[m_currentHandleIndex] == VERTICAL_AXIS ) - { - cvf::Plane plane; - cvf::Vec3d planeNormal = (newMouseRay->direction() ^ cvf::Vec3d::Z_AXIS) ^ cvf::Vec3d::Z_AXIS; - double length = planeNormal.length(); - - if (length < 1e-5) return; - - planeNormal /= length; - plane.setFromPointAndNormal(m_initialPickPoint, planeNormal ); - cvf::Vec3d newIntersection; - newMouseRay->planeIntersect(plane, &newIntersection); - - cvf::Vec3d newOrigin = m_originOnStartManipulation; - newOrigin.z() += (newIntersection.z() - m_initialPickPoint.z()); - - m_origin = newOrigin; - } - //m_tangent = newTangent; - - clearAllGeometryAndParts(); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RicPointTangentManipulatorPartMgr::endManipulator() -{ - m_currentHandleIndex = cvf::UNDEFINED_SIZE_T; - -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RicPointTangentManipulatorPartMgr::clearAllGeometryAndParts() -{ - m_handleIds.clear(); - m_handleParts.clear(); - m_activeDragModeParts.clear(); -} - - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RicPointTangentManipulatorPartMgr::recreateAllGeometryAndParts() -{ - createAllHandleParts(); - -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RicPointTangentManipulatorPartMgr::createAllHandleParts() -{ - createHorizontalPlaneHandle(); - createVerticalAxisHandle(); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RicPointTangentManipulatorPartMgr::createHorizontalPlaneHandle() -{ - using namespace cvf; - cvf::ref vertexArray = new cvf::Vec3fArray(6); - - vertexArray->set(0, {-1, -1, 0} ); - vertexArray->set(1, { 1, -1, 0}); - vertexArray->set(2, { 1, 1, 0}); - vertexArray->set(3, {-1, -1, 0}); - vertexArray->set(4, { 1, 1, 0}); - vertexArray->set(5, {-1, 1, 0}); - - Vec3f origin(m_origin); - for (cvf::Vec3f& vx: *vertexArray) - { - vx *= 0.5*m_handleSize; - vx += origin; - } - - ref geo = createTriangelDrawableGeo(vertexArray.p()); - - HandleType handleId = HORIZONTAL_PLANE; - cvf::Color4f color = cvf::Color4f(1.0f, 0.0f, 1.0f, 0.5f); - cvf::String partName("PointTangentManipulator Horizontal Plane Handle"); - - addHandlePart(geo.p(), color, handleId, partName); -} - - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RicPointTangentManipulatorPartMgr::createVerticalAxisHandle() -{ - using namespace cvf; - - cvf::ref< cvf::GeometryBuilderTriangles> geomBuilder = new cvf::GeometryBuilderTriangles; - cvf::GeometryUtils::createBox({-0.3f, -0.3f, -1.0f}, { 0.3f, 0.3f, 1.0f}, geomBuilder.p()); - - cvf::ref vertexArray = geomBuilder->vertices(); - cvf::ref indexArray = geomBuilder->triangles(); - - Vec3f origin(m_origin); - for (cvf::Vec3f& vx: *vertexArray) - { - vx *= 0.5*m_handleSize; - vx += origin; - } - - ref geo = createIndexedTriangelDrawableGeo(vertexArray.p(), indexArray.p()); - - HandleType handleId = VERTICAL_AXIS; - cvf::Color4f color = cvf::Color4f(0.0f, 0.2f, 0.8f, 0.5f); - cvf::String partName("PointTangentManipulator Vertical Axis Handle"); - - addHandlePart(geo.p(), color, handleId, partName); -} - -#if 0 -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RicPointTangentManipulatorPartMgr::createAzimuthHandle() -{ - using namespace cvf; - - cvf::ref< cvf::GeometryBuilderTriangles> geomBuilder = new cvf::GeometryBuilderTriangles; - cvf::GeometryUtils::createDisc(1.3, 1.1, 16, geomBuilder.p()); - - cvf::ref vertexArray = geomBuilder->vertices(); - cvf::ref indexArray = geomBuilder->triangles(); - - Vec3f origin(m_origin); - for (cvf::Vec3f& vx: *vertexArray) - { - vx *= 0.5*m_handleSize; - vx += origin; - } - - ref geo = createIndexedTriangelDrawableGeo(vertexArray.p(), indexArray.p()); - - HandleType handleId = AZIMUTH; - cvf::Color4f color = cvf::Color4f(0.0f, 0.2f, 0.8f, 0.5f); - cvf::String partName("PointTangentManipulator Azimuth Handle"); - - addHandlePart(geo.p(), color, handleId, partName); -} - -#endif - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -cvf::ref RicPointTangentManipulatorPartMgr::createIndexedTriangelDrawableGeo(cvf::Vec3fArray* triangleVertexArray, - cvf::UIntArray* triangleIndices) -{ - using namespace cvf; - ref geo = new DrawableGeo; - ref primSet = new PrimitiveSetIndexedUInt(PT_TRIANGLES, triangleIndices); - - geo->setVertexArray(triangleVertexArray); - geo->addPrimitiveSet(primSet.p()); - geo->computeNormals(); - - return geo; -} - - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -cvf::ref RicPointTangentManipulatorPartMgr::createTriangelDrawableGeo(cvf::Vec3fArray* triangleVertexArray) -{ - using namespace cvf; - ref geo = new DrawableGeo; - - geo->setVertexArray(triangleVertexArray); - ref primSet = new cvf::PrimitiveSetDirect(cvf::PT_TRIANGLES); - primSet->setIndexCount(triangleVertexArray->size()); - - geo->addPrimitiveSet(primSet.p()); - geo->computeNormals(); - - return geo; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RicPointTangentManipulatorPartMgr::addHandlePart(cvf::DrawableGeo* geo, - const cvf::Color4f& color, - HandleType handleId, - const cvf::String& partName) -{ - cvf::ref handlePart = createPart(geo, color, partName); - - m_handleParts.push_back(handlePart.p()); - m_handleIds.push_back(handleId); -} - - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RicPointTangentManipulatorPartMgr::addActiveModePart(cvf::DrawableGeo* geo, - const cvf::Color4f& color, - HandleType handleId, - const cvf::String& partName) -{ - cvf::ref handlePart = createPart(geo, color, partName); - - m_activeDragModeParts.push_back(handlePart.p()); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -cvf::ref RicPointTangentManipulatorPartMgr::createPart(cvf::DrawableGeo* geo, - const cvf::Color4f& color, - const cvf::String& partName) -{ - cvf::ref part = new cvf::Part; - part->setName(partName); - part->setDrawable(geo); - part->updateBoundingBox(); - - caf::SurfaceEffectGenerator surfaceGen(color, caf::PO_1); - cvf::ref eff = surfaceGen.generateCachedEffect(); - part->setEffect(eff.p()); - if (color.a() < 1.0) part->setPriority(RivPartPriority::Transparent); - - return part; -} - -//================================================================================================== -/// -/// -/// -//================================================================================================== -namespace caf -{ -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -PdmUi3dObjectEditorHandle::PdmUi3dObjectEditorHandle() -{ - -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -PdmUi3dObjectEditorHandle::~PdmUi3dObjectEditorHandle() -{ - -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void PdmUi3dObjectEditorHandle::setViewer(caf::Viewer* ownerViewer) -{ - // Not allowed to change viewer. Should be constructor argument, but makes factory stuff difficult. - CAF_ASSERT(m_ownerViewer.isNull()); - m_ownerViewer = ownerViewer; -} -} - -//================================================================================================== -/// -/// -/// -//================================================================================================== - -#include "cafSelectionManager.h" -#include "RimWellPathGeometryDef.h" - -namespace caf -{ -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -PdmUiSelectionVisualizer3d::PdmUiSelectionVisualizer3d(caf::Viewer* ownerViewer) - : m_ownerViewer(ownerViewer) -{ - this->setParent(ownerViewer); // Makes this owned by the viewer. -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -PdmUiSelectionVisualizer3d::~PdmUiSelectionVisualizer3d() -{ - for (auto editor: m_active3DEditors) - { - delete editor; - } -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void PdmUiSelectionVisualizer3d::updateVisibleEditors() -{ - for (auto editor: m_active3DEditors) - { - if (editor) editor->updateUi(); - } -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void PdmUiSelectionVisualizer3d::onSelectionManagerSelectionChanged( const std::set& changedSelectionLevels ) -{ - if (!changedSelectionLevels.count(0)) return; - - for (auto editor: m_active3DEditors) - { - delete editor; - } - - m_active3DEditors.clear(); - - if (!m_ownerViewer) return; - - // Todo: How do we deduce the editor from the selected object ? - // Alt 1: Register the rim object type name as key in the factory as well - // Alt 2: Set the editor type name as PdmUiItem::setUiEditorTypeName - // Alt 3: Use a specific config-name in alt 2. - // Alt 4: Introduce a PdmUiItem::editorTypeName3d - - std::vector wellPathGeomDefs; - caf::SelectionManager::instance()->objectsByType(&wellPathGeomDefs); - - for (auto geomDef: wellPathGeomDefs) - { - auto editor = new RicWellPathGeometry3dEditor(); - editor->setViewer(m_ownerViewer); - editor->setPdmObject(geomDef); - m_active3DEditors.push_back(editor); - editor->updateUi(); - } - m_ownerViewer->update(); -} - -} // caf - -//================================================================================================== -/// -/// -/// -//================================================================================================== - -#include "RimWellPathTarget.h" - -CAF_PDM_UI_3D_OBJECT_EDITOR_SOURCE_INIT(RicWellPathGeometry3dEditor); - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -RicWellPathGeometry3dEditor::RicWellPathGeometry3dEditor() -{ - -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -RicWellPathGeometry3dEditor::~RicWellPathGeometry3dEditor() -{ - for (auto targetEditor: m_targetEditors) - { - delete targetEditor; - } -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RicWellPathGeometry3dEditor::configureAndUpdateUi(const QString& uiConfigName) -{ - RimWellPathGeometryDef* geomDef = dynamic_cast(this->pdmObject()); - - for (auto targetEditor: m_targetEditors) - { - delete targetEditor; - } - m_targetEditors.clear(); - - if (!geomDef) return; - - - std::vector targets = geomDef->activeWellTargets(); - - for (auto target: targets) - { - auto targetEditor = new RicWellTarget3dEditor; - targetEditor->setViewer(m_ownerViewer); - targetEditor->setPdmObject(target); - m_targetEditors.push_back(targetEditor); - targetEditor->updateUi(); - } -} - -//================================================================================================== -/// -/// -/// -//================================================================================================== - - -#include "RimWellPathTarget.h" -#include "RiuViewer.h" -#include "cafDisplayCoordTransform.h" -#include "Rim3dView.h" -#include "RimCase.h" - -CAF_PDM_UI_3D_OBJECT_EDITOR_SOURCE_INIT(RicWellTarget3dEditor); - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -RicWellTarget3dEditor::RicWellTarget3dEditor() -{ - -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -RicWellTarget3dEditor::~RicWellTarget3dEditor() -{ - if (m_cvfModel.notNull() && m_ownerViewer) - { - // Could result in some circularities .... - m_ownerViewer->removeStaticModel(m_cvfModel.p()); - } - - RimWellPathTarget* oldTarget = dynamic_cast(this->pdmObject()); - if (oldTarget) - { - oldTarget->m_targetType.uiCapability()->removeFieldEditor(this); - oldTarget->m_targetPoint.uiCapability()->removeFieldEditor(this); - oldTarget->m_azimuth.uiCapability()->removeFieldEditor(this); - oldTarget->m_inclination.uiCapability()->removeFieldEditor(this); - } - - delete m_manipulator; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RicWellTarget3dEditor::configureAndUpdateUi(const QString& uiConfigName) -{ - RimWellPathTarget* target = dynamic_cast(this->pdmObject()); - - if ( !target || !target->isEnabled()) - { - m_cvfModel->removeAllParts(); - return; - } - - RimWellPathGeometryDef* geomDef; - target->firstAncestorOrThisOfTypeAsserted(geomDef); - - target->m_targetType.uiCapability()->addFieldEditor(this); - target->m_targetPoint.uiCapability()->addFieldEditor(this); - target->m_azimuth.uiCapability()->addFieldEditor(this); - target->m_inclination.uiCapability()->addFieldEditor(this); - - if (m_manipulator.isNull()) - { - m_manipulator = new RicPointTangentManipulator(m_ownerViewer); - QObject::connect(m_manipulator, - SIGNAL( notifyUpdate(const cvf::Vec3d& , const cvf::Vec3d& ) ), - this, - SLOT( slotUpdated(const cvf::Vec3d& , const cvf::Vec3d& ) ) ); - QObject::connect(m_manipulator, - SIGNAL( notifySelected() ), - this, - SLOT( slotSelectedIn3D() ) ); - QObject::connect(m_manipulator, - SIGNAL( notifyDragFinished() ), - this, - SLOT( slotDragFinished() ) ); - m_cvfModel = new cvf::ModelBasicList; - m_ownerViewer->addStaticModelOnce(m_cvfModel.p()); - } - - cvf::ref dispXf; - double handleSize = 1.0; - { - RiuViewer* viewer = dynamic_cast(m_ownerViewer.data()); - dispXf = viewer->ownerReservoirView()->displayCoordTransform(); - Rim3dView* view = dynamic_cast(viewer->ownerReservoirView()); - handleSize = 0.7 * view->ownerCase()->characteristicCellSize(); - } - - m_manipulator->setOrigin(dispXf->transformToDisplayCoord( target->targetPointXYZ() + geomDef->referencePointXyz())); - m_manipulator->setTangent(target->tangent()); - m_manipulator->setHandleSize(handleSize); - m_cvfModel->removeAllParts(); - m_manipulator->appendPartsToModel(m_cvfModel.p()); - - m_cvfModel->updateBoundingBoxesRecursive(); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RicWellTarget3dEditor::cleanupBeforeSettingPdmObject() -{ - RimWellPathTarget* oldTarget = dynamic_cast(this->pdmObject()); - if (oldTarget) - { - oldTarget->m_targetType.uiCapability()->removeFieldEditor(this); - oldTarget->m_targetPoint.uiCapability()->removeFieldEditor(this); - oldTarget->m_azimuth.uiCapability()->removeFieldEditor(this); - oldTarget->m_inclination.uiCapability()->removeFieldEditor(this); - } -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RicWellTarget3dEditor::slotUpdated(const cvf::Vec3d& origin, const cvf::Vec3d& tangent) -{ - RimWellPathTarget* target = dynamic_cast(this->pdmObject()); - - if ( !target) - { - return; - } - - cvf::ref dispXf; - { - RiuViewer* viewer = dynamic_cast(m_ownerViewer.data()); - dispXf = viewer->ownerReservoirView()->displayCoordTransform(); - } - - RimWellPathGeometryDef* geomDef; - target->firstAncestorOrThisOfTypeAsserted(geomDef); - - cvf::Vec3d domainOrigin = dispXf->transformToDomainCoord( origin) - geomDef->referencePointXyz(); - domainOrigin.z() = -domainOrigin.z(); - QVariant originVariant = caf::PdmValueFieldSpecialization < cvf::Vec3d >::convert(domainOrigin); - - target->enableFullUpdate(false); - caf::PdmUiCommandSystemProxy::instance()->setUiValueToField(target->m_targetPoint.uiCapability(), originVariant); - target->enableFullUpdate(true); -} - -void RicWellTarget3dEditor::slotSelectedIn3D() -{ - RimWellPathTarget* target = dynamic_cast(this->pdmObject()); - if ( !target) - { - return; - } - - caf::SelectionManager::instance()->setSelectedItemAtLevel(target, caf::SelectionManager::FIRST_LEVEL); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RicWellTarget3dEditor::slotDragFinished() -{ - RimWellPathTarget* target = dynamic_cast(this->pdmObject()); - if ( !target) - { - return; - } - - RimModeledWellPath* wellpath; - target->firstAncestorOrThisOfTypeAsserted(wellpath); - wellpath->scheduleUpdateOfDependentVisualization(); -} diff --git a/ApplicationCode/Commands/WellPathCommands/PointTangentManipulator/RicPointTangentManipulator.h b/ApplicationCode/Commands/WellPathCommands/PointTangentManipulator/RicPointTangentManipulator.h index 0326cd7fcd..43474f8916 100644 --- a/ApplicationCode/Commands/WellPathCommands/PointTangentManipulator/RicPointTangentManipulator.h +++ b/ApplicationCode/Commands/WellPathCommands/PointTangentManipulator/RicPointTangentManipulator.h @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018- Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -72,228 +72,3 @@ class RicPointTangentManipulator : public QObject cvf::ref m_partManager; }; - -#pragma once - -#include "cvfBase.h" -#include "cvfObject.h" - -#include "cvfVector3.h" -#include "cvfCollection.h" -#include "cvfMatrix4.h" -#include "cvfString.h" -#include "cvfColor4.h" - -namespace cvf -{ -class ModelBasicList; -class Part; -class DrawableGeo; -class Ray; -class HitItem; - -template class Array; -typedef Array Vec3fArray; -typedef Array UIntArray; - -} - -class RicPointTangentManipulatorPartMgr : public cvf::Object -{ -public: - enum HandleType - { - HORIZONTAL_PLANE, - VERTICAL_AXIS, - AZIMUTH, - INCLINATION - }; - -public: - RicPointTangentManipulatorPartMgr(); - ~RicPointTangentManipulatorPartMgr() override; - - void setOrigin(const cvf::Vec3d& origin); - void setTangent(const cvf::Vec3d& tangent); - void setHandleSize(double handleSize); - void originAndTangent(cvf::Vec3d* origin, cvf::Vec3d* tangent); - - bool isManipulatorActive() const; - void tryToActivateManipulator(const cvf::HitItem* hitItem); - void updateManipulatorFromRay(const cvf::Ray* ray); - void endManipulator(); - - void appendPartsToModel(cvf::ModelBasicList* model); - -private: - void createAllHandleParts(); - void clearAllGeometryAndParts(); - void recreateAllGeometryAndParts(); - - void createHorizontalPlaneHandle(); - void createVerticalAxisHandle(); - - void addHandlePart(cvf::DrawableGeo* geo, - const cvf::Color4f& color, - HandleType handleId, - const cvf::String& partName); - - void addActiveModePart(cvf::DrawableGeo* geo, - const cvf::Color4f& color, - HandleType handleId, - const cvf::String& partName); - - static cvf::ref createTriangelDrawableGeo(cvf::Vec3fArray* triangleVertexArray); - static cvf::ref createIndexedTriangelDrawableGeo(cvf::Vec3fArray* triangleVertexArray, - cvf::UIntArray* triangleIndices); - static cvf::ref createPart(cvf::DrawableGeo* geo, - const cvf::Color4f& color, - const cvf::String& partName); -private: - size_t m_currentHandleIndex; - std::vector< HandleType > m_handleIds; // These arrays have the same length - cvf::Collection m_handleParts; // These arrays have the same length - cvf::Collection m_activeDragModeParts; - - cvf::Vec3d m_origin; - cvf::Vec3d m_tangent; - double m_handleSize; - - cvf::Vec3d m_initialPickPoint; - cvf::Vec3d m_tangentOnStartManipulation; - cvf::Vec3d m_originOnStartManipulation; - -}; - - -//================================================================================================== -/// -/// -/// -//================================================================================================== - - -#include "cafSelectionChangedReceiver.h" -#include "cafPdmUiObjectEditorHandle.h" -#include "cafFactory.h" -// PdmUiObjectEditorHandle -<| PdmUiWidgetObjectEditorHandle --<| PdmUiFormLayoutObjectEditor -// -<| PdmUi3dObjectEditorHandle -namespace caf -{ - -//================================================================================================== -/// Macros helping in development of PDM UI 3d editors -//================================================================================================== - -/// CAF_PDM_UI_3D_OBJECT_EDITOR_HEADER_INIT assists the factory used when creating editors -/// Place this in the header file inside the class definition of your PdmUiEditor - -#define CAF_PDM_UI_3D_OBJECT_EDITOR_HEADER_INIT \ -public: \ - static QString uiEditorTypeName() - -/// CAF_PDM_UI_3D_OBJECT_EDITOR_SOURCE_INIT implements editorTypeName() and registers the field editor in the field editor factory -/// Place this in the cpp file, preferably above the constructor - -#define CAF_PDM_UI_3D_OBJECT_EDITOR_SOURCE_INIT(EditorClassName) \ - QString EditorClassName::uiEditorTypeName() { return #EditorClassName; } \ - CAF_FACTORY_REGISTER(caf::PdmUi3dObjectEditorHandle, EditorClassName, QString, EditorClassName::uiEditorTypeName()) - - -class PdmUi3dObjectEditorHandle : public caf::PdmUiObjectEditorHandle -{ -public: - PdmUi3dObjectEditorHandle(); - ~PdmUi3dObjectEditorHandle() override; - - void setViewer(caf::Viewer* ownerViewer); - -protected: - // To be removed when splitting the PdmUiObjectEditorHandle - QWidget* createWidget(QWidget* parent) override { return nullptr;} - - QPointer m_ownerViewer; -}; - -//================================================================================================== -/// -/// -/// -//================================================================================================== - - -// Selected object 3D editor visualizer -class PdmUiSelectionVisualizer3d : public QObject, caf::SelectionChangedReceiver -{ - Q_OBJECT -public: - PdmUiSelectionVisualizer3d(caf::Viewer* ownerViewer); - ~PdmUiSelectionVisualizer3d() override; - - void updateVisibleEditors(); -protected: - void onSelectionManagerSelectionChanged( const std::set& changedSelectionLevels ) override; - - std::vector< QPointer > m_active3DEditors; - - QPointer m_ownerViewer; -}; - - -} - -//================================================================================================== -/// -/// -/// -//================================================================================================== - -class RicWellTarget3dEditor; - -class RicWellPathGeometry3dEditor : public caf::PdmUi3dObjectEditorHandle -{ - CAF_PDM_UI_3D_OBJECT_EDITOR_HEADER_INIT; - Q_OBJECT -public: - RicWellPathGeometry3dEditor(); - ~RicWellPathGeometry3dEditor() override; - -protected: - void configureAndUpdateUi(const QString& uiConfigName) override; - -private: - - std::vector m_targetEditors; -}; - -//================================================================================================== -/// -/// -/// -//================================================================================================== - - -class RicWellTarget3dEditor : public caf::PdmUi3dObjectEditorHandle -{ - CAF_PDM_UI_3D_OBJECT_EDITOR_HEADER_INIT; - Q_OBJECT -public: - RicWellTarget3dEditor(); - ~RicWellTarget3dEditor() override; - -protected: - void configureAndUpdateUi(const QString& uiConfigName) override; - void cleanupBeforeSettingPdmObject() override; - -private slots: - void slotUpdated(const cvf::Vec3d& origin, const cvf::Vec3d& tangent); - void slotSelectedIn3D(); - void slotDragFinished(); -private: - QPointer m_manipulator; - cvf::ref m_cvfModel; -}; - -class RiuViewer; - -// 3D editor manager diff --git a/ApplicationCode/Commands/WellPathCommands/PointTangentManipulator/RicPointTangentManipulatorPartMgr.cpp b/ApplicationCode/Commands/WellPathCommands/PointTangentManipulator/RicPointTangentManipulatorPartMgr.cpp new file mode 100644 index 0000000000..3ed819ebed --- /dev/null +++ b/ApplicationCode/Commands/WellPathCommands/PointTangentManipulator/RicPointTangentManipulatorPartMgr.cpp @@ -0,0 +1,422 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2018- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "RicPointTangentManipulatorPartMgr.h" + +#include "RivPartPriority.h" + +#include "cafEffectGenerator.h" +#include "cafLine.h" +#include "cafSelectionManager.h" + +#include "cvfBoxGenerator.h" +#include "cvfDrawableGeo.h" +#include "cvfGeometryBuilderFaceList.h" +#include "cvfModelBasicList.h" +#include "cvfPart.h" +#include "cvfPrimitiveSetIndexedUInt.h" +#include "cvfRay.h" +#include "cvfPlane.h" +#include "cvfPrimitiveSetDirect.h" +#include "cvfHitItem.h" + +#include "cvfGeometryBuilderTriangles.h" +#include "cvfGeometryUtils.h" + +#include + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RicPointTangentManipulatorPartMgr::RicPointTangentManipulatorPartMgr() + : m_tangentOnStartManipulation(cvf::Vec3d::UNDEFINED), + m_originOnStartManipulation(cvf::Vec3d::UNDEFINED), + m_currentHandleIndex(cvf::UNDEFINED_SIZE_T), + m_handleSize(1.0) +{ +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RicPointTangentManipulatorPartMgr::~RicPointTangentManipulatorPartMgr() +{ +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicPointTangentManipulatorPartMgr::setOrigin(const cvf::Vec3d& origin) +{ + if (isManipulatorActive()) return; + + m_origin = origin; + if (m_originOnStartManipulation.isUndefined()) m_originOnStartManipulation = origin; + + clearAllGeometryAndParts(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicPointTangentManipulatorPartMgr::setTangent(const cvf::Vec3d& tangent) +{ + if(isManipulatorActive()) return; + + m_tangent = tangent; + if (m_tangentOnStartManipulation.isUndefined()) m_tangentOnStartManipulation = m_tangent; + + clearAllGeometryAndParts(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicPointTangentManipulatorPartMgr::setHandleSize(double handleSize) +{ + m_handleSize = handleSize; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicPointTangentManipulatorPartMgr::originAndTangent(cvf::Vec3d* origin, cvf::Vec3d* tangent) +{ + *origin = m_origin; + *tangent = m_tangent; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RicPointTangentManipulatorPartMgr::isManipulatorActive() const +{ + return m_currentHandleIndex != cvf::UNDEFINED_SIZE_T; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicPointTangentManipulatorPartMgr::appendPartsToModel(cvf::ModelBasicList* model) +{ + if (!m_handleParts.size()) + { + recreateAllGeometryAndParts(); + } + + for (size_t i = 0; i < m_handleParts.size(); i++) + { + model->addPart(m_handleParts.at(i)); + } + + for (auto activeModePart: m_activeDragModeParts) + { + model->addPart(activeModePart.p()); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicPointTangentManipulatorPartMgr::tryToActivateManipulator(const cvf::HitItem* hitItem) +{ + endManipulator(); + + if (!hitItem) return; + + const cvf::Part* pickedPart = hitItem->part(); + const cvf::Vec3d intersectionPoint = hitItem->intersectionPoint(); + + if (!pickedPart) return; + + for (size_t i = 0; i < m_handleParts.size(); i++) + { + if (pickedPart == m_handleParts.at(i)) + { + m_initialPickPoint = intersectionPoint; + m_tangentOnStartManipulation = m_tangent; + m_originOnStartManipulation = m_origin; + m_currentHandleIndex = i; + } + } + +} + + +//-------------------------------------------------------------------------------------------------- +/// Calculate new origin and tangent based on the new ray position +/// Clear geometry to trigger regeneration +//-------------------------------------------------------------------------------------------------- +void RicPointTangentManipulatorPartMgr::updateManipulatorFromRay(const cvf::Ray* newMouseRay) +{ + if (!isManipulatorActive()) return; + + if ( m_handleIds[m_currentHandleIndex] == HORIZONTAL_PLANE ) + { + cvf::Plane plane; + plane.setFromPointAndNormal(m_origin, cvf::Vec3d::Z_AXIS); + cvf::Vec3d newIntersection; + newMouseRay->planeIntersect(plane, &newIntersection); + + cvf::Vec3d newOrigin = m_originOnStartManipulation + (newIntersection - m_initialPickPoint); + + m_origin = newOrigin; + } + else if ( m_handleIds[m_currentHandleIndex] == VERTICAL_AXIS ) + { + cvf::Plane plane; + cvf::Vec3d planeNormal = (newMouseRay->direction() ^ cvf::Vec3d::Z_AXIS) ^ cvf::Vec3d::Z_AXIS; + double length = planeNormal.length(); + + if (length < 1e-5) return; + + planeNormal /= length; + plane.setFromPointAndNormal(m_initialPickPoint, planeNormal ); + cvf::Vec3d newIntersection; + newMouseRay->planeIntersect(plane, &newIntersection); + + cvf::Vec3d newOrigin = m_originOnStartManipulation; + newOrigin.z() += (newIntersection.z() - m_initialPickPoint.z()); + + m_origin = newOrigin; + } + //m_tangent = newTangent; + + clearAllGeometryAndParts(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicPointTangentManipulatorPartMgr::endManipulator() +{ + m_currentHandleIndex = cvf::UNDEFINED_SIZE_T; + +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicPointTangentManipulatorPartMgr::clearAllGeometryAndParts() +{ + m_handleIds.clear(); + m_handleParts.clear(); + m_activeDragModeParts.clear(); +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicPointTangentManipulatorPartMgr::recreateAllGeometryAndParts() +{ + createAllHandleParts(); + +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicPointTangentManipulatorPartMgr::createAllHandleParts() +{ + createHorizontalPlaneHandle(); + createVerticalAxisHandle(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicPointTangentManipulatorPartMgr::createHorizontalPlaneHandle() +{ + using namespace cvf; + cvf::ref vertexArray = new cvf::Vec3fArray(6); + + vertexArray->set(0, {-1, -1, 0} ); + vertexArray->set(1, { 1, -1, 0}); + vertexArray->set(2, { 1, 1, 0}); + vertexArray->set(3, {-1, -1, 0}); + vertexArray->set(4, { 1, 1, 0}); + vertexArray->set(5, {-1, 1, 0}); + + Vec3f origin(m_origin); + for (cvf::Vec3f& vx: *vertexArray) + { + vx *= 0.5*m_handleSize; + vx += origin; + } + + ref geo = createTriangelDrawableGeo(vertexArray.p()); + + HandleType handleId = HORIZONTAL_PLANE; + cvf::Color4f color = cvf::Color4f(1.0f, 0.0f, 1.0f, 0.5f); + cvf::String partName("PointTangentManipulator Horizontal Plane Handle"); + + addHandlePart(geo.p(), color, handleId, partName); +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicPointTangentManipulatorPartMgr::createVerticalAxisHandle() +{ + using namespace cvf; + + cvf::ref< cvf::GeometryBuilderTriangles> geomBuilder = new cvf::GeometryBuilderTriangles; + cvf::GeometryUtils::createBox({-0.3f, -0.3f, -1.0f}, { 0.3f, 0.3f, 1.0f}, geomBuilder.p()); + + cvf::ref vertexArray = geomBuilder->vertices(); + cvf::ref indexArray = geomBuilder->triangles(); + + Vec3f origin(m_origin); + for (cvf::Vec3f& vx: *vertexArray) + { + vx *= 0.5*m_handleSize; + vx += origin; + } + + ref geo = createIndexedTriangelDrawableGeo(vertexArray.p(), indexArray.p()); + + HandleType handleId = VERTICAL_AXIS; + cvf::Color4f color = cvf::Color4f(0.0f, 0.2f, 0.8f, 0.5f); + cvf::String partName("PointTangentManipulator Vertical Axis Handle"); + + addHandlePart(geo.p(), color, handleId, partName); +} + +#if 0 +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicPointTangentManipulatorPartMgr::createAzimuthHandle() +{ + using namespace cvf; + + cvf::ref< cvf::GeometryBuilderTriangles> geomBuilder = new cvf::GeometryBuilderTriangles; + cvf::GeometryUtils::createDisc(1.3, 1.1, 16, geomBuilder.p()); + + cvf::ref vertexArray = geomBuilder->vertices(); + cvf::ref indexArray = geomBuilder->triangles(); + + Vec3f origin(m_origin); + for (cvf::Vec3f& vx: *vertexArray) + { + vx *= 0.5*m_handleSize; + vx += origin; + } + + ref geo = createIndexedTriangelDrawableGeo(vertexArray.p(), indexArray.p()); + + HandleType handleId = AZIMUTH; + cvf::Color4f color = cvf::Color4f(0.0f, 0.2f, 0.8f, 0.5f); + cvf::String partName("PointTangentManipulator Azimuth Handle"); + + addHandlePart(geo.p(), color, handleId, partName); +} + +#endif + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +cvf::ref RicPointTangentManipulatorPartMgr::createIndexedTriangelDrawableGeo(cvf::Vec3fArray* triangleVertexArray, + cvf::UIntArray* triangleIndices) +{ + using namespace cvf; + ref geo = new DrawableGeo; + ref primSet = new PrimitiveSetIndexedUInt(PT_TRIANGLES, triangleIndices); + + geo->setVertexArray(triangleVertexArray); + geo->addPrimitiveSet(primSet.p()); + geo->computeNormals(); + + return geo; +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +cvf::ref RicPointTangentManipulatorPartMgr::createTriangelDrawableGeo(cvf::Vec3fArray* triangleVertexArray) +{ + using namespace cvf; + ref geo = new DrawableGeo; + + geo->setVertexArray(triangleVertexArray); + ref primSet = new cvf::PrimitiveSetDirect(cvf::PT_TRIANGLES); + primSet->setIndexCount(triangleVertexArray->size()); + + geo->addPrimitiveSet(primSet.p()); + geo->computeNormals(); + + return geo; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicPointTangentManipulatorPartMgr::addHandlePart(cvf::DrawableGeo* geo, + const cvf::Color4f& color, + HandleType handleId, + const cvf::String& partName) +{ + cvf::ref handlePart = createPart(geo, color, partName); + + m_handleParts.push_back(handlePart.p()); + m_handleIds.push_back(handleId); +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicPointTangentManipulatorPartMgr::addActiveModePart(cvf::DrawableGeo* geo, + const cvf::Color4f& color, + HandleType handleId, + const cvf::String& partName) +{ + cvf::ref handlePart = createPart(geo, color, partName); + + m_activeDragModeParts.push_back(handlePart.p()); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +cvf::ref RicPointTangentManipulatorPartMgr::createPart(cvf::DrawableGeo* geo, + const cvf::Color4f& color, + const cvf::String& partName) +{ + cvf::ref part = new cvf::Part; + part->setName(partName); + part->setDrawable(geo); + part->updateBoundingBox(); + + caf::SurfaceEffectGenerator surfaceGen(color, caf::PO_1); + cvf::ref eff = surfaceGen.generateCachedEffect(); + part->setEffect(eff.p()); + if (color.a() < 1.0) part->setPriority(RivPartPriority::Transparent); + + return part; +} + + + + + + diff --git a/ApplicationCode/Commands/WellPathCommands/PointTangentManipulator/RicPointTangentManipulatorPartMgr.h b/ApplicationCode/Commands/WellPathCommands/PointTangentManipulator/RicPointTangentManipulatorPartMgr.h new file mode 100644 index 0000000000..a7dca46733 --- /dev/null +++ b/ApplicationCode/Commands/WellPathCommands/PointTangentManipulator/RicPointTangentManipulatorPartMgr.h @@ -0,0 +1,111 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2018- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "cvfBase.h" +#include "cvfObject.h" + +#include "cvfVector3.h" +#include "cvfCollection.h" +#include "cvfMatrix4.h" +#include "cvfColor4.h" + +namespace cvf +{ + +class ModelBasicList; +class Part; +class DrawableGeo; +class Ray; +class HitItem; +class String; + +template class Array; +typedef Array Vec3fArray; +typedef Array UIntArray; + +} + +class RicPointTangentManipulatorPartMgr : public cvf::Object +{ +public: + enum HandleType + { + HORIZONTAL_PLANE, + VERTICAL_AXIS, + AZIMUTH, + INCLINATION + }; + +public: + RicPointTangentManipulatorPartMgr(); + ~RicPointTangentManipulatorPartMgr() override; + + void setOrigin(const cvf::Vec3d& origin); + void setTangent(const cvf::Vec3d& tangent); + void setHandleSize(double handleSize); + void originAndTangent(cvf::Vec3d* origin, cvf::Vec3d* tangent); + + bool isManipulatorActive() const; + void tryToActivateManipulator(const cvf::HitItem* hitItem); + void updateManipulatorFromRay(const cvf::Ray* ray); + void endManipulator(); + + void appendPartsToModel(cvf::ModelBasicList* model); + +private: + void createAllHandleParts(); + void clearAllGeometryAndParts(); + void recreateAllGeometryAndParts(); + + void createHorizontalPlaneHandle(); + void createVerticalAxisHandle(); + + void addHandlePart(cvf::DrawableGeo* geo, + const cvf::Color4f& color, + HandleType handleId, + const cvf::String& partName); + + void addActiveModePart(cvf::DrawableGeo* geo, + const cvf::Color4f& color, + HandleType handleId, + const cvf::String& partName); + + static cvf::ref createTriangelDrawableGeo(cvf::Vec3fArray* triangleVertexArray); + static cvf::ref createIndexedTriangelDrawableGeo(cvf::Vec3fArray* triangleVertexArray, + cvf::UIntArray* triangleIndices); + static cvf::ref createPart(cvf::DrawableGeo* geo, + const cvf::Color4f& color, + const cvf::String& partName); +private: + size_t m_currentHandleIndex; + std::vector< HandleType > m_handleIds; // These arrays have the same length + cvf::Collection m_handleParts; // These arrays have the same length + cvf::Collection m_activeDragModeParts; + cvf::Vec3d m_origin; + cvf::Vec3d m_tangent; + double m_handleSize; + cvf::Vec3d m_initialPickPoint; + cvf::Vec3d m_tangentOnStartManipulation; + cvf::Vec3d m_originOnStartManipulation; + +}; + + + diff --git a/ApplicationCode/Commands/WellPathCommands/PointTangentManipulator/RicPolyline3dEditor.cpp b/ApplicationCode/Commands/WellPathCommands/PointTangentManipulator/RicPolyline3dEditor.cpp new file mode 100644 index 0000000000..7e1e955d09 --- /dev/null +++ b/ApplicationCode/Commands/WellPathCommands/PointTangentManipulator/RicPolyline3dEditor.cpp @@ -0,0 +1,93 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2018- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "RicPolyline3dEditor.h" + +#include "RicPolylineTarget3dEditor.h" + +#include "RimPolylineTarget.h" +#include "RimUserDefinedPolylinesAnnotation.h" + +#include "cafPickEventHandler.h" + +CAF_PDM_UI_3D_OBJECT_EDITOR_SOURCE_INIT(RicPolyline3dEditor); + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RicPolyline3dEditor::RicPolyline3dEditor() +{ + +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RicPolyline3dEditor::~RicPolyline3dEditor() +{ + for (auto targetEditor: m_targetEditors) + { + delete targetEditor; + } + if (m_attribute.pickEventHandler != nullptr) + { + m_attribute.pickEventHandler->unregisterAsPickEventHandler(); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicPolyline3dEditor::configureAndUpdateUi(const QString& uiConfigName) +{ + auto* geomDef = dynamic_cast(this->pdmObject()); + + for (auto targetEditor: m_targetEditors) + { + delete targetEditor; + } + m_targetEditors.clear(); + + if (!geomDef) return; + + geomDef->objectEditorAttribute("", &m_attribute); + if (m_attribute.pickEventHandler != nullptr) + { + if (m_attribute.enablePicking) + { + m_attribute.pickEventHandler->registerAsPickEventHandler(); + } + else + { + m_attribute.pickEventHandler->unregisterAsPickEventHandler(); + } + } + + std::vector targets = geomDef->activeTargets(); + + for (auto target: targets) + { + auto targetEditor = new RicPolylineTarget3dEditor; + targetEditor->setViewer(ownerViewer()); + targetEditor->setPdmObject(target); + m_targetEditors.push_back(targetEditor); + targetEditor->updateUi(); + } +} + + diff --git a/ApplicationCode/Commands/WellPathCommands/PointTangentManipulator/RicPolyline3dEditor.h b/ApplicationCode/Commands/WellPathCommands/PointTangentManipulator/RicPolyline3dEditor.h new file mode 100644 index 0000000000..a0df3c30cf --- /dev/null +++ b/ApplicationCode/Commands/WellPathCommands/PointTangentManipulator/RicPolyline3dEditor.h @@ -0,0 +1,69 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2018- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "cafPdmUi3dObjectEditorHandle.h" +#include "cafPdmUiFieldEditorHandle.h" + +#include + +namespace caf +{ + class PickEventHandler; +}; + +class RicPolylineTarget3dEditor; + + +//================================================================================================== +/// +//================================================================================================== +class RicPolyline3dEditorAttribute : public caf::PdmUiEditorAttribute +{ +public: + RicPolyline3dEditorAttribute() + : enablePicking(false) + { + } + +public: + bool enablePicking; + std::shared_ptr pickEventHandler; +}; + +//================================================================================================== +/// +//================================================================================================== +class RicPolyline3dEditor : public caf::PdmUi3dObjectEditorHandle +{ + CAF_PDM_UI_3D_OBJECT_EDITOR_HEADER_INIT; + Q_OBJECT +public: + RicPolyline3dEditor(); + ~RicPolyline3dEditor() override; + +protected: + void configureAndUpdateUi(const QString& uiConfigName) override; + +private: + std::vector m_targetEditors; + RicPolyline3dEditorAttribute m_attribute; +}; + + diff --git a/ApplicationCode/Commands/WellPathCommands/PointTangentManipulator/RicPolylineTarget3dEditor.cpp b/ApplicationCode/Commands/WellPathCommands/PointTangentManipulator/RicPolylineTarget3dEditor.cpp new file mode 100644 index 0000000000..b3bcdb750a --- /dev/null +++ b/ApplicationCode/Commands/WellPathCommands/PointTangentManipulator/RicPolylineTarget3dEditor.cpp @@ -0,0 +1,195 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2018- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "RicPolylineTarget3dEditor.h" + +#include "RicPointTangentManipulator.h" + +#include "RimAnnotationCollectionBase.h" +#include "RimPolylineTarget.h" +#include "Rim3dView.h" +#include "RimCase.h" +#include "RimUserDefinedPolylinesAnnotation.h" + +#include "RiuViewer.h" + +#include "cafDisplayCoordTransform.h" +#include "cafPdmUiCommandSystemProxy.h" +#include "cafSelectionManager.h" + +#include "cvfPart.h" +#include "cvfModelBasicList.h" + +CAF_PDM_UI_3D_OBJECT_EDITOR_SOURCE_INIT(RicPolylineTarget3dEditor); + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RicPolylineTarget3dEditor::RicPolylineTarget3dEditor() +{ + +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RicPolylineTarget3dEditor::~RicPolylineTarget3dEditor() +{ + RiuViewer* ownerRiuViewer = dynamic_cast(ownerViewer()); + + if (m_cvfModel.notNull() && ownerRiuViewer) + { + + // Could result in some circularities .... + ownerRiuViewer->removeStaticModel(m_cvfModel.p()); + } + + RimPolylineTarget* oldTarget = dynamic_cast(this->pdmObject()); + if (oldTarget) + { + oldTarget->targetPointUiCapability()->removeFieldEditor(this); + } + + delete m_manipulator; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicPolylineTarget3dEditor::configureAndUpdateUi(const QString& uiConfigName) +{ + RimPolylineTarget* target = dynamic_cast(this->pdmObject()); + RiuViewer* ownerRiuViewer = dynamic_cast(ownerViewer()); + + if ( !target || !target->isEnabled()) + { + m_cvfModel->removeAllParts(); + return; + } + + RimUserDefinedPolylinesAnnotation* polylineDef; + target->firstAncestorOrThisOfTypeAsserted(polylineDef); + + target->targetPointUiCapability()->addFieldEditor(this); + + if (m_manipulator.isNull()) + { + m_manipulator = new RicPointTangentManipulator(ownerRiuViewer); + QObject::connect(m_manipulator, + SIGNAL( notifyUpdate(const cvf::Vec3d& , const cvf::Vec3d& ) ), + this, + SLOT( slotUpdated(const cvf::Vec3d& , const cvf::Vec3d& ) ) ); + QObject::connect(m_manipulator, + SIGNAL( notifySelected() ), + this, + SLOT( slotSelectedIn3D() ) ); + QObject::connect(m_manipulator, + SIGNAL( notifyDragFinished() ), + this, + SLOT( slotDragFinished() ) ); + m_cvfModel = new cvf::ModelBasicList; + ownerRiuViewer->addStaticModelOnce(m_cvfModel.p()); + } + + cvf::ref dispXf; + double handleSize = 1.0; + { + dispXf = ownerRiuViewer->ownerReservoirView()->displayCoordTransform(); + Rim3dView* view = dynamic_cast(ownerRiuViewer->ownerReservoirView()); + handleSize = 0.7 * view->ownerCase()->characteristicCellSize(); + } + + m_manipulator->setOrigin(dispXf->transformToDisplayCoord( target->targetPointXYZ())); + //m_manipulator->setTangent(target->tangent()); + m_manipulator->setHandleSize(handleSize); + m_cvfModel->removeAllParts(); + m_manipulator->appendPartsToModel(m_cvfModel.p()); + + m_cvfModel->updateBoundingBoxesRecursive(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicPolylineTarget3dEditor::cleanupBeforeSettingPdmObject() +{ + RimPolylineTarget* oldTarget = dynamic_cast(this->pdmObject()); + if (oldTarget) + { + oldTarget->targetPointUiCapability()->removeFieldEditor(this); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicPolylineTarget3dEditor::slotUpdated(const cvf::Vec3d& origin, const cvf::Vec3d& tangent) +{ + RimPolylineTarget* target = dynamic_cast(this->pdmObject()); + + if ( !target) + { + return; + } + + cvf::ref dispXf; + { + RiuViewer* viewer = dynamic_cast(ownerViewer()); + dispXf = viewer->ownerReservoirView()->displayCoordTransform(); + } + + RimUserDefinedPolylinesAnnotation* polylineDef; + target->firstAncestorOrThisOfTypeAsserted(polylineDef); + + cvf::Vec3d domainOrigin = dispXf->transformToDomainCoord( origin); + domainOrigin.z() = -domainOrigin.z(); + QVariant originVariant = caf::PdmValueFieldSpecialization < cvf::Vec3d >::convert(domainOrigin); + + target->enableFullUpdate(false); + caf::PdmUiCommandSystemProxy::instance()->setUiValueToField(target->targetPointUiCapability(), originVariant); + target->enableFullUpdate(true); +} + +void RicPolylineTarget3dEditor::slotSelectedIn3D() +{ + RimPolylineTarget* target = dynamic_cast(this->pdmObject()); + if ( !target) + { + return; + } + + caf::SelectionManager::instance()->setSelectedItemAtLevel(target, caf::SelectionManager::FIRST_LEVEL); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicPolylineTarget3dEditor::slotDragFinished() +{ + RimPolylineTarget* target = dynamic_cast(this->pdmObject()); + if ( !target) + { + return; + } + + RimAnnotationCollectionBase* annColl; + target->firstAncestorOrThisOfTypeAsserted(annColl); + annColl->scheduleRedrawOfRelevantViews(); +} + + diff --git a/ApplicationCode/Commands/WellPathCommands/PointTangentManipulator/RicPolylineTarget3dEditor.h b/ApplicationCode/Commands/WellPathCommands/PointTangentManipulator/RicPolylineTarget3dEditor.h new file mode 100644 index 0000000000..e32c7d6a72 --- /dev/null +++ b/ApplicationCode/Commands/WellPathCommands/PointTangentManipulator/RicPolylineTarget3dEditor.h @@ -0,0 +1,57 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2018- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "cafPdmUi3dObjectEditorHandle.h" + +class RicPointTangentManipulator; + +#include "cvfBase.h" +#include "cvfObject.h" +#include "cvfVector3.h" + +namespace cvf { +class ModelBasicList; +} + +class QString; +#include + +class RicPolylineTarget3dEditor : public caf::PdmUi3dObjectEditorHandle +{ + CAF_PDM_UI_3D_OBJECT_EDITOR_HEADER_INIT; + Q_OBJECT +public: + RicPolylineTarget3dEditor(); + ~RicPolylineTarget3dEditor() override; + +protected: + void configureAndUpdateUi(const QString& uiConfigName) override; + void cleanupBeforeSettingPdmObject() override; + +private slots: + void slotUpdated(const cvf::Vec3d& origin, const cvf::Vec3d& tangent); + void slotSelectedIn3D(); + void slotDragFinished(); +private: + QPointer m_manipulator; + cvf::ref m_cvfModel; +}; + + diff --git a/ApplicationCode/Commands/WellPathCommands/PointTangentManipulator/RicWellPathGeometry3dEditor.cpp b/ApplicationCode/Commands/WellPathCommands/PointTangentManipulator/RicWellPathGeometry3dEditor.cpp new file mode 100644 index 0000000000..df09721c38 --- /dev/null +++ b/ApplicationCode/Commands/WellPathCommands/PointTangentManipulator/RicWellPathGeometry3dEditor.cpp @@ -0,0 +1,95 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2018- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "RicWellPathGeometry3dEditor.h" + +#include "RicWellPathGeometry3dEditor.h" +#include "RicWellTarget3dEditor.h" + +#include "RimWellPathTarget.h" +#include "RimWellPathGeometryDef.h" + +#include "cafPickEventHandler.h" + +CAF_PDM_UI_3D_OBJECT_EDITOR_SOURCE_INIT(RicWellPathGeometry3dEditor); + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RicWellPathGeometry3dEditor::RicWellPathGeometry3dEditor() +{ + +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RicWellPathGeometry3dEditor::~RicWellPathGeometry3dEditor() +{ + for (auto targetEditor: m_targetEditors) + { + delete targetEditor; + } + if (m_attribute.pickEventHandler) + { + m_attribute.pickEventHandler->unregisterAsPickEventHandler(); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicWellPathGeometry3dEditor::configureAndUpdateUi(const QString& uiConfigName) +{ + RimWellPathGeometryDef* geomDef = dynamic_cast(this->pdmObject()); + + for (auto targetEditor: m_targetEditors) + { + delete targetEditor; + } + m_targetEditors.clear(); + + if (!geomDef) return; + + geomDef->objectEditorAttribute("", &m_attribute); + + std::vector targets = geomDef->activeWellTargets(); + + for (auto target: targets) + { + auto targetEditor = new RicWellTarget3dEditor; + targetEditor->setViewer(ownerViewer()); + targetEditor->setPdmObject(target); + m_targetEditors.push_back(targetEditor); + targetEditor->updateUi(); + } + + if (m_attribute.pickEventHandler) + { + if (m_attribute.enablePicking) + { + m_attribute.pickEventHandler->registerAsPickEventHandler(); + } + else + { + m_attribute.pickEventHandler->unregisterAsPickEventHandler(); + } + } +} + + diff --git a/ApplicationCode/Commands/WellPathCommands/PointTangentManipulator/RicWellPathGeometry3dEditor.h b/ApplicationCode/Commands/WellPathCommands/PointTangentManipulator/RicWellPathGeometry3dEditor.h new file mode 100644 index 0000000000..a29bd8808e --- /dev/null +++ b/ApplicationCode/Commands/WellPathCommands/PointTangentManipulator/RicWellPathGeometry3dEditor.h @@ -0,0 +1,56 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2018- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once +#include "cafPdmUi3dObjectEditorHandle.h" +#include "cafPdmUiFieldEditorHandle.h" +#include + +namespace caf +{ +class PickEventHandler; +} + +class RicWellTarget3dEditor; + + +class RicWellPathGeometry3dEditorAttribute : public caf::PdmUiEditorAttribute +{ +public: + RicWellPathGeometry3dEditorAttribute() : enablePicking(false) {} + bool enablePicking; + std::shared_ptr pickEventHandler; +}; + +class RicWellPathGeometry3dEditor : public caf::PdmUi3dObjectEditorHandle +{ + CAF_PDM_UI_3D_OBJECT_EDITOR_HEADER_INIT; + Q_OBJECT +public: + RicWellPathGeometry3dEditor(); + ~RicWellPathGeometry3dEditor() override; + +protected: + void configureAndUpdateUi(const QString& uiConfigName) override; + +private: + std::vector m_targetEditors; + RicWellPathGeometry3dEditorAttribute m_attribute; +}; + + diff --git a/ApplicationCode/Commands/WellPathCommands/PointTangentManipulator/RicWellTarget3dEditor.cpp b/ApplicationCode/Commands/WellPathCommands/PointTangentManipulator/RicWellTarget3dEditor.cpp new file mode 100644 index 0000000000..8fad3fe9ac --- /dev/null +++ b/ApplicationCode/Commands/WellPathCommands/PointTangentManipulator/RicWellTarget3dEditor.cpp @@ -0,0 +1,204 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2018- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "RicWellTarget3dEditor.h" + +#include "RicPointTangentManipulator.h" + +#include "RimWellPathTarget.h" +#include "Rim3dView.h" +#include "RimCase.h" +#include "RimModeledWellPath.h" +#include "RimWellPathGeometryDef.h" + +#include "RiuViewer.h" + +#include "cafDisplayCoordTransform.h" +#include "cafPdmUiCommandSystemProxy.h" +#include "cafSelectionManager.h" + +#include "cvfPart.h" +#include "cvfModelBasicList.h" + +CAF_PDM_UI_3D_OBJECT_EDITOR_SOURCE_INIT(RicWellTarget3dEditor); + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RicWellTarget3dEditor::RicWellTarget3dEditor() +{ + +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RicWellTarget3dEditor::~RicWellTarget3dEditor() +{ + RiuViewer* ownerRiuViewer = dynamic_cast(ownerViewer()); + + if (m_cvfModel.notNull() && ownerRiuViewer) + { + + // Could result in some circularities .... + ownerRiuViewer->removeStaticModel(m_cvfModel.p()); + } + + RimWellPathTarget* oldTarget = dynamic_cast(this->pdmObject()); + if (oldTarget) + { + oldTarget->m_targetType.uiCapability()->removeFieldEditor(this); + oldTarget->m_targetPoint.uiCapability()->removeFieldEditor(this); + oldTarget->m_azimuth.uiCapability()->removeFieldEditor(this); + oldTarget->m_inclination.uiCapability()->removeFieldEditor(this); + } + + delete m_manipulator; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicWellTarget3dEditor::configureAndUpdateUi(const QString& uiConfigName) +{ + RimWellPathTarget* target = dynamic_cast(this->pdmObject()); + RiuViewer* ownerRiuViewer = dynamic_cast(ownerViewer()); + + if ( !target || !target->isEnabled()) + { + m_cvfModel->removeAllParts(); + return; + } + + RimWellPathGeometryDef* geomDef; + target->firstAncestorOrThisOfTypeAsserted(geomDef); + + target->m_targetType.uiCapability()->addFieldEditor(this); + target->m_targetPoint.uiCapability()->addFieldEditor(this); + target->m_azimuth.uiCapability()->addFieldEditor(this); + target->m_inclination.uiCapability()->addFieldEditor(this); + + if (m_manipulator.isNull()) + { + m_manipulator = new RicPointTangentManipulator(ownerRiuViewer); + QObject::connect(m_manipulator, + SIGNAL( notifyUpdate(const cvf::Vec3d& , const cvf::Vec3d& ) ), + this, + SLOT( slotUpdated(const cvf::Vec3d& , const cvf::Vec3d& ) ) ); + QObject::connect(m_manipulator, + SIGNAL( notifySelected() ), + this, + SLOT( slotSelectedIn3D() ) ); + QObject::connect(m_manipulator, + SIGNAL( notifyDragFinished() ), + this, + SLOT( slotDragFinished() ) ); + m_cvfModel = new cvf::ModelBasicList; + ownerRiuViewer->addStaticModelOnce(m_cvfModel.p()); + } + + cvf::ref dispXf; + double handleSize = 1.0; + { + dispXf = ownerRiuViewer->ownerReservoirView()->displayCoordTransform(); + Rim3dView* view = dynamic_cast(ownerRiuViewer->ownerReservoirView()); + handleSize = 0.7 * view->ownerCase()->characteristicCellSize(); + } + + m_manipulator->setOrigin(dispXf->transformToDisplayCoord( target->targetPointXYZ() + geomDef->referencePointXyz())); + m_manipulator->setTangent(target->tangent()); + m_manipulator->setHandleSize(handleSize); + m_cvfModel->removeAllParts(); + m_manipulator->appendPartsToModel(m_cvfModel.p()); + + m_cvfModel->updateBoundingBoxesRecursive(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicWellTarget3dEditor::cleanupBeforeSettingPdmObject() +{ + RimWellPathTarget* oldTarget = dynamic_cast(this->pdmObject()); + if (oldTarget) + { + oldTarget->m_targetType.uiCapability()->removeFieldEditor(this); + oldTarget->m_targetPoint.uiCapability()->removeFieldEditor(this); + oldTarget->m_azimuth.uiCapability()->removeFieldEditor(this); + oldTarget->m_inclination.uiCapability()->removeFieldEditor(this); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicWellTarget3dEditor::slotUpdated(const cvf::Vec3d& origin, const cvf::Vec3d& tangent) +{ + RimWellPathTarget* target = dynamic_cast(this->pdmObject()); + + if ( !target) + { + return; + } + + cvf::ref dispXf; + { + RiuViewer* viewer = dynamic_cast(ownerViewer()); + dispXf = viewer->ownerReservoirView()->displayCoordTransform(); + } + + RimWellPathGeometryDef* geomDef; + target->firstAncestorOrThisOfTypeAsserted(geomDef); + + cvf::Vec3d domainOrigin = dispXf->transformToDomainCoord( origin) - geomDef->referencePointXyz(); + domainOrigin.z() = -domainOrigin.z(); + QVariant originVariant = caf::PdmValueFieldSpecialization < cvf::Vec3d >::convert(domainOrigin); + + target->enableFullUpdate(false); + caf::PdmUiCommandSystemProxy::instance()->setUiValueToField(target->m_targetPoint.uiCapability(), originVariant); + target->enableFullUpdate(true); +} + +void RicWellTarget3dEditor::slotSelectedIn3D() +{ + RimWellPathTarget* target = dynamic_cast(this->pdmObject()); + if ( !target) + { + return; + } + + caf::SelectionManager::instance()->setSelectedItemAtLevel(target, caf::SelectionManager::FIRST_LEVEL); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicWellTarget3dEditor::slotDragFinished() +{ + RimWellPathTarget* target = dynamic_cast(this->pdmObject()); + if ( !target) + { + return; + } + + RimModeledWellPath* wellpath; + target->firstAncestorOrThisOfTypeAsserted(wellpath); + wellpath->scheduleUpdateOfDependentVisualization(); +} + + diff --git a/ApplicationCode/Commands/WellPathCommands/PointTangentManipulator/RicWellTarget3dEditor.h b/ApplicationCode/Commands/WellPathCommands/PointTangentManipulator/RicWellTarget3dEditor.h new file mode 100644 index 0000000000..9a7e567a4f --- /dev/null +++ b/ApplicationCode/Commands/WellPathCommands/PointTangentManipulator/RicWellTarget3dEditor.h @@ -0,0 +1,57 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2018- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "cafPdmUi3dObjectEditorHandle.h" + +class RicPointTangentManipulator; + +#include "cvfBase.h" +#include "cvfObject.h" +#include "cvfVector3.h" + +namespace cvf { +class ModelBasicList; +} + +class QString; +#include + +class RicWellTarget3dEditor : public caf::PdmUi3dObjectEditorHandle +{ + CAF_PDM_UI_3D_OBJECT_EDITOR_HEADER_INIT; + Q_OBJECT +public: + RicWellTarget3dEditor(); + ~RicWellTarget3dEditor() override; + +protected: + void configureAndUpdateUi(const QString& uiConfigName) override; + void cleanupBeforeSettingPdmObject() override; + +private slots: + void slotUpdated(const cvf::Vec3d& origin, const cvf::Vec3d& tangent); + void slotSelectedIn3D(); + void slotDragFinished(); +private: + QPointer m_manipulator; + cvf::ref m_cvfModel; +}; + + diff --git a/ApplicationCode/Commands/WellPathCommands/RicCreateWellTargetsPickEventHandler.cpp b/ApplicationCode/Commands/WellPathCommands/RicCreateWellTargetsPickEventHandler.cpp index f901d5f825..6fe26379df 100644 --- a/ApplicationCode/Commands/WellPathCommands/RicCreateWellTargetsPickEventHandler.cpp +++ b/ApplicationCode/Commands/WellPathCommands/RicCreateWellTargetsPickEventHandler.cpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018- Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -18,11 +18,19 @@ #include "RicCreateWellTargetsPickEventHandler.h" +#include "RiaApplication.h" #include "RiaOffshoreSphericalCoords.h" +#include "RigFemPart.h" +#include "RigFemPartCollection.h" +#include "RigFemPartGrid.h" +#include "RigHexIntersectionTools.h" +#include "RigMainGrid.h" #include "RigWellPath.h" #include "Rim3dView.h" +#include "RimGeoMechView.h" +#include "RimEclipseView.h" #include "RimModeledWellPath.h" #include "RimWellPath.h" #include "RimWellPathGeometryDef.h" @@ -30,11 +38,18 @@ #include "RiuViewerCommands.h" +#include "RivFemPartGeometryGenerator.h" +#include "RivFemPickSourceInfo.h" +#include "RivSourceInfo.h" #include "RivWellPathSourceInfo.h" #include "cafDisplayCoordTransform.h" #include "cafSelectionManager.h" +#include "cvfStructGridGeometryGenerator.h" + +#include + #include //-------------------------------------------------------------------------------------------------- @@ -53,23 +68,25 @@ RicCreateWellTargetsPickEventHandler::~RicCreateWellTargetsPickEventHandler() {} //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RicCreateWellTargetsPickEventHandler::notifyUnregistered() +void RicCreateWellTargetsPickEventHandler::registerAsPickEventHandler() { - m_geometryToAddTargetsTo->enableTargetPointPicking(false); + RiaApplication::instance()->setOverrideCursor(Qt::CrossCursor); + Ric3dViewPickEventHandler::registerAsPickEventHandler(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -bool RicCreateWellTargetsPickEventHandler::handlePickEvent(const Ric3DPickEvent& eventObject) +void RicCreateWellTargetsPickEventHandler::notifyUnregistered() { - if (!caf::SelectionManager::instance()->isSelected(m_geometryToAddTargetsTo.p(), 0)) - { - m_geometryToAddTargetsTo->enableTargetPointPicking(false); - - return false; - } + RiaApplication::instance()->restoreOverrideCursor(); +} +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RicCreateWellTargetsPickEventHandler::handle3dPickEvent(const Ric3dPickEvent& eventObject) +{ if (m_geometryToAddTargetsTo) { Rim3dView* rimView = eventObject.m_view; @@ -94,6 +111,22 @@ bool RicCreateWellTargetsPickEventHandler::handlePickEvent(const Ric3DPickEvent& doSetAzimuthAndInclination = calculateAzimuthAndInclinationAtMd( md, wellPathSourceInfo->wellPath()->wellPathGeometry(), &azimuth, &inclination); } + else if (isGridSourceObject(firstPickItem.sourceInfo())) + { + targetPointInDomain = intersectionPointInDomain; + doSetAzimuthAndInclination = false; + + cvf::Vec3d domainRayOrigin = + rimView->displayCoordTransform()->transformToDomainCoord(firstPickItem.globalRayOrigin()); + cvf::Vec3d domainRayEnd = targetPointInDomain + (targetPointInDomain - domainRayOrigin); + + cvf::Vec3d hexElementIntersection = findHexElementIntersection(rimView, firstPickItem, domainRayOrigin, domainRayEnd); + CVF_TIGHT_ASSERT(!hexElementIntersection.isUndefined()); + if (!hexElementIntersection.isUndefined()) + { + targetPointInDomain = hexElementIntersection; + } + } else { targetPointInDomain = intersectionPointInDomain; @@ -196,3 +229,85 @@ bool RicCreateWellTargetsPickEventHandler::calculateAzimuthAndInclinationAtMd(do *inclination = 0.0; return false; } + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RicCreateWellTargetsPickEventHandler::isGridSourceObject(const cvf::Object* object) +{ + auto sourceInfo = dynamic_cast(object); + auto femSourceInfo = dynamic_cast(object); + return sourceInfo || femSourceInfo; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +cvf::Vec3d RicCreateWellTargetsPickEventHandler::findHexElementIntersection(Rim3dView* view, const RiuPickItemInfo& pickItem, const cvf::Vec3d& domainRayOrigin, const cvf::Vec3d& domainRayEnd) +{ + auto sourceInfo = dynamic_cast(pickItem.sourceInfo()); + auto femSourceInfo = dynamic_cast(pickItem.sourceInfo()); + + size_t cellIndex = cvf::UNDEFINED_SIZE_T; + std::array cornerVertices; + if (sourceInfo) + { + size_t gridIndex = sourceInfo->gridIndex(); + if (sourceInfo->hasCellFaceMapping()) + { + cellIndex = sourceInfo->m_cellFaceFromTriangleMapper->cellIndex(pickItem.faceIdx()); + + RimEclipseView* eclipseView = dynamic_cast(view); + if (eclipseView && eclipseView->mainGrid()) + { + RigGridBase* hitGrid = eclipseView->mainGrid()->gridByIndex(gridIndex); + hitGrid->cellCornerVertices(cellIndex, cornerVertices.data()); + } + } + } + else if (femSourceInfo) + { + size_t femPartIndex = femSourceInfo->femPartIndex(); + if (femSourceInfo->triangleToElmMapper()) + { + size_t elementIndex = femSourceInfo->triangleToElmMapper()->elementIndex(pickItem.faceIdx()); + + RimGeoMechView* geoMechView = dynamic_cast(view); + if (geoMechView && geoMechView->femParts()) + { + RigFemPart* femPart = geoMechView->femParts()->part(femPartIndex); + RigElementType elType = femPart->elementType(elementIndex); + + if (elType == HEX8 || elType == HEX8P) + { + cellIndex = elementIndex; + const RigFemPartGrid* femGrid = femPart->getOrCreateStructGrid(); + femGrid->cellCornerVertices(cellIndex, cornerVertices.data()); + } + } + } + } + + if (cellIndex) + { + std::vector intersectionInfo; + RigHexIntersectionTools::lineHexCellIntersection(domainRayOrigin, domainRayEnd, cornerVertices.data(), cellIndex, &intersectionInfo); + if (!intersectionInfo.empty()) + { + // Sort intersection on distance to ray origin + CVF_ASSERT(intersectionInfo.size() > 1); + std::sort(intersectionInfo.begin(), intersectionInfo.end(), + [&domainRayOrigin](const HexIntersectionInfo& lhs, const HexIntersectionInfo& rhs) + { + return (lhs.m_intersectionPoint - domainRayOrigin).lengthSquared() < (rhs.m_intersectionPoint - domainRayOrigin).lengthSquared(); + } + ); + const double eps = 1.0e-2; + cvf::Vec3d intersectionRay = intersectionInfo.back().m_intersectionPoint - intersectionInfo.front().m_intersectionPoint; + cvf::Vec3d newPoint = intersectionInfo.front().m_intersectionPoint + intersectionRay * eps; + CVF_ASSERT(RigHexIntersectionTools::isPointInCell(newPoint, cornerVertices.data())); + return newPoint; + } + } + return cvf::Vec3d::UNDEFINED; +} diff --git a/ApplicationCode/Commands/WellPathCommands/RicCreateWellTargetsPickEventHandler.h b/ApplicationCode/Commands/WellPathCommands/RicCreateWellTargetsPickEventHandler.h index 3e3ebf60de..ff098da52b 100644 --- a/ApplicationCode/Commands/WellPathCommands/RicCreateWellTargetsPickEventHandler.h +++ b/ApplicationCode/Commands/WellPathCommands/RicCreateWellTargetsPickEventHandler.h @@ -18,7 +18,7 @@ #pragma once -#include "RicPickEventHandler.h" +#include "Ric3dViewPickEventHandler.h" #include "cafPdmPointer.h" @@ -28,14 +28,16 @@ class RigWellPath; //================================================================================================== /// //================================================================================================== -class RicCreateWellTargetsPickEventHandler : public RicPickEventHandler +class RicCreateWellTargetsPickEventHandler : public Ric3dViewPickEventHandler { public: RicCreateWellTargetsPickEventHandler(RimWellPathGeometryDef* wellGeometryDef); ~RicCreateWellTargetsPickEventHandler(); + void registerAsPickEventHandler() override; + protected: - bool handlePickEvent(const Ric3DPickEvent& eventObject) override; + bool handle3dPickEvent(const Ric3dPickEvent& eventObject) override; void notifyUnregistered() override; private: @@ -44,6 +46,8 @@ class RicCreateWellTargetsPickEventHandler : public RicPickEventHandler double* azimuth, double* inclination) const; + static bool isGridSourceObject(const cvf::Object* object); + static cvf::Vec3d findHexElementIntersection(Rim3dView* view, const RiuPickItemInfo& pickItem, const cvf::Vec3d& domainRayOrigin, const cvf::Vec3d& domainRayEnd); private: caf::PdmPointer m_geometryToAddTargetsTo; }; diff --git a/ApplicationCode/Commands/WellPathCommands/RicDeletePolylineTargetFeature.cpp b/ApplicationCode/Commands/WellPathCommands/RicDeletePolylineTargetFeature.cpp new file mode 100644 index 0000000000..02a606f789 --- /dev/null +++ b/ApplicationCode/Commands/WellPathCommands/RicDeletePolylineTargetFeature.cpp @@ -0,0 +1,77 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2018- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// +#include "RicDeletePolylineTargetFeature.h" + +CAF_CMD_SOURCE_INIT(RicDeletePolylineTargetFeature, "RicDeletePolylineTargetFeature"); + +#include "RimUserDefinedPolylinesAnnotation.h" +#include "RimPolylineTarget.h" +#include "cafSelectionManager.h" +#include + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RicDeletePolylineTargetFeature::isCommandEnabled() +{ + std::vector objects; + caf::SelectionManager::instance()->objectsByType(&objects, caf::SelectionManager::FIRST_LEVEL); + + if ( !objects.empty() ) + { + return true; + } + + return false; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicDeletePolylineTargetFeature::onActionTriggered(bool isChecked) +{ + std::vector targets; + caf::SelectionManager::instance()->objectsByType(&targets, caf::SelectionManager::FIRST_LEVEL); + + if (!targets.empty()) + { + + RimUserDefinedPolylinesAnnotation* polylineDef = nullptr; + targets[0]->firstAncestorOrThisOfTypeAsserted(polylineDef); + + for ( auto target: targets ) + { + polylineDef->deleteTarget(target); + } + + polylineDef->updateConnectedEditors(); + polylineDef->updateVisualization(); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicDeletePolylineTargetFeature::setupActionLook(QAction* actionToSetup) +{ + actionToSetup->setText("Delete Target"); + actionToSetup->setIcon(QIcon(":/Erase.png")); + applyShortcutWithHintToAction(actionToSetup, QKeySequence::Delete); +} + + diff --git a/ApplicationCode/Commands/WellPathCommands/RicDeletePolylineTargetFeature.h b/ApplicationCode/Commands/WellPathCommands/RicDeletePolylineTargetFeature.h new file mode 100644 index 0000000000..be88d2ea96 --- /dev/null +++ b/ApplicationCode/Commands/WellPathCommands/RicDeletePolylineTargetFeature.h @@ -0,0 +1,35 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2018- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "cafCmdFeature.h" + +//================================================================================================== +/// +//================================================================================================== +class RicDeletePolylineTargetFeature : public caf::CmdFeature +{ + CAF_CMD_HEADER_INIT; +protected: + + // Overrides + bool isCommandEnabled() override; + void onActionTriggered( bool isChecked ) override; + void setupActionLook( QAction* actionToSetup ) override; +}; diff --git a/ApplicationCode/Commands/WellPathCommands/RicDeleteWellPathAttributeFeature.cpp b/ApplicationCode/Commands/WellPathCommands/RicDeleteWellPathAttributeFeature.cpp index e702e53271..60d6676a84 100644 --- a/ApplicationCode/Commands/WellPathCommands/RicDeleteWellPathAttributeFeature.cpp +++ b/ApplicationCode/Commands/WellPathCommands/RicDeleteWellPathAttributeFeature.cpp @@ -109,10 +109,12 @@ void RicDeleteWellPathAttributeFeature::setupActionLook(QAction* actionToSetup) { actionToSetup->setText("Delete Attribute"); actionToSetup->setIcon(QIcon(":/Erase.png")); + applyShortcutWithHintToAction(actionToSetup, QKeySequence::Delete); } else if (caf::SelectionManager::instance()->selectedItemOfType()) { actionToSetup->setText("Delete Casing Design"); actionToSetup->setIcon(QIcon(":/Erase.png")); + applyShortcutWithHintToAction(actionToSetup, QKeySequence::Delete); } } diff --git a/ApplicationCode/Commands/WellPathCommands/RicIntersectionPickEventHandler.cpp b/ApplicationCode/Commands/WellPathCommands/RicIntersectionPickEventHandler.cpp index cb8f2dfe05..7d889ca3ac 100644 --- a/ApplicationCode/Commands/WellPathCommands/RicIntersectionPickEventHandler.cpp +++ b/ApplicationCode/Commands/WellPathCommands/RicIntersectionPickEventHandler.cpp @@ -1,24 +1,26 @@ ///////////////////////////////////////////////////////////////////////////////// // // Copyright (C) 2017- Statoil ASA -// +// // ResInsight 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 3 of the License, or // (at your option) any later version. -// +// // ResInsight 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 at +// +// See the GNU General Public License at // for more details. // ///////////////////////////////////////////////////////////////////////////////// #include "RicIntersectionPickEventHandler.h" +#include "RiaApplication.h" + +#include "RimGridView.h" #include "RimIntersection.h" -#include "Rim3dView.h" #include "cafDisplayCoordTransform.h" #include "cafSelectionManager.h" @@ -26,7 +28,7 @@ #include //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- RicIntersectionPickEventHandler* RicIntersectionPickEventHandler::instance() { @@ -35,9 +37,9 @@ RicIntersectionPickEventHandler* RicIntersectionPickEventHandler::instance() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- -bool RicIntersectionPickEventHandler::handlePickEvent(const Ric3DPickEvent& eventObject) +bool RicIntersectionPickEventHandler::handle3dPickEvent(const Ric3dPickEvent& eventObject) { std::vector selection; caf::SelectionManager::instance()->objectsByType(&selection); @@ -47,11 +49,15 @@ bool RicIntersectionPickEventHandler::handlePickEvent(const Ric3DPickEvent& even { RimIntersection* intersection = selection[0]; - Rim3dView* rimView = nullptr; - intersection->firstAncestorOrThisOfType(rimView); - CVF_ASSERT(rimView); + RimGridView* gridView = nullptr; + intersection->firstAncestorOrThisOfTypeAsserted(gridView); - cvf::ref transForm = rimView->displayCoordTransform(); + if (RiaApplication::instance()->activeGridView() != gridView) + { + return false; + } + + cvf::ref transForm = gridView->displayCoordTransform(); cvf::Vec3d domainCoord = transForm->transformToDomainCoord(eventObject.m_pickItemInfos.front().globalPickedPoint()); if (intersection->inputPolyLineFromViewerEnabled()) @@ -80,4 +86,3 @@ bool RicIntersectionPickEventHandler::handlePickEvent(const Ric3DPickEvent& even return false; } - diff --git a/ApplicationCode/Commands/WellPathCommands/RicIntersectionPickEventHandler.h b/ApplicationCode/Commands/WellPathCommands/RicIntersectionPickEventHandler.h index 1881ebafa8..3609c260fd 100644 --- a/ApplicationCode/Commands/WellPathCommands/RicIntersectionPickEventHandler.h +++ b/ApplicationCode/Commands/WellPathCommands/RicIntersectionPickEventHandler.h @@ -29,6 +29,6 @@ class RicIntersectionPickEventHandler : public RicDefaultPickEventHandler static RicIntersectionPickEventHandler* instance(); protected: - bool handlePickEvent(const Ric3DPickEvent& eventObject) override; + bool handle3dPickEvent(const Ric3dPickEvent& eventObject) override; }; diff --git a/ApplicationCode/Commands/WellPathCommands/RicNewPolylineTargetFeature.cpp b/ApplicationCode/Commands/WellPathCommands/RicNewPolylineTargetFeature.cpp new file mode 100644 index 0000000000..e3b8b4fb96 --- /dev/null +++ b/ApplicationCode/Commands/WellPathCommands/RicNewPolylineTargetFeature.cpp @@ -0,0 +1,174 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2018- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// +#include "RicNewPolylineTargetFeature.h" + +CAF_CMD_SOURCE_INIT(RicNewPolylineTargetFeature, "RicNewPolylineTargetFeature"); + +#include "RiaApplication.h" + +#include "RimProject.h" +#include "RimGridView.h" +#include "RimCase.h" +#include "RimUserDefinedPolylinesAnnotation.h" +#include "RimPolylineTarget.h" +#include "cafSelectionManager.h" +#include + +#include "cvfBoundingBox.h" + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RicNewPolylineTargetFeature::isCommandEnabled() +{ + { + std::vector objects; + caf::SelectionManager::instance()->objectsByType(&objects); + + if ( !objects.empty() ) + { + return true; + } + } + { + std::vector objects; + caf::SelectionManager::instance()->objectsByType(&objects, caf::SelectionManager::FIRST_LEVEL); + + if ( !objects.empty() ) + { + return true; + } + } + + return false; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicNewPolylineTargetFeature::onActionTriggered(bool isChecked) +{ + std::vector selectedTargets; + caf::SelectionManager::instance()->objectsByType(&selectedTargets, caf::SelectionManager::FIRST_LEVEL); + if (!selectedTargets.empty()) + { + auto firstTarget = selectedTargets.front(); + RimUserDefinedPolylinesAnnotation* polylineDef = nullptr; + firstTarget->firstAncestorOrThisOfTypeAsserted(polylineDef); + + auto afterBeforePair = polylineDef->findActiveTargetsAroundInsertionPoint(firstTarget); + + cvf::Vec3d newPos = cvf::Vec3d::ZERO; + + if (!afterBeforePair.first && afterBeforePair.second) + { + newPos = afterBeforePair.second->targetPointXYZ(); + + // Small displacement to separate the targets + newPos.x() -= 50; + newPos.y() -= 50; + } + else if (afterBeforePair.first && afterBeforePair.second) + { + newPos = 0.5*(afterBeforePair.first->targetPointXYZ() + afterBeforePair.second->targetPointXYZ()); + } + else if (afterBeforePair.first && !afterBeforePair.second) + { + std::vector activeTargets = polylineDef->activeTargets(); + size_t targetCount = activeTargets.size(); + if (targetCount > 1) + { + newPos = activeTargets[targetCount-1]->targetPointXYZ(); + cvf::Vec3d nextLastToLast = newPos - activeTargets[targetCount-2]->targetPointXYZ(); + newPos += 0.5*nextLastToLast; + } + else + { + newPos = afterBeforePair.first->targetPointXYZ() + cvf::Vec3d(0, 0, 200); + } + } + + auto* newTarget = new RimPolylineTarget; + newTarget->setAsPointTargetXYD({ newPos[0], newPos[1], -newPos[2] }); + + polylineDef->insertTarget(firstTarget, newTarget); + polylineDef->updateConnectedEditors(); + polylineDef->updateVisualization(); + + return; + } + + std::vector polylineDefs; + caf::SelectionManager::instance()->objectsByType(&polylineDefs); + if (!polylineDefs.empty()) + { + auto* polylineDef = polylineDefs[0]; + std::vector activeTargets = polylineDef->activeTargets(); + + size_t targetCount = activeTargets.size(); + + if ( targetCount == 0 ) + { + auto defaultPos = cvf::Vec3d::ZERO; + + // Set decent position + std::vector gridViews; + RiaApplication::instance()->project()->allVisibleGridViews(gridViews); + if (!gridViews.empty()) + { + auto minPos = gridViews.front()->ownerCase()->allCellsBoundingBox().min(); + defaultPos = minPos; + } + + polylineDef->appendTarget(defaultPos); + } + else + { + cvf::Vec3d newPos = cvf::Vec3d::ZERO; + + if ( targetCount > 1 ) + { + newPos = activeTargets[targetCount-1]->targetPointXYZ(); + cvf::Vec3d nextLastToLast = newPos - activeTargets[targetCount-2]->targetPointXYZ(); + newPos += 0.5*nextLastToLast; + } + else if ( targetCount > 0 ) + { + newPos = activeTargets[targetCount-1]->targetPointXYZ() + cvf::Vec3d(0, 0, 200); + } + + auto* newTarget = new RimPolylineTarget; + newTarget->setAsPointTargetXYD({ newPos[0], newPos[1], -newPos[2] }); + polylineDef->insertTarget(nullptr, newTarget); + } + + polylineDef->updateConnectedEditors(); + polylineDef->updateVisualization(); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicNewPolylineTargetFeature::setupActionLook(QAction* actionToSetup) +{ + actionToSetup->setText("New Target"); + actionToSetup->setIcon(QIcon(":/Well.png")); +} + + diff --git a/ApplicationCode/Commands/WellPathCommands/RicNewPolylineTargetFeature.h b/ApplicationCode/Commands/WellPathCommands/RicNewPolylineTargetFeature.h new file mode 100644 index 0000000000..a5bc531c24 --- /dev/null +++ b/ApplicationCode/Commands/WellPathCommands/RicNewPolylineTargetFeature.h @@ -0,0 +1,35 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2018- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "cafCmdFeature.h" + +//================================================================================================== +/// +//================================================================================================== +class RicNewPolylineTargetFeature : public caf::CmdFeature +{ + CAF_CMD_HEADER_INIT; +protected: + + // Overrides + bool isCommandEnabled() override; + void onActionTriggered( bool isChecked ) override; + void setupActionLook( QAction* actionToSetup ) override; +}; diff --git a/ApplicationCode/Commands/WellPathCommands/RicNewWellPathAttributeFeature.cpp b/ApplicationCode/Commands/WellPathCommands/RicNewWellPathAttributeFeature.cpp index 5613dfa1c3..5878793be6 100644 --- a/ApplicationCode/Commands/WellPathCommands/RicNewWellPathAttributeFeature.cpp +++ b/ApplicationCode/Commands/WellPathCommands/RicNewWellPathAttributeFeature.cpp @@ -60,12 +60,14 @@ void RicNewWellPathAttributeFeature::onActionTriggered(bool isChecked) { std::vector attributes; caf::SelectionManager::instance()->objectsByType(&attributes, caf::SelectionManager::FIRST_LEVEL); + + RimWellPathAttribute* attribute = nullptr; if (attributes.size() == 1u) { RimWellPathAttributeCollection* attributeCollection = nullptr; attributes[0]->firstAncestorOrThisOfTypeAsserted(attributeCollection); - RimWellPathAttribute* attribute = new RimWellPathAttribute; + attribute = new RimWellPathAttribute; RimWellPath* wellPath = nullptr; attributeCollection->firstAncestorOrThisOfTypeAsserted(wellPath); @@ -73,27 +75,34 @@ void RicNewWellPathAttributeFeature::onActionTriggered(bool isChecked) attributeCollection->insertAttribute(attributes[0], attribute); attributeCollection->updateAllRequiredEditors(); - return; } - - RimWellPath* wellPath = caf::SelectionManager::instance()->selectedItemAncestorOfType(); - if (wellPath) + else { - std::vector attributeCollections; - wellPath->descendantsIncludingThisOfType(attributeCollections); - if (!attributeCollections.empty()) + RimWellPath* wellPath = caf::SelectionManager::instance()->selectedItemAncestorOfType(); + if (wellPath) { - RimWellPathAttribute* attribute = new RimWellPathAttribute; - attribute->setDepthsFromWellPath(wellPath); - - attributeCollections[0]->insertAttribute(nullptr, attribute); - attributeCollections[0]->updateAllRequiredEditors(); - - wellPath->updateConnectedEditors(); - Riu3DMainWindowTools::selectAsCurrentItem(attributeCollections[0]); - + std::vector attributeCollections; + wellPath->descendantsIncludingThisOfType(attributeCollections); + if (!attributeCollections.empty()) + { + attribute = new RimWellPathAttribute; + attribute->setDepthsFromWellPath(wellPath); + + attributeCollections[0]->insertAttribute(nullptr, attribute); + attributeCollections[0]->updateAllRequiredEditors(); + + wellPath->updateConnectedEditors(); + Riu3DMainWindowTools::selectAsCurrentItem(attributeCollections[0]); + } } } + + if (attribute) + { + RimProject* project = nullptr; + attribute->firstAncestorOrThisOfTypeAsserted(project); + project->scheduleCreateDisplayModelAndRedrawAllViews(); + } } //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/Commands/WellPathCommands/RicPolylineTargetsPickEventHandler.cpp b/ApplicationCode/Commands/WellPathCommands/RicPolylineTargetsPickEventHandler.cpp new file mode 100644 index 0000000000..ad8b2011e4 --- /dev/null +++ b/ApplicationCode/Commands/WellPathCommands/RicPolylineTargetsPickEventHandler.cpp @@ -0,0 +1,95 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2018- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "RicPolylineTargetsPickEventHandler.h" + +#include "RiaApplication.h" +#include "RiaOffshoreSphericalCoords.h" + +#include "RigWellPath.h" + +#include "Rim3dView.h" +#include "RimModeledWellPath.h" +#include "RimPolylineTarget.h" +#include "RimUserDefinedPolylinesAnnotation.h" + +#include "RiuViewerCommands.h" +#include "RiuViewer.h" + +#include "RivPolylinesAnnotationSourceInfo.h" + +#include "cafDisplayCoordTransform.h" +#include "cafSelectionManager.h" + +#include + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RicPolylineTargetsPickEventHandler::RicPolylineTargetsPickEventHandler(RimUserDefinedPolylinesAnnotation* polylineDef) + : m_polylineDef(polylineDef) +{ +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RicPolylineTargetsPickEventHandler::~RicPolylineTargetsPickEventHandler() {} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicPolylineTargetsPickEventHandler::registerAsPickEventHandler() +{ + RiuViewer::setHoverCursor(Qt::CrossCursor); + Ric3dViewPickEventHandler::registerAsPickEventHandler(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicPolylineTargetsPickEventHandler::notifyUnregistered() +{ + RiuViewer::clearHoverCursor(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RicPolylineTargetsPickEventHandler::handle3dPickEvent(const Ric3dPickEvent& eventObject) +{ + if (m_polylineDef) + { + Rim3dView* rimView = eventObject.m_view; + + auto firstPickItem = eventObject.m_pickItemInfos.front(); + auto targetPointInDomain = rimView->displayCoordTransform()->transformToDomainCoord(firstPickItem.globalPickedPoint()); + + auto* newTarget = new RimPolylineTarget(); + newTarget->setAsPointTargetXYD(cvf::Vec3d(targetPointInDomain.x(), targetPointInDomain.y(), -targetPointInDomain.z())); + + m_polylineDef->insertTarget(nullptr, newTarget); + m_polylineDef->updateConnectedEditors(); + m_polylineDef->updateVisualization(); + + return true; + } + + return false; +} + diff --git a/ApplicationCode/Commands/WellPathCommands/RicPolylineTargetsPickEventHandler.h b/ApplicationCode/Commands/WellPathCommands/RicPolylineTargetsPickEventHandler.h new file mode 100644 index 0000000000..0579c027ff --- /dev/null +++ b/ApplicationCode/Commands/WellPathCommands/RicPolylineTargetsPickEventHandler.h @@ -0,0 +1,44 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2017- Statoil ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "Ric3dViewPickEventHandler.h" + +#include "cafPdmPointer.h" + +class RimUserDefinedPolylinesAnnotation; + +//================================================================================================== +/// +//================================================================================================== +class RicPolylineTargetsPickEventHandler : public Ric3dViewPickEventHandler +{ +public: + RicPolylineTargetsPickEventHandler(RimUserDefinedPolylinesAnnotation* polylineDef); + ~RicPolylineTargetsPickEventHandler(); + + void registerAsPickEventHandler() override; + +protected: + bool handle3dPickEvent(const Ric3dPickEvent& eventObject) override; + void notifyUnregistered() override; + +private: + caf::PdmPointer m_polylineDef; +}; diff --git a/ApplicationCode/Commands/WellPathCommands/RicWellPathDeleteFeature.cpp b/ApplicationCode/Commands/WellPathCommands/RicWellPathDeleteFeature.cpp index c44d12bf29..7fb5fb4f09 100644 --- a/ApplicationCode/Commands/WellPathCommands/RicWellPathDeleteFeature.cpp +++ b/ApplicationCode/Commands/WellPathCommands/RicWellPathDeleteFeature.cpp @@ -75,6 +75,16 @@ void RicWellPathDeleteFeature::onActionTriggered(bool isChecked) //-------------------------------------------------------------------------------------------------- void RicWellPathDeleteFeature::setupActionLook(QAction* actionToSetup) { - actionToSetup->setText("Delete Well Path(s)"); + std::vector objects; + caf::SelectionManager::instance()->objectsByType(&objects); + if (objects.size() > 1u) + { + actionToSetup->setText("Delete Well Paths"); + } + else + { + actionToSetup->setText("Delete Well Path"); + } actionToSetup->setIcon(QIcon(":/Erase.png")); + applyShortcutWithHintToAction(actionToSetup, QKeySequence::Delete); } diff --git a/ApplicationCode/Commands/WellPathCommands/RicWellPathPickEventHandler.cpp b/ApplicationCode/Commands/WellPathCommands/RicWellPathPickEventHandler.cpp index 3dd08505e5..a4b112405a 100644 --- a/ApplicationCode/Commands/WellPathCommands/RicWellPathPickEventHandler.cpp +++ b/ApplicationCode/Commands/WellPathCommands/RicWellPathPickEventHandler.cpp @@ -24,6 +24,9 @@ #include "Rim3dView.h" #include "RimPerforationInterval.h" #include "RimWellPath.h" +#include "RimWellPathAttribute.h" +#include "RimWellPathAttributeCollection.h" +#include "RimWellPathValve.h" #include "Rim2dIntersectionView.h" #include "RiuMainWindow.h" @@ -32,7 +35,7 @@ #include "RivWellPathSourceInfo.h" #include "cafDisplayCoordTransform.h" - +#include "cafSelectionManager.h" #include "cvfPart.h" #include "cvfVector3.h" #include "RivIntersectionPartMgr.h" @@ -50,7 +53,7 @@ RicWellPathPickEventHandler* RicWellPathPickEventHandler::instance() //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -bool RicWellPathPickEventHandler::handlePickEvent(const Ric3DPickEvent& eventObject) +bool RicWellPathPickEventHandler::handle3dPickEvent(const Ric3dPickEvent& eventObject) { if (eventObject.m_pickItemInfos.empty()) return false; @@ -95,6 +98,35 @@ bool RicWellPathPickEventHandler::handlePickEvent(const Ric3DPickEvent& eventObj } } } + else if (dynamic_cast(sourceInfo->object())) + { + objectToSelect = sourceInfo->object(); + RimWellPath* wellPath = nullptr; + objectToSelect->firstAncestorOrThisOfType(wellPath); + + RimWellPathValve* valve = static_cast(sourceInfo->object()); + + QString valveText = QString("Well Path: %1\nValve: %2\nTemplate: %3").arg(wellPath->name()).arg(valve->name()).arg(valve->valveTemplate()->name()); + + RiuMainWindow::instance()->setResultInfo(valveText); + RiuMainWindow::instance()->selectAsCurrentItem(objectToSelect); + } + else if (dynamic_cast(sourceInfo->object())) + { + RimWellPath* wellPath = nullptr; + + RimWellPathAttribute* attribute = static_cast(sourceInfo->object()); + RimWellPathAttributeCollection* collection = nullptr; + attribute->firstAncestorOrThisOfTypeAsserted(collection); + collection->firstAncestorOrThisOfTypeAsserted(wellPath); + + QString attrText = QString("Well Path: %1\nCasing Design Attribute: %2") + .arg(wellPath->name()) + .arg(attribute->componentLabel()); + + RiuMainWindow::instance()->setResultInfo(attrText); + RiuMainWindow::instance()->selectAsCurrentItem(collection); + } } if (dynamic_cast(firstPickedPart->sourceInfo())) diff --git a/ApplicationCode/Commands/WellPathCommands/RicWellPathPickEventHandler.h b/ApplicationCode/Commands/WellPathCommands/RicWellPathPickEventHandler.h index 905aaf355d..32e390434c 100644 --- a/ApplicationCode/Commands/WellPathCommands/RicWellPathPickEventHandler.h +++ b/ApplicationCode/Commands/WellPathCommands/RicWellPathPickEventHandler.h @@ -30,6 +30,6 @@ class RicWellPathPickEventHandler : public RicDefaultPickEventHandler public: static RicWellPathPickEventHandler* instance(); - bool handlePickEvent(const Ric3DPickEvent& eventObject) override; + bool handle3dPickEvent(const Ric3dPickEvent& eventObject) override; }; diff --git a/ApplicationCode/FileInterface/RifCaseRealizationParametersReader.cpp b/ApplicationCode/FileInterface/RifCaseRealizationParametersReader.cpp index e34193dc72..7f13fb81a6 100644 --- a/ApplicationCode/FileInterface/RifCaseRealizationParametersReader.cpp +++ b/ApplicationCode/FileInterface/RifCaseRealizationParametersReader.cpp @@ -159,7 +159,7 @@ void RifCaseRealizationParametersReader::parse() } else { - if (!RiaStdStringTools::isNumber(strValue.toStdString(), QLocale::c().decimalPoint().toAscii())) + if (!RiaStdStringTools::isNumber(strValue.toStdString(), QLocale::c().decimalPoint().toLatin1())) { throw FileParseException(QString("RifEnsembleParametersReader: Invalid number format in line %1").arg(lineNo)); } @@ -264,7 +264,7 @@ void RifCaseRealizationRunspecificationReader::parse() } else { - if (!RiaStdStringTools::isNumber(paramStrValue.toStdString(), QLocale::c().decimalPoint().toAscii())) + if (!RiaStdStringTools::isNumber(paramStrValue.toStdString(), QLocale::c().decimalPoint().toLatin1())) { throw FileParseException(QString("RifEnsembleParametersReader: Invalid number format in line %1").arg(xml->lineNumber())); } diff --git a/ApplicationCode/FileInterface/RifCsvUserDataParser.cpp b/ApplicationCode/FileInterface/RifCsvUserDataParser.cpp index 56cbd8cd41..55a99b4e88 100644 --- a/ApplicationCode/FileInterface/RifCsvUserDataParser.cpp +++ b/ApplicationCode/FileInterface/RifCsvUserDataParser.cpp @@ -218,6 +218,52 @@ QString RifCsvUserDataParser::previewText(int lineCount, const AsciiDataParseOpt return preview; } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QStringList RifCsvUserDataParser::timeColumnPreviewData(int lineCount, const AsciiDataParseOptions& parseOptions) +{ + QStringList timeStrings; + + QTextStream* stream = openDataStream(); + + if (stream) + { + int timeColumnIndex = -1; + int iLine = 0; + + while (iLine < lineCount && !stream->atEnd()) + { + QString line = stream->readLine(); + + if (line.isEmpty()) continue; + + int iCol = 0; + QStringList cols = RifFileParseTools::splitLineAndTrim(line, parseOptions.cellSeparator); + for (const QString& cellData : cols) + { + if (cellData == parseOptions.timeSeriesColumnName && iLine == 0) + { + timeColumnIndex = iCol; + } + + if (iLine > 0 && timeColumnIndex != -1 && timeColumnIndex == iCol) + { + timeStrings.push_back(cellData); + } + + iCol++; + } + + iLine++; + } + } + + closeDataStream(); + + return timeStrings; +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -325,7 +371,7 @@ bool RifCsvUserDataParser::parseColumnBasedData(const AsciiDataParseOptions& par } else { - if (parseOptions.assumeNumericDataColumns || RiaStdStringTools::isNumber(colData, parseOptions.locale.decimalPoint().toAscii())) + if (parseOptions.assumeNumericDataColumns || RiaStdStringTools::isNumber(colData, parseOptions.locale.decimalPoint().toLatin1())) { col.dataType = Column::NUMERIC; } @@ -784,4 +830,4 @@ void RifCsvUserDataPastedTextParser::closeDataStream() delete m_textStream; m_textStream = nullptr; } -} \ No newline at end of file +} diff --git a/ApplicationCode/FileInterface/RifCsvUserDataParser.h b/ApplicationCode/FileInterface/RifCsvUserDataParser.h index 639b00ff23..6cc1a14079 100644 --- a/ApplicationCode/FileInterface/RifCsvUserDataParser.h +++ b/ApplicationCode/FileInterface/RifCsvUserDataParser.h @@ -54,6 +54,7 @@ class RifCsvUserDataParser bool parseColumnInfo(const AsciiDataParseOptions& parseOptions); QString previewText(int lineCount, const AsciiDataParseOptions& parseOptions); + QStringList timeColumnPreviewData(int lineCount, const AsciiDataParseOptions& parseOptions); CsvLayout determineCsvLayout(); diff --git a/ApplicationCode/FileInterface/RifEclipseDataTableFormatter.cpp b/ApplicationCode/FileInterface/RifEclipseDataTableFormatter.cpp index e41515e47f..07d55f8c6f 100644 --- a/ApplicationCode/FileInterface/RifEclipseDataTableFormatter.cpp +++ b/ApplicationCode/FileInterface/RifEclipseDataTableFormatter.cpp @@ -20,6 +20,10 @@ #include "cvfAssert.h" +#include + +#define MAX_ECLIPSE_DATA_ROW_WIDTH 132 // Maximum eclipse data row width + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -28,7 +32,21 @@ RifEclipseDataTableFormatter::RifEclipseDataTableFormatter(QTextStream& out) , m_colSpacing(5) , m_tableRowPrependText(" ") , m_tableRowAppendText(" /") - , m_commentPrefix("--") + , m_commentPrefix("-- ") + , m_maxDataRowWidth(MAX_ECLIPSE_DATA_ROW_WIDTH) +{ +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RifEclipseDataTableFormatter::RifEclipseDataTableFormatter(const RifEclipseDataTableFormatter& rhs) + : m_out(rhs.m_out) + , m_colSpacing(rhs.m_colSpacing) + , m_tableRowPrependText(rhs.m_tableRowPrependText) + , m_tableRowAppendText(rhs.m_tableRowAppendText) + , m_commentPrefix(rhs.m_commentPrefix) + , m_maxDataRowWidth(rhs.m_maxDataRowWidth) { } @@ -41,6 +59,14 @@ RifEclipseDataTableFormatter::~RifEclipseDataTableFormatter() CVF_ASSERT(m_columns.empty()); } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +int RifEclipseDataTableFormatter::columnSpacing() const +{ + return m_colSpacing; +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -49,6 +75,22 @@ void RifEclipseDataTableFormatter::setColumnSpacing(int spacing) m_colSpacing = spacing; } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RifEclipseDataTableFormatter::tableRowPrependText() const +{ + return m_tableRowPrependText; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RifEclipseDataTableFormatter::tableRowAppendText() const +{ + return m_tableRowAppendText; +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -65,6 +107,14 @@ void RifEclipseDataTableFormatter::setTableRowLineAppendText(const QString& text m_tableRowAppendText = text; } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RifEclipseDataTableFormatter::commentPrefix() const +{ + return m_commentPrefix; +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -73,6 +123,22 @@ void RifEclipseDataTableFormatter::setCommentPrefix(const QString& commentPrefix m_commentPrefix = commentPrefix; } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RifEclipseDataTableFormatter::setUnlimitedDataRowWidth() +{ + m_maxDataRowWidth = std::numeric_limits::max(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +int RifEclipseDataTableFormatter::maxDataRowWidth() const +{ + return m_maxDataRowWidth; +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -80,10 +146,10 @@ void RifEclipseDataTableFormatter::outputBuffer() { if (!m_columns.empty() && !isAllHeadersEmpty(m_columns)) { - m_out << m_commentPrefix << " "; - for (RifEclipseOutputTableColumn& column : m_columns) - { - m_out << formatColumn(column.title, column); + m_out << m_commentPrefix; + for (size_t i = 0u; i < m_columns.size(); ++i) + { + m_out << formatColumn(m_columns[i].title, i); } m_out << "\n"; } @@ -100,14 +166,27 @@ void RifEclipseDataTableFormatter::outputBuffer() } else if (line.lineType == CONTENTS) { - m_out << m_tableRowPrependText; + QString lineText = m_tableRowPrependText; + bool isComment = m_tableRowPrependText.startsWith(m_commentPrefix); + QString appendText = (line.appendTextSet ? line.appendText : m_tableRowAppendText); for (size_t i = 0; i < line.data.size(); ++i) { - m_out << formatColumn(line.data[i], m_columns[i]); + QString column = formatColumn(line.data[i], i); + QString newLineText = lineText + column; + if (i == line.data.size() - 1) + { + newLineText += appendText; + } + if (!isComment && newLineText.length() > maxDataRowWidth()) + { + m_out << lineText << "\n"; + lineText = m_tableRowPrependText; + } + lineText += column; } - m_out << (line.appendTextSet ? line.appendText : m_tableRowAppendText) << "\n"; + m_out << lineText << appendText << "\n"; } } m_columns.clear(); @@ -119,7 +198,7 @@ void RifEclipseDataTableFormatter::outputBuffer() //-------------------------------------------------------------------------------------------------- void RifEclipseDataTableFormatter::outputComment(RifEclipseOutputTableLine& comment) { - m_out << m_commentPrefix << " " << comment.data[0] << "\n"; + m_out << m_commentPrefix << comment.data[0] << "\n"; } //-------------------------------------------------------------------------------------------------- @@ -185,29 +264,6 @@ void RifEclipseDataTableFormatter::tableCompleted(const QString& appendText, boo } } -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RifEclipseDataTableFormatter::addValueTable(QTextStream& stream, const QString& name, size_t columns, const std::vector& values) -{ - RifEclipseDataTableFormatter subFormatter(stream); - - std::vector cols(columns, RifEclipseOutputTableColumn("")); - - subFormatter.setTableRowPrependText(""); - subFormatter.keyword(name); - subFormatter.header(cols); - - int colCount = 0; - for (size_t i = 0; i < values.size(); i++) - { - subFormatter.add(values[i]); - if (++colCount % columns == 0 && i < values.size() - 1) subFormatter.rowCompleted(""); - } - subFormatter.rowCompleted(); - subFormatter.tableCompleted("", false); -} - //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -226,9 +282,10 @@ RifEclipseDataTableFormatter& RifEclipseDataTableFormatter::header(const std::ve { outputBuffer(); m_columns = header; - for (RifEclipseOutputTableColumn& column : m_columns) + + for (size_t colNumber = 0u; colNumber < m_columns.size(); ++colNumber) { - column.width = measure(column.title); + m_columns[colNumber].width = measure(m_columns[colNumber].title); } return *this; } @@ -415,12 +472,13 @@ int RifEclipseDataTableFormatter::measure(size_t num) //-------------------------------------------------------------------------------------------------- int RifEclipseDataTableFormatter::tableWidth() const { - int characterCount = 0; + int characterCount = m_tableRowPrependText.length(); - for (const auto& col : m_columns) + for (size_t i = 0u; i < m_columns.size(); ++i) { - characterCount += formatColumn(" ", col).size(); + characterCount += formatColumn(" ", i).size(); } + characterCount += m_tableRowAppendText.length(); return characterCount; } @@ -433,9 +491,11 @@ QString RifEclipseDataTableFormatter::format(double num, RifEclipseOutputTableDo switch (doubleFormat.format) { case RifEclipseOutputTableDoubleFormat::RIF_FLOAT: - return QString("%1").arg(num, 0, 'f', doubleFormat.width); + return QString("%1").arg(num, 0, 'f', doubleFormat.precision); case RifEclipseOutputTableDoubleFormat::RIF_SCIENTIFIC: return QString("%1").arg(num, 0, 'E'); + case RifEclipseOutputTableDoubleFormat::RIF_CONSISE: + return QString::number(num, 'g', doubleFormat.precision); default: return QString("%1"); } @@ -460,14 +520,18 @@ QString RifEclipseDataTableFormatter::format(size_t num) //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -QString RifEclipseDataTableFormatter::formatColumn(const QString str, RifEclipseOutputTableColumn column) const +QString RifEclipseDataTableFormatter::formatColumn(const QString str, size_t columnIndex) const { + const RifEclipseOutputTableColumn& column = m_columns[columnIndex]; + if (column.alignment == LEFT) { - return str.leftJustified(column.width + m_colSpacing, ' '); + int colSpacing = (columnIndex == m_columns.size() - 1) ? 0 : m_colSpacing; + return str.leftJustified(column.width + colSpacing, ' '); } else { - return str.rightJustified(column.width + m_colSpacing, ' '); + int colSpacing = (columnIndex == 0) ? 0 : m_colSpacing; + return str.rightJustified(column.width + colSpacing, ' '); } } diff --git a/ApplicationCode/FileInterface/RifEclipseDataTableFormatter.h b/ApplicationCode/FileInterface/RifEclipseDataTableFormatter.h index 3b1a680df1..385dbe3636 100644 --- a/ApplicationCode/FileInterface/RifEclipseDataTableFormatter.h +++ b/ApplicationCode/FileInterface/RifEclipseDataTableFormatter.h @@ -49,6 +49,7 @@ enum RifEclipseOutputTableDoubleFormat { RIF_SCIENTIFIC, RIF_FLOAT, + RIF_CONSISE }; //================================================================================================== @@ -67,14 +68,14 @@ struct RifEclipseOutputTableLine //================================================================================================== struct RifEclipseOutputTableDoubleFormatting { - RifEclipseOutputTableDoubleFormatting(RifEclipseOutputTableDoubleFormat format = RIF_FLOAT, int width = 5) + RifEclipseOutputTableDoubleFormatting(RifEclipseOutputTableDoubleFormat format = RIF_FLOAT, int precision = 5) : format(format) - , width(width) + , precision(precision) { } RifEclipseOutputTableDoubleFormat format; - int width; + int precision; }; //================================================================================================== @@ -106,12 +107,20 @@ class RifEclipseDataTableFormatter { public: RifEclipseDataTableFormatter(QTextStream& out); + RifEclipseDataTableFormatter(const RifEclipseDataTableFormatter& rhs); + virtual ~RifEclipseDataTableFormatter(); + int columnSpacing() const; void setColumnSpacing(int spacing); + QString tableRowPrependText() const; + QString tableRowAppendText() const; void setTableRowPrependText(const QString& text); void setTableRowLineAppendText(const QString& text); + QString commentPrefix() const; void setCommentPrefix(const QString& commentPrefix); + void setUnlimitedDataRowWidth(); + int maxDataRowWidth() const; RifEclipseDataTableFormatter& keyword(const QString& keyword); RifEclipseDataTableFormatter& header(std::vector tableHeader); @@ -128,7 +137,7 @@ class RifEclipseDataTableFormatter void tableCompleted(); void tableCompleted(const QString& appendText, bool appendNewline); - static void addValueTable(QTextStream& stream, const QString& keyword, size_t columns, const std::vector& values); + int tableWidth() const; private: int measure(const QString str); @@ -136,12 +145,10 @@ class RifEclipseDataTableFormatter int measure(int num); int measure(size_t num); - int tableWidth() const; - QString format(double num, RifEclipseOutputTableDoubleFormatting doubleFormat); QString format(int num); QString format(size_t num); - QString formatColumn(const QString str, RifEclipseOutputTableColumn column) const; + QString formatColumn(const QString str, size_t columnIndex) const; void outputBuffer(); void outputComment(RifEclipseOutputTableLine& comment); @@ -158,4 +165,5 @@ class RifEclipseDataTableFormatter QString m_tableRowPrependText; QString m_tableRowAppendText; QString m_commentPrefix; + int m_maxDataRowWidth; }; diff --git a/ApplicationCode/FileInterface/RifEclipseInputFileTools.cpp b/ApplicationCode/FileInterface/RifEclipseInputFileTools.cpp index 455e0118ef..cc0ddd69e9 100644 --- a/ApplicationCode/FileInterface/RifEclipseInputFileTools.cpp +++ b/ApplicationCode/FileInterface/RifEclipseInputFileTools.cpp @@ -3,30 +3,33 @@ // Copyright (C) 2011- Statoil ASA // Copyright (C) 2013- Ceetron Solutions AS // Copyright (C) 2011-2012 Ceetron AS -// +// // ResInsight 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 3 of the License, or // (at your option) any later version. -// +// // ResInsight 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 at +// +// See the GNU General Public License at // for more details. // ///////////////////////////////////////////////////////////////////////////////// #include "RifEclipseInputFileTools.h" +#include "RiaCellDividingTools.h" #include "RiaLogging.h" +#include "RiaStringEncodingTools.h" #include "RifReaderEclipseOutput.h" #include "RigActiveCellInfo.h" #include "RigCaseCellResultsData.h" #include "RigEclipseCaseData.h" +#include "RigFault.h" #include "RigMainGrid.h" #include "cafProgressInfo.h" @@ -36,14 +39,15 @@ #include #include +#include +#include #include #include -#include #include -#include #include "ert/ecl/ecl_box.hpp" #include "ert/ecl/ecl_kw.h" +#include "ert/ecl/ecl_grid.hpp" QString includeKeyword("INCLUDE"); QString faultsKeyword("FAULTS"); @@ -51,43 +55,37 @@ QString editKeyword("EDIT"); QString gridKeyword("GRID"); QString pathsKeyword("PATHS"); - - //-------------------------------------------------------------------------------------------------- /// Constructor //-------------------------------------------------------------------------------------------------- -RifEclipseInputFileTools::RifEclipseInputFileTools() -{ - -} - +RifEclipseInputFileTools::RifEclipseInputFileTools() {} //-------------------------------------------------------------------------------------------------- /// Destructor //-------------------------------------------------------------------------------------------------- -RifEclipseInputFileTools::~RifEclipseInputFileTools() -{ - -} - +RifEclipseInputFileTools::~RifEclipseInputFileTools() {} //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- -bool RifEclipseInputFileTools::openGridFile(const QString& fileName, RigEclipseCaseData* eclipseCase, bool readFaultData) +bool RifEclipseInputFileTools::openGridFile(const QString& fileName, + RigEclipseCaseData* eclipseCase, + bool readFaultData, + QString* errorMessages) { - CVF_ASSERT(eclipseCase); + CVF_ASSERT(eclipseCase && errorMessages); - std::vector< RifKeywordAndFilePos > keywordsAndFilePos; + std::vector keywordsAndFilePos; findKeywordsOnFile(fileName, &keywordsAndFilePos); - qint64 coordPos = -1; - qint64 zcornPos = -1; + qint64 coordPos = -1; + qint64 zcornPos = -1; qint64 specgridPos = -1; - qint64 actnumPos = -1; - qint64 mapaxesPos = -1; + qint64 actnumPos = -1; + qint64 mapaxesPos = -1; + qint64 gridunitPos = -1; - findGridKeywordPositions(keywordsAndFilePos, &coordPos, &zcornPos, &specgridPos, &actnumPos, &mapaxesPos); + findGridKeywordPositions(keywordsAndFilePos, &coordPos, &zcornPos, &specgridPos, &actnumPos, &mapaxesPos, &gridunitPos); if (coordPos < 0 || zcornPos < 0 || specgridPos < 0) { @@ -108,11 +106,23 @@ bool RifEclipseInputFileTools::openGridFile(const QString& fileName, RigEclipseC errorText += " Missing required keyword SPECGRID"; } - RiaLogging::error(errorText); + *errorMessages += errorText; return false; } + if (gridunitPos >= 0) + { + QFile gridFile(fileName); + if (gridFile.open(QFile::ReadOnly)) + { + RiaEclipseUnitTools::UnitSystem units = readUnitSystem(gridFile, gridunitPos); + if (units != RiaEclipseUnitTools::UNITS_UNKNOWN) + { + eclipseCase->setUnitsType(units); + } + } + } FILE* gridFilePointer = util_fopen(fileName.toLatin1().data(), "r"); if (!gridFilePointer) return false; @@ -122,41 +132,42 @@ bool RifEclipseInputFileTools::openGridFile(const QString& fileName, RigEclipseC // DIMENS - Is what Eclipse expects and uses, but is not defined in the GRID section and is not (?) available normally // ZCORN, COORD, ACTNUM, MAPAXES - //ecl_kw_type * ecl_kw_fscanf_alloc_grdecl_dynamic__( FILE * stream , const char * kw , bool strict , ecl_type_enum ecl_type); - //ecl_grid_type * ecl_grid_alloc_GRDECL_kw( int nx, int ny , int nz , const ecl_kw_type * zcorn_kw , const ecl_kw_type * coord_kw , const ecl_kw_type * actnum_kw , const ecl_kw_type * mapaxes_kw ); + // ecl_kw_type * ecl_kw_fscanf_alloc_grdecl_dynamic__( FILE * stream , const char * kw , bool strict , ecl_type_enum + // ecl_type); ecl_grid_type * ecl_grid_alloc_GRDECL_kw( int nx, int ny , int nz , const ecl_kw_type * zcorn_kw , const + // ecl_kw_type * coord_kw , const ecl_kw_type * actnum_kw , const ecl_kw_type * mapaxes_kw ); - - - ecl_kw_type* specGridKw = nullptr; - ecl_kw_type* zCornKw = nullptr; - ecl_kw_type* coordKw = nullptr; - ecl_kw_type* actNumKw = nullptr; - ecl_kw_type* mapAxesKw = nullptr; + ecl_kw_type* specGridKw = nullptr; + ecl_kw_type* zCornKw = nullptr; + ecl_kw_type* coordKw = nullptr; + ecl_kw_type* actNumKw = nullptr; + ecl_kw_type* mapAxesKw = nullptr; // Try to read all the needed keywords. Early exit if some are not found caf::ProgressInfo progress(8, "Read Grid from Eclipse Input file"); - - bool allKwReadOk = true; fseek(gridFilePointer, specgridPos, SEEK_SET); - allKwReadOk = allKwReadOk && nullptr != (specGridKw = ecl_kw_fscanf_alloc_current_grdecl__(gridFilePointer, false , ecl_type_create_from_type(ECL_INT_TYPE))); + allKwReadOk = allKwReadOk && nullptr != (specGridKw = ecl_kw_fscanf_alloc_current_grdecl__( + gridFilePointer, false, ecl_type_create_from_type(ECL_INT_TYPE))); progress.setProgress(1); fseek(gridFilePointer, zcornPos, SEEK_SET); - allKwReadOk = allKwReadOk && nullptr != (zCornKw = ecl_kw_fscanf_alloc_current_grdecl__(gridFilePointer, false , ecl_type_create_from_type(ECL_FLOAT_TYPE))); + allKwReadOk = allKwReadOk && nullptr != (zCornKw = ecl_kw_fscanf_alloc_current_grdecl__( + gridFilePointer, false, ecl_type_create_from_type(ECL_FLOAT_TYPE))); progress.setProgress(2); fseek(gridFilePointer, coordPos, SEEK_SET); - allKwReadOk = allKwReadOk && nullptr != (coordKw = ecl_kw_fscanf_alloc_current_grdecl__(gridFilePointer, false , ecl_type_create_from_type(ECL_FLOAT_TYPE))); + allKwReadOk = allKwReadOk && nullptr != (coordKw = ecl_kw_fscanf_alloc_current_grdecl__( + gridFilePointer, false, ecl_type_create_from_type(ECL_FLOAT_TYPE))); progress.setProgress(3); // If ACTNUM is not defined, this pointer will be nullptr, which is a valid condition if (actnumPos >= 0) { fseek(gridFilePointer, actnumPos, SEEK_SET); - allKwReadOk = allKwReadOk && nullptr != (actNumKw = ecl_kw_fscanf_alloc_current_grdecl__(gridFilePointer, false , ecl_type_create_from_type(ECL_INT_TYPE))); + allKwReadOk = allKwReadOk && nullptr != (actNumKw = ecl_kw_fscanf_alloc_current_grdecl__( + gridFilePointer, false, ecl_type_create_from_type(ECL_INT_TYPE))); progress.setProgress(4); } @@ -164,27 +175,27 @@ bool RifEclipseInputFileTools::openGridFile(const QString& fileName, RigEclipseC if (mapaxesPos >= 0) { fseek(gridFilePointer, mapaxesPos, SEEK_SET); - mapAxesKw = ecl_kw_fscanf_alloc_current_grdecl__( gridFilePointer, false , ecl_type_create_from_type(ECL_FLOAT_TYPE)); + mapAxesKw = ecl_kw_fscanf_alloc_current_grdecl__(gridFilePointer, false, ecl_type_create_from_type(ECL_FLOAT_TYPE)); } if (!allKwReadOk) { - if(specGridKw) ecl_kw_free(specGridKw); - if(zCornKw) ecl_kw_free(zCornKw); - if(coordKw) ecl_kw_free(coordKw); - if(actNumKw) ecl_kw_free(actNumKw); - if(mapAxesKw) ecl_kw_free(mapAxesKw); + if (specGridKw) ecl_kw_free(specGridKw); + if (zCornKw) ecl_kw_free(zCornKw); + if (coordKw) ecl_kw_free(coordKw); + if (actNumKw) ecl_kw_free(actNumKw); + if (mapAxesKw) ecl_kw_free(mapAxesKw); return false; } progress.setProgress(5); - int nx = ecl_kw_iget_int(specGridKw, 0); - int ny = ecl_kw_iget_int(specGridKw, 1); + int nx = ecl_kw_iget_int(specGridKw, 0); + int ny = ecl_kw_iget_int(specGridKw, 1); int nz = ecl_kw_iget_int(specGridKw, 2); - ecl_grid_type* inputGrid = ecl_grid_alloc_GRDECL_kw( nx, ny, nz, zCornKw, coordKw, actNumKw, mapAxesKw ); + ecl_grid_type* inputGrid = ecl_grid_alloc_GRDECL_kw(nx, ny, nz, zCornKw, coordKw, actNumKw, mapAxesKw); progress.setProgress(6); @@ -201,7 +212,17 @@ bool RifEclipseInputFileTools::openGridFile(const QString& fileName, RigEclipseC RigMainGrid* mainGrid = eclipseCase->mainGrid(); mainGrid->setFaults(faults); } - + + bool useMapAxes = ecl_grid_use_mapaxes(inputGrid); + eclipseCase->mainGrid()->setUseMapAxes(useMapAxes); + + if (useMapAxes) + { + std::array mapAxesValues; + ecl_grid_init_mapaxes_data_double(inputGrid, mapAxesValues.data()); + eclipseCase->mainGrid()->setMapAxes(mapAxesValues); + } + progress.setProgress(8); progress.setProgressDescription("Cleaning up ..."); @@ -214,10 +235,487 @@ bool RifEclipseInputFileTools::openGridFile(const QString& fileName, RigEclipseC ecl_grid_free(inputGrid); fclose(gridFilePointer); - + return true; } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RifEclipseInputFileTools::exportGrid(const QString& fileName, + RigEclipseCaseData* eclipseCase, + bool exportInLocalCoordinates, + const cvf::UByteArray* cellVisibilityOverrideForActnum, + const cvf::Vec3st& min, + const cvf::Vec3st& maxIn, + const cvf::Vec3st& refinement) +{ + if (!eclipseCase) + { + return false; + } + + const RigActiveCellInfo* activeCellInfo = eclipseCase->activeCellInfo(RiaDefines::MATRIX_MODEL); + + CVF_ASSERT(activeCellInfo); + + const RigMainGrid* mainGrid = eclipseCase->mainGrid(); + + cvf::Vec3st max = maxIn; + if (max == cvf::Vec3st::UNDEFINED) + { + max = cvf::Vec3st(mainGrid->cellCountI() - 1, mainGrid->cellCountJ() - 1, mainGrid->cellCountK() - 1); + } + + int ecl_nx = static_cast((max.x() - min.x()) * refinement.x() + 1); + int ecl_ny = static_cast((max.y() - min.y()) * refinement.y() + 1); + int ecl_nz = static_cast((max.z() - min.z()) * refinement.z() + 1); + + CVF_ASSERT(ecl_nx > 0 && ecl_ny > 0 && ecl_nz > 0); + + size_t cellsPerOriginal = refinement.x() * refinement.y() * refinement.z(); + + caf::ProgressInfo progress(mainGrid->cellCount() * 2, "Save Eclipse Grid"); + int cellProgressInterval = 1000; + + std::vector ecl_corners; + ecl_corners.reserve(mainGrid->cellCount() * cellsPerOriginal); + std::vector ecl_coords; + ecl_coords.reserve(mainGrid->cellCount() * cellsPerOriginal); + + std::array mapAxes = mainGrid->mapAxesF(); + cvf::Mat4d mapAxisTrans = mainGrid->mapAxisTransform(); + if (exportInLocalCoordinates) + { + cvf::Vec3d minPoint3d(mainGrid->boundingBox().min()); + cvf::Vec2f minPoint2f(minPoint3d.x(), minPoint3d.y()); + cvf::Vec2f origin(mapAxes[2] - minPoint2f.x(), mapAxes[3] - minPoint2f.y()); + cvf::Vec2f xPoint = cvf::Vec2f(mapAxes[4], mapAxes[5]) - minPoint2f; + cvf::Vec2f yPoint = cvf::Vec2f(mapAxes[0], mapAxes[1]) - minPoint2f; + mapAxes = { yPoint.x(), yPoint.y(), origin.x(), origin.y(), xPoint.x(), xPoint.y() }; + + mapAxisTrans.setTranslation(mapAxisTrans.translation() - minPoint3d); + } + + const size_t* cellMappingECLRi = RifReaderEclipseOutput::eclipseCellIndexMapping(); + + int incrementalIndex = 0; + for (size_t k = min.z() * refinement.z(); k <= max.z() * refinement.z(); ++k) + { + size_t mainK = k / refinement.z(); + size_t k0 = k - min.z() * refinement.z(); + for (size_t j = min.y() * refinement.y(); j <= max.y() * refinement.y(); ++j) + { + size_t mainJ = j / refinement.y(); + size_t j0 = j - min.y() * refinement.y(); + for (size_t i = min.x() * refinement.x(); i <= max.x() * refinement.x(); ++i) + { + size_t mainI = i / refinement.x(); + size_t i0 = i - min.x() * refinement.x(); + + size_t mainIndex = mainGrid->cellIndexFromIJK(mainI, mainJ, mainK); + + int active = activeCellInfo->isActive(mainIndex) ? 1 : 0; + if (active && cellVisibilityOverrideForActnum) + { + active = (*cellVisibilityOverrideForActnum)[mainIndex]; + } + + int* ecl_cell_coords = new int[5]; + ecl_cell_coords[0] = (int)(i0 + 1); + ecl_cell_coords[1] = (int)(j0 + 1); + ecl_cell_coords[2] = (int)(k0 + 1); + ecl_cell_coords[3] = incrementalIndex++; + ecl_cell_coords[4] = active; + ecl_coords.push_back(ecl_cell_coords); + + std::array cellCorners; + mainGrid->cellCornerVertices(mainIndex, cellCorners.data()); + + if (mainGrid->useMapAxes()) + { + for (cvf::Vec3d& corner : cellCorners) + { + corner.transformPoint(mapAxisTrans); + } + } + + auto refinedCoords = + RiaCellDividingTools::createHexCornerCoords(cellCorners, refinement.x(), refinement.y(), refinement.z()); + + size_t subI = i % refinement.x(); + size_t subJ = j % refinement.y(); + size_t subK = k % refinement.z(); + size_t subIndex = subI + subJ * refinement.x() + subK * refinement.x() * refinement.y(); + + float* ecl_cell_corners = new float[24]; + for (size_t cIdx = 0; cIdx < 8; ++cIdx) + { + cvf::Vec3d cellCorner = refinedCoords[subIndex * 8 + cIdx]; + ecl_cell_corners[cellMappingECLRi[cIdx] * 3] = cellCorner[0]; + ecl_cell_corners[cellMappingECLRi[cIdx] * 3 + 1] = cellCorner[1]; + ecl_cell_corners[cellMappingECLRi[cIdx] * 3 + 2] = -cellCorner[2]; + } + ecl_corners.push_back(ecl_cell_corners); + } + } + if (incrementalIndex % cellProgressInterval == 0) + { + progress.setProgress(incrementalIndex / cellsPerOriginal); + } + } + + // Do not perform the transformation (applyMapaxes == false): + // The coordinates have been transformed to the mapaxes coordinate system already. + // However, send the mapaxes data in to libecl so that the coordinate system description is saved. + bool applyMapaxes = false; + ecl_grid_type* mainEclGrid = + ecl_grid_alloc_GRID_data((int)ecl_coords.size(), ecl_nx, ecl_ny, ecl_nz, 5, &ecl_coords[0], &ecl_corners[0], applyMapaxes, mapAxes.data()); + progress.setProgress(mainGrid->cellCount()); + + for (float* floatArray : ecl_corners) + { + delete floatArray; + } + + for (int* intArray : ecl_coords) + { + delete intArray; + } + + FILE* filePtr = util_fopen(RiaStringEncodingTools::toNativeEncoded(fileName).data(), "w"); + + if (!filePtr) + { + return false; + } + + ert_ecl_unit_enum ecl_units = ECL_METRIC_UNITS; + if (eclipseCase->unitsType() == RiaEclipseUnitTools::UNITS_FIELD) + ecl_units = ECL_FIELD_UNITS; + else if (eclipseCase->unitsType() == RiaEclipseUnitTools::UNITS_LAB) + ecl_units = ECL_LAB_UNITS; + + ecl_grid_fprintf_grdecl2(mainEclGrid, filePtr, ecl_units); + ecl_grid_free(mainEclGrid); + fclose(filePtr); + + return true; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RifEclipseInputFileTools::exportKeywords(const QString& resultFileName, + RigEclipseCaseData* eclipseCase, + const std::vector& keywords, + const QString& fileWriteMode, + const cvf::Vec3st& min, + const cvf::Vec3st& maxIn, + const cvf::Vec3st& refinement) +{ + FILE* filePtr = util_fopen(RiaStringEncodingTools::toNativeEncoded(resultFileName).data(), + RiaStringEncodingTools::toNativeEncoded(fileWriteMode).data()); + if (!filePtr) + { + return false; + } + RigCaseCellResultsData* cellResultsData = eclipseCase->results(RiaDefines::MATRIX_MODEL); + RigActiveCellInfo* activeCells = cellResultsData->activeCellInfo(); + RigMainGrid* mainGrid = eclipseCase->mainGrid(); + + cvf::Vec3st max = maxIn; + if (max == cvf::Vec3st::UNDEFINED) + { + max = cvf::Vec3st(mainGrid->cellCountI() - 1, mainGrid->cellCountJ() - 1, mainGrid->cellCountK() - 1); + } + + caf::ProgressInfo progress(keywords.size(), "Saving Keywords"); + + for (const QString& keyword : keywords) + { + std::vector resultValues; + + RigEclipseResultAddress resAddr(RiaDefines::STATIC_NATIVE, keyword); + if (!cellResultsData->hasResultEntry(resAddr)) continue; + + cellResultsData->ensureKnownResultLoaded(resAddr); + + CVF_ASSERT(!cellResultsData->cellScalarResults(resAddr).empty()); + + resultValues = cellResultsData->cellScalarResults(resAddr)[0]; + CVF_ASSERT(!resultValues.empty()); + if (resultValues.empty()) continue; + + + std::vector filteredResults; + filteredResults.reserve(resultValues.size()); + + for (size_t k = min.z() * refinement.z(); k <= max.z() * refinement.z(); ++k) + { + size_t mainK = k / refinement.z(); + for (size_t j = min.y() * refinement.y(); j <= max.y() * refinement.y(); ++j) + { + size_t mainJ = j / refinement.y(); + for (size_t i = min.x() * refinement.x(); i <= max.x() * refinement.x(); ++i) + { + size_t mainI = i / refinement.x(); + + size_t mainIndex = mainGrid->cellIndexFromIJK(mainI, mainJ, mainK); + + size_t resIndex = activeCells->cellResultIndex(mainIndex); + if (resIndex != cvf::UNDEFINED_SIZE_T) + { + filteredResults.push_back(resultValues[resIndex]); + } + } + } + } + + ecl_kw_type* ecl_kw = nullptr; + + if (keyword.endsWith("NUM")) + { + std::vector resultValuesInt; + resultValuesInt.reserve(filteredResults.size()); + for (double val : filteredResults) + { + resultValuesInt.push_back(static_cast(val)); + } + ecl_kw = ecl_kw_alloc_new(keyword.toLatin1().data(), (int)resultValuesInt.size(), ECL_INT, resultValuesInt.data()); + } + else + { + std::vector resultValuesFloat; + resultValuesFloat.reserve(filteredResults.size()); + for (double val : filteredResults) + { + resultValuesFloat.push_back(static_cast(val)); + } + ecl_kw = + ecl_kw_alloc_new(keyword.toLatin1().data(), (int)resultValuesFloat.size(), ECL_FLOAT, resultValuesFloat.data()); + } + + ecl_kw_fprintf_grdecl(ecl_kw, filePtr); + ecl_kw_free(ecl_kw); + progress.incrementProgress(); + } + + fclose(filePtr); + return true; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RifEclipseInputFileTools::saveFault(QString completeFilename, + const RigMainGrid* mainGrid, + const std::vector& faultFaces, + QString faultName, + const cvf::Vec3st& min, + const cvf::Vec3st& maxIn, + const cvf::Vec3st& refinement) +{ + QFile exportFile(completeFilename); + + if (!exportFile.open(QIODevice::WriteOnly | QIODevice::Text)) + { + RiaLogging::error("Could not open the file : " + completeFilename); + } + + QTextStream stream(&exportFile); + stream << "FAULTS" << endl; + + stream << "-- Name I1 I2 J1 J2 K1 K2 Face ( I/J/K )" << endl; + + saveFault(stream, mainGrid, faultFaces, faultName, min, maxIn, refinement); + stream << "/" << endl; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RifEclipseInputFileTools::saveFault(QTextStream& stream, + const RigMainGrid* mainGrid, + const std::vector& faultFaces, + QString faultName, + const cvf::Vec3st& min, + const cvf::Vec3st& maxIn, + const cvf::Vec3st& refinement) +{ + // 'NAME' 1 1 1 1 1 2 J / + + if (faultName.contains(' ')) + { + RiaLogging::error(QString("Fault name '%1' contains spaces").arg(faultName)); + return; + } + else if (faultName.length() > 8) + { + // Keep going anyway, eclipse files sometimes have longer than + // the specified 8 characters in the name without Eclipse complaining + RiaLogging::warning(QString("Fault name '%1' is longer than 8 characters").arg(faultName)); + } + + std::vector faultCellAndFaces; + + cvf::Vec3st max = maxIn; + if (max == cvf::Vec3st::UNDEFINED) + { + max = cvf::Vec3st(mainGrid->cellCountI() - 1, mainGrid->cellCountJ() - 1, mainGrid->cellCountK() - 1); + } + + for (const RigFault::FaultFace& faultCellAndFace : faultFaces) + { + size_t i, j, k; + bool ok = mainGrid->ijkFromCellIndex(faultCellAndFace.m_nativeReservoirCellIndex, &i, &j, &k); + if (!ok) continue; + + if (i < min.x() || i > max.x() || j < min.y() || j > max.y() || k < min.z() || k > max.z()) continue; + + size_t shifted_i = (i - min.x()) * refinement.x(); + size_t shifted_j = (j - min.y()) * refinement.y(); + size_t shifted_k = (k - min.z()) * refinement.z(); + + // 2x2 Refinement of Original Cell 0, 0 + // Y/J POS_J boundary + // ^ _______________ + // | | | | + // | | 0,1 | 1,1 | + // | |_______|_______| POS_I boundary + // | | | | + // | | 0,0 | 1,0 | + // | |_______|_______| + // ---------------------> X/I + // NEG_J boundary + // + // POS_J gets shifted 1 index in J direction, NEG_J stays the same in J but spans two I. + // POS_I gets shifted 1 index in I direction, NEG_I stays the same in I but spans two J. + + if (refinement != cvf::Vec3st(1, 1, 1)) + { + if (faultCellAndFace.m_nativeFace == cvf::StructGridInterface::POS_I || + faultCellAndFace.m_nativeFace == cvf::StructGridInterface::NEG_I) + { + if (faultCellAndFace.m_nativeFace == cvf::StructGridInterface::POS_I) + { + shifted_i += refinement.x() - 1; + } + for (size_t refineK = 0; refineK < refinement.z(); ++refineK) + { + for (size_t refineJ = 0; refineJ < refinement.y(); ++refineJ) + { + faultCellAndFaces.push_back( + std::make_tuple(shifted_i, shifted_j + refineJ, shifted_k + refineK, faultCellAndFace.m_nativeFace)); + } + } + } + else if (faultCellAndFace.m_nativeFace == cvf::StructGridInterface::POS_J || + faultCellAndFace.m_nativeFace == cvf::StructGridInterface::NEG_J) + { + if (faultCellAndFace.m_nativeFace == cvf::StructGridInterface::POS_J) + { + shifted_j += refinement.y() - 1; + } + + for (size_t refineK = 0; refineK < refinement.z(); ++refineK) + { + for (size_t refineI = 0; refineI < refinement.x(); ++refineI) + { + faultCellAndFaces.push_back( + std::make_tuple(shifted_i + refineI, shifted_j, shifted_k + refineK, faultCellAndFace.m_nativeFace)); + } + } + } + else if (faultCellAndFace.m_nativeFace == cvf::StructGridInterface::POS_K || + faultCellAndFace.m_nativeFace == cvf::StructGridInterface::NEG_K) + { + if (faultCellAndFace.m_nativeFace == cvf::StructGridInterface::POS_K) + { + shifted_k += refinement.z() - 1; + } + + for (size_t refineJ = 0; refineJ < refinement.y(); ++refineJ) + { + for (size_t refineI = 0; refineI < refinement.x(); ++refineI) + { + faultCellAndFaces.push_back( + std::make_tuple(shifted_i + refineI, shifted_j + refineJ, shifted_k, faultCellAndFace.m_nativeFace)); + } + } + } + } + else + { + faultCellAndFaces.push_back(std::make_tuple(shifted_i, shifted_j, shifted_k, faultCellAndFace.m_nativeFace)); + } + } + + // Sort order: i, j, face then k. + std::sort(faultCellAndFaces.begin(), faultCellAndFaces.end(), RigFault::ordering); + + size_t lastI = std::numeric_limits::max(); + size_t lastJ = std::numeric_limits::max(); + size_t lastK = std::numeric_limits::max(); + size_t startK = std::numeric_limits::max(); + cvf::StructGridInterface::FaceType lastFaceType = cvf::StructGridInterface::FaceType::NO_FACE; + + for (const RigFault::CellAndFace& faultCellAndFace : faultCellAndFaces) + { + size_t i, j, k; + cvf::StructGridInterface::FaceType faceType; + std::tie(i, j, k, faceType) = faultCellAndFace; + + if (i != lastI || j != lastJ || lastFaceType != faceType || k != lastK + 1) + { + // No fault should have no face + if (lastFaceType != cvf::StructGridInterface::FaceType::NO_FACE) + { + writeFaultLine(stream, faultName, lastI, lastJ, startK, lastK, lastFaceType); + } + lastI = i; + lastJ = j; + lastK = k; + lastFaceType = faceType; + startK = k; + } + else + { + lastK = k; + } + } + + // No fault should have no face + if (lastFaceType != cvf::StructGridInterface::FaceType::NO_FACE) + { + writeFaultLine(stream, faultName, lastI, lastJ, startK, lastK, lastFaceType); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RifEclipseInputFileTools::saveFaults(QTextStream& stream, + const RigMainGrid* mainGrid, + const cvf::Vec3st& min /*= cvf::Vec3st::ZERO*/, + const cvf::Vec3st& max /*= cvf::Vec3st::UNDEFINED*/, + const cvf::Vec3st& refinement /*= cvf::Vec3st(1, 1, 1)*/) +{ + stream << "FAULTS" << endl; + + stream << "-- Name I1 I2 J1 J2 K1 K2 Face ( I/J/K )" << endl; + + const cvf::Collection& faults = mainGrid->faults(); + for (const auto fault : faults) + { + if (fault->name() != RiaDefines::undefinedGridFaultName() && + fault->name() != RiaDefines::undefinedGridFaultWithInactiveName()) + { + saveFault(stream, mainGrid, fault->faultFaces(), fault->name(), min, max, refinement); + } + } + stream << "/" << endl; +} //-------------------------------------------------------------------------------------------------- /// Read known properties from the input file @@ -231,34 +729,51 @@ std::map RifEclipseInputFileTools::readProperties(const QStrin std::vector fileKeywords; RifEclipseInputFileTools::findKeywordsOnFile(fileName, &fileKeywords); + if (!fileKeywords.size()) + { + RiaLogging::warning(QString("No keywords found in file: %1").arg(fileName)); + } mainProgress.setProgress(1); caf::ProgressInfo progress(fileKeywords.size(), "Reading properties"); FILE* gridFilePointer = util_fopen(fileName.toLatin1().data(), "r"); - if (!gridFilePointer || !fileKeywords.size() ) + if (!gridFilePointer) { + RiaLogging::warning(QString("Could not open file: %1").arg(fileName)); return std::map(); } std::map newResults; for (size_t i = 0; i < fileKeywords.size(); ++i) { - if (!isValidDataKeyword(fileKeywords[i].keyword)) continue; + if (!isValidDataKeyword(fileKeywords[i].keyword)) + { + continue; + } fseek(gridFilePointer, fileKeywords[i].filePos, SEEK_SET); - ecl_kw_type* eclipseKeywordData = ecl_kw_fscanf_alloc_current_grdecl__(gridFilePointer, false, ecl_type_create_from_type(ECL_FLOAT_TYPE)); + ecl_kw_type* eclipseKeywordData = + ecl_kw_fscanf_alloc_current_grdecl__(gridFilePointer, false, ecl_type_create_from_type(ECL_FLOAT_TYPE)); if (eclipseKeywordData) { QString newResultName = caseData->results(RiaDefines::MATRIX_MODEL)->makeResultNameUnique(fileKeywords[i].keyword); - if (readDataFromKeyword(eclipseKeywordData, caseData, newResultName)) + QString errMsg; + if (readDataFromKeyword(eclipseKeywordData, caseData, newResultName, &errMsg)) { newResults[newResultName] = fileKeywords[i].keyword; } - + else + { + RiaLogging::error(QString("Failed to read keyword: %1").arg(errMsg)); + } ecl_kw_free(eclipseKeywordData); } + else + { + RiaLogging::error(QString("Failed to allocate keyword: %1").arg(fileKeywords[i].keyword)); + } progress.setProgress(i); } @@ -267,28 +782,44 @@ std::map RifEclipseInputFileTools::readProperties(const QStrin return newResults; } - //-------------------------------------------------------------------------------------------------- -/// Reads the property data requested into the \a reservoir, overwriting any previous +/// Reads the property data requested into the \a reservoir, overwriting any previous /// properties with the same name. //-------------------------------------------------------------------------------------------------- -bool RifEclipseInputFileTools::readProperty(const QString& fileName, RigEclipseCaseData* caseData, const QString& eclipseKeyWord, const QString& resultName) +bool RifEclipseInputFileTools::readProperty(const QString& fileName, + RigEclipseCaseData* caseData, + const QString& eclipseKeyWord, + const QString& resultName) { CVF_ASSERT(caseData); if (!isValidDataKeyword(eclipseKeyWord)) return false; FILE* filePointer = util_fopen(fileName.toLatin1().data(), "r"); - if (!filePointer) return false; + if (!filePointer) + { + RiaLogging::error(QString("Could not open property file: %1").arg(fileName)); + return false; + } - ecl_kw_type* eclipseKeywordData = ecl_kw_fscanf_alloc_grdecl_dynamic__(filePointer, eclipseKeyWord.toLatin1().data(), false, ecl_type_create_from_type(ECL_FLOAT_TYPE)); + ecl_kw_type* eclipseKeywordData = ecl_kw_fscanf_alloc_grdecl_dynamic__( + filePointer, eclipseKeyWord.toLatin1().data(), false, ecl_type_create_from_type(ECL_FLOAT_TYPE)); bool isOk = false; if (eclipseKeywordData) { - isOk = readDataFromKeyword(eclipseKeywordData, caseData, resultName); + QString errMsg; + isOk = readDataFromKeyword(eclipseKeywordData, caseData, resultName, &errMsg); + if (!isOk) + { + RiaLogging::error(QString("Failed to read property: %1").arg(errMsg)); + } ecl_kw_free(eclipseKeywordData); } + else + { + RiaLogging::error(QString("Failed to load keyword %1 from file: %2").arg(eclipseKeyWord).arg(fileName)); + } fclose(filePointer); @@ -296,34 +827,47 @@ bool RifEclipseInputFileTools::readProperty(const QString& fileName, RigEclipseC } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- -bool RifEclipseInputFileTools::readDataFromKeyword(ecl_kw_type* eclipseKeywordData, RigEclipseCaseData* caseData, const QString& resultName) +bool RifEclipseInputFileTools::readDataFromKeyword(ecl_kw_type* eclipseKeywordData, + RigEclipseCaseData* caseData, + const QString& resultName, + QString* errMsg) { CVF_ASSERT(caseData); CVF_ASSERT(eclipseKeywordData); + CVF_ASSERT(errMsg); bool mathingItemCount = false; + size_t keywordItemCount = 0u; { - size_t itemCount = static_cast(ecl_kw_get_size(eclipseKeywordData)); - if (itemCount == caseData->mainGrid()->cellCount()) + keywordItemCount = static_cast(ecl_kw_get_size(eclipseKeywordData)); + if (keywordItemCount == caseData->mainGrid()->cellCount()) { mathingItemCount = true; } - if (itemCount == caseData->activeCellInfo(RiaDefines::MATRIX_MODEL)->reservoirActiveCellCount()) + if (keywordItemCount == caseData->activeCellInfo(RiaDefines::MATRIX_MODEL)->reservoirActiveCellCount()) { mathingItemCount = true; } } + + if (!mathingItemCount) + { + QString errFormat("Size mismatch: Main Grid has %1 cells, keyword %2 has %3 cells"); + *errMsg = errFormat.arg(caseData->mainGrid()->cellCount()).arg(resultName).arg(keywordItemCount); + return false; + } - if (!mathingItemCount) return false; + RigEclipseResultAddress resAddr(RiaDefines::INPUT_PROPERTY, resultName); + caseData->results(RiaDefines::MATRIX_MODEL)->createResultEntry(resAddr, false); - size_t resultIndex = RifEclipseInputFileTools::findOrCreateResult(resultName, caseData); - if (resultIndex == cvf::UNDEFINED_SIZE_T) return false; + std::vector>& newPropertyData = + caseData->results(RiaDefines::MATRIX_MODEL)->modifiableCellScalarResultTimesteps(resAddr); - std::vector< std::vector >& newPropertyData = caseData->results(RiaDefines::MATRIX_MODEL)->cellScalarResults(resultIndex); newPropertyData.push_back(std::vector()); newPropertyData[0].resize(ecl_kw_get_size(eclipseKeywordData), HUGE_VAL); + ecl_kw_get_data_as_double(eclipseKeywordData, newPropertyData[0].data()); return true; @@ -339,7 +883,7 @@ bool RifEclipseInputFileTools::readDataFromKeyword(ecl_kw_type* eclipseKeywordDa // https://bugreports.qt-project.org/browse/QTBUG-9814 // //-------------------------------------------------------------------------------------------------- -void RifEclipseInputFileTools::findKeywordsOnFile(const QString &fileName, std::vector< RifKeywordAndFilePos >* keywords) +void RifEclipseInputFileTools::findKeywordsOnFile(const QString& fileName, std::vector* keywords) { char buf[1024]; @@ -347,24 +891,24 @@ void RifEclipseInputFileTools::findKeywordsOnFile(const QString &fileName, std:: data.open(QFile::ReadOnly); QString line; - qint64 filepos = -1; - qint64 lineLength = -1; + qint64 filepos = -1; + qint64 lineLength = -1; do { lineLength = data.readLine(buf, sizeof(buf)); if (lineLength > 0) { - line = QString::fromAscii(buf); + line = QString::fromLatin1(buf); if (line.size() && line[0].isLetter()) { RifKeywordAndFilePos keyPos; - filepos = data.pos() - lineLength; + filepos = data.pos() - lineLength; keyPos.filePos = filepos; QString keywordCandidate = line; - int commentStart = keywordCandidate.indexOf("--"); + int commentStart = keywordCandidate.indexOf("--"); if (commentStart > 0) { keywordCandidate = keywordCandidate.left(commentStart); @@ -374,17 +918,17 @@ void RifEclipseInputFileTools::findKeywordsOnFile(const QString &fileName, std:: keyPos.keyword = keywordCandidate; keywords->push_back(keyPos); - //qDebug() << keyPos.keyword << " - " << keyPos.filePos; + // qDebug() << keyPos.keyword << " - " << keyPos.filePos; } } - } - while (lineLength != -1); + } while (lineLength != -1); } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- -void RifEclipseInputFileTools::parseAndReadPathAliasKeyword(const QString &fileName, std::vector< std::pair >* pathAliasDefinitions) +void RifEclipseInputFileTools::parseAndReadPathAliasKeyword(const QString& fileName, + std::vector>* pathAliasDefinitions) { char buf[1024]; @@ -400,11 +944,11 @@ void RifEclipseInputFileTools::parseAndReadPathAliasKeyword(const QString &fileN qint64 lineLength = data.readLine(buf, sizeof(buf)); if (lineLength > 0) { - line = QString::fromAscii(buf); + line = QString::fromLatin1(buf); if (line.size() && (line[0].isLetter() || foundPathsKeyword)) { line = line.trimmed(); - + if (line == gridKeyword) { return; @@ -443,16 +987,16 @@ void RifEclipseInputFileTools::parseAndReadPathAliasKeyword(const QString &fileN } } } - } while (!data.atEnd()); + } while (!data.atEnd()); } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- const std::vector& RifEclipseInputFileTools::invalidPropertyDataKeywords() { static std::vector keywords; - static bool isInitialized = false; + static bool isInitialized = false; if (!isInitialized) { // Related to geometry @@ -461,6 +1005,8 @@ const std::vector& RifEclipseInputFileTools::invalidPropertyDataKeyword keywords.push_back("SPECGRID"); keywords.push_back("MAPAXES"); keywords.push_back("NOECHO"); + keywords.push_back("MAPUNITS"); + keywords.push_back("GRIDUNIT"); keywords.push_back(faultsKeyword); @@ -471,42 +1017,54 @@ const std::vector& RifEclipseInputFileTools::invalidPropertyDataKeyword } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- -void RifEclipseInputFileTools::findGridKeywordPositions(const std::vector< RifKeywordAndFilePos >& keywordsAndFilePos, qint64* coordPos, qint64* zcornPos, qint64* specgridPos, qint64* actnumPos, qint64* mapaxesPos) +void RifEclipseInputFileTools::findGridKeywordPositions(const std::vector& keywords, + qint64* coordPos, + qint64* zcornPos, + qint64* specgridPos, + qint64* actnumPos, + qint64* mapaxesPos, + qint64* gridunitPos) { - CVF_ASSERT(coordPos && zcornPos && specgridPos && actnumPos && mapaxesPos); + CVF_ASSERT(coordPos && zcornPos && specgridPos && actnumPos && mapaxesPos && gridunitPos); size_t i; - for (i = 0; i < keywordsAndFilePos.size(); i++) + for (i = 0; i < keywords.size(); i++) { - if (keywordsAndFilePos[i].keyword == "COORD") + if (keywords[i].keyword == "COORD") + { + *coordPos = keywords[i].filePos; + } + else if (keywords[i].keyword == "ZCORN") { - *coordPos = keywordsAndFilePos[i].filePos; + *zcornPos = keywords[i].filePos; } - else if (keywordsAndFilePos[i].keyword == "ZCORN") + else if (keywords[i].keyword == "SPECGRID") { - *zcornPos = keywordsAndFilePos[i].filePos; + *specgridPos = keywords[i].filePos; } - else if (keywordsAndFilePos[i].keyword == "SPECGRID") + else if (keywords[i].keyword == "ACTNUM") { - *specgridPos = keywordsAndFilePos[i].filePos; + *actnumPos = keywords[i].filePos; } - else if (keywordsAndFilePos[i].keyword == "ACTNUM") + else if (keywords[i].keyword == "MAPAXES") { - *actnumPos = keywordsAndFilePos[i].filePos; + *mapaxesPos = keywords[i].filePos; } - else if (keywordsAndFilePos[i].keyword == "MAPAXES") + else if (keywords[i].keyword == "GRIDUNIT") { - *mapaxesPos = keywordsAndFilePos[i].filePos; + *gridunitPos = keywords[i].filePos; } } } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- -void RifEclipseInputFileTools::readFaults(const QString& fileName, const std::vector& fileKeywords, cvf::Collection* faults) +void RifEclipseInputFileTools::readFaults(const QString& fileName, + const std::vector& fileKeywords, + cvf::Collection* faults) { QFile data(fileName); if (!data.open(QFile::ReadOnly)) @@ -538,7 +1096,7 @@ void RifEclipseInputFileTools::readFaults(const QString& fileName, const std::ve } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RifEclipseInputFileTools::parseAndReadFaults(const QString& fileName, cvf::Collection* faults) { @@ -558,9 +1116,12 @@ void RifEclipseInputFileTools::parseAndReadFaults(const QString& fileName, cvf:: } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- -void RifEclipseInputFileTools::readFaultsInGridSection(const QString& fileName, cvf::Collection* faults, std::vector* filenamesWithFaults, const QString& faultIncludeFileAbsolutePathPrefix) +void RifEclipseInputFileTools::readFaultsInGridSection(const QString& fileName, + cvf::Collection* faults, + std::vector* filenamesWithFaults, + const QString& faultIncludeFileAbsolutePathPrefix) { QFile data(fileName); if (!data.open(QFile::ReadOnly)) @@ -577,15 +1138,20 @@ void RifEclipseInputFileTools::readFaultsInGridSection(const QString& fileName, bool isEditKeywordDetected = false; - std::vector< std::pair > pathAliasDefinitions; + std::vector> pathAliasDefinitions; parseAndReadPathAliasKeyword(fileName, &pathAliasDefinitions); - readFaultsAndParseIncludeStatementsRecursively(data, gridPos, pathAliasDefinitions, faults, filenamesWithFaults, &isEditKeywordDetected, faultIncludeFileAbsolutePathPrefix); + readFaultsAndParseIncludeStatementsRecursively(data, + gridPos, + pathAliasDefinitions, + faults, + filenamesWithFaults, + &isEditKeywordDetected, + faultIncludeFileAbsolutePathPrefix); } - //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- size_t RifEclipseInputFileTools::findFaultByName(const cvf::Collection& faults, const QString& name) { @@ -601,7 +1167,7 @@ size_t RifEclipseInputFileTools::findFaultByName(const cvf::Collection } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- qint64 RifEclipseInputFileTools::findKeyword(const QString& keyword, QFile& file, qint64 startPos) { @@ -609,7 +1175,7 @@ qint64 RifEclipseInputFileTools::findKeyword(const QString& keyword, QFile& file file.seek(startPos); - do + do { line = file.readLine(); line = line.trimmed(); @@ -626,26 +1192,11 @@ qint64 RifEclipseInputFileTools::findKeyword(const QString& keyword, QFile& file } while (!file.atEnd()); - return -1; } //-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -size_t RifEclipseInputFileTools::findOrCreateResult(const QString& newResultName, RigEclipseCaseData* reservoir) -{ - size_t resultIndex = reservoir->results(RiaDefines::MATRIX_MODEL)->findScalarResultIndex(newResultName); - if (resultIndex == cvf::UNDEFINED_SIZE_T) - { - resultIndex = reservoir->results(RiaDefines::MATRIX_MODEL)->findOrCreateScalarResultIndex(RiaDefines::INPUT_PROPERTY, newResultName, false); - } - - return resultIndex; -} - -//-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- bool RifEclipseInputFileTools::isValidDataKeyword(const QString& keyword) { @@ -662,15 +1213,64 @@ bool RifEclipseInputFileTools::isValidDataKeyword(const QString& keyword) } //-------------------------------------------------------------------------------------------------- -/// +/// +//-------------------------------------------------------------------------------------------------- +void RifEclipseInputFileTools::writeFaultLine(QTextStream& stream, + QString faultName, + size_t i, + size_t j, + size_t startK, + size_t endK, + cvf::StructGridInterface::FaceType faceType) +{ + // Convert indices to eclipse format + i++; + j++; + startK++; + endK++; + + stream << "'" << faultName << "'" + << " " << i << " " << i << " " << j << " " << j << " " << startK << " " << endK << " " + << faultFaceText(faceType) << " / "; + stream << endl; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RifEclipseInputFileTools::faultFaceText(cvf::StructGridInterface::FaceType faceType) +{ + switch (faceType) + { + case cvf::StructGridInterface::POS_I: + return QString(" I"); + case cvf::StructGridInterface::NEG_I: + return QString("-I"); + case cvf::StructGridInterface::POS_J: + return QString(" J"); + case cvf::StructGridInterface::NEG_J: + return QString("-J"); + case cvf::StructGridInterface::POS_K: + return QString(" K"); + case cvf::StructGridInterface::NEG_K: + return QString("-K"); + default: + CVF_ASSERT(false); + } + return ""; +} + +//-------------------------------------------------------------------------------------------------- +/// //-------------------------------------------------------------------------------------------------- -bool RifEclipseInputFileTools::readFaultsAndParseIncludeStatementsRecursively( QFile& file, - qint64 startPos, - const std::vector< std::pair >& pathAliasDefinitions, - cvf::Collection* faults, - std::vector* filenamesWithFaults, - bool* isEditKeywordDetected, - const QString& faultIncludeFileAbsolutePathPrefix) +bool RifEclipseInputFileTools::readFaultsAndParseIncludeStatementsRecursively( + QFile& file, + qint64 startPos, + const std::vector>& pathAliasDefinitions, + cvf::Collection* faults, + std::vector* filenamesWithFaults, + bool* isEditKeywordDetected, + const QString& faultIncludeFileAbsolutePathPrefix) { QString line; @@ -681,7 +1281,7 @@ bool RifEclipseInputFileTools::readFaultsAndParseIncludeStatementsRecursively( bool continueParsing = true; - do + do { line = file.readLine(); line = line.trimmed(); @@ -712,7 +1312,7 @@ bool RifEclipseInputFileTools::readFaultsAndParseIncludeStatementsRecursively( } int firstQuote = line.indexOf("'"); - int lastQuote = line.lastIndexOf("'"); + int lastQuote = line.lastIndexOf("'"); if (!(firstQuote < 0 || lastQuote < 0 || firstQuote == lastQuote)) { @@ -721,7 +1321,7 @@ bool RifEclipseInputFileTools::readFaultsAndParseIncludeStatementsRecursively( QFileInfo fi(file.fileName()); currentFileFolder = fi.absoluteDir(); } - + // Read include file name, and both relative and absolute path is supported QString includeFilename = line.mid(firstQuote + 1, lastQuote - firstQuote - 1); @@ -743,12 +1343,18 @@ bool RifEclipseInputFileTools::readFaultsAndParseIncludeStatementsRecursively( if (fi.exists()) { QString absoluteFilename = fi.canonicalFilePath(); - QFile includeFile(absoluteFilename); + QFile includeFile(absoluteFilename); if (includeFile.open(QFile::ReadOnly)) { - //qDebug() << "Found include statement, and start parsing of\n " << absoluteFilename; - - if (!readFaultsAndParseIncludeStatementsRecursively(includeFile, 0, pathAliasDefinitions, faults, filenamesWithFaults, isEditKeywordDetected, faultIncludeFileAbsolutePathPrefix)) + // qDebug() << "Found include statement, and start parsing of\n " << absoluteFilename; + + if (!readFaultsAndParseIncludeStatementsRecursively(includeFile, + 0, + pathAliasDefinitions, + faults, + filenamesWithFaults, + isEditKeywordDetected, + faultIncludeFileAbsolutePathPrefix)) { qDebug() << "Error when parsing include file : " << absoluteFilename; } @@ -776,12 +1382,217 @@ bool RifEclipseInputFileTools::readFaultsAndParseIncludeStatementsRecursively( } } while (continueParsing); - + return true; } //-------------------------------------------------------------------------------------------------- -/// +/// +//-------------------------------------------------------------------------------------------------- +bool RifEclipseInputFileTools::readKeywordAndParseIncludeStatementsRecursively( + const QString& keyword, + const QString& keywordToStopParsing, + QFile& file, + qint64 startPos, + const std::vector>& pathAliasDefinitions, + QStringList* keywordDataContent, + std::vector* filenamesContainingKeyword, + bool* isStopParsingKeywordDetected, + const QString& faultIncludeFileAbsolutePathPrefix /* rename to includeStatementAbsolutePathPrefix */) +{ + QString line; + + if (!file.seek(startPos)) + { + return false; + } + + bool continueParsing = true; + + do + { + line = file.readLine(); + line = line.trimmed(); + + if (line.startsWith("--", Qt::CaseInsensitive)) + { + continue; + } + + if (!keywordToStopParsing.isEmpty() && line.startsWith(keywordToStopParsing, Qt::CaseInsensitive)) + { + if (isStopParsingKeywordDetected) + { + *isStopParsingKeywordDetected = true; + } + + return false; + } + + if (line.startsWith(includeKeyword, Qt::CaseInsensitive)) + { + line = file.readLine(); + line = line.trimmed(); + + while (line.startsWith("--", Qt::CaseInsensitive)) + { + line = file.readLine(); + line = line.trimmed(); + } + + int firstQuote = line.indexOf("'"); + int lastQuote = line.lastIndexOf("'"); + + if (!(firstQuote < 0 || lastQuote < 0 || firstQuote == lastQuote)) + { + QDir currentFileFolder; + { + QFileInfo fi(file.fileName()); + currentFileFolder = fi.absoluteDir(); + } + + // Read include file name, and both relative and absolute path is supported + QString includeFilename = line.mid(firstQuote + 1, lastQuote - firstQuote - 1); + + for (auto entry : pathAliasDefinitions) + { + QString textToReplace = "$" + entry.first; + includeFilename.replace(textToReplace, entry.second); + } + +#ifdef WIN32 + if (includeFilename.startsWith('/')) + { + // Absolute UNIX path, prefix on Windows + includeFilename = faultIncludeFileAbsolutePathPrefix + includeFilename; + } +#endif + + QFileInfo fi(currentFileFolder, includeFilename); + if (fi.exists()) + { + QString absoluteFilename = fi.canonicalFilePath(); + QFile includeFile(absoluteFilename); + if (includeFile.open(QFile::ReadOnly)) + { + // qDebug() << "Found include statement, and start parsing of\n " << absoluteFilename; + + if (!readKeywordAndParseIncludeStatementsRecursively(keyword, + keywordToStopParsing, + includeFile, + 0, + pathAliasDefinitions, + keywordDataContent, + filenamesContainingKeyword, + isStopParsingKeywordDetected, + faultIncludeFileAbsolutePathPrefix)) + { + qDebug() << "Error when parsing include file : " << absoluteFilename; + } + } + } + } + } + else if (line.startsWith(keyword, Qt::CaseInsensitive)) + { + if (!line.contains("/")) + { + readKeywordDataContent(file, file.pos(), keywordDataContent, isStopParsingKeywordDetected); + filenamesContainingKeyword->push_back(file.fileName()); + } + } + + if (isStopParsingKeywordDetected && *isStopParsingKeywordDetected) + { + continueParsing = false; + } + + if (file.atEnd()) + { + continueParsing = false; + } + + } while (continueParsing); + + return true; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RifEclipseInputFileTools::readKeywordDataContent(QFile& data, + qint64 filePos, + QStringList* textContent, + bool* isEditKeywordDetected) +{ + if (!data.seek(filePos)) + { + return; + } + + // This function assumes the keyword is read from file, and the file pointer is pointing to the first line containing data for + // the keyword + + do + { + QString line = data.readLine(); + line = line.trimmed(); + + if (line.startsWith("--", Qt::CaseInsensitive)) + { + // Skip comment lines + continue; + } + else if (line.startsWith("/", Qt::CaseInsensitive)) + { + // Detected end of keyword data section + return; + } + else if (line.startsWith(editKeyword, Qt::CaseInsensitive)) + { + // End parsing when edit keyword is detected + + if (isEditKeywordDetected) + { + *isEditKeywordDetected = true; + } + + return; + } + + textContent->push_back(line); + + } while (!data.atEnd()); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RiaEclipseUnitTools::UnitSystem RifEclipseInputFileTools::readUnitSystem(QFile& file, qint64 gridunitPos) +{ + bool stopParsing = false; + QStringList unitText; + readKeywordDataContent(file, gridunitPos, &unitText, &stopParsing); + for (QString unitString : unitText) + { + if (unitString.contains("FEET", Qt::CaseInsensitive)) + { + return RiaEclipseUnitTools::UNITS_FIELD; + } + else if (unitString.contains("CM", Qt::CaseInsensitive)) + { + return RiaEclipseUnitTools::UNITS_LAB; + } + else if (unitString.contains("MET", Qt::CaseInsensitive)) + { + return RiaEclipseUnitTools::UNITS_METRIC; + } + } + return RiaEclipseUnitTools::UNITS_UNKNOWN; +} + +//-------------------------------------------------------------------------------------------------- +/// //-------------------------------------------------------------------------------------------------- cvf::StructGridInterface::FaceEnum RifEclipseInputFileTools::faceEnumFromText(const QString& faceString) { @@ -794,7 +1605,7 @@ cvf::StructGridInterface::FaceEnum RifEclipseInputFileTools::faceEnumFromText(co if (firstTwoChars == "X+" || firstTwoChars == "I+") return cvf::StructGridInterface::POS_I; if (firstTwoChars == "Y+" || firstTwoChars == "J+") return cvf::StructGridInterface::POS_J; if (firstTwoChars == "Z+" || firstTwoChars == "K+") return cvf::StructGridInterface::POS_K; - + if (firstTwoChars == "X-" || firstTwoChars == "I-") return cvf::StructGridInterface::NEG_I; if (firstTwoChars == "Y-" || firstTwoChars == "J-") return cvf::StructGridInterface::NEG_J; if (firstTwoChars == "Z-" || firstTwoChars == "K-") return cvf::StructGridInterface::NEG_K; @@ -817,7 +1628,10 @@ cvf::StructGridInterface::FaceEnum RifEclipseInputFileTools::faceEnumFromText(co /// Parse content of this keyword until end of file or /// end of keyword when a single line with '/' is found //-------------------------------------------------------------------------------------------------- -void RifEclipseInputFileTools::readFaults(QFile &data, qint64 filePos, cvf::Collection* faults, bool* isEditKeywordDetected) +void RifEclipseInputFileTools::readFaults(QFile& data, + qint64 filePos, + cvf::Collection* faults, + bool* isEditKeywordDetected) { if (!data.seek(filePos)) { @@ -828,10 +1642,10 @@ void RifEclipseInputFileTools::readFaults(QFile &data, qint64 filePos, cvf::Coll RigFault* fault = nullptr; - do + do { QString line = data.readLine(); - line = line.trimmed(); + line = line.trimmed(); if (line.startsWith("--", Qt::CaseInsensitive)) { @@ -858,16 +1672,47 @@ void RifEclipseInputFileTools::readFaults(QFile &data, qint64 filePos, cvf::Coll // Replace tab with space to be able to split the string using space as splitter line.replace("\t", " "); - // Remove character ' used to mark start and end of fault name, possibly also around face definition; 'I+' - line.remove("'"); + QStringList entries; + bool insideQuotes = false; + QString column; + for (int i = 0; i < line.length(); ++i) + { + if (line[i] == '\'') + { + insideQuotes = !insideQuotes; + } + else if (line[i] == ' ' && !insideQuotes) + { + if (column.length() > 0) + { + entries.push_back(column); + } + column.clear(); + } + else + { + column += line[i]; + } + } - QStringList entries = line.split(" ", QString::SkipEmptyParts); if (entries.size() < 8) { continue; } - QString name = entries[0]; + QString faultName = entries[0]; + + if (faultName.contains(' ')) + { + RiaLogging::error(QString("Fault name '%1' contains spaces").arg(faultName)); + continue; + } + else if (faultName.length() > 8) + { + // Keep going anyway, eclipse files sometimes have longer than + // the specified 8 characters in the name without Eclipse complaining + RiaLogging::warning(QString("Fault name '%1' is longer than 8 characters").arg(faultName)); + } int i1, i2, j1, j2, k1, k2; i1 = entries[1].toInt(); @@ -883,19 +1728,24 @@ void RifEclipseInputFileTools::readFaults(QFile &data, qint64 filePos, cvf::Coll // Adjust from 1-based to 0-based cell indices // Guard against invalid cell ranges by limiting lowest possible range value to zero - cvf::CellRange cellrange(CVF_MAX(i1 - 1, 0), CVF_MAX(j1 - 1, 0), CVF_MAX(k1 - 1, 0), CVF_MAX(i2 - 1, 0), CVF_MAX(j2 - 1, 0), CVF_MAX(k2 - 1, 0)); - - if (!(fault && fault->name() == name)) + cvf::CellRange cellrange(CVF_MAX(i1 - 1, 0), + CVF_MAX(j1 - 1, 0), + CVF_MAX(k1 - 1, 0), + CVF_MAX(i2 - 1, 0), + CVF_MAX(j2 - 1, 0), + CVF_MAX(k2 - 1, 0)); + + if (!(fault && fault->name() == faultName)) { - if (findFaultByName(*faults, name) == cvf::UNDEFINED_SIZE_T) + if (findFaultByName(*faults, faultName) == cvf::UNDEFINED_SIZE_T) { RigFault* newFault = new RigFault; - newFault->setName(name); + newFault->setName(faultName); faults->push_back(newFault); } - size_t faultIndex = findFaultByName(*faults, name); + size_t faultIndex = findFaultByName(*faults, faultName); if (faultIndex == cvf::UNDEFINED_SIZE_T) { CVF_ASSERT(faultIndex != cvf::UNDEFINED_SIZE_T); diff --git a/ApplicationCode/FileInterface/RifEclipseInputFileTools.h b/ApplicationCode/FileInterface/RifEclipseInputFileTools.h index ca6f40b348..717bd37e2f 100644 --- a/ApplicationCode/FileInterface/RifEclipseInputFileTools.h +++ b/ApplicationCode/FileInterface/RifEclipseInputFileTools.h @@ -24,6 +24,7 @@ #include "cvfObject.h" #include "cvfCollection.h" +#include "RiaEclipseUnitTools.h" #include "RifReaderInterface.h" #include "RigFault.h" @@ -58,8 +59,46 @@ class RifEclipseInputFileTools : public cvf::Object RifEclipseInputFileTools(); ~RifEclipseInputFileTools() override; - static bool openGridFile(const QString& fileName, RigEclipseCaseData* eclipseCase, bool readFaultData); - + static bool openGridFile(const QString& fileName, RigEclipseCaseData* eclipseCase, bool readFaultData, QString* errorMessages); + + static bool exportGrid(const QString& gridFileName, + RigEclipseCaseData* eclipseCase, + bool exportInLocalCoordinates, + const cvf::UByteArray* cellVisibilityOverrideForActnum = nullptr, + const cvf::Vec3st& min = cvf::Vec3st::ZERO, + const cvf::Vec3st& max = cvf::Vec3st::UNDEFINED, + const cvf::Vec3st& refinement = cvf::Vec3st(1, 1, 1)); + + static bool exportKeywords(const QString& resultFileName, + RigEclipseCaseData* eclipseCase, + const std::vector& keywords, + const QString& fileWriteMode, + const cvf::Vec3st& min = cvf::Vec3st::ZERO, + const cvf::Vec3st& max = cvf::Vec3st::UNDEFINED, + const cvf::Vec3st& refinement = cvf::Vec3st(1, 1, 1)); + + static void saveFault(QString completeFilename, + const RigMainGrid* mainGrid, + const std::vector& faultFaces, + QString faultName, + const cvf::Vec3st& min = cvf::Vec3st::ZERO, + const cvf::Vec3st& max = cvf::Vec3st::UNDEFINED, + const cvf::Vec3st& refinement = cvf::Vec3st(1, 1, 1)); + + static void saveFault(QTextStream& stream, + const RigMainGrid* mainGrid, + const std::vector& faultFaces, + QString faultName, + const cvf::Vec3st& min = cvf::Vec3st::ZERO, + const cvf::Vec3st& max = cvf::Vec3st::UNDEFINED, + const cvf::Vec3st& refinement = cvf::Vec3st(1, 1, 1)); + + static void saveFaults(QTextStream& stream, + const RigMainGrid* mainGrid, + const cvf::Vec3st& min = cvf::Vec3st::ZERO, + const cvf::Vec3st& max = cvf::Vec3st::UNDEFINED, + const cvf::Vec3st& refinement = cvf::Vec3st(1, 1, 1)); + // Returns map of assigned resultName and Eclipse Keyword. static std::map readProperties(const QString& fileName, RigEclipseCaseData* eclipseCase); static bool readProperty (const QString& fileName, RigEclipseCaseData* eclipseCase, const QString& eclipseKeyWord, const QString& resultName ); @@ -82,18 +121,41 @@ class RifEclipseInputFileTools : public cvf::Object bool* isEditKeywordDetected, const QString& faultIncludeFileAbsolutePathPrefix); + static bool readKeywordAndParseIncludeStatementsRecursively(const QString& keyword, + const QString& keywordToStopParsing, + QFile& file, + qint64 startPos, + const std::vector< std::pair >& pathAliasDefinitions, + QStringList* keywordDataContent, + std::vector* filenamesContainingKeyword, + bool* isEditKeywordDetected, + const QString& faultIncludeFileAbsolutePathPrefix // rename to includeStatementAbsolutePathPrefix + ); + + static void readKeywordDataContent(QFile &data, qint64 filePos, QStringList* textContent, bool* isEditKeywordDetected); + static RiaEclipseUnitTools::UnitSystem readUnitSystem(QFile& file, qint64 gridunitPos); + static cvf::StructGridInterface::FaceEnum faceEnumFromText(const QString& faceString); private: - static bool readDataFromKeyword(ecl_kw_type* eclipseKeywordData, RigEclipseCaseData* caseData, const QString& resultName); - static void findGridKeywordPositions(const std::vector< RifKeywordAndFilePos >& keywords, qint64* coordPos, qint64* zcornPos, qint64* specgridPos, qint64* actnumPos, qint64* mapaxesPos); + static bool readDataFromKeyword(ecl_kw_type* eclipseKeywordData, RigEclipseCaseData* caseData, const QString& resultName, QString* errMsg); + static void findGridKeywordPositions(const std::vector< RifKeywordAndFilePos >& keywords, qint64* coordPos, qint64* zcornPos, qint64* specgridPos, qint64* actnumPos, qint64* mapaxesPos, qint64* gridunitPos); static size_t findFaultByName(const cvf::Collection& faults, const QString& name); static qint64 findKeyword(const QString& keyword, QFile& file, qint64 startPos); - static size_t findOrCreateResult(const QString& newResultName, RigEclipseCaseData* reservoir); static bool isValidDataKeyword(const QString& keyword); + + static void writeFaultLine(QTextStream& stream, + QString faultName, + size_t i, + size_t j, + size_t startK, + size_t endK, + cvf::StructGridInterface::FaceType faceType); + + static QString faultFaceText(cvf::StructGridInterface::FaceType faceType); private: - static const std::vector& invalidPropertyDataKeywords(); + static const std::vector& invalidPropertyDataKeywords(); }; diff --git a/ApplicationCode/FileInterface/RifEclipseOutputFileTools.cpp b/ApplicationCode/FileInterface/RifEclipseOutputFileTools.cpp index d8d70e4d7b..8d05154f7b 100644 --- a/ApplicationCode/FileInterface/RifEclipseOutputFileTools.cpp +++ b/ApplicationCode/FileInterface/RifEclipseOutputFileTools.cpp @@ -35,10 +35,11 @@ #include "cvfMath.h" +#include #include #include -#include +#include #include @@ -282,6 +283,25 @@ bool RifEclipseOutputFileTools::isValidEclipseFileName(const QString& fileName) return ecl_util_valid_basename(RiaStringEncodingTools::toNativeEncoded(fileNameBase).data()); } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QByteArray RifEclipseOutputFileTools::md5sum(const QString& fileName) +{ + QFile file(fileName); + if (file.open(QFile::ReadOnly)) + { + QCryptographicHash hash(QCryptographicHash::Md5); + QByteArray fileContent = file.readAll(); + if (!fileContent.isEmpty()) + { + hash.addData(fileContent); + return hash.result(); + } + } + return QByteArray(); +} + //-------------------------------------------------------------------------------------------------- /// Get set of Eclipse files based on an input file and its path //-------------------------------------------------------------------------------------------------- @@ -524,6 +544,26 @@ ecl_kw_type* RifEclipseOutputFileTools::createActnumFromPorv(ecl_file_type* ecl_ return nullptr; } +//-------------------------------------------------------------------------------------------------- +/// Convenience method to hide C fopen calls in #pragma declarations to avoid warnings on Windows +//-------------------------------------------------------------------------------------------------- +FILE* RifEclipseOutputFileTools::fopen(const QString& filePath, const QString& mode) +{ +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable : 4996) +#endif + + FILE* filePtr = std::fopen(RiaStringEncodingTools::toNativeEncoded(filePath).data(), RiaStringEncodingTools::toNativeEncoded(mode).data()); + +#ifdef _MSC_VER +#pragma warning(pop) +#endif + + return filePtr; + +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/FileInterface/RifEclipseOutputFileTools.h b/ApplicationCode/FileInterface/RifEclipseOutputFileTools.h index 276e051cd4..0486cfd337 100644 --- a/ApplicationCode/FileInterface/RifEclipseOutputFileTools.h +++ b/ApplicationCode/FileInterface/RifEclipseOutputFileTools.h @@ -36,7 +36,7 @@ typedef struct ecl_file_struct ecl_file_type; class RifEclipseRestartDataAccess; - +class QByteArray; //================================================================================================== // @@ -57,6 +57,7 @@ class RifEclipseOutputFileTools static void timeSteps(ecl_file_type* ecl_file, std::vector* timeSteps, std::vector* daysSinceSimulationStart); static bool isValidEclipseFileName(const QString& fileName); + static QByteArray md5sum(const QString& fileName); static bool findSiblingFilesWithSameBaseName(const QString& fileName, QStringList* fileSet); static QString firstFileNameOfType(const QStringList& fileSet, ecl_file_enum fileType); @@ -79,6 +80,8 @@ class RifEclipseOutputFileTools static ecl_kw_type* createActnumFromPorv(ecl_file_type* ecl_file); + static FILE* fopen(const QString& filePath, const QString& mode); + private: static void createReportStepsMetaData(std::vector ecl_files, std::vector* reportSteps); }; diff --git a/ApplicationCode/FileInterface/RifEclipseRestartFilesetAccess.cpp b/ApplicationCode/FileInterface/RifEclipseRestartFilesetAccess.cpp index 2713e12d80..db4462689c 100644 --- a/ApplicationCode/FileInterface/RifEclipseRestartFilesetAccess.cpp +++ b/ApplicationCode/FileInterface/RifEclipseRestartFilesetAccess.cpp @@ -189,7 +189,7 @@ bool RifEclipseRestartFilesetAccess::results(const QString& resultName, size_t t return false; } - size_t fileGridCount = ecl_file_get_num_named_kw(m_ecl_files[timeStep], resultName.toAscii().data()); + size_t fileGridCount = ecl_file_get_num_named_kw(m_ecl_files[timeStep], resultName.toLatin1().data()); // No results for this result variable for current time step found if (fileGridCount == 0) return true; diff --git a/ApplicationCode/FileInterface/RifEclipseRftAddress.cpp b/ApplicationCode/FileInterface/RifEclipseRftAddress.cpp index 633c887b17..a6e9c57580 100644 --- a/ApplicationCode/FileInterface/RifEclipseRftAddress.cpp +++ b/ApplicationCode/FileInterface/RifEclipseRftAddress.cpp @@ -1,17 +1,17 @@ ///////////////////////////////////////////////////////////////////////////////// // // Copyright (C) 2017 Statoil ASA -// +// // ResInsight 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 3 of the License, or // (at your option) any later version. -// +// // ResInsight 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 at +// +// See the GNU General Public License at // for more details. // ///////////////////////////////////////////////////////////////////////////////// @@ -19,10 +19,11 @@ #include "RifEclipseRftAddress.h" //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- -RifEclipseRftAddress::RifEclipseRftAddress(QString wellName, QDateTime timeStep, RftWellLogChannelType wellLogChannelName) : - m_wellName(wellName), m_wellLogChannel(wellLogChannelName) +RifEclipseRftAddress::RifEclipseRftAddress(QString wellName, QDateTime timeStep, RftWellLogChannelType wellLogChannelName) + : m_wellName(wellName) + , m_wellLogChannel(wellLogChannelName) { timeStep.setTimeSpec(Qt::TimeSpec::UTC); @@ -31,19 +32,19 @@ RifEclipseRftAddress::RifEclipseRftAddress(QString wellName, QDateTime timeStep, } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- bool operator==(const RifEclipseRftAddress& first, const RifEclipseRftAddress& second) { if (first.wellName() != second.wellName()) return false; if (first.timeStep() != second.timeStep()) return false; if (first.wellLogChannel() != second.wellLogChannel()) return false; - + return true; } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- bool operator<(const RifEclipseRftAddress& first, const RifEclipseRftAddress& second) { @@ -53,4 +54,3 @@ bool operator<(const RifEclipseRftAddress& first, const RifEclipseRftAddress& se return false; } - diff --git a/ApplicationCode/FileInterface/RifEclipseRftAddress.h b/ApplicationCode/FileInterface/RifEclipseRftAddress.h index 12e2157438..d10dcebbbc 100644 --- a/ApplicationCode/FileInterface/RifEclipseRftAddress.h +++ b/ApplicationCode/FileInterface/RifEclipseRftAddress.h @@ -21,6 +21,7 @@ #include #include +#include #include @@ -52,6 +53,16 @@ class RifEclipseRftAddress QDateTime timeStep() const { return m_timeStep; } const RftWellLogChannelType& wellLogChannel() const { return m_wellLogChannel; } + static std::set rftPlotChannelTypes() + { + return {RifEclipseRftAddress::PRESSURE}; + } + + static std::set pltPlotChannelTypes() + { + return {RifEclipseRftAddress::ORAT, RifEclipseRftAddress::WRAT, RifEclipseRftAddress::GRAT}; + } + private: QString m_wellName; QDateTime m_timeStep; diff --git a/ApplicationCode/FileInterface/RifEclipseSummaryTools.cpp b/ApplicationCode/FileInterface/RifEclipseSummaryTools.cpp index 59e1b9a1cc..d829d64948 100644 --- a/ApplicationCode/FileInterface/RifEclipseSummaryTools.cpp +++ b/ApplicationCode/FileInterface/RifEclipseSummaryTools.cpp @@ -81,8 +81,6 @@ void RifEclipseSummaryTools::findSummaryFiles(const QString& inputFile, } } stringlist_free(summary_file_list); - - return; } //-------------------------------------------------------------------------------------------------- @@ -92,7 +90,6 @@ QString RifEclipseSummaryTools::findGridCaseFileFromSummaryHeaderFile(const QStr { char* myPath = nullptr; char* myBase = nullptr; - bool formattedFile = true; util_alloc_file_components(RiaStringEncodingTools::toNativeEncoded(QDir::toNativeSeparators(summaryHeaderFile)).data(), &myPath, &myBase, nullptr); @@ -100,10 +97,6 @@ QString RifEclipseSummaryTools::findGridCaseFileFromSummaryHeaderFile(const QStr if (!caseFile) { caseFile= ecl_util_alloc_exfilename(myPath, myBase, ECL_EGRID_FILE, false, -1); - if (caseFile) - { - formattedFile = false; - } } QString gridCaseFile; diff --git a/ApplicationCode/FileInterface/RifEclipseUnifiedRestartFileAccess.cpp b/ApplicationCode/FileInterface/RifEclipseUnifiedRestartFileAccess.cpp index 2961776e32..3a043ed8b3 100644 --- a/ApplicationCode/FileInterface/RifEclipseUnifiedRestartFileAccess.cpp +++ b/ApplicationCode/FileInterface/RifEclipseUnifiedRestartFileAccess.cpp @@ -249,7 +249,7 @@ bool RifEclipseUnifiedRestartFileAccess::results(const QString& resultName, size { ecl_file_select_block(m_ecl_file, INTEHEAD_KW, static_cast(timeStep * gridCount + i)); - int namedKeywordCount = ecl_file_get_num_named_kw(m_ecl_file, resultName.toAscii().data()); + int namedKeywordCount = ecl_file_get_num_named_kw(m_ecl_file, resultName.toLatin1().data()); for (int iOcc = 0; iOcc < namedKeywordCount; iOcc++) { std::vector partValues; diff --git a/ApplicationCode/FileInterface/RifEclipseUserDataParserTools.cpp b/ApplicationCode/FileInterface/RifEclipseUserDataParserTools.cpp index 6c61050100..b161667960 100644 --- a/ApplicationCode/FileInterface/RifEclipseUserDataParserTools.cpp +++ b/ApplicationCode/FileInterface/RifEclipseUserDataParserTools.cpp @@ -668,7 +668,6 @@ std::vector RifEclipseUserDataParserTools::columnInfoFromColumnHeaders(c std::string quantity = columnLines[0]; std::string unit; - std::string scaling; size_t startIndex = 1; @@ -681,7 +680,7 @@ std::vector RifEclipseUserDataParserTools::columnInfoFromColumnHeaders(c if (isScalingDetected) { - scaling = columnLines[2]; + //std::string scaling = columnLines[2]; startIndex = 3; } diff --git a/ApplicationCode/FileInterface/RifElementPropertyReader.cpp b/ApplicationCode/FileInterface/RifElementPropertyReader.cpp index f3a339308c..2c43a5f406 100644 --- a/ApplicationCode/FileInterface/RifElementPropertyReader.cpp +++ b/ApplicationCode/FileInterface/RifElementPropertyReader.cpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018- Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by diff --git a/ApplicationCode/FileInterface/RifElementPropertyReader.h b/ApplicationCode/FileInterface/RifElementPropertyReader.h index fc9227447b..648af4f5e1 100644 --- a/ApplicationCode/FileInterface/RifElementPropertyReader.h +++ b/ApplicationCode/FileInterface/RifElementPropertyReader.h @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018- Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by diff --git a/ApplicationCode/FileInterface/RifEnsembleStatisticsReader.cpp b/ApplicationCode/FileInterface/RifEnsembleStatisticsReader.cpp index 8e57ac02bd..2a766988c2 100644 --- a/ApplicationCode/FileInterface/RifEnsembleStatisticsReader.cpp +++ b/ApplicationCode/FileInterface/RifEnsembleStatisticsReader.cpp @@ -1,17 +1,17 @@ ///////////////////////////////////////////////////////////////////////////////// // // Copyright (C) 2017- Statoil ASA -// +// // ResInsight 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 3 of the License, or // (at your option) any later version. -// +// // ResInsight 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 at +// +// See the GNU General Public License at // for more details. // ///////////////////////////////////////////////////////////////////////////////// @@ -20,11 +20,10 @@ #include "RimEnsembleStatisticsCase.h" - static const std::vector EMPTY_TIME_STEPS_VECTOR; //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- RifEnsembleStatisticsReader::RifEnsembleStatisticsReader(RimEnsembleStatisticsCase* ensStatCase) { @@ -33,16 +32,14 @@ RifEnsembleStatisticsReader::RifEnsembleStatisticsReader(RimEnsembleStatisticsCa m_ensembleStatCase = ensStatCase; m_allResultAddresses = std::set( - { - RifEclipseSummaryAddress::ensembleStatisticsAddress(ENSEMBLE_STAT_P10_QUANTITY_NAME, ""), - RifEclipseSummaryAddress::ensembleStatisticsAddress(ENSEMBLE_STAT_P50_QUANTITY_NAME, ""), - RifEclipseSummaryAddress::ensembleStatisticsAddress(ENSEMBLE_STAT_P90_QUANTITY_NAME, ""), - RifEclipseSummaryAddress::ensembleStatisticsAddress(ENSEMBLE_STAT_MEAN_QUANTITY_NAME, "") - }); + {RifEclipseSummaryAddress::ensembleStatisticsAddress(ENSEMBLE_STAT_P10_QUANTITY_NAME, ""), + RifEclipseSummaryAddress::ensembleStatisticsAddress(ENSEMBLE_STAT_P50_QUANTITY_NAME, ""), + RifEclipseSummaryAddress::ensembleStatisticsAddress(ENSEMBLE_STAT_P90_QUANTITY_NAME, ""), + RifEclipseSummaryAddress::ensembleStatisticsAddress(ENSEMBLE_STAT_MEAN_QUANTITY_NAME, "")}); } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- const std::vector& RifEnsembleStatisticsReader::timeSteps(const RifEclipseSummaryAddress& resultAddress) const { @@ -51,30 +48,35 @@ const std::vector& RifEnsembleStatisticsReader::timeSteps(const RifEclip } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- bool RifEnsembleStatisticsReader::values(const RifEclipseSummaryAddress& resultAddress, std::vector* values) const { if (!validateAddress(resultAddress)) return false; - const std::vector* sourceData = nullptr; - auto quantityName = resultAddress.ensembleStatisticsQuantityName(); + const std::vector* sourceData = nullptr; + auto quantityName = resultAddress.ensembleStatisticsQuantityName(); - if (quantityName == ENSEMBLE_STAT_P10_QUANTITY_NAME) sourceData = &m_ensembleStatCase->p10(); - else if (quantityName == ENSEMBLE_STAT_P50_QUANTITY_NAME) sourceData = &m_ensembleStatCase->p50(); - else if (quantityName == ENSEMBLE_STAT_P90_QUANTITY_NAME) sourceData = &m_ensembleStatCase->p90(); - else if (quantityName == ENSEMBLE_STAT_MEAN_QUANTITY_NAME) sourceData = &m_ensembleStatCase->mean(); + if (quantityName == ENSEMBLE_STAT_P10_QUANTITY_NAME) + sourceData = &m_ensembleStatCase->p10(); + else if (quantityName == ENSEMBLE_STAT_P50_QUANTITY_NAME) + sourceData = &m_ensembleStatCase->p50(); + else if (quantityName == ENSEMBLE_STAT_P90_QUANTITY_NAME) + sourceData = &m_ensembleStatCase->p90(); + else if (quantityName == ENSEMBLE_STAT_MEAN_QUANTITY_NAME) + sourceData = &m_ensembleStatCase->mean(); if (!sourceData) return false; values->clear(); values->reserve(sourceData->size()); - for (auto val : *sourceData) values->push_back(val); + for (auto val : *sourceData) + values->push_back(val); return true; } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- std::string RifEnsembleStatisticsReader::unitName(const RifEclipseSummaryAddress& resultAddress) const { @@ -82,10 +84,9 @@ std::string RifEnsembleStatisticsReader::unitName(const RifEclipseSummaryAddress } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- bool RifEnsembleStatisticsReader::validateAddress(const RifEclipseSummaryAddress& address) const { - return address.category() == RifEclipseSummaryAddress::SUMMARY_ENSEMBLE_STATISTICS && - !address.quantityName().empty(); + return address.category() == RifEclipseSummaryAddress::SUMMARY_ENSEMBLE_STATISTICS && !address.quantityName().empty(); } diff --git a/ApplicationCode/FileInterface/RifJsonEncodeDecode.cpp b/ApplicationCode/FileInterface/RifJsonEncodeDecode.cpp index 6b6871f3ac..54facf11ff 100644 --- a/ApplicationCode/FileInterface/RifJsonEncodeDecode.cpp +++ b/ApplicationCode/FileInterface/RifJsonEncodeDecode.cpp @@ -52,7 +52,7 @@ void JsonReader::dumpToFile(std::vector& points, QString filePath) cvf::Vec3d point = points[idx]; QString string; string.sprintf("(%0.10e, %0.10e, %0.10e)\n", point.x(), point.y(), point.z()); - QByteArray byteArray(string.toAscii()); + QByteArray byteArray(string.toLatin1()); file.write(byteArray); } file.close(); diff --git a/ApplicationCode/FileInterface/RifReaderEclipseInput.cpp b/ApplicationCode/FileInterface/RifReaderEclipseInput.cpp index d490da9e13..d1c9dc7572 100644 --- a/ApplicationCode/FileInterface/RifReaderEclipseInput.cpp +++ b/ApplicationCode/FileInterface/RifReaderEclipseInput.cpp @@ -20,6 +20,7 @@ #include "RifReaderEclipseInput.h" +#include "RiaLogging.h" #include "RifEclipseInputFileTools.h" #include "RigEclipseCaseData.h" @@ -74,7 +75,12 @@ bool RifReaderEclipseInput::open(const QString& fileName, RigEclipseCaseData* ec bool isOk = false; if (eclipseCase->mainGrid()->gridPointDimensions() == cvf::Vec3st(0,0,0)) { - isOk = RifEclipseInputFileTools::openGridFile(fileName, eclipseCase, isFaultImportEnabled()); + QString errorMesssages; + isOk = RifEclipseInputFileTools::openGridFile(fileName, eclipseCase, isFaultImportEnabled(), &errorMesssages); + if (!isOk) + { + RiaLogging::error(errorMesssages); + } } return isOk; diff --git a/ApplicationCode/FileInterface/RifReaderEclipseOutput.cpp b/ApplicationCode/FileInterface/RifReaderEclipseOutput.cpp index 47b434f81f..fdf5313d0f 100644 --- a/ApplicationCode/FileInterface/RifReaderEclipseOutput.cpp +++ b/ApplicationCode/FileInterface/RifReaderEclipseOutput.cpp @@ -21,6 +21,7 @@ #include "RifReaderEclipseOutput.h" #include "RiaApplication.h" +#include "RiaCellDividingTools.h" #include "RiaLogging.h" #include "RiaPreferences.h" @@ -37,9 +38,10 @@ #include "RigActiveCellInfo.h" #include "RigCaseCellResultsData.h" #include "RigEclipseCaseData.h" +#include "RigEclipseResultInfo.h" +#include "RigEquil.h" #include "RigMainGrid.h" #include "RigSimWellData.h" -#include "RigEclipseResultInfo.h" #include "cafProgressInfo.h" @@ -125,8 +127,9 @@ bool transferGridCellData(RigMainGrid* mainGrid, RigActiveCellInfo* activeCellIn mainGrid->nodes().resize(nodeStartIndex + cellCount*8, cvf::Vec3d(0,0,0)); int progTicks = 100; - double cellsPrProgressTick = cellCount/(float)progTicks; + int cellsPrProgressTick = std::max(1, cellCount/progTicks); caf::ProgressInfo progInfo(progTicks, ""); + size_t computedCellCount = 0; // Loop over cells and fill them with data @@ -187,10 +190,11 @@ bool transferGridCellData(RigMainGrid* mainGrid, RigActiveCellInfo* activeCellIn //if (!invalid && (cell.isInCoarseCell() || (!cell.isActiveInMatrixModel() && !cell.isActiveInFractureModel()) ) ) cell.setInvalid(cell.isLongPyramidCell()); -#pragma omp atomic - computedCellCount++; - - progInfo.setProgress((int)(computedCellCount/cellsPrProgressTick)); +#pragma omp critical + { + computedCellCount++; + if (computedCellCount % cellsPrProgressTick == 0) progInfo.incrementProgress(); + } } return true; } @@ -303,12 +307,11 @@ bool RifReaderEclipseOutput::transferGeometry(const ecl_grid_type* mainEclGrid, mainGrid->nodes().reserve(8*totalCellCount); caf::ProgressInfo progInfo(3 + numLGRs, ""); - progInfo.setProgressDescription("Main Grid"); - progInfo.setNextProgressIncrement(3); - - transferGridCellData(mainGrid, activeCellInfo, fractureActiveCellInfo, mainGrid, mainEclGrid, 0, 0); - progInfo.setProgress(3); + { + auto task = progInfo.task("Loading Main Grid Data", 3); + transferGridCellData(mainGrid, activeCellInfo, fractureActiveCellInfo, mainGrid, mainEclGrid, 0, 0); + } size_t globalMatrixActiveSize = ecl_grid_get_nactive(mainEclGrid); size_t globalFractureActiveSize = ecl_grid_get_nactive_fracture(mainEclGrid); @@ -324,7 +327,7 @@ bool RifReaderEclipseOutput::transferGeometry(const ecl_grid_type* mainEclGrid, for (lgrIdx = 0; lgrIdx < numLGRs; ++lgrIdx) { - progInfo.setProgressDescription("LGR number " + QString::number(lgrIdx+1)); + auto task = progInfo.task("LGR number " + QString::number(lgrIdx + 1), 1); ecl_grid_type* localEclGrid = ecl_grid_iget_lgr(mainEclGrid, lgrIdx); RigLocalGrid* localGrid = static_cast(mainGrid->gridByIndex(lgrIdx+1)); @@ -341,8 +344,6 @@ bool RifReaderEclipseOutput::transferGeometry(const ecl_grid_type* mainEclGrid, fractureActiveCellInfo->setGridActiveCellCounts(lgrIdx + 1, fractureActiveCellCount); transferCoarseningInfo(localEclGrid, localGrid); - - progInfo.setProgress(3 + lgrIdx); } mainGrid->initAllSubGridsParentGridPointer(); @@ -358,9 +359,7 @@ bool RifReaderEclipseOutput::transferGeometry(const ecl_grid_type* mainEclGrid, bool RifReaderEclipseOutput::open(const QString& fileName, RigEclipseCaseData* eclipseCase) { CVF_ASSERT(eclipseCase); - caf::ProgressInfo progInfo(100, ""); - - progInfo.setProgressDescription("Reading Grid"); + caf::ProgressInfo progress(100, "Reading Grid"); if (!RifEclipseOutputFileTools::isValidEclipseFileName(fileName)) { @@ -370,102 +369,102 @@ bool RifReaderEclipseOutput::open(const QString& fileName, RigEclipseCaseData* e return false; } - // Get set of files QStringList fileSet; - if (!RifEclipseOutputFileTools::findSiblingFilesWithSameBaseName(fileName, &fileSet)) return false; - - m_fileName = fileName; - - progInfo.incrementProgress(); - - progInfo.setNextProgressIncrement(20); - // Keep the set of files of interest - m_filesWithSameBaseName = fileSet; - - openInitFile(); - - // Read geometry - // Todo: Needs to check existence of file before calling ert, else it will abort - ecl_grid_type* mainEclGrid = createMainGrid(); - if (!mainEclGrid) { - QString errorMessage = QString(" Failed to create a main grid from file\n%1").arg(m_fileName); - RiaLogging::error(errorMessage); + auto task = progress.task("Get set of files"); + + if (!RifEclipseOutputFileTools::findSiblingFilesWithSameBaseName(fileName, &fileSet)) return false; - return false; + m_fileName = fileName; } + + ecl_grid_type* mainEclGrid = nullptr; + { + auto task = progress.task("Open Init File and Load Main Grid", 19); + // Keep the set of files of interest + m_filesWithSameBaseName = fileSet; - progInfo.incrementProgress(); + openInitFile(); - progInfo.setNextProgressIncrement(10); - progInfo.setProgressDescription("Transferring grid geometry"); + // Read geometry + // Todo: Needs to check existence of file before calling ert, else it will abort + mainEclGrid = loadMainGrid(); + if (!mainEclGrid) + { + QString errorMessage = QString(" Failed to create a main grid from file\n%1").arg(m_fileName); + RiaLogging::error(errorMessage); - if (!transferGeometry(mainEclGrid, eclipseCase)) return false; + return false; + } + } - progInfo.incrementProgress(); - progInfo.setProgressDescription("Reading faults"); - progInfo.setNextProgressIncrement(10); + { + auto task = progress.task("Transferring grid geometry", 10); + if (!transferGeometry(mainEclGrid, eclipseCase)) return false; + } - if (isFaultImportEnabled()) { - cvf::Collection faults; + auto task = progress.task("Reading faults", 10); - importFaults(fileSet, &faults); + if (isFaultImportEnabled()) + { + cvf::Collection faults; - RigMainGrid* mainGrid = eclipseCase->mainGrid(); - mainGrid->setFaults(faults); - } + importFaults(fileSet, &faults); - progInfo.incrementProgress(); + RigMainGrid* mainGrid = eclipseCase->mainGrid(); + mainGrid->setFaults(faults); + } + } m_eclipseCase = eclipseCase; - // Build results meta data - progInfo.setProgressDescription("Reading Result index"); - progInfo.setNextProgressIncrement(25); - buildMetaData(mainEclGrid); - progInfo.incrementProgress(); - - if (isNNCsEnabled()) { - progInfo.setProgressDescription("Reading NNC data"); - progInfo.setNextProgressIncrement(4); - transferStaticNNCData(mainEclGrid, m_ecl_init_file, eclipseCase->mainGrid()); - progInfo.incrementProgress(); + auto task = progress.task("Reading Results Meta data", 25); + buildMetaData(mainEclGrid); + } - // This test should probably be improved to test more directly for presence of NNC data - if (m_eclipseCase->results(RiaDefines::MATRIX_MODEL)->hasFlowDiagUsableFluxes()) + { + auto task = progress.task("Handling NCC data", 20); + if (isNNCsEnabled()) { - transferDynamicNNCData(mainEclGrid, eclipseCase->mainGrid()); - } - progInfo.incrementProgress(); + caf::ProgressInfo nncProgress(10, ""); + + { + auto subNncTask = nncProgress.task("Reading static NNC data"); + transferStaticNNCData(mainEclGrid, m_ecl_init_file, eclipseCase->mainGrid()); + } - progInfo.setProgressDescription("Processing NNC data"); - progInfo.setNextProgressIncrement(20); - eclipseCase->mainGrid()->nncData()->processConnections( *(eclipseCase->mainGrid())); - progInfo.incrementProgress(); + // This test should probably be improved to test more directly for presence of NNC data + if (m_eclipseCase->results(RiaDefines::MATRIX_MODEL)->hasFlowDiagUsableFluxes()) + { + auto subNncTask = nncProgress.task("Reading dynamic NNC data"); + transferDynamicNNCData(mainEclGrid, eclipseCase->mainGrid()); + } + + { + auto subNncTask = nncProgress.task("Processing connections", 8); + eclipseCase->mainGrid()->nncData()->processConnections(*(eclipseCase->mainGrid())); + } + } } - else + { - progInfo.setNextProgressIncrement(25); - progInfo.incrementProgress(); + auto task = progress.task("Handling well information", 10); + if (!RiaApplication::instance()->preferences()->readerSettings()->skipWellData()) + { + readWellCells(mainEclGrid, isImportOfCompleteMswDataEnabled()); + } + else + { + RiaLogging::info("Skipping import of simulation well data"); + } } - progInfo.setNextProgressIncrement(8); - if (!RiaApplication::instance()->preferences()->readerSettings()->skipWellData()) { - progInfo.setProgressDescription("Reading Well information"); - readWellCells(mainEclGrid, isImportOfCompleteMswDataEnabled()); + auto task = progress.task("Releasing reader memory", 5); + ecl_grid_free(mainEclGrid); } - else - { - RiaLogging::info("Skipping import of simulation well data"); - } - progInfo.incrementProgress(); - - progInfo.setProgressDescription("Releasing reader memory"); - ecl_grid_free( mainEclGrid ); - progInfo.incrementProgress(); return true; } @@ -573,10 +572,12 @@ void RifReaderEclipseOutput::setHdf5FileName(const QString& fileName) } QStringList resultNames = hdf5ReaderInterface->propertyNames(); + for (int i = 0; i < resultNames.size(); ++i) { - size_t resIndex = matrixModelResults->findOrCreateScalarResultIndex(RiaDefines::SOURSIMRL, resultNames[i], false); - matrixModelResults->setTimeStepInfos(resIndex, timeStepInfos); + RigEclipseResultAddress resAddr(RiaDefines::SOURSIMRL, resultNames[i]); + matrixModelResults->createResultEntry(resAddr, false); + matrixModelResults->setTimeStepInfos(resAddr, timeStepInfos); } m_hdfReaderInterface = std::move(hdf5ReaderInterface); @@ -590,6 +591,14 @@ void RifReaderEclipseOutput::setFileDataAccess(RifEclipseRestartDataAccess* rest m_dynamicResultsAccess = restartDataAccess; } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +const size_t* RifReaderEclipseOutput::eclipseCellIndexMapping() +{ + return cellMappingECLRi; +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -623,6 +632,45 @@ void RifReaderEclipseOutput::importFaults(const QStringList& fileSet, cvf::Colle } } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RifReaderEclipseOutput::importEquilData(const QString& deckFileName, + const QString& includeStatementAbsolutePathPrefix, + RigEclipseCaseData* eclipseCase) +{ + QFile data(deckFileName); + if (data.open(QFile::ReadOnly)) + { + const QString keyword("EQUIL"); + const QString keywordToStopParsing("SCHEDULE"); + const qint64 startPositionInFile = 0; + std::vector> pathAliasDefinitions; + QStringList keywordContent; + std::vector fileNamesContainingKeyword; + bool isStopParsingKeywordDetected = false; + + RifEclipseInputFileTools::readKeywordAndParseIncludeStatementsRecursively(keyword, + keywordToStopParsing, + data, + startPositionInFile, + pathAliasDefinitions, + &keywordContent, + &fileNamesContainingKeyword, + &isStopParsingKeywordDetected, + includeStatementAbsolutePathPrefix); + std::vector equilItems; + for (const auto& s : keywordContent) + { + RigEquil equilRec = RigEquil::parseString(s); + + equilItems.push_back(equilRec); + } + + eclipseCase->setEquilData(equilItems); + } +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -855,8 +903,9 @@ void RifReaderEclipseOutput::buildMetaData(ecl_grid_type* grid) for (int i = 0; i < matrixResultNames.size(); ++i) { - size_t resIndex = matrixModelResults->findOrCreateScalarResultIndex(RiaDefines::DYNAMIC_NATIVE, matrixResultNames[i], false); - matrixModelResults->setTimeStepInfos(resIndex, timeStepInfos); + RigEclipseResultAddress resAddr(RiaDefines::DYNAMIC_NATIVE, matrixResultNames[i]); + matrixModelResults->createResultEntry(resAddr, false); + matrixModelResults->setTimeStepInfos(resAddr, timeStepInfos); } } @@ -868,8 +917,9 @@ void RifReaderEclipseOutput::buildMetaData(ecl_grid_type* grid) for (int i = 0; i < fractureResultNames.size(); ++i) { - size_t resIndex = fractureModelResults->findOrCreateScalarResultIndex(RiaDefines::DYNAMIC_NATIVE, fractureResultNames[i], false); - fractureModelResults->setTimeStepInfos(resIndex, timeStepInfos); + RigEclipseResultAddress resAddr(RiaDefines::DYNAMIC_NATIVE, fractureResultNames[i]); + fractureModelResults->createResultEntry(resAddr, false); + fractureModelResults->setTimeStepInfos(resAddr, timeStepInfos); } } } @@ -939,8 +989,9 @@ void RifReaderEclipseOutput::buildMetaData(ecl_grid_type* grid) for (int i = 0; i < matrixResultNames.size(); ++i) { - size_t resIndex = matrixModelResults->findOrCreateScalarResultIndex(RiaDefines::STATIC_NATIVE, matrixResultNames[i], false); - matrixModelResults->setTimeStepInfos(resIndex, staticTimeStepInfo); + RigEclipseResultAddress resAddr(RiaDefines::STATIC_NATIVE, matrixResultNames[i]); + matrixModelResults->createResultEntry(resAddr, false); + matrixModelResults->setTimeStepInfos(resAddr, staticTimeStepInfo); } } @@ -954,8 +1005,9 @@ void RifReaderEclipseOutput::buildMetaData(ecl_grid_type* grid) for (int i = 0; i < fractureResultNames.size(); ++i) { - size_t resIndex = fractureModelResults->findOrCreateScalarResultIndex(RiaDefines::STATIC_NATIVE, fractureResultNames[i], false); - fractureModelResults->setTimeStepInfos(resIndex, staticTimeStepInfo); + RigEclipseResultAddress resAddr(RiaDefines::STATIC_NATIVE, fractureResultNames[i]); + fractureModelResults->createResultEntry(resAddr, false); + fractureModelResults->setTimeStepInfos(resAddr, staticTimeStepInfo); } } } @@ -993,7 +1045,7 @@ bool RifReaderEclipseOutput::staticResult(const QString& result, RiaDefines::Por { std::vector fileValues; - size_t numOccurrences = ecl_file_get_num_named_kw(m_ecl_init_file, result.toAscii().data()); + size_t numOccurrences = ecl_file_get_num_named_kw(m_ecl_init_file, result.toLatin1().data()); size_t i; for (i = 0; i < numOccurrences; i++) { @@ -1884,74 +1936,6 @@ void RifReaderEclipseOutput::readWellCells(const ecl_grid_type* mainEclGrid, boo } } // End of the MSW section - else if ( false ) - { - // Code handling None-MSW Wells ... Normal wells that is. - - // Loop over all the grids in the model. If we have connections in one, we will discard - // the main grid connections as the well connections are duplicated in the main grid and LGR grids - // Verified on 10 k case JJS. But smarter things could be done, like showing the "main grid well" if turning off the LGR's - - bool hasWellConnectionsInLGR = false; - - for (size_t gridIdx = 1; gridIdx < grids.size(); ++gridIdx) - { - RigGridBase* lgrGrid = m_eclipseCase->grid(gridIdx); - if (well_state_has_grid_connections(ert_well_state, lgrGrid->gridName().data())) - { - hasWellConnectionsInLGR = true; - break; - } - } - - size_t gridNr = hasWellConnectionsInLGR ? 1 : 0; - for (; gridNr < grids.size(); ++gridNr) - { - - // Wellhead. If several grids have a wellhead definition for this well, we use the last one. (Possibly the innermost LGR) - const well_conn_type* ert_wellhead = well_state_iget_wellhead(ert_well_state, static_cast(gridNr)); - if (ert_wellhead) - { - wellResFrame.m_wellHead = createWellResultPoint(grids[gridNr], ert_wellhead, -1, -1, wellName); - // HACK: Ert returns open as "this is equally wrong as closed for well heads". - // Well heads are not open jfr mail communication with HHGS and JH Statoil 07.01.2016 - wellResFrame.m_wellHead.m_isOpen = false; - - //std::cout << "Wellhead YES at timeIdx: " << timeIdx << " wellIdx: " << wellIdx << " Grid: " << gridNr << std::endl; - } - else - { - // std::cout << "Wellhead NO at timeIdx: " << timeIdx << " wellIdx: " << wellIdx << " Grid: " << gridNr << std::endl; - //CVF_ASSERT(0); // This is just a test assert to see if this condition exists in some files and it does. - // All the grids does not necessarily have a well head definition. - } - - const well_conn_collection_type* connections = well_state_get_grid_connections(ert_well_state, this->ertGridName(gridNr).data()); - - // Import all well result cells for all connections - if (connections) - { - int connectionCount = well_conn_collection_get_size(connections); - if (connectionCount) - { - wellResFrame.m_wellResultBranches.push_back(RigWellResultBranch()); - RigWellResultBranch& wellResultBranch = wellResFrame.m_wellResultBranches.back(); - - wellResultBranch.m_ertBranchId = 0; // Normal wells have only one branch - - size_t existingCellCount = wellResultBranch.m_branchResultPoints.size(); - wellResultBranch.m_branchResultPoints.resize(existingCellCount + connectionCount); - - for (int connIdx = 0; connIdx < connectionCount; connIdx++) - { - well_conn_type* ert_connection = well_conn_collection_iget(connections, connIdx); - wellResultBranch.m_branchResultPoints[existingCellCount + connIdx] = - createWellResultPoint(grids[gridNr], ert_connection, -1, -1, wellName); - } - } - } - } - } else { // Code handling None-MSW Wells ... Normal wells that is. @@ -2194,7 +2178,7 @@ bool RifReaderEclipseOutput::isEclipseAndSoursimTimeStepsEqual(const QDateTime& //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -ecl_grid_type* RifReaderEclipseOutput::createMainGrid() const +ecl_grid_type* RifReaderEclipseOutput::loadMainGrid() const { ecl_grid_type* mainEclGrid = nullptr; @@ -2250,6 +2234,7 @@ void RifReaderEclipseOutput::extractResultValuesBasedOnPorosityModel(RiaDefines: actCellInfo->gridActiveCellCounts(i, matrixActiveCellCount); fracActCellInfo->gridActiveCellCounts(i, fractureActiveCellCount); + if (matrixOrFracture == RiaDefines::MATRIX_MODEL) { destinationResultValues->insert(destinationResultValues->end(), @@ -2258,9 +2243,16 @@ void RifReaderEclipseOutput::extractResultValuesBasedOnPorosityModel(RiaDefines: } else { - destinationResultValues->insert(destinationResultValues->end(), - sourceResultValues.begin() + sourceStartPosition + matrixActiveCellCount, - sourceResultValues.begin() + sourceStartPosition + matrixActiveCellCount + fractureActiveCellCount); + if ((matrixActiveCellCount + fractureActiveCellCount) > sourceResultValues.size()) + { + // Special handling of the situation where we only have data for one fracture mode + matrixActiveCellCount = 0; + } + + destinationResultValues->insert(destinationResultValues->end(), + sourceResultValues.begin() + sourceStartPosition + matrixActiveCellCount, + sourceResultValues.begin() + sourceStartPosition + matrixActiveCellCount + + fractureActiveCellCount); } sourceStartPosition += (matrixActiveCellCount + fractureActiveCellCount); diff --git a/ApplicationCode/FileInterface/RifReaderEclipseOutput.h b/ApplicationCode/FileInterface/RifReaderEclipseOutput.h index c0c06044c8..8efcb14c05 100644 --- a/ApplicationCode/FileInterface/RifReaderEclipseOutput.h +++ b/ApplicationCode/FileInterface/RifReaderEclipseOutput.h @@ -23,6 +23,7 @@ #include "RifReaderInterface.h" #include "cvfCollection.h" +#include "cvfVector3.h" #include @@ -57,6 +58,8 @@ class RifReaderEclipseOutput : public RifReaderInterface void setHdf5FileName(const QString& fileName); void setFileDataAccess(RifEclipseRestartDataAccess* restartDataAccess); + static const size_t* eclipseCellIndexMapping(); + virtual bool openAndReadActiveCellData(const QString& fileName, const std::vector& mainCaseTimeSteps, RigEclipseCaseData* eclipseCase); bool staticResult(const QString& result, RiaDefines::PorosityModelType matrixOrFracture, std::vector* values) override; @@ -66,7 +69,17 @@ class RifReaderEclipseOutput : public RifReaderInterface std::vector allTimeSteps() const; static bool transferGeometry(const ecl_grid_type* mainEclGrid, RigEclipseCaseData* eclipseCase); + static bool exportGrid(const QString& gridFileName, + RigEclipseCaseData* eclipseCase, + const cvf::Vec3st& min, + const cvf::Vec3st& max, + const cvf::Vec3st& refinement); + static void transferCoarseningInfo(const ecl_grid_type* eclGrid, RigGridBase* grid); + + static void importEquilData(const QString& deckFileName, + const QString& includeStatementAbsolutePathPrefix, + RigEclipseCaseData* eclipseCase); std::set availablePhases() const override; @@ -95,7 +108,7 @@ class RifReaderEclipseOutput : public RifReaderInterface static bool isEclipseAndSoursimTimeStepsEqual(const QDateTime& eclipseDateTime, const QDateTime& sourSimDateTime); - ecl_grid_type* createMainGrid() const; + ecl_grid_type* loadMainGrid() const; private: QString m_fileName; // Name of file used to start accessing Eclipse output files diff --git a/ApplicationCode/FileInterface/RifReaderEclipseSummary.cpp b/ApplicationCode/FileInterface/RifReaderEclipseSummary.cpp index f00071fd3a..b4cbe4780d 100644 --- a/ApplicationCode/FileInterface/RifReaderEclipseSummary.cpp +++ b/ApplicationCode/FileInterface/RifReaderEclipseSummary.cpp @@ -1,41 +1,46 @@ ///////////////////////////////////////////////////////////////////////////////// // // Copyright (C) Statoil ASA -// +// // ResInsight 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 3 of the License, or // (at your option) any later version. -// +// // ResInsight 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 at +// +// See the GNU General Public License at // for more details. // ///////////////////////////////////////////////////////////////////////////////// #include "RifReaderEclipseSummary.h" -#include "RiaStringEncodingTools.h" + #include "RiaFilePathTools.h" -#include "RifReaderEclipseOutput.h" +#include "RiaStringEncodingTools.h" + #include "RifEclipseSummaryTools.h" +#include "RifReaderEclipseOutput.h" +#include #include -#include #include +#include #include #include -#include -#include "ert/ecl/ecl_sum.h" -#include "ert/ecl/smspec_node.h" #include "ert/ecl/ecl_file.h" -#include "ert/ecl/ecl_kw_magic.h" #include "ert/ecl/ecl_kw.h" +#include "ert/ecl/ecl_kw_magic.h" +#include "ert/ecl/ecl_sum.h" +#include "ert/ecl/smspec_node.h" +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- std::vector getTimeSteps(ecl_sum_type* ecl_sum) { std::vector timeSteps; @@ -50,20 +55,21 @@ std::vector getTimeSteps(ecl_sum_type* ecl_sum) { timeSteps.push_back(time_t_vector_iget(steps, i)); } - free(steps); + + time_t_vector_free(steps); } } return timeSteps; } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- ecl_sum_type* openEclSum(const QString& inHeaderFileName, bool includeRestartFiles) { - QString headerFileName; + QString headerFileName; QStringList dataFileNames; - QString nativeHeaderFileName = QDir::toNativeSeparators(inHeaderFileName); + QString nativeHeaderFileName = QDir::toNativeSeparators(inHeaderFileName); RifEclipseSummaryTools::findSummaryFiles(nativeHeaderFileName, &headerFileName, &dataFileNames); if (headerFileName.isEmpty() || dataFileNames.size() == 0) return nullptr; @@ -77,8 +83,8 @@ ecl_sum_type* openEclSum(const QString& inHeaderFileName, bool includeRestartFil stringlist_append_copy(dataFiles, RiaStringEncodingTools::toNativeEncoded(dataFileNames[i]).data()); } - bool lazyLoad = true; - std::string itemSeparatorInVariableNames = ":"; + bool lazyLoad = true; + std::string itemSeparatorInVariableNames = ":"; ecl_sum_type* ecl_sum = ecl_sum_fread_alloc(RiaStringEncodingTools::toNativeEncoded(headerFileName).data(), dataFiles, itemSeparatorInVariableNames.data(), @@ -92,24 +98,24 @@ ecl_sum_type* openEclSum(const QString& inHeaderFileName, bool includeRestartFil } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void closeEclSum(ecl_sum_type* ecl_sum) { - if(ecl_sum) ecl_sum_free(ecl_sum); + if (ecl_sum) ecl_sum_free(ecl_sum); } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- RifReaderEclipseSummary::RifReaderEclipseSummary() - : m_ecl_sum(nullptr), - m_ecl_SmSpec(nullptr) + : m_ecl_sum(nullptr) + , m_ecl_SmSpec(nullptr) { m_valuesCache.reset(new ValuesCache()); } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- RifReaderEclipseSummary::~RifReaderEclipseSummary() { @@ -121,19 +127,19 @@ RifReaderEclipseSummary::~RifReaderEclipseSummary() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- bool RifReaderEclipseSummary::open(const QString& headerFileName, bool includeRestartFiles) { - assert(m_ecl_sum == nullptr); - + assert(m_ecl_sum == nullptr); + m_ecl_sum = openEclSum(headerFileName, includeRestartFiles); if (m_ecl_sum) { m_timeSteps.clear(); m_ecl_SmSpec = ecl_sum_get_smspec(m_ecl_sum); - m_timeSteps = getTimeSteps(m_ecl_sum); + m_timeSteps = getTimeSteps(m_ecl_sum); buildMetaData(); @@ -144,7 +150,7 @@ bool RifReaderEclipseSummary::open(const QString& headerFileName, bool includeRe } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- std::vector RifReaderEclipseSummary::getRestartFiles(const QString& headerFileName, bool* hasWarnings) { @@ -156,14 +162,14 @@ std::vector RifReaderEclipseSummary::getRestartFiles(const Q RifRestartFileInfo currFile; currFile.fileName = headerFileName; - while(!currFile.fileName.isEmpty()) + while (!currFile.fileName.isEmpty()) { // Due to a weakness in libecl regarding restart summary header file selection, // do some extra checking { - QString formattedHeaderExtension = ".FSMSPEC"; + QString formattedHeaderExtension = ".FSMSPEC"; QString nonformattedHeaderExtension = ".SMSPEC"; - QString formattedDataFileExtension = ".FUNSMRY"; + QString formattedDataFileExtension = ".FUNSMRY"; if (currFile.fileName.endsWith(nonformattedHeaderExtension, Qt::CaseInsensitive)) { @@ -173,8 +179,8 @@ std::vector RifReaderEclipseSummary::getRestartFiles(const Q formattedDateFile.replace(nonformattedHeaderExtension, formattedDataFileExtension, Qt::CaseInsensitive); QFileInfo nonformattedHeaderFileInfo = QFileInfo(currFile.fileName); - QFileInfo formattedHeaderFileInfo = QFileInfo(formattedHeaderFile); - QFileInfo formattedDateFileInfo = QFileInfo(formattedDateFile); + QFileInfo formattedHeaderFileInfo = QFileInfo(formattedHeaderFile); + QFileInfo formattedDateFileInfo = QFileInfo(formattedDateFile); if (formattedHeaderFileInfo.lastModified() < nonformattedHeaderFileInfo.lastModified() && formattedHeaderFileInfo.exists() && !formattedDateFileInfo.exists()) { @@ -187,7 +193,7 @@ std::vector RifReaderEclipseSummary::getRestartFiles(const Q } } QString prevFile = currFile.fileName; - currFile = getRestartFile(currFile.fileName); + currFile = getRestartFile(currFile.fileName); // Fix to stop potential infinite loop if (currFile.fileName == prevFile) @@ -196,35 +202,33 @@ std::vector RifReaderEclipseSummary::getRestartFiles(const Q *hasWarnings = true; break; } - } - if (!currFile.fileName.isEmpty()) - restartFiles.push_back(currFile); + if (!currFile.fileName.isEmpty()) restartFiles.push_back(currFile); } return restartFiles; } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- RifRestartFileInfo RifReaderEclipseSummary::getFileInfo(const QString& headerFileName) { - RifRestartFileInfo fileInfo; - ecl_sum_type* ecl_sum = openEclSum(headerFileName, false); - std::vector timeSteps = getTimeSteps(ecl_sum); + RifRestartFileInfo fileInfo; + ecl_sum_type* ecl_sum = openEclSum(headerFileName, false); + std::vector timeSteps = getTimeSteps(ecl_sum); if (timeSteps.size() > 0) { - fileInfo.fileName = headerFileName; + fileInfo.fileName = headerFileName; fileInfo.startDate = timeSteps.front(); - fileInfo.endDate = timeSteps.back(); + fileInfo.endDate = timeSteps.back(); } closeEclSum(ecl_sum); return fileInfo; } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- std::string stringFromPointer(const char* pointerToChar) { @@ -240,44 +244,44 @@ std::string stringFromPointer(const char* pointerToChar) } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- -std::string wellNameFromNode(const smspec_node_type * ertSumVarNode) +std::string wellNameFromNode(const smspec_node_type* ertSumVarNode) { return stringFromPointer(smspec_node_get_wgname(ertSumVarNode)); } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- -std::string lgrNameFromNode(const smspec_node_type * ertSumVarNode) +std::string lgrNameFromNode(const smspec_node_type* ertSumVarNode) { return stringFromPointer(smspec_node_get_lgr_name(ertSumVarNode)); } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- -RifEclipseSummaryAddress addressFromErtSmSpecNode(const smspec_node_type * ertSumVarNode) +RifEclipseSummaryAddress addressFromErtSmSpecNode(const smspec_node_type* ertSumVarNode) { - if (smspec_node_get_var_type(ertSumVarNode) == ECL_SMSPEC_INVALID_VAR) + if (smspec_node_get_var_type(ertSumVarNode) == ECL_SMSPEC_INVALID_VAR) { return RifEclipseSummaryAddress(); } RifEclipseSummaryAddress::SummaryVarCategory sumCategory(RifEclipseSummaryAddress::SUMMARY_INVALID); - std::string quantityName; - int regionNumber(-1); - int regionNumber2(-1); - std::string wellGroupName; - std::string wellName; - int wellSegmentNumber(-1); - std::string lgrName; - int cellI(-1); - int cellJ(-1); - int cellK(-1); - int aquiferNumber(-1); - bool isErrorResult(false); + std::string quantityName; + int regionNumber(-1); + int regionNumber2(-1); + std::string wellGroupName; + std::string wellName; + int wellSegmentNumber(-1); + std::string lgrName; + int cellI(-1); + int cellJ(-1); + int cellK(-1); + int aquiferNumber(-1); + bool isErrorResult(false); quantityName = smspec_node_get_keyword(ertSumVarNode); @@ -285,19 +289,19 @@ RifEclipseSummaryAddress addressFromErtSmSpecNode(const smspec_node_type * ertSu { case ECL_SMSPEC_AQUIFER_VAR: { - sumCategory = RifEclipseSummaryAddress::SUMMARY_AQUIFER; + sumCategory = RifEclipseSummaryAddress::SUMMARY_AQUIFER; aquiferNumber = smspec_node_get_num(ertSumVarNode); } break; case ECL_SMSPEC_WELL_VAR: { sumCategory = RifEclipseSummaryAddress::SUMMARY_WELL; - wellName = wellNameFromNode(ertSumVarNode); + wellName = wellNameFromNode(ertSumVarNode); } break; case ECL_SMSPEC_REGION_VAR: { - sumCategory = RifEclipseSummaryAddress::SUMMARY_REGION; + sumCategory = RifEclipseSummaryAddress::SUMMARY_REGION; regionNumber = smspec_node_get_num(ertSumVarNode); } break; @@ -308,56 +312,56 @@ RifEclipseSummaryAddress addressFromErtSmSpecNode(const smspec_node_type * ertSu break; case ECL_SMSPEC_GROUP_VAR: { - sumCategory = RifEclipseSummaryAddress::SUMMARY_WELL_GROUP; + sumCategory = RifEclipseSummaryAddress::SUMMARY_WELL_GROUP; wellGroupName = wellNameFromNode(ertSumVarNode); } break; case ECL_SMSPEC_BLOCK_VAR: { sumCategory = RifEclipseSummaryAddress::SUMMARY_BLOCK; - + const int* ijk = smspec_node_get_ijk(ertSumVarNode); - cellI = ijk[0]; - cellJ = ijk[1]; - cellK = ijk[2]; + cellI = ijk[0]; + cellJ = ijk[1]; + cellK = ijk[2]; } break; case ECL_SMSPEC_COMPLETION_VAR: { - sumCategory = RifEclipseSummaryAddress::SUMMARY_WELL_COMPLETION; - wellName = wellNameFromNode(ertSumVarNode); + sumCategory = RifEclipseSummaryAddress::SUMMARY_WELL_COMPLETION; + wellName = wellNameFromNode(ertSumVarNode); const int* ijk = smspec_node_get_ijk(ertSumVarNode); - cellI = ijk[0]; - cellJ = ijk[1]; - cellK = ijk[2]; + cellI = ijk[0]; + cellJ = ijk[1]; + cellK = ijk[2]; } break; case ECL_SMSPEC_LOCAL_BLOCK_VAR: { - sumCategory = RifEclipseSummaryAddress::SUMMARY_BLOCK_LGR; - lgrName = lgrNameFromNode(ertSumVarNode); + sumCategory = RifEclipseSummaryAddress::SUMMARY_BLOCK_LGR; + lgrName = lgrNameFromNode(ertSumVarNode); const int* ijk = smspec_node_get_lgr_ijk(ertSumVarNode); - cellI = ijk[0]; - cellJ = ijk[1]; - cellK = ijk[2]; + cellI = ijk[0]; + cellJ = ijk[1]; + cellK = ijk[2]; } break; case ECL_SMSPEC_LOCAL_COMPLETION_VAR: { - sumCategory = RifEclipseSummaryAddress::SUMMARY_WELL_COMPLETION_LGR; - wellName = wellNameFromNode(ertSumVarNode); - lgrName = lgrNameFromNode(ertSumVarNode); + sumCategory = RifEclipseSummaryAddress::SUMMARY_WELL_COMPLETION_LGR; + wellName = wellNameFromNode(ertSumVarNode); + lgrName = lgrNameFromNode(ertSumVarNode); const int* ijk = smspec_node_get_lgr_ijk(ertSumVarNode); - cellI = ijk[0]; - cellJ = ijk[1]; - cellK = ijk[2]; + cellI = ijk[0]; + cellJ = ijk[1]; + cellK = ijk[2]; } break; case ECL_SMSPEC_LOCAL_WELL_VAR: { sumCategory = RifEclipseSummaryAddress::SUMMARY_WELL_LGR; - wellName = wellNameFromNode(ertSumVarNode); - lgrName = lgrNameFromNode(ertSumVarNode); + wellName = wellNameFromNode(ertSumVarNode); + lgrName = lgrNameFromNode(ertSumVarNode); } break; case ECL_SMSPEC_NETWORK_VAR: @@ -367,16 +371,15 @@ RifEclipseSummaryAddress addressFromErtSmSpecNode(const smspec_node_type * ertSu break; case ECL_SMSPEC_REGION_2_REGION_VAR: { - sumCategory = RifEclipseSummaryAddress::SUMMARY_REGION_2_REGION; - regionNumber = smspec_node_get_R1(ertSumVarNode); + sumCategory = RifEclipseSummaryAddress::SUMMARY_REGION_2_REGION; + regionNumber = smspec_node_get_R1(ertSumVarNode); regionNumber2 = smspec_node_get_R2(ertSumVarNode); - } break; case ECL_SMSPEC_SEGMENT_VAR: { - sumCategory = RifEclipseSummaryAddress::SUMMARY_WELL_SEGMENT; - wellName = wellNameFromNode(ertSumVarNode); + sumCategory = RifEclipseSummaryAddress::SUMMARY_WELL_SEGMENT; + wellName = wellNameFromNode(ertSumVarNode); wellSegmentNumber = smspec_node_get_num(ertSumVarNode); } break; @@ -387,24 +390,26 @@ RifEclipseSummaryAddress addressFromErtSmSpecNode(const smspec_node_type * ertSu break; default: CVF_ASSERT(false); - break; + break; } - return RifEclipseSummaryAddress(sumCategory, - quantityName, - regionNumber, - regionNumber2, - wellGroupName, - wellName, - wellSegmentNumber, - lgrName, - cellI, cellJ, cellK, + return RifEclipseSummaryAddress(sumCategory, + quantityName, + regionNumber, + regionNumber2, + wellGroupName, + wellName, + wellSegmentNumber, + lgrName, + cellI, + cellJ, + cellK, aquiferNumber, isErrorResult); } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- bool RifReaderEclipseSummary::values(const RifEclipseSummaryAddress& resultAddress, std::vector* values) const { @@ -412,7 +417,7 @@ bool RifReaderEclipseSummary::values(const RifEclipseSummaryAddress& resultAddre int variableIndex = indexFromAddress(resultAddress); - if ( variableIndex < 0 ) return false; + if (variableIndex < 0) return false; values->clear(); values->reserve(timeStepCount()); @@ -425,17 +430,16 @@ bool RifReaderEclipseSummary::values(const RifEclipseSummaryAddress& resultAddre else if (m_ecl_SmSpec) { const smspec_node_type* ertSumVarNode = ecl_smspec_iget_node(m_ecl_SmSpec, variableIndex); - int paramsIndex = smspec_node_get_params_index(ertSumVarNode); + int paramsIndex = smspec_node_get_params_index(ertSumVarNode); double_vector_type* dataValues = ecl_sum_alloc_data_vector(m_ecl_sum, paramsIndex, false); if (dataValues) { - for (int i = 0; i < double_vector_size(dataValues); i++) - { - values->push_back(double_vector_iget(dataValues, i)); - } - free(dataValues); + int dataSize = double_vector_size(dataValues); + const double* dataPtr = double_vector_get_const_ptr(dataValues); + values->insert(values->end(), dataPtr, dataPtr + dataSize); + double_vector_free(dataValues); m_valuesCache->insertValues(resultAddress, *values); } @@ -445,7 +449,7 @@ bool RifReaderEclipseSummary::values(const RifEclipseSummaryAddress& resultAddre } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- int RifReaderEclipseSummary::timeStepCount() const { @@ -457,7 +461,7 @@ int RifReaderEclipseSummary::timeStepCount() const } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- const std::vector& RifReaderEclipseSummary::timeSteps(const RifEclipseSummaryAddress& resultAddress) const { @@ -467,7 +471,7 @@ const std::vector& RifReaderEclipseSummary::timeSteps(const RifEclipseSu } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- int RifReaderEclipseSummary::indexFromAddress(const RifEclipseSummaryAddress& resultAddress) const { @@ -481,20 +485,20 @@ int RifReaderEclipseSummary::indexFromAddress(const RifEclipseSummaryAddress& re } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RifReaderEclipseSummary::buildMetaData() { m_allResultAddresses.clear(); m_resultAddressToErtNodeIdx.clear(); - if(m_ecl_SmSpec) + if (m_ecl_SmSpec) { int varCount = ecl_smspec_num_nodes(m_ecl_SmSpec); - for(int i = 0; i < varCount; i++) + for (int i = 0; i < varCount; i++) { - const smspec_node_type * ertSumVarNode = ecl_smspec_iget_node(m_ecl_SmSpec, i); - RifEclipseSummaryAddress addr = addressFromErtSmSpecNode(ertSumVarNode); + const smspec_node_type* ertSumVarNode = ecl_smspec_iget_node(m_ecl_SmSpec, i); + RifEclipseSummaryAddress addr = addressFromErtSmSpecNode(ertSumVarNode); m_allResultAddresses.insert(addr); m_resultAddressToErtNodeIdx[addr] = i; } @@ -502,23 +506,24 @@ void RifReaderEclipseSummary::buildMetaData() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- RifRestartFileInfo RifReaderEclipseSummary::getRestartFile(const QString& headerFileName) { ecl_sum_type* ecl_sum = openEclSum(headerFileName, true); - const ecl_smspec_type* smspec = ecl_sum ? ecl_sum_get_smspec(ecl_sum) : nullptr; - const char* rstCase = smspec ? ecl_smspec_get_restart_case(smspec) : nullptr; - QString restartCase = rstCase? RiaFilePathTools::canonicalPath(RiaStringEncodingTools::fromNativeEncoded(rstCase)) : ""; + const ecl_smspec_type* smspec = ecl_sum ? ecl_sum_get_smspec(ecl_sum) : nullptr; + const char* rstCase = smspec ? ecl_smspec_get_restart_case(smspec) : nullptr; + QString restartCase = rstCase ? RiaFilePathTools::canonicalPath(RiaStringEncodingTools::fromNativeEncoded(rstCase)) : ""; closeEclSum(ecl_sum); if (!restartCase.isEmpty()) { - QString path = QFileInfo(restartCase).dir().path(); + QString path = QFileInfo(restartCase).dir().path(); QString restartBase = QDir(restartCase).dirName(); - - char* smspec_header = ecl_util_alloc_exfilename(path.toStdString().data(), restartBase.toStdString().data(), ECL_SUMMARY_HEADER_FILE, false /*unformatted*/, 0); + + char* smspec_header = ecl_util_alloc_exfilename( + path.toStdString().data(), restartBase.toStdString().data(), ECL_SUMMARY_HEADER_FILE, false /*unformatted*/, 0); QString restartFileName = RiaFilePathTools::toInternalSeparator(RiaStringEncodingTools::fromNativeEncoded(smspec_header)); free(smspec_header); @@ -528,7 +533,7 @@ RifRestartFileInfo RifReaderEclipseSummary::getRestartFile(const QString& header } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- std::string RifReaderEclipseSummary::unitName(const RifEclipseSummaryAddress& resultAddress) const { @@ -536,14 +541,14 @@ std::string RifReaderEclipseSummary::unitName(const RifEclipseSummaryAddress& re int variableIndex = indexFromAddress(resultAddress); - if(variableIndex < 0) return ""; + if (variableIndex < 0) return ""; - const smspec_node_type * ertSumVarNode = ecl_smspec_iget_node(m_ecl_SmSpec, variableIndex); + const smspec_node_type* ertSumVarNode = ecl_smspec_iget_node(m_ecl_SmSpec, variableIndex); return smspec_node_get_unit(ertSumVarNode); } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RifReaderEclipseSummary::markForCachePurge(const RifEclipseSummaryAddress& address) { @@ -551,7 +556,7 @@ void RifReaderEclipseSummary::markForCachePurge(const RifEclipseSummaryAddress& } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RifReaderEclipseSummary::purgeCache() { @@ -575,40 +580,39 @@ void RifReaderEclipseSummary::populateVectorFromStringList(stringlist_type* stri #endif //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- const std::vector RifReaderEclipseSummary::ValuesCache::EMPTY_VECTOR; std::set RifReaderEclipseSummary::ValuesCache::m_instances; //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- RifReaderEclipseSummary::ValuesCache::ValuesCache() { - // Register instance m_instances.insert(this); } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- RifReaderEclipseSummary::ValuesCache::~ValuesCache() { - // Deregister instance m_instances.erase(this); } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- -void RifReaderEclipseSummary::ValuesCache::insertValues(const RifEclipseSummaryAddress& address, const std::vector& values) +void RifReaderEclipseSummary::ValuesCache::insertValues(const RifEclipseSummaryAddress& address, + const std::vector& values) { m_cachedValues[address] = values; m_purgeList.erase(address); } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- const std::vector& RifReaderEclipseSummary::ValuesCache::getValues(const RifEclipseSummaryAddress& address) const { @@ -620,7 +624,7 @@ const std::vector& RifReaderEclipseSummary::ValuesCache::getValues(const } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RifReaderEclipseSummary::ValuesCache::markAddressForPurge(const RifEclipseSummaryAddress& address) { @@ -628,19 +632,20 @@ void RifReaderEclipseSummary::ValuesCache::markAddressForPurge(const RifEclipseS } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RifReaderEclipseSummary::ValuesCache::purge() { - for (auto instance : m_instances) instance->purgeData(); + for (auto instance : m_instances) + instance->purgeData(); } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RifReaderEclipseSummary::ValuesCache::purgeData() { - for (const auto purgeAddr : m_purgeList) + for (const auto& purgeAddr : m_purgeList) { m_cachedValues.erase(purgeAddr); } diff --git a/ApplicationCode/FileInterface/RifReaderInterface.cpp b/ApplicationCode/FileInterface/RifReaderInterface.cpp index e650b6863e..5f03b22144 100644 --- a/ApplicationCode/FileInterface/RifReaderInterface.cpp +++ b/ApplicationCode/FileInterface/RifReaderInterface.cpp @@ -53,7 +53,7 @@ bool RifReaderInterface::isNNCsEnabled() //-------------------------------------------------------------------------------------------------- const QString RifReaderInterface::faultIncludeFileAbsolutePathPrefix() { - return readerSettings()->faultIncludeFileAbsolutePathPrefix; + return readerSettings()->includeFileAbsolutePathPrefix; } //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/FileInterface/RifReaderMockModel.cpp b/ApplicationCode/FileInterface/RifReaderMockModel.cpp index c46c629a51..993bd45710 100644 --- a/ApplicationCode/FileInterface/RifReaderMockModel.cpp +++ b/ApplicationCode/FileInterface/RifReaderMockModel.cpp @@ -53,8 +53,9 @@ bool RifReaderMockModel::open(const QString& fileName, RigEclipseCaseData* eclip for (size_t i = 0; i < m_reservoirBuilder.resultCount(); i++) { - size_t resIdx = cellResults->findOrCreateScalarResultIndex(RiaDefines::DYNAMIC_NATIVE, QString("Dynamic_Result_%1").arg(i), false); - cellResults->setTimeStepInfos(resIdx, timeStepInfos); + RigEclipseResultAddress resAddr(RiaDefines::DYNAMIC_NATIVE, QString("Dynamic_Result_%1").arg(i)); + cellResults->createResultEntry(resAddr, false); + cellResults->setTimeStepInfos(resAddr, timeStepInfos); } if (m_reservoirBuilder.timeStepCount() == 0) return true; @@ -69,20 +70,22 @@ bool RifReaderMockModel::open(const QString& fileName, RigEclipseCaseData* eclip if (i == 1) varEnd = "Y"; int resIndex = 0; if (i > 1) resIndex = i; + + RigEclipseResultAddress resAddr(RiaDefines::STATIC_NATIVE, QString("Static_Result_%1%2").arg(resIndex).arg(varEnd)); - size_t resIdx = cellResults->findOrCreateScalarResultIndex(RiaDefines::STATIC_NATIVE, QString("Static_Result_%1%2").arg(resIndex).arg(varEnd), false); - cellResults->setTimeStepInfos(resIdx, staticResultTimeStepInfos); + cellResults->createResultEntry(resAddr, false); + cellResults->setTimeStepInfos(resAddr, staticResultTimeStepInfos); } #define ADD_INPUT_PROPERTY(Name) \ { \ - size_t resIdx; \ QString resultName(Name); \ - resIdx = cellResults->findOrCreateScalarResultIndex(RiaDefines::INPUT_PROPERTY, resultName, false); \ - cellResults->setTimeStepInfos(resIdx, staticResultTimeStepInfos); \ - cellResults->cellScalarResults(resIdx).resize(1); \ - std::vector& values = cellResults->cellScalarResults(resIdx)[0]; \ + RigEclipseResultAddress resAddr(RiaDefines::INPUT_PROPERTY, resultName);\ + cellResults->createResultEntry(resAddr, false); \ + cellResults->setTimeStepInfos(resAddr, staticResultTimeStepInfos); \ + cellResults->modifiableCellScalarResultTimesteps(resAddr).resize(1); \ + std::vector& values = cellResults->modifiableCellScalarResultTimesteps(resAddr)[0]; \ this->inputProperty(resultName, &values); \ } diff --git a/ApplicationCode/FileInterface/RifReaderSettings.cpp b/ApplicationCode/FileInterface/RifReaderSettings.cpp index 2178259323..87837416e7 100644 --- a/ApplicationCode/FileInterface/RifReaderSettings.cpp +++ b/ApplicationCode/FileInterface/RifReaderSettings.cpp @@ -50,7 +50,14 @@ RifReaderSettings::RifReaderSettings() CAF_PDM_InitField(&skipWellData, "skipWellData", false, "Skip Import of Simulation Well Data", "", "", ""); skipWellData.uiCapability()->setUiLabelPosition(caf::PdmUiItemInfo::HIDDEN); - CAF_PDM_InitField(&faultIncludeFileAbsolutePathPrefix, "faultIncludeFileAbsolutePathPrefix", QString(), "Fault Include File Absolute Path Prefix", "", "Path used to prefix absolute UNIX paths in fault include statements on Windows", ""); + CAF_PDM_InitField( + &includeFileAbsolutePathPrefix, + "includeFileAbsolutePathPrefix", + QString(), + "Include File Absolute Path Prefix", + "", + "Path used to prefix absolute UNIX paths in include statements on Windows, used when searching for FAULTS and EQUIL", + ""); } //-------------------------------------------------------------------------------------------------- @@ -79,7 +86,7 @@ void RifReaderSettings::defineUiOrdering(QString uiConfigName, caf::PdmUiOrderin { uiOrdering.add(&importFaults); #ifdef WIN32 - uiOrdering.add(&faultIncludeFileAbsolutePathPrefix); + uiOrdering.add(&includeFileAbsolutePathPrefix); #endif uiOrdering.add(&importNNCs); uiOrdering.add(&importAdvancedMswData); diff --git a/ApplicationCode/FileInterface/RifReaderSettings.h b/ApplicationCode/FileInterface/RifReaderSettings.h index 58af3b853d..f478cf17a9 100644 --- a/ApplicationCode/FileInterface/RifReaderSettings.h +++ b/ApplicationCode/FileInterface/RifReaderSettings.h @@ -39,7 +39,7 @@ class RifReaderSettings : public caf::PdmObject caf::PdmField importFaults; caf::PdmField importNNCs; caf::PdmField importAdvancedMswData; - caf::PdmField faultIncludeFileAbsolutePathPrefix; + caf::PdmField includeFileAbsolutePathPrefix; caf::PdmField useResultIndexFile; caf::PdmField skipWellData; diff --git a/ApplicationCode/FileInterface/RifSummaryCaseRestartSelector.cpp b/ApplicationCode/FileInterface/RifSummaryCaseRestartSelector.cpp index 215b40c220..42beb40b76 100644 --- a/ApplicationCode/FileInterface/RifSummaryCaseRestartSelector.cpp +++ b/ApplicationCode/FileInterface/RifSummaryCaseRestartSelector.cpp @@ -31,7 +31,7 @@ #include "cafProgressInfo.h" #include -#include +#include #include #include @@ -154,7 +154,6 @@ QStringList RifSummaryCaseRestartSelector::gridCaseFiles() const //-------------------------------------------------------------------------------------------------- void RifSummaryCaseRestartSelector::determineFilesToImport(const std::vector& initialFiles) { - std::vector fileInfos; if (m_showDialog) { bool enableApplyToAllField = initialFiles.size() > 1; diff --git a/ApplicationCode/GeoMech/GeoMechDataModel/CMakeLists.txt b/ApplicationCode/GeoMech/GeoMechDataModel/CMakeLists.txt index c082dd9ac3..e6ceaea728 100644 --- a/ApplicationCode/GeoMech/GeoMechDataModel/CMakeLists.txt +++ b/ApplicationCode/GeoMech/GeoMechDataModel/CMakeLists.txt @@ -53,3 +53,8 @@ target_link_libraries( ${PROJECT_NAME} ) source_group("" FILES ${PROJECT_FILES}) + +# cotire +if (COMMAND caf_apply_cotire) + caf_apply_cotire("${PROJECT_NAME}") +endif() diff --git a/ApplicationCode/GeoMech/GeoMechDataModel/RigFemNativeStatCalc.h b/ApplicationCode/GeoMech/GeoMechDataModel/RigFemNativeStatCalc.h index 929b5b5b4e..0113fbf9bc 100644 --- a/ApplicationCode/GeoMech/GeoMechDataModel/RigFemNativeStatCalc.h +++ b/ApplicationCode/GeoMech/GeoMechDataModel/RigFemNativeStatCalc.h @@ -35,16 +35,16 @@ class RigFemNativeStatCalc : public RigStatisticsCalculator public: RigFemNativeStatCalc(RigFemPartResultsCollection* femResultCollection, const RigFemResultAddress& resVarAddr); - virtual void minMaxCellScalarValues(size_t timeStepIndex, double& min, double& max); - virtual void posNegClosestToZero(size_t timeStepIndex, double& pos, double& neg); + void minMaxCellScalarValues(size_t timeStepIndex, double& min, double& max) override; + void posNegClosestToZero(size_t timeStepIndex, double& pos, double& neg) override; - virtual void valueSumAndSampleCount(size_t timeStepIndex, double& valueSum, size_t& sampleCount); + void valueSumAndSampleCount(size_t timeStepIndex, double& valueSum, size_t& sampleCount) override; - virtual void addDataToHistogramCalculator(size_t timeStepIndex, RigHistogramCalculator& histogramCalculator); + void addDataToHistogramCalculator(size_t timeStepIndex, RigHistogramCalculator& histogramCalculator) override; - virtual void uniqueValues(size_t timeStepIndex, std::set& values); + void uniqueValues(size_t timeStepIndex, std::set& values) override; - virtual size_t timeStepCount(); + size_t timeStepCount() override; private: RigFemPartResultsCollection* m_resultsData; diff --git a/ApplicationCode/GeoMech/GeoMechDataModel/RigFemNativeVisibleCellsStatCalc.h b/ApplicationCode/GeoMech/GeoMechDataModel/RigFemNativeVisibleCellsStatCalc.h index 8653d2a7be..248645ac46 100644 --- a/ApplicationCode/GeoMech/GeoMechDataModel/RigFemNativeVisibleCellsStatCalc.h +++ b/ApplicationCode/GeoMech/GeoMechDataModel/RigFemNativeVisibleCellsStatCalc.h @@ -41,12 +41,12 @@ class RigFemNativeVisibleCellsStatCalc : public RigStatisticsCalculator const RigFemResultAddress& resVarAddr, const cvf::UByteArray* cellVisibilities); - virtual void minMaxCellScalarValues(size_t timeStepIndex, double& min, double& max); - virtual void posNegClosestToZero(size_t timeStepIndex, double& pos, double& neg); - virtual void valueSumAndSampleCount(size_t timeStepIndex, double& valueSum, size_t& sampleCount); - virtual void addDataToHistogramCalculator(size_t timeStepIndex, RigHistogramCalculator& histogramCalculator); - virtual void uniqueValues(size_t timeStepIndex, std::set& values); - virtual size_t timeStepCount(); + void minMaxCellScalarValues(size_t timeStepIndex, double& min, double& max) override; + void posNegClosestToZero(size_t timeStepIndex, double& pos, double& neg) override; + void valueSumAndSampleCount(size_t timeStepIndex, double& valueSum, size_t& sampleCount) override; + void addDataToHistogramCalculator(size_t timeStepIndex, RigHistogramCalculator& histogramCalculator) override; + void uniqueValues(size_t timeStepIndex, std::set& values) override; + size_t timeStepCount() override; private: RigGeoMechCaseData* m_caseData; diff --git a/ApplicationCode/GeoMech/GeoMechDataModel/RigFemPart.cpp b/ApplicationCode/GeoMech/GeoMechDataModel/RigFemPart.cpp index 55b1e1cc37..a7e03233af 100644 --- a/ApplicationCode/GeoMech/GeoMechDataModel/RigFemPart.cpp +++ b/ApplicationCode/GeoMech/GeoMechDataModel/RigFemPart.cpp @@ -342,10 +342,28 @@ cvf::BoundingBox RigFemPart::boundingBox() const //-------------------------------------------------------------------------------------------------- void RigFemPart::findIntersectingCells(const cvf::BoundingBox& inputBB, std::vector* elementIndices) const { + ensureIntersectionSearchTreeIsBuilt(); + findIntersectingCellsWithExistingSearchTree(inputBB, elementIndices); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RigFemPart::findIntersectingCellsWithExistingSearchTree(const cvf::BoundingBox& inputBB, + std::vector* elementIndices) const +{ + CVF_ASSERT(m_elementSearchTree.notNull()); + m_elementSearchTree->findIntersections(inputBB, elementIndices); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RigFemPart::ensureIntersectionSearchTreeIsBuilt() const +{ + // build tree if (m_elementSearchTree.isNull()) { - // build tree - size_t elmCount = elementCount(); std::vector cellBoundingBoxes; @@ -353,7 +371,7 @@ void RigFemPart::findIntersectingCells(const cvf::BoundingBox& inputBB, std::vec for (size_t elmIdx = 0; elmIdx < elmCount; ++elmIdx) { - const int* cellIndices = connectivities(elmIdx); + const int* cellIndices = connectivities(elmIdx); cvf::BoundingBox& cellBB = cellBoundingBoxes[elmIdx]; cellBB.add(m_nodes.coordinates[cellIndices[0]]); cellBB.add(m_nodes.coordinates[cellIndices[1]]); @@ -368,8 +386,6 @@ void RigFemPart::findIntersectingCells(const cvf::BoundingBox& inputBB, std::vec m_elementSearchTree = new cvf::BoundingBoxTree; m_elementSearchTree->buildTreeFromBoundingBoxes(cellBoundingBoxes, nullptr); } - - m_elementSearchTree->findIntersections(inputBB, elementIndices); } //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/GeoMech/GeoMechDataModel/RigFemPart.h b/ApplicationCode/GeoMech/GeoMechDataModel/RigFemPart.h index cae026c8e9..4a7efbf569 100644 --- a/ApplicationCode/GeoMech/GeoMechDataModel/RigFemPart.h +++ b/ApplicationCode/GeoMech/GeoMechDataModel/RigFemPart.h @@ -47,7 +47,7 @@ class RigFemPart : public cvf::Object { public: RigFemPart(); - virtual ~RigFemPart(); + ~RigFemPart() override; int elementPartId() const { return m_elementPartId; } void setElementPartId(int partId) { m_elementPartId = partId; } @@ -82,6 +82,9 @@ class RigFemPart : public cvf::Object float characteristicElementSize() const; const std::vector& possibleGridCornerElements() const { return m_possibleGridCornerElements; } void findIntersectingCells(const cvf::BoundingBox& inputBB, std::vector* elementIndices) const; + void findIntersectingCellsWithExistingSearchTree(const cvf::BoundingBox& inputBB, std::vector* elementIndices) const; + + void ensureIntersectionSearchTreeIsBuilt() const; cvf::Vec3f faceNormal(int elmentIndex, int faceIndex) const; diff --git a/ApplicationCode/GeoMech/GeoMechDataModel/RigFemPartCollection.h b/ApplicationCode/GeoMech/GeoMechDataModel/RigFemPartCollection.h index 3e78e1d04d..803fb513d4 100644 --- a/ApplicationCode/GeoMech/GeoMechDataModel/RigFemPartCollection.h +++ b/ApplicationCode/GeoMech/GeoMechDataModel/RigFemPartCollection.h @@ -27,7 +27,7 @@ class RigFemPartCollection: public cvf::Object { public: RigFemPartCollection(); - ~RigFemPartCollection(); + ~RigFemPartCollection() override; void addFemPart(RigFemPart* part); RigFemPart* part(size_t index); diff --git a/ApplicationCode/GeoMech/GeoMechDataModel/RigFemPartGrid.cpp b/ApplicationCode/GeoMech/GeoMechDataModel/RigFemPartGrid.cpp index 624f2adb21..03627f0e0d 100644 --- a/ApplicationCode/GeoMech/GeoMechDataModel/RigFemPartGrid.cpp +++ b/ApplicationCode/GeoMech/GeoMechDataModel/RigFemPartGrid.cpp @@ -462,7 +462,13 @@ bool RigFemPartGrid::cellIJKFromCoordinate(const cvf::Vec3d& coord, size_t* i, s //-------------------------------------------------------------------------------------------------- void RigFemPartGrid::cellCornerVertices(size_t cellIndex, cvf::Vec3d vertices[8]) const { - CVF_ASSERT(false); + const std::vector& nodeCoords = m_femPart->nodes().coordinates; + const int* cornerIndices = m_femPart->connectivities(cellIndex); + + for (size_t i = 0; i < 8; ++i) + { + vertices[i] = cvf::Vec3d(nodeCoords[cornerIndices[i]]); + } } //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/GeoMech/GeoMechDataModel/RigFemPartGrid.h b/ApplicationCode/GeoMech/GeoMechDataModel/RigFemPartGrid.h index 4a40bf88b6..708f762a1b 100644 --- a/ApplicationCode/GeoMech/GeoMechDataModel/RigFemPartGrid.h +++ b/ApplicationCode/GeoMech/GeoMechDataModel/RigFemPartGrid.h @@ -28,7 +28,7 @@ class RigFemPartGrid : public cvf::StructGridInterface { public: explicit RigFemPartGrid(const RigFemPart* femPart); - virtual ~RigFemPartGrid(); + ~RigFemPartGrid() override; bool ijkFromCellIndex(size_t cellIndex, size_t* i, size_t* j, size_t* k) const override; size_t cellIndexFromIJK(size_t i, size_t j, size_t k) const override; @@ -40,6 +40,7 @@ class RigFemPartGrid : public cvf::StructGridInterface cvf::Vec3i findMainIJKFaces(int elementIndex) const; std::pair reservoirIJKBoundingBox() const; + void cellCornerVertices(size_t cellIndex, cvf::Vec3d vertices[8]) const override; private: void generateStructGridData(); @@ -59,7 +60,6 @@ class RigFemPartGrid : public cvf::StructGridInterface bool cellIJKFromCoordinate(const cvf::Vec3d& coord, size_t* i, size_t* j, size_t* k) const override; - virtual void cellCornerVertices(size_t cellIndex, cvf::Vec3d vertices[8]) const; cvf::Vec3d cellCentroid(size_t cellIndex) const override; void cellMinMaxCordinates(size_t cellIndex, cvf::Vec3d* minCoordinate, cvf::Vec3d* maxCoordinate) const override; size_t gridPointIndexFromIJK(size_t i, size_t j, size_t k) const override; diff --git a/ApplicationCode/GeoMech/GeoMechDataModel/RigFemPartResults.h b/ApplicationCode/GeoMech/GeoMechDataModel/RigFemPartResults.h index 5df61d0c19..14533e901d 100644 --- a/ApplicationCode/GeoMech/GeoMechDataModel/RigFemPartResults.h +++ b/ApplicationCode/GeoMech/GeoMechDataModel/RigFemPartResults.h @@ -35,7 +35,7 @@ class RigFemPartResults : public cvf::Object { public: RigFemPartResults(); - ~RigFemPartResults(); + ~RigFemPartResults() override; void initResultSteps(const std::vector& stepNames); diff --git a/ApplicationCode/GeoMech/GeoMechDataModel/RigFemPartResultsCollection.cpp b/ApplicationCode/GeoMech/GeoMechDataModel/RigFemPartResultsCollection.cpp index 4a6021ab55..23f5312c55 100644 --- a/ApplicationCode/GeoMech/GeoMechDataModel/RigFemPartResultsCollection.cpp +++ b/ApplicationCode/GeoMech/GeoMechDataModel/RigFemPartResultsCollection.cpp @@ -193,12 +193,12 @@ void RigFemPartResultsCollection::setCalculationParameters(double cohesion, doub m_frictionAngleRad = frictionAngleRad; // Todo, delete all dependent results - this->deleteResult(RigFemResultAddress(RIG_ELEMENT_NODAL, "SE", "SFI", RigFemResultAddress::ALL_TIME_LAPSES)); - this->deleteResult(RigFemResultAddress(RIG_INTEGRATION_POINT, "SE", "SFI", RigFemResultAddress::ALL_TIME_LAPSES)); - this->deleteResult(RigFemResultAddress(RIG_ELEMENT_NODAL, "SE", "DSM", RigFemResultAddress::ALL_TIME_LAPSES)); - this->deleteResult(RigFemResultAddress(RIG_INTEGRATION_POINT, "SE", "DSM", RigFemResultAddress::ALL_TIME_LAPSES)); - this->deleteResult(RigFemResultAddress(RIG_ELEMENT_NODAL, "SE", "FOS", RigFemResultAddress::ALL_TIME_LAPSES)); - this->deleteResult(RigFemResultAddress(RIG_INTEGRATION_POINT, "SE", "FOS", RigFemResultAddress::ALL_TIME_LAPSES)); + this->deleteResult(RigFemResultAddress(RIG_ELEMENT_NODAL, "SE", "SFI", RigFemResultAddress::allTimeLapsesValue())); + this->deleteResult(RigFemResultAddress(RIG_INTEGRATION_POINT, "SE", "SFI", RigFemResultAddress::allTimeLapsesValue())); + this->deleteResult(RigFemResultAddress(RIG_ELEMENT_NODAL, "SE", "DSM", RigFemResultAddress::allTimeLapsesValue())); + this->deleteResult(RigFemResultAddress(RIG_INTEGRATION_POINT, "SE", "DSM", RigFemResultAddress::allTimeLapsesValue())); + this->deleteResult(RigFemResultAddress(RIG_ELEMENT_NODAL, "SE", "FOS", RigFemResultAddress::allTimeLapsesValue())); + this->deleteResult(RigFemResultAddress(RIG_INTEGRATION_POINT, "SE", "FOS", RigFemResultAddress::allTimeLapsesValue())); } //-------------------------------------------------------------------------------------------------- @@ -224,7 +224,6 @@ RigFemScalarResultFrames* RigFemPartResultsCollection::findOrLoadScalarResult(in { std::map> elementProperties = m_elementPropertyReader->readAllElementPropertiesInFileContainingField(resVarAddr.fieldName); - std::vector resultsForEachComponent; for (std::pair< std::string, std::vector> elem : elementProperties) { RigFemResultAddress addressForElement(RIG_ELEMENT, elem.first, ""); @@ -605,7 +604,7 @@ RigFemScalarResultFrames* RigFemPartResultsCollection::calculateTimeLapseResult( frameCountProgress.setProgressDescription("Calculating " + QString::fromStdString(resVarAddr.fieldName + ": " + resVarAddr.componentName)); frameCountProgress.setNextProgressIncrement(this->frameCount()); - RigFemResultAddress resVarNative(resVarAddr.resultPosType, resVarAddr.fieldName, resVarAddr.componentName, RigFemResultAddress::NO_TIME_LAPSE, resVarAddr.refKLayerIndex); + RigFemResultAddress resVarNative(resVarAddr.resultPosType, resVarAddr.fieldName, resVarAddr.componentName, RigFemResultAddress::noTimeLapseValue(), resVarAddr.refKLayerIndex); RigFemScalarResultFrames * srcDataFrames = this->findOrLoadScalarResult(partIndex, resVarNative); RigFemScalarResultFrames * dstDataFrames = m_femPartResults[partIndex]->createScalarResult(resVarAddr); @@ -1499,6 +1498,8 @@ RigFemScalarResultFrames* RigFemPartResultsCollection::calculateCompactionValues RigFemScalarResultFrames* compactionFrames = m_femPartResults[partIndex]->createScalarResult(resVarAddr); const RigFemPart* part = m_femParts->part(partIndex); + part->ensureIntersectionSearchTreeIsBuilt(); + for (int t = 0; t < u3Frames->frameCount(); t++) { std::vector& compactionFrame = compactionFrames->frameData(t); @@ -2259,6 +2260,19 @@ void RigFemPartResultsCollection::deleteResult(const RigFemResultAddress& resVar } } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RigFemPartResultsCollection::deleteResultFrame(const RigFemResultAddress& resVarAddr, int partIndex, int frameIndex) +{ + CVF_ASSERT(resVarAddr.isValid()); + RigFemScalarResultFrames* frames = m_femPartResults[partIndex]->findScalarResult(resVarAddr); + if (frames) + { + std::vector().swap(frames->frameData(frameIndex)); + } +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -2775,7 +2789,6 @@ void findReferenceElementForNode(const RigFemPart& part, size_t nodeIdx, size_t part.findIntersectingCells(bb, &refElementCandidates); const RigFemPartGrid* grid = part.getOrCreateStructGrid(); - const std::vector& nodeCoords = part.nodes().coordinates; refElement->elementIdx = cvf::UNDEFINED_SIZE_T; refElement->intersectionPointToCurrentNodeDistance = std::numeric_limits::infinity(); diff --git a/ApplicationCode/GeoMech/GeoMechDataModel/RigFemPartResultsCollection.h b/ApplicationCode/GeoMech/GeoMechDataModel/RigFemPartResultsCollection.h index 8268be176a..fdb7363b2b 100644 --- a/ApplicationCode/GeoMech/GeoMechDataModel/RigFemPartResultsCollection.h +++ b/ApplicationCode/GeoMech/GeoMechDataModel/RigFemPartResultsCollection.h @@ -50,8 +50,10 @@ class RigFemPartResultsCollection: public cvf::Object public: static const std::string FIELD_NAME_COMPACTION; - RigFemPartResultsCollection(RifGeoMechReaderInterface* readerInterface, RifElementPropertyReader* elementPropertyReader, const RigFemPartCollection * femPartCollection); - ~RigFemPartResultsCollection(); + RigFemPartResultsCollection(RifGeoMechReaderInterface* readerInterface, + RifElementPropertyReader* elementPropertyReader, + const RigFemPartCollection * femPartCollection); + ~RigFemPartResultsCollection() override; void setActiveFormationNames(RigFormationNames* activeFormationNames); RigFormationNames* activeFormationNames(); @@ -67,7 +69,7 @@ class RigFemPartResultsCollection: public cvf::Object std::vector filteredStepNames() const; bool assertResultsLoaded(const RigFemResultAddress& resVarAddr); void deleteResult(const RigFemResultAddress& resVarAddr); - + void deleteResultFrame(const RigFemResultAddress& resVarAddr, int partIndex, int frameIndex); std::vector loadedResults() const; const std::vector& resultValues(const RigFemResultAddress& resVarAddr, int partIndex, int frameIndex); diff --git a/ApplicationCode/GeoMech/GeoMechDataModel/RigFemResultAddress.h b/ApplicationCode/GeoMech/GeoMechDataModel/RigFemResultAddress.h index 72b1e8cd0d..834ddf5d20 100644 --- a/ApplicationCode/GeoMech/GeoMechDataModel/RigFemResultAddress.h +++ b/ApplicationCode/GeoMech/GeoMechDataModel/RigFemResultAddress.h @@ -57,9 +57,9 @@ class RigFemResultAddress int timeLapseBaseFrameIdx; int refKLayerIndex; - static const int ALL_TIME_LAPSES = -2; - static const int NO_TIME_LAPSE = -1; - static const int NO_COMPACTION = -1; + static constexpr int allTimeLapsesValue() { return ALL_TIME_LAPSES; } + static constexpr int noTimeLapseValue() { return NO_TIME_LAPSE; } + static constexpr int noCompactionValue() { return NO_COMPACTION; } bool isTimeLapse() const { return timeLapseBaseFrameIdx > NO_TIME_LAPSE;} bool representsAllTimeLapses() const { return timeLapseBaseFrameIdx == ALL_TIME_LAPSES;} @@ -114,6 +114,12 @@ class RigFemResultAddress return true; } + +private: + static const int ALL_TIME_LAPSES = -2; + static const int NO_TIME_LAPSE = -1; + static const int NO_COMPACTION = -1; + }; diff --git a/ApplicationCode/GeoMech/GeoMechDataModel/RigFemScalarResultFrames.h b/ApplicationCode/GeoMech/GeoMechDataModel/RigFemScalarResultFrames.h index 2ab37169ef..1cce465bb5 100644 --- a/ApplicationCode/GeoMech/GeoMechDataModel/RigFemScalarResultFrames.h +++ b/ApplicationCode/GeoMech/GeoMechDataModel/RigFemScalarResultFrames.h @@ -29,7 +29,7 @@ class RigFemScalarResultFrames: public cvf::Object { public: explicit RigFemScalarResultFrames(int frameCount); - virtual ~RigFemScalarResultFrames(); + ~RigFemScalarResultFrames() override; void enableAsSingleFrameResult(); diff --git a/ApplicationCode/GeoMech/GeoMechDataModel/RigGeoMechCaseData.h b/ApplicationCode/GeoMech/GeoMechDataModel/RigGeoMechCaseData.h index 27a7ce14c9..7e992f6f8b 100644 --- a/ApplicationCode/GeoMech/GeoMechDataModel/RigGeoMechCaseData.h +++ b/ApplicationCode/GeoMech/GeoMechDataModel/RigGeoMechCaseData.h @@ -18,18 +18,17 @@ ///////////////////////////////////////////////////////////////////////////////// #pragma once + +#include "RigFemPartResults.h" +#include "RigFemResultPosEnum.h" + #include "cvfObject.h" + #include -#include #include -#include "RigFemResultPosEnum.h" -#include "cvfCollection.h" -#include "RigFemPartResults.h" -#include "RigFemResultAddress.h" class RifGeoMechReaderInterface; class RigFemPartCollection; -class RigFemScalarResultFrames; class RigFemPartResultsCollection; class RifElementPropertyReader; @@ -37,7 +36,7 @@ class RigGeoMechCaseData: public cvf::Object { public: explicit RigGeoMechCaseData(const std::string& fileName); - ~RigGeoMechCaseData(); + ~RigGeoMechCaseData() override; bool open(std::string* errorMessage); bool readTimeSteps(std::string* errorMessage, std::vector* stepNames); diff --git a/ApplicationCode/GeoMech/GeoMechDataModel/RimFemResultObserver.h b/ApplicationCode/GeoMech/GeoMechDataModel/RimFemResultObserver.h index c91f3ce84d..1be888db39 100644 --- a/ApplicationCode/GeoMech/GeoMechDataModel/RimFemResultObserver.h +++ b/ApplicationCode/GeoMech/GeoMechDataModel/RimFemResultObserver.h @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018- Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -18,12 +18,12 @@ #pragma once -#include "RigFemResultAddress.h" - #include "cafPdmObject.h" #include +class RigFemResultAddress; + class RimFemResultObserver : public caf::PdmObject { CAF_PDM_HEADER_INIT; diff --git a/ApplicationCode/GeoMech/GeoMechDataModel/RimGeoMechGeometrySelectionItem.cpp b/ApplicationCode/GeoMech/GeoMechDataModel/RimGeoMechGeometrySelectionItem.cpp index 39bfb88364..306bcfed6c 100644 --- a/ApplicationCode/GeoMech/GeoMechDataModel/RimGeoMechGeometrySelectionItem.cpp +++ b/ApplicationCode/GeoMech/GeoMechDataModel/RimGeoMechGeometrySelectionItem.cpp @@ -22,7 +22,7 @@ #include "RimGeoMechView.h" -#include "RiuSelectionManager.h" +#include "Riu3dSelectionManager.h" CAF_PDM_SOURCE_INIT(RimGeoMechGeometrySelectionItem, "GeoMechGeometrySelectionItem"); diff --git a/ApplicationCode/GeoMech/GeoMechDataModel/RimGeoMechGeometrySelectionItem.h b/ApplicationCode/GeoMech/GeoMechDataModel/RimGeoMechGeometrySelectionItem.h index 9144cb1cb8..5e16606461 100644 --- a/ApplicationCode/GeoMech/GeoMechDataModel/RimGeoMechGeometrySelectionItem.h +++ b/ApplicationCode/GeoMech/GeoMechDataModel/RimGeoMechGeometrySelectionItem.h @@ -36,11 +36,11 @@ class RimGeoMechGeometrySelectionItem : public RimGeometrySelectionItem CAF_PDM_HEADER_INIT; public: RimGeoMechGeometrySelectionItem(); - virtual ~RimGeoMechGeometrySelectionItem() override; + ~RimGeoMechGeometrySelectionItem() override; void setFromSelectionItem(const RiuGeoMechSelectionItem* selectionItem); - virtual QString geometrySelectionText() const override; + QString geometrySelectionText() const override; RimGeoMechCase* geoMechCase() const; public: diff --git a/ApplicationCode/GeoMech/GeoMechVisualization/RivFemElmVisibilityCalculator.cpp b/ApplicationCode/GeoMech/GeoMechVisualization/RivFemElmVisibilityCalculator.cpp index 07eb7bcc6e..d080b06d86 100644 --- a/ApplicationCode/GeoMech/GeoMechVisualization/RivFemElmVisibilityCalculator.cpp +++ b/ApplicationCode/GeoMech/GeoMechVisualization/RivFemElmVisibilityCalculator.cpp @@ -52,7 +52,7 @@ void RivFemElmVisibilityCalculator::computeAllVisible(cvf::UByteArray* elmVisibi //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RivFemElmVisibilityCalculator::computeRangeVisibility(cvf::UByteArray* elmVisibilities, RigFemPart* femPart, +void RivFemElmVisibilityCalculator::computeRangeVisibility(cvf::UByteArray* elmVisibilities, const RigFemPart* femPart, const cvf::CellRangeFilter& rangeFilter) { elmVisibilities->resize(femPart->elementCount()); diff --git a/ApplicationCode/GeoMech/GeoMechVisualization/RivFemElmVisibilityCalculator.h b/ApplicationCode/GeoMech/GeoMechVisualization/RivFemElmVisibilityCalculator.h index 659661ac41..3af5f24282 100644 --- a/ApplicationCode/GeoMech/GeoMechVisualization/RivFemElmVisibilityCalculator.h +++ b/ApplicationCode/GeoMech/GeoMechVisualization/RivFemElmVisibilityCalculator.h @@ -37,7 +37,7 @@ class RivFemElmVisibilityCalculator { public: static void computeAllVisible(cvf::UByteArray* elmVisibilities, const RigFemPart* femPart ); - static void computeRangeVisibility(cvf::UByteArray* elmVisibilities, RigFemPart* femPart, + static void computeRangeVisibility(cvf::UByteArray* elmVisibilities, const RigFemPart* femPart, const cvf::CellRangeFilter& rangeFilter); static void computePropertyVisibility(cvf::UByteArray* cellVisibility, diff --git a/ApplicationCode/GeoMech/GeoMechVisualization/RivFemPartGeometryGenerator.cpp b/ApplicationCode/GeoMech/GeoMechVisualization/RivFemPartGeometryGenerator.cpp index bafaff6b79..0963f1c6fe 100644 --- a/ApplicationCode/GeoMech/GeoMechVisualization/RivFemPartGeometryGenerator.cpp +++ b/ApplicationCode/GeoMech/GeoMechVisualization/RivFemPartGeometryGenerator.cpp @@ -29,7 +29,7 @@ #include "cvfPrimitiveSetIndexedUInt.h" #include "cvfScalarMapper.h" -#include +#include #include diff --git a/ApplicationCode/GeoMech/GeoMechVisualization/RivFemPartPartMgr.cpp b/ApplicationCode/GeoMech/GeoMechVisualization/RivFemPartPartMgr.cpp index ff1b983fb7..e5bbe5054f 100644 --- a/ApplicationCode/GeoMech/GeoMechVisualization/RivFemPartPartMgr.cpp +++ b/ApplicationCode/GeoMech/GeoMechVisualization/RivFemPartPartMgr.cpp @@ -17,7 +17,7 @@ // ///////////////////////////////////////////////////////////////////////////////// -#include +#include #include "RivGeoMechPartMgr.h" diff --git a/ApplicationCode/GeoMech/GeoMechVisualization/RivGeoMechPartMgr.cpp b/ApplicationCode/GeoMech/GeoMechVisualization/RivGeoMechPartMgr.cpp index 3d5401af6f..40f518dd8b 100644 --- a/ApplicationCode/GeoMech/GeoMechVisualization/RivGeoMechPartMgr.cpp +++ b/ApplicationCode/GeoMech/GeoMechVisualization/RivGeoMechPartMgr.cpp @@ -17,7 +17,7 @@ // ///////////////////////////////////////////////////////////////////////////////// -#include +#include #include "RivGeoMechPartMgr.h" #include "cvfPart.h" #include "cvfModelBasicList.h" diff --git a/ApplicationCode/GeoMech/OdbReader/CMakeLists.txt b/ApplicationCode/GeoMech/OdbReader/CMakeLists.txt index 57719f104f..f9a9a6950a 100644 --- a/ApplicationCode/GeoMech/OdbReader/CMakeLists.txt +++ b/ApplicationCode/GeoMech/OdbReader/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required (VERSION 2.8) +cmake_minimum_required (VERSION 2.8.12) project (RifOdbReader) @@ -92,3 +92,8 @@ target_include_directories(${PROJECT_NAME} target_link_libraries(${PROJECT_NAME} ${RI_ODB_LIBS} RigGeoMechDataModel LibCore) source_group("" FILES ${PROJECT_FILES}) + +# cotire +if (COMMAND caf_apply_cotire) + caf_apply_cotire("${PROJECT_NAME}") +endif() diff --git a/ApplicationCode/GeoMech/OdbReader/RifGeoMechReaderInterface.h b/ApplicationCode/GeoMech/OdbReader/RifGeoMechReaderInterface.h index 10ade9ac64..bf7bdfe6dc 100644 --- a/ApplicationCode/GeoMech/OdbReader/RifGeoMechReaderInterface.h +++ b/ApplicationCode/GeoMech/OdbReader/RifGeoMechReaderInterface.h @@ -39,7 +39,7 @@ class RifGeoMechReaderInterface : public cvf::Object { public: RifGeoMechReaderInterface(); - virtual ~RifGeoMechReaderInterface(); + ~RifGeoMechReaderInterface() override; virtual bool openFile(const std::string& fileName, std::string* errorMessage) = 0; virtual bool isOpen() const = 0; diff --git a/ApplicationCode/GeoMech/OdbReader/RifOdbReader.h b/ApplicationCode/GeoMech/OdbReader/RifOdbReader.h index 55fd3f514c..0fcf1d2284 100644 --- a/ApplicationCode/GeoMech/OdbReader/RifOdbReader.h +++ b/ApplicationCode/GeoMech/OdbReader/RifOdbReader.h @@ -39,27 +39,27 @@ class RifOdbReader : public RifGeoMechReaderInterface { public: RifOdbReader(); - virtual ~RifOdbReader(); + ~RifOdbReader() override; - virtual bool openFile(const std::string& fileName, std::string* errorMessage); - virtual bool isOpen() const; - virtual bool readFemParts(RigFemPartCollection* geoMechCase); - virtual std::vector allStepNames() const override; - virtual std::vector filteredStepNames() const override; - virtual std::vector frameTimes(int stepIndex) const override; + bool openFile(const std::string& fileName, std::string* errorMessage) override; + bool isOpen() const override; + bool readFemParts(RigFemPartCollection* geoMechCase) override; + std::vector allStepNames() const override; + std::vector filteredStepNames() const override; + std::vector frameTimes(int stepIndex) const override; - virtual std::vector elementSetNames(int partIndex); - virtual std::vector elementSet(int partIndex, int setIndex); + std::vector elementSetNames(int partIndex) override; + std::vector elementSet(int partIndex, int setIndex) override; - virtual std::map > scalarNodeFieldAndComponentNames(); - virtual std::map > scalarElementNodeFieldAndComponentNames(); - virtual std::map > scalarIntegrationPointFieldAndComponentNames(); + std::map > scalarNodeFieldAndComponentNames() override; + std::map > scalarElementNodeFieldAndComponentNames() override; + std::map > scalarIntegrationPointFieldAndComponentNames() override; - virtual void readDisplacements(int partIndex, int stepIndex, int frameIndex, std::vector* displacements); + void readDisplacements(int partIndex, int stepIndex, int frameIndex, std::vector* displacements) override; - virtual void readNodeField(const std::string& fieldName, int partIndex, int stepIndex, int frameIndex, std::vector*>* resultValues); - virtual void readElementNodeField(const std::string& fieldName, int partIndex, int stepIndex, int frameIndex, std::vector*>* resultValues); - virtual void readIntegrationPointField(const std::string& fieldName, int partIndex, int stepIndex, int frameIndex, std::vector*>* resultValues); + void readNodeField(const std::string& fieldName, int partIndex, int stepIndex, int frameIndex, std::vector*>* resultValues) override; + void readElementNodeField(const std::string& fieldName, int partIndex, int stepIndex, int frameIndex, std::vector*>* resultValues) override; + void readIntegrationPointField(const std::string& fieldName, int partIndex, int stepIndex, int frameIndex, std::vector*>* resultValues) override; private: enum ResultPosition diff --git a/ApplicationCode/ModelVisualization/CMakeLists_files.cmake b/ApplicationCode/ModelVisualization/CMakeLists_files.cmake index 2750550fdd..d57e2efa0d 100644 --- a/ApplicationCode/ModelVisualization/CMakeLists_files.cmake +++ b/ApplicationCode/ModelVisualization/CMakeLists_files.cmake @@ -46,6 +46,15 @@ ${CMAKE_CURRENT_LIST_DIR}/RivSimWellConnectionSourceInfo.h ${CMAKE_CURRENT_LIST_DIR}/Riv3dWellLogDrawSurfaceGenerator.h ${CMAKE_CURRENT_LIST_DIR}/RivMeshLinesSourceInfo.h ${CMAKE_CURRENT_LIST_DIR}/RivContourMapProjectionPartMgr.h +${CMAKE_CURRENT_LIST_DIR}/RivAnnotationsPartMgr.h +${CMAKE_CURRENT_LIST_DIR}/RivTextAnnotationPartMgr.h +${CMAKE_CURRENT_LIST_DIR}/RivReachCircleAnnotationPartMgr.h +${CMAKE_CURRENT_LIST_DIR}/RivPolylineAnnotationPartMgr.h +${CMAKE_CURRENT_LIST_DIR}/RivReachCircleAnnotationSourceInfo.h +${CMAKE_CURRENT_LIST_DIR}/RivPolylinesAnnotationSourceInfo.h +${CMAKE_CURRENT_LIST_DIR}/RivPolylineGenerator.h +${CMAKE_CURRENT_LIST_DIR}/RivMeasurementPartMgr.h +${CMAKE_CURRENT_LIST_DIR}/RivTextLabelSourceInfo.h ) set (SOURCE_GROUP_SOURCE_FILES @@ -90,6 +99,15 @@ ${CMAKE_CURRENT_LIST_DIR}/RivSimWellConnectionSourceInfo.cpp ${CMAKE_CURRENT_LIST_DIR}/Riv3dWellLogDrawSurfaceGenerator.cpp ${CMAKE_CURRENT_LIST_DIR}/RivMeshLinesSourceInfo.cpp ${CMAKE_CURRENT_LIST_DIR}/RivContourMapProjectionPartMgr.cpp +${CMAKE_CURRENT_LIST_DIR}/RivAnnotationsPartMgr.cpp +${CMAKE_CURRENT_LIST_DIR}/RivTextAnnotationPartMgr.cpp +${CMAKE_CURRENT_LIST_DIR}/RivReachCircleAnnotationPartMgr.cpp +${CMAKE_CURRENT_LIST_DIR}/RivPolylineAnnotationPartMgr.cpp +${CMAKE_CURRENT_LIST_DIR}/RivReachCircleAnnotationSourceInfo.cpp +${CMAKE_CURRENT_LIST_DIR}/RivPolylinesAnnotationSourceInfo.cpp +${CMAKE_CURRENT_LIST_DIR}/RivPolylineGenerator.cpp +${CMAKE_CURRENT_LIST_DIR}/RivMeasurementPartMgr.cpp +${CMAKE_CURRENT_LIST_DIR}/RivTextLabelSourceInfo.cpp ) list(APPEND CODE_HEADER_FILES diff --git a/ApplicationCode/ModelVisualization/GridBox/RivGridBoxGenerator.cpp b/ApplicationCode/ModelVisualization/GridBox/RivGridBoxGenerator.cpp index bd029f1fa1..4f90045efd 100644 --- a/ApplicationCode/ModelVisualization/GridBox/RivGridBoxGenerator.cpp +++ b/ApplicationCode/ModelVisualization/GridBox/RivGridBoxGenerator.cpp @@ -639,7 +639,7 @@ void RivGridBoxGenerator::createLegend(EdgeType edge, cvf::Collection cvf::ref geo = new cvf::DrawableText; - cvf::Font* standardFont = RiaApplication::instance()->standardFont(); + cvf::Font* standardFont = RiaApplication::instance()->defaultSceneFont(); geo->setFont(standardFont); geo->setTextColor(m_gridLegendColor); @@ -741,7 +741,7 @@ cvf::Vec3f RivGridBoxGenerator::cornerDirection(FaceType face1, FaceType face2) void RivGridBoxGenerator::updateFromBackgroundColor(const cvf::Color3f& backgroundColor) { m_gridColor = RiaColorTools::computeOffsetColor(backgroundColor, 0.3f); - m_gridLegendColor = RiaColorTools::constrastColor(backgroundColor); + m_gridLegendColor = RiaColorTools::contrastColor(backgroundColor); } //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/ModelVisualization/Intersections/RivIntersectionBoxGeometryGenerator.cpp b/ApplicationCode/ModelVisualization/Intersections/RivIntersectionBoxGeometryGenerator.cpp index 5a634fd745..e90bcf16d4 100644 --- a/ApplicationCode/ModelVisualization/Intersections/RivIntersectionBoxGeometryGenerator.cpp +++ b/ApplicationCode/ModelVisualization/Intersections/RivIntersectionBoxGeometryGenerator.cpp @@ -203,7 +203,7 @@ class Box std::array adjacentFaces(FaceType face) { - std::array clipFaces; + std::array clipFaces = {FaceType::NO_FACE, FaceType::NO_FACE, FaceType::NO_FACE, FaceType::NO_FACE} ; FaceType oppFace = cvf::StructGridInterface::oppositeFace(face); int clipFaceCount = 0; for (int faceCand = 0; faceCand < 6; ++faceCand ) diff --git a/ApplicationCode/ModelVisualization/Intersections/RivIntersectionGeometryGenerator.cpp b/ApplicationCode/ModelVisualization/Intersections/RivIntersectionGeometryGenerator.cpp index ed8d4ff94b..4eb501a8d0 100644 --- a/ApplicationCode/ModelVisualization/Intersections/RivIntersectionGeometryGenerator.cpp +++ b/ApplicationCode/ModelVisualization/Intersections/RivIntersectionGeometryGenerator.cpp @@ -27,6 +27,7 @@ #include "RivHexGridIntersectionTools.h" #include "RivIntersectionPartMgr.h" +#include "RivPolylineGenerator.h" #include "cafHexGridIntersectionTools/cafHexGridIntersectionTools.h" #include "cafDisplayCoordTransform.h" @@ -483,7 +484,7 @@ cvf::ref RivIntersectionGeometryGenerator::createFaultMeshDraw //-------------------------------------------------------------------------------------------------- cvf::ref RivIntersectionGeometryGenerator::createLineAlongPolylineDrawable() { - return createLineAlongPolylineDrawable(m_flattenedOrOffsettedPolyLines); + return RivPolylineGenerator::createLineAlongPolylineDrawable(m_flattenedOrOffsettedPolyLines); } //-------------------------------------------------------------------------------------------------- @@ -499,48 +500,7 @@ cvf::ref RivIntersectionGeometryGenerator::createLineAlongExtr displayCoords.push_back(transform->translateToDisplayCoord(pt)); } - return createLineAlongPolylineDrawable(std::vector>({ displayCoords })); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -cvf::ref RivIntersectionGeometryGenerator::createLineAlongPolylineDrawable(const std::vector >& polyLines) -{ - std::vector lineIndices; - std::vector vertices; - - for (size_t pLineIdx = 0; pLineIdx < polyLines.size(); ++pLineIdx) - { - const std::vector& polyLine = polyLines[pLineIdx]; - if (polyLine.size() < 2) continue; - - for (size_t i = 0; i < polyLine.size(); ++i) - { - vertices.push_back(cvf::Vec3f(polyLine[i])); - if (i < polyLine.size() - 1) - { - lineIndices.push_back(static_cast(i)); - lineIndices.push_back(static_cast(i + 1)); - } - } - } - - if (vertices.size() == 0) return nullptr; - - cvf::ref vx = new cvf::Vec3fArray; - vx->assign(vertices); - cvf::ref idxes = new cvf::UIntArray; - idxes->assign(lineIndices); - - cvf::ref prim = new cvf::PrimitiveSetIndexedUInt(cvf::PT_LINES); - prim->setIndices(idxes.p()); - - cvf::ref polylineGeo = new cvf::DrawableGeo; - polylineGeo->setVertexArray(vx.p()); - polylineGeo->addPrimitiveSet(prim.p()); - - return polylineGeo; + return RivPolylineGenerator::createLineAlongPolylineDrawable(std::vector>({ displayCoords })); } //-------------------------------------------------------------------------------------------------- @@ -548,7 +508,7 @@ cvf::ref RivIntersectionGeometryGenerator::createLineAlongPoly //-------------------------------------------------------------------------------------------------- cvf::ref RivIntersectionGeometryGenerator::createPointsFromPolylineDrawable() { - return createPointsFromPolylineDrawable(m_flattenedOrOffsettedPolyLines); + return RivPolylineGenerator::createPointsFromPolylineDrawable(m_flattenedOrOffsettedPolyLines); } //-------------------------------------------------------------------------------------------------- @@ -564,39 +524,7 @@ cvf::ref RivIntersectionGeometryGenerator::createPointsFromExt displayCoords.push_back(transform->translateToDisplayCoord(pt)); } - return createPointsFromPolylineDrawable(std::vector>({displayCoords})); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -cvf::ref RivIntersectionGeometryGenerator::createPointsFromPolylineDrawable(const std::vector >& polyLines) -{ - std::vector vertices; - - for (size_t pLineIdx = 0; pLineIdx < polyLines.size(); ++pLineIdx) - { - const std::vector& polyLine = polyLines[pLineIdx]; - for (size_t i = 0; i < polyLine.size(); ++i) - { - vertices.push_back(cvf::Vec3f(polyLine[i])); - } - } - - if (vertices.size() == 0) return nullptr; - - cvf::ref primSet = new cvf::PrimitiveSetDirect(cvf::PT_POINTS); - primSet->setStartIndex(0); - primSet->setIndexCount(vertices.size()); - - cvf::ref geo = new cvf::DrawableGeo; - - cvf::ref vx = new cvf::Vec3fArray(vertices); - geo->setVertexArray(vx.p()); - geo->addPrimitiveSet(primSet.p()); - - return geo; - + return RivPolylineGenerator::createPointsFromPolylineDrawable(std::vector>({displayCoords})); } //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/ModelVisualization/Intersections/RivIntersectionGeometryGenerator.h b/ApplicationCode/ModelVisualization/Intersections/RivIntersectionGeometryGenerator.h index 24954f8e77..ba3d09a9e1 100644 --- a/ApplicationCode/ModelVisualization/Intersections/RivIntersectionGeometryGenerator.h +++ b/ApplicationCode/ModelVisualization/Intersections/RivIntersectionGeometryGenerator.h @@ -83,9 +83,6 @@ class RivIntersectionGeometryGenerator : public cvf::Object cvf::Mat4d unflattenTransformMatrix(const cvf::Vec3d& intersectionPointFlat); private: - cvf::ref createLineAlongPolylineDrawable(const std::vector >& polyLines); - cvf::ref createPointsFromPolylineDrawable(const std::vector >& polyLines); - void calculateArrays(); void calculateSegementTransformPrLinePoint(); void calculateFlattenedOrOffsetedPolyline(); diff --git a/ApplicationCode/ModelVisualization/Intersections/RivIntersectionPartMgr.cpp b/ApplicationCode/ModelVisualization/Intersections/RivIntersectionPartMgr.cpp index 7caae7a6e8..e639ce69de 100644 --- a/ApplicationCode/ModelVisualization/Intersections/RivIntersectionPartMgr.cpp +++ b/ApplicationCode/ModelVisualization/Intersections/RivIntersectionPartMgr.cpp @@ -606,8 +606,8 @@ void RivIntersectionPartMgr::createFaultLabelParts(const std::vectorshowFaultLabel())) return; - cvf::Color3f defWellLabelColor = faultInViewColl->faultLabelColor(); - cvf::Font* font = RiaApplication::instance()->customFont(); + cvf::Color3f faultLabelColor = faultInViewColl->faultLabelColor(); + cvf::Font* font = RiaApplication::instance()->defaultSceneFont(); std::vector lineVertices; @@ -618,7 +618,7 @@ void RivIntersectionPartMgr::createFaultLabelParts(const std::vectorsetDrawBorder(false); drawableText->setDrawBackground(false); drawableText->setVerticalAlignment(cvf::TextDrawer::BASELINE); - drawableText->setTextColor(defWellLabelColor); + drawableText->setTextColor(faultLabelColor); } cvf::BoundingBox bb = m_crossSectionFaces->boundingBox(); diff --git a/ApplicationCode/ModelVisualization/Intersections/RivSectionFlattner.cpp b/ApplicationCode/ModelVisualization/Intersections/RivSectionFlattner.cpp index b189e6ddca..89ca84db92 100644 --- a/ApplicationCode/ModelVisualization/Intersections/RivSectionFlattner.cpp +++ b/ApplicationCode/ModelVisualization/Intersections/RivSectionFlattner.cpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018- Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by diff --git a/ApplicationCode/ModelVisualization/Intersections/RivSectionFlattner.h b/ApplicationCode/ModelVisualization/Intersections/RivSectionFlattner.h index 6d3a9288ae..cc799d18ed 100644 --- a/ApplicationCode/ModelVisualization/Intersections/RivSectionFlattner.h +++ b/ApplicationCode/ModelVisualization/Intersections/RivSectionFlattner.h @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018- Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by diff --git a/ApplicationCode/ModelVisualization/Riv3dWellLogCurveGeometryGenerator.cpp b/ApplicationCode/ModelVisualization/Riv3dWellLogCurveGeometryGenerator.cpp index e7687dfc74..6062c0b731 100644 --- a/ApplicationCode/ModelVisualization/Riv3dWellLogCurveGeometryGenerator.cpp +++ b/ApplicationCode/ModelVisualization/Riv3dWellLogCurveGeometryGenerator.cpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018- Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -98,21 +98,17 @@ void Riv3dWellLogCurveGeometryGenerator::createCurveDrawables(const caf::Display } clipLocation = displayCoordTransform->transformToDisplayCoord(clipLocation); - std::vector wellPathPoints = wellPathGeometry()->m_wellPathPoints; - for (cvf::Vec3d& wellPathPoint : wellPathPoints) - { - wellPathPoint = displayCoordTransform->transformToDisplayCoord(wellPathPoint); - } + std::vector displayCoords = displayCoordTransform->transformToDisplayCoords(wellPathGeometry()->m_wellPathPoints); std::vector wellPathCurveNormals = - RigWellPathGeometryTools::calculateLineSegmentNormals(wellPathPoints, rim3dWellLogCurve->drawPlaneAngle(rim3dWellLogCurve->drawPlane())); + RigWellPathGeometryTools::calculateLineSegmentNormals(displayCoords, rim3dWellLogCurve->drawPlaneAngle(rim3dWellLogCurve->drawPlane())); std::vector interpolatedWellPathPoints; std::vector interpolatedCurveNormals; // Iterate from bottom of well path and up to be able to stop at given Z max clipping height for (auto md = resultMds.rbegin(); md != resultMds.rend(); md++) { - cvf::Vec3d point = wellPathGeometry()->interpolatedVectorValuesAlongWellPath(wellPathPoints, *md); + cvf::Vec3d point = wellPathGeometry()->interpolatedVectorValuesAlongWellPath(displayCoords, *md); cvf::Vec3d normal = wellPathGeometry()->interpolatedVectorValuesAlongWellPath(wellPathCurveNormals, *md); if (point.z() > clipLocation.z()) break; diff --git a/ApplicationCode/ModelVisualization/Riv3dWellLogCurveGeometryGenerator.h b/ApplicationCode/ModelVisualization/Riv3dWellLogCurveGeometryGenerator.h index 9eeee18ff8..df37a6da34 100644 --- a/ApplicationCode/ModelVisualization/Riv3dWellLogCurveGeometryGenerator.h +++ b/ApplicationCode/ModelVisualization/Riv3dWellLogCurveGeometryGenerator.h @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018- Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by diff --git a/ApplicationCode/ModelVisualization/Riv3dWellLogDrawSurfaceGenerator.cpp b/ApplicationCode/ModelVisualization/Riv3dWellLogDrawSurfaceGenerator.cpp index 82fb5a3a98..ca0b3ff358 100644 --- a/ApplicationCode/ModelVisualization/Riv3dWellLogDrawSurfaceGenerator.cpp +++ b/ApplicationCode/ModelVisualization/Riv3dWellLogDrawSurfaceGenerator.cpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018- Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -72,20 +72,20 @@ Riv3dWellLogDrawSurfaceGenerator::createDrawSurface(const caf::DisplayCoordTrans RimWellPathCollection* wellPathCollection = nullptr; m_wellPath->firstAncestorOrThisOfTypeAsserted(wellPathCollection); - std::vector wellPathPoints = wellPathGeometry()->m_wellPathPoints; - if (wellPathPoints.size() < (size_t)2) + std::vector wellPathDisplayCoords; { - // Need at least two well path points to create a valid path. - return false; - } - - for (cvf::Vec3d& wellPathPoint : wellPathPoints) - { - wellPathPoint = displayCoordTransform->transformToDisplayCoord(wellPathPoint); + std::vector domainCoords = wellPathGeometry()->m_wellPathPoints; + if (domainCoords.size() < (size_t)2) + { + // Need at least two well path points to create a valid path. + return false; + } + + wellPathDisplayCoords = displayCoordTransform->transformToDisplayCoords(domainCoords); } std::vector wellPathSegmentNormals = - RigWellPathGeometryTools::calculateLineSegmentNormals(wellPathPoints, planeAngle); + RigWellPathGeometryTools::calculateLineSegmentNormals(wellPathDisplayCoords, planeAngle); size_t indexToFirstVisibleSegment = 0u; if (wellPathCollection->wellPathClip) @@ -95,27 +95,27 @@ Riv3dWellLogDrawSurfaceGenerator::createDrawSurface(const caf::DisplayCoordTrans clipLocation = displayCoordTransform->transformToDisplayCoord(clipLocation); double horizontalLengthAlongWellToClipPoint; - wellPathPoints = RigWellPath::clipPolylineStartAboveZ( - wellPathPoints, clipLocation.z(), &horizontalLengthAlongWellToClipPoint, &indexToFirstVisibleSegment); + wellPathDisplayCoords = RigWellPath::clipPolylineStartAboveZ( + wellPathDisplayCoords, clipLocation.z(), &horizontalLengthAlongWellToClipPoint, &indexToFirstVisibleSegment); } // Create curve normal vectors using the unclipped well path points and normals. createCurveNormalVectors(displayCoordTransform, indexToFirstVisibleSegment, planeOffsetFromWellPathCenter, planeWidth, samplingIntervalSize, wellPathSegmentNormals); // Note that normals are calculated on the full non-clipped well path. So we need to clip the start here. - wellPathSegmentNormals.erase(wellPathSegmentNormals.begin(), wellPathSegmentNormals.end() - wellPathPoints.size()); + wellPathSegmentNormals.erase(wellPathSegmentNormals.begin(), wellPathSegmentNormals.end() - wellPathDisplayCoords.size()); - if (wellPathPoints.size() < (size_t)2) + if (wellPathDisplayCoords.size() < (size_t)2) { // Need at least two well path points to create a valid path. return false; } - m_vertices.reserve(wellPathPoints.size() * 2); - for (size_t i = 0; i < wellPathPoints.size(); i++) + m_vertices.reserve(wellPathDisplayCoords.size() * 2); + for (size_t i = 0; i < wellPathDisplayCoords.size(); i++) { - m_vertices.push_back(wellPathPoints[i] + wellPathSegmentNormals[i] * (planeOffsetFromWellPathCenter - 0.025*planeWidth)); - m_vertices.push_back(wellPathPoints[i] + wellPathSegmentNormals[i] * (planeOffsetFromWellPathCenter + 1.025*planeWidth)); + m_vertices.push_back(wellPathDisplayCoords[i] + wellPathSegmentNormals[i] * (planeOffsetFromWellPathCenter - 0.025*planeWidth)); + m_vertices.push_back(wellPathDisplayCoords[i] + wellPathSegmentNormals[i] * (planeOffsetFromWellPathCenter + 1.025*planeWidth)); } cvf::ref vertexArray = new cvf::Vec3fArray(m_vertices.size()); diff --git a/ApplicationCode/ModelVisualization/Riv3dWellLogDrawSurfaceGenerator.h b/ApplicationCode/ModelVisualization/Riv3dWellLogDrawSurfaceGenerator.h index 8b7922c28b..ea670cd176 100644 --- a/ApplicationCode/ModelVisualization/Riv3dWellLogDrawSurfaceGenerator.h +++ b/ApplicationCode/ModelVisualization/Riv3dWellLogDrawSurfaceGenerator.h @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018- Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by diff --git a/ApplicationCode/ModelVisualization/Riv3dWellLogPlanePartMgr.cpp b/ApplicationCode/ModelVisualization/Riv3dWellLogPlanePartMgr.cpp index e4a1c5e7b0..0a35d826a5 100644 --- a/ApplicationCode/ModelVisualization/Riv3dWellLogPlanePartMgr.cpp +++ b/ApplicationCode/ModelVisualization/Riv3dWellLogPlanePartMgr.cpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018- Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by diff --git a/ApplicationCode/ModelVisualization/Riv3dWellLogPlanePartMgr.h b/ApplicationCode/ModelVisualization/Riv3dWellLogPlanePartMgr.h index 372455e715..254308b2b6 100644 --- a/ApplicationCode/ModelVisualization/Riv3dWellLogPlanePartMgr.h +++ b/ApplicationCode/ModelVisualization/Riv3dWellLogPlanePartMgr.h @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018- Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by diff --git a/ApplicationCode/ModelVisualization/RivAnnotationsPartMgr.cpp b/ApplicationCode/ModelVisualization/RivAnnotationsPartMgr.cpp new file mode 100644 index 0000000000..4199cb021b --- /dev/null +++ b/ApplicationCode/ModelVisualization/RivAnnotationsPartMgr.cpp @@ -0,0 +1,142 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2011- Statoil ASA +// Copyright (C) 2013- Ceetron Solutions AS +// Copyright (C) 2011-2012 Ceetron AS +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + + + +#include "RivAnnotationsPartMgr.h" + +#include "RiaApplication.h" + +#include "Rim3dView.h" +#include "RimAnnotationInViewCollection.h" +#include "RimProject.h" + +#include "RimUserDefinedPolylinesAnnotationInView.h" +#include "RimPolylinesFromFileAnnotationInView.h" + +#include "RivTextAnnotationPartMgr.h" +#include "RivReachCircleAnnotationPartMgr.h" +#include "RivPolylineAnnotationPartMgr.h" + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RivAnnotationsPartMgr::RivAnnotationsPartMgr(Rim3dView* view) +: m_rimView(view) +{ +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RivAnnotationsPartMgr::~RivAnnotationsPartMgr() +{ + +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RivAnnotationsPartMgr::appendGeometryPartsToModel(cvf::ModelBasicList* model, + const caf::DisplayCoordTransform* displayCoordTransform, + const cvf::BoundingBox& boundingBox) +{ + createAnnotationPartManagers(); + + for (auto& partMgr : m_textAnnotationPartMgrs) + { + partMgr->appendDynamicGeometryPartsToModel(model, displayCoordTransform, boundingBox); + } + for (auto& partMgr : m_reachCircleAnnotationPartMgrs) + { + partMgr->appendDynamicGeometryPartsToModel(model, displayCoordTransform, boundingBox); + } + for (auto& partMgr : m_polylineAnnotationPartMgrs) + { + partMgr->appendDynamicGeometryPartsToModel(model, displayCoordTransform, boundingBox); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RivAnnotationsPartMgr::createAnnotationPartManagers() +{ + std::vector colls; + m_rimView->descendantsIncludingThisOfType(colls); + + if (colls.empty()) return; + auto coll = colls.front(); + + auto localTextAnnotations = coll->textAnnotations(); + auto textAnnotations = coll->globalTextAnnotations(); + auto reachCircleAnnotations = coll->globalReachCircleAnnotations(); + auto userDefinedPolylineAnnotations = coll->globalUserDefinedPolylineAnnotations(); + auto polylineFromFileAnnotations = coll->globalPolylineFromFileAnnotations(); + + clearGeometryCache(); + + if (m_textAnnotationPartMgrs.size() != localTextAnnotations.size() + textAnnotations.size()) + { + for (auto annotation : localTextAnnotations) + { + auto* apm = new RivTextAnnotationPartMgr(m_rimView, annotation); + m_textAnnotationPartMgrs.push_back(apm); + } + for (auto annotation : textAnnotations) + { + auto* apm = new RivTextAnnotationPartMgr(m_rimView, annotation); + m_textAnnotationPartMgrs.push_back(apm); + } + } + if (m_reachCircleAnnotationPartMgrs.size() != reachCircleAnnotations.size()) + { + for (auto annotation : reachCircleAnnotations) + { + auto* apm = new RivReachCircleAnnotationPartMgr(m_rimView, annotation); + m_reachCircleAnnotationPartMgrs.push_back(apm); + } + } + if (m_polylineAnnotationPartMgrs.size() != userDefinedPolylineAnnotations.size() + polylineFromFileAnnotations.size()) + { + for (auto annotation : userDefinedPolylineAnnotations) + { + auto* apm = new RivPolylineAnnotationPartMgr(m_rimView, annotation); + m_polylineAnnotationPartMgrs.push_back(apm); + } + for (auto annotation : polylineFromFileAnnotations) + { + auto* apm = new RivPolylineAnnotationPartMgr(m_rimView, annotation); + m_polylineAnnotationPartMgrs.push_back(apm); + } + } + +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RivAnnotationsPartMgr::clearGeometryCache() +{ + m_textAnnotationPartMgrs.clear(); + m_reachCircleAnnotationPartMgrs.clear(); + m_polylineAnnotationPartMgrs.clear(); +} diff --git a/ApplicationCode/ModelVisualization/RivAnnotationsPartMgr.h b/ApplicationCode/ModelVisualization/RivAnnotationsPartMgr.h new file mode 100644 index 0000000000..229e1c6728 --- /dev/null +++ b/ApplicationCode/ModelVisualization/RivAnnotationsPartMgr.h @@ -0,0 +1,69 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2011-2012 Statoil ASA, Ceetron AS +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "cvfBase.h" +#include "cvfAssert.h" +#include "cvfCollection.h" +#include "cvfObject.h" +#include "cafPdmPointer.h" + +namespace cvf +{ + class BoundingBox; + class Part; + class ModelBasicList; + class Transform; + class Font; +} +namespace caf +{ + class DisplayCoordTransform; +} + +class Rim3dView; +class RimAnnotationInViewCollection; +class RivTextAnnotationPartMgr; +class RivReachCircleAnnotationPartMgr; +class RivPolylineAnnotationPartMgr; +class RimSimWellInView; +class RimSimWellInViewCollection; + +class RivAnnotationsPartMgr : public cvf::Object +{ +public: + RivAnnotationsPartMgr( Rim3dView* view); + ~RivAnnotationsPartMgr() override; + + void appendGeometryPartsToModel(cvf::ModelBasicList* model, + const caf::DisplayCoordTransform* displayCoordTransform, + const cvf::BoundingBox& boundingBox); + + void clearGeometryCache(); + + +private: + void createAnnotationPartManagers(); + +private: + caf::PdmPointer m_rimView; + cvf::Collection m_textAnnotationPartMgrs; + cvf::Collection m_reachCircleAnnotationPartMgrs; + cvf::Collection m_polylineAnnotationPartMgrs; +}; diff --git a/ApplicationCode/ModelVisualization/RivCellEdgeGeometryUtils.cpp b/ApplicationCode/ModelVisualization/RivCellEdgeGeometryUtils.cpp index 0b6cf69ba0..e0c45b5af5 100644 --- a/ApplicationCode/ModelVisualization/RivCellEdgeGeometryUtils.cpp +++ b/ApplicationCode/ModelVisualization/RivCellEdgeGeometryUtils.cpp @@ -310,8 +310,8 @@ cvf::ref RivCellEdgeGeometryUtils::createCellEdgeResultAccess } else { - size_t resultIndices[6]; - cellEdgeResultColors->gridScalarIndices(resultIndices); + RigEclipseResultAddress resultAddresses[6]; + cellEdgeResultColors->gridScalarIndices(resultAddresses); std::vector metaData; cellEdgeResultColors->cellEdgeMetaData(&metaData); @@ -326,7 +326,7 @@ cvf::ref RivCellEdgeGeometryUtils::createCellEdgeResultAccess } RiaDefines::PorosityModelType porosityModel = cellResultColors->porosityModel(); - cvf::ref daObj = RigResultAccessorFactory::createFromResultIdx(eclipseCase, grid->gridIndex(), porosityModel, adjustedTimeStep, resultIndices[cubeFaceIdx]); + cvf::ref daObj = RigResultAccessorFactory::createFromResultAddress(eclipseCase, grid->gridIndex(), porosityModel, adjustedTimeStep, resultAddresses[cubeFaceIdx]); cellEdgeResultAccessor->setDataAccessObjectForFace(static_cast(cubeFaceIdx), daObj.p()); } } diff --git a/ApplicationCode/ModelVisualization/RivContourMapProjectionPartMgr.cpp b/ApplicationCode/ModelVisualization/RivContourMapProjectionPartMgr.cpp index 0dfe93034b..ac72d34dc0 100644 --- a/ApplicationCode/ModelVisualization/RivContourMapProjectionPartMgr.cpp +++ b/ApplicationCode/ModelVisualization/RivContourMapProjectionPartMgr.cpp @@ -1,71 +1,65 @@ #include "RivContourMapProjectionPartMgr.h" +#include "RiaColorTools.h" +#include "RiaFontCache.h" #include "RiaWeightedMeanCalculator.h" +#include "RigCellGeometryTools.h" #include "RivMeshLinesSourceInfo.h" #include "RivScalarMapperUtils.h" +#include "RivPartPriority.h" -#include "RimContourMapView.h" +#include "RimGridView.h" #include "RimContourMapProjection.h" #include "cafEffectGenerator.h" +#include "cafFixedAtlasFont.h" +#include "cafCategoryMapper.h" +#include "cvfCamera.h" +#include "cvfDrawableText.h" #include "cvfGeometryBuilderFaceList.h" +#include "cvfGeometryTools.h" #include "cvfGeometryUtils.h" #include "cvfMeshEdgeExtractor.h" #include "cvfPart.h" #include "cvfPrimitiveSetIndexedUInt.h" +#include "cvfScalarMapper.h" +#include "cvfRay.h" #include +#include //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -RivContourMapProjectionPartMgr::RivContourMapProjectionPartMgr(RimContourMapProjection* contourMapProjection, RimContourMapView* contourMap) +RivContourMapProjectionPartMgr::RivContourMapProjectionPartMgr(RimContourMapProjection* contourMapProjection, RimGridView* contourMap) { m_contourMapProjection = contourMapProjection; m_parentContourMap = contourMap; + + m_labelEffect = new cvf::Effect; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RivContourMapProjectionPartMgr::appendProjectionToModel(cvf::ModelBasicList* model, const caf::DisplayCoordTransform* displayCoordTransform) const +void RivContourMapProjectionPartMgr::createProjectionGeometry() { - cvf::ref drawable = createProjectionMapDrawable(displayCoordTransform); - if (drawable.notNull() && drawable->boundingBox().isValid()) - { - cvf::ref part = new cvf::Part; - part->setDrawable(drawable.p()); - - cvf::ref textureCoords = createTextureCoords(); - cvf::ScalarMapper* mapper = m_contourMapProjection->legendConfig()->scalarMapper(); - RivScalarMapperUtils::applyTextureResultsToPart(part.p(), textureCoords.p(), mapper, 1.0f, caf::FC_NONE, true, m_parentContourMap->backgroundColor()); - - part->setSourceInfo(new RivObjectSourceInfo(m_contourMapProjection.p())); - - model->addPart(part.p()); - } + m_contourMapProjection->generateGeometryIfNecessary(); - if (m_contourMapProjection->showContourLines()) - { - std::vector> contourDrawables = createContourPolygons(displayCoordTransform); - for (cvf::ref contourDrawable : contourDrawables) - { - if (contourDrawable.notNull() && contourDrawable->boundingBox().isValid()) - { - caf::MeshEffectGenerator meshEffectGen(cvf::Color3::BLACK); - meshEffectGen.setLineWidth(1.0f); - meshEffectGen.createAndConfigurePolygonOffsetRenderState(caf::PO_1); - cvf::ref effect = meshEffectGen.generateCachedEffect(); - - cvf::ref part = new cvf::Part; - part->setDrawable(contourDrawable.p()); - part->setEffect(effect.p()); - part->setSourceInfo(new RivMeshLinesSourceInfo(m_contourMapProjection.p())); + m_contourLinePolygons = m_contourMapProjection->contourPolygons(); + m_contourMapTriangles = m_contourMapProjection->trianglesWithVertexValues(); +} - model->addPart(part.p()); - } - } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RivContourMapProjectionPartMgr::appendProjectionToModel(cvf::ModelBasicList* model, const caf::DisplayCoordTransform* displayCoordTransform) const +{ + cvf::ref mapPart = createProjectionMapPart(displayCoordTransform); + if (mapPart.notNull()) + { + model->addPart(mapPart.p()); } } @@ -95,126 +89,420 @@ void RivContourMapProjectionPartMgr::appendPickPointVisToModel(cvf::ModelBasicLi //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -cvf::ref RivContourMapProjectionPartMgr::createTextureCoords() const +cvf::ref RivContourMapProjectionPartMgr::createTextureCoords(const std::vector& values) const { cvf::Vec2ui patchSize = m_contourMapProjection->numberOfVerticesIJ(); - cvf::ref textureCoords = new cvf::Vec2fArray(m_contourMapProjection->numberOfVertices()); + cvf::ref textureCoords = new cvf::Vec2fArray(values.size()); #pragma omp parallel for - for (int j = 0; j < static_cast(patchSize.y()); ++j) + for (int i = 0; i < (int) values.size(); ++i) { - for (int i = 0; i < static_cast(patchSize.x()); ++i) + if (values[i] != std::numeric_limits::infinity()) { - if (m_contourMapProjection->hasResultAtVertex(i, j)) - { - double value = m_contourMapProjection->valueAtVertex(i, j); - cvf::Vec2f textureCoord = m_contourMapProjection->legendConfig()->scalarMapper()->mapToTextureCoord(value); - textureCoord.y() = 0.0; - (*textureCoords)[i + j * patchSize.x()] = textureCoord; - } - else + cvf::Vec2f textureCoord = m_contourMapProjection->legendConfig()->scalarMapper()->mapToTextureCoord(values[i]); + textureCoord.y() = 0.0; + (*textureCoords)[i] = textureCoord; + } + else + { + (*textureCoords)[i] = cvf::Vec2f(0.0, 1.0); + } + } + return textureCoords; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RivContourMapProjectionPartMgr::appendContourLinesToModel(const cvf::Camera* camera, + cvf::ModelBasicList* model, + const caf::DisplayCoordTransform* displayCoordTransform) +{ + if (m_contourMapProjection->showContourLines()) + { + cvf::ScalarMapper* mapper = m_contourMapProjection->legendConfig()->scalarMapper(); + + std::vector> labelBBoxes; + std::vector> labelDrawables = createContourLabels(camera, displayCoordTransform, &labelBBoxes); + + std::vector>> contourDrawablesForAllLevels = + createContourPolygons(displayCoordTransform, labelBBoxes); + + std::vector tickValues; + mapper->majorTickValues(&tickValues); + + for (size_t i = 0; i < contourDrawablesForAllLevels.size(); ++i) + { + std::vector> contourDrawables = contourDrawablesForAllLevels[i]; + + cvf::Color3f backgroundColor(mapper->mapToColor(tickValues[i])); + cvf::Color3f lineColor = RiaColorTools::contrastColor(backgroundColor); + + for (cvf::ref contourDrawable : contourDrawables) { - RiaWeightedMeanCalculator calc; - for (int jj = j - 1; jj <= j + 1; ++jj) + if (contourDrawable.notNull() && contourDrawable->boundingBox().isValid()) { - for (int ii = i - 1; ii <= i + 1; ++ii) - { - if (jj >= 0 && ii >= 0 && jj < static_cast(patchSize.y()) && ii < static_cast(patchSize.x())) - { - if (!(ii == i && jj == j) && m_contourMapProjection->hasResultAtVertex(ii, jj)) - { - double value = m_contourMapProjection->valueAtVertex(ii, jj); - calc.addValueAndWeight(value, 1. / std::sqrt((i - ii)*(i - ii) + (j - jj)*(j - jj))); - } - } - } - } - if (calc.validAggregatedWeight()) - { - const double maxTheoreticalWeightSum = 4.0 + 4.0 / std::sqrt(2.0); - double value = calc.weightedMean(); - cvf::Vec2f textureCoord = m_contourMapProjection->legendConfig()->scalarMapper()->mapToTextureCoord(value); - textureCoord.y() = 1.0 - calc.aggregatedWeight() / maxTheoreticalWeightSum; - (*textureCoords)[i + j * patchSize.x()] = textureCoord; - } - else - { - (*textureCoords)[i + j * patchSize.x()] = cvf::Vec2f(0.0, 1.0); + caf::MeshEffectGenerator meshEffectGen(lineColor); + meshEffectGen.setLineWidth(1.0f); + meshEffectGen.createAndConfigurePolygonOffsetRenderState(caf::PO_1); + + cvf::ref effect = meshEffectGen.generateCachedEffect(); + + cvf::ref part = new cvf::Part; + part->setDrawable(contourDrawable.p()); + part->setEffect(effect.p()); + part->setPriority(RivPartPriority::MeshLines); + part->setSourceInfo(new RivMeshLinesSourceInfo(m_contourMapProjection.p())); + + model->addPart(part.p()); } } } + for (auto labelDrawableRef : labelDrawables) + { + cvf::ref part = new cvf::Part; + part->setDrawable(labelDrawableRef.p()); + part->setEffect(m_labelEffect.p()); + part->setPriority(RivPartPriority::Text); + part->setSourceInfo(new RivMeshLinesSourceInfo(m_contourMapProjection.p())); + model->addPart(part.p()); + } } - return textureCoords; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -cvf::ref RivContourMapProjectionPartMgr::createProjectionMapDrawable(const caf::DisplayCoordTransform* displayCoordTransform) const +cvf::ref RivContourMapProjectionPartMgr::createTextLabel(const cvf::Color3f& textColor, const cvf::Color3f& backgroundColor) { - cvf::ref vertexArray = new cvf::Vec3fArray; - m_contourMapProjection->generateVertices(vertexArray.p(), displayCoordTransform); - cvf::Vec2ui patchSize = m_contourMapProjection->numberOfVerticesIJ(); + auto font = RiaFontCache::getFont(RiaFontCache::FONT_SIZE_10); + + cvf::ref labelDrawable = new cvf::DrawableText(); + labelDrawable->setFont(font.p()); + labelDrawable->setCheckPosVisible(false); + labelDrawable->setUseDepthBuffer(true); + labelDrawable->setDrawBorder(false); + labelDrawable->setDrawBackground(false); + labelDrawable->setBackgroundColor(backgroundColor); + labelDrawable->setVerticalAlignment(cvf::TextDrawer::CENTER); + labelDrawable->setTextColor(textColor); + labelDrawable->setBorderColor(textColor); + + return labelDrawable; +} - // Surface - cvf::ref faceList = new cvf::UIntArray; - cvf::GeometryUtils::tesselatePatchAsTriangles(patchSize.x(), patchSize.y(), 0u, true, faceList.p()); +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +cvf::ref RivContourMapProjectionPartMgr::createProjectionMapPart(const caf::DisplayCoordTransform* displayCoordTransform) const +{ + const std::vector& vertices = m_contourMapTriangles; + if (vertices.size() < 3u) + { + return cvf::ref(); + } + cvf::ref vertexArray = new cvf::Vec3fArray(vertices.size()); + cvf::ref faceList = new cvf::UIntArray(vertices.size()); + std::vector values(vertices.size()); + for (uint i = 0; i < vertices.size(); ++i) + { + cvf::Vec3d globalVertex = cvf::Vec3d(vertices[i].x(), vertices[i].y(), vertices[i].z()) + m_contourMapProjection->origin3d(); + cvf::Vec3f displayVertexPos (displayCoordTransform->transformToDisplayCoord(globalVertex)); + (*vertexArray)[i] = displayVertexPos; + (*faceList)[i] = i; + values[i] = vertices[i].w(); + } cvf::ref indexUInt = new cvf::PrimitiveSetIndexedUInt(cvf::PrimitiveType::PT_TRIANGLES, faceList.p()); cvf::ref geo = new cvf::DrawableGeo; geo->addPrimitiveSet(indexUInt.p()); geo->setVertexArray(vertexArray.p()); - return geo; + + cvf::ref part = new cvf::Part; + part->setDrawable(geo.p()); + + cvf::ScalarMapper* mapper = m_contourMapProjection->legendConfig()->scalarMapper(); + + cvf::ref textureCoords = createTextureCoords(values); + RivScalarMapperUtils::applyTextureResultsToPart( + part.p(), textureCoords.p(), mapper, 1.0f, caf::FC_NONE, true, m_parentContourMap->backgroundColor()); + + part->setSourceInfo(new RivObjectSourceInfo(m_contourMapProjection.p())); + part->setPriority(RivPartPriority::BaseLevel); + return part; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -std::vector> RivContourMapProjectionPartMgr::createContourPolygons(const caf::DisplayCoordTransform* displayCoordTransform) const +std::vector>> RivContourMapProjectionPartMgr::createContourPolygons(const caf::DisplayCoordTransform* displayCoordTransform, const std::vector>& labelBBoxes) const { - RimContourMapProjection::ContourPolygons contourPolygons = m_contourMapProjection->generateContourPolygons(displayCoordTransform); + const cvf::ScalarMapper* mapper = m_contourMapProjection->legendConfig()->scalarMapper(); + std::vector tickValues; + mapper->majorTickValues(&tickValues); + + std::vector>> contourDrawablesForAllLevels; + contourDrawablesForAllLevels.resize(tickValues.size()); - std::vector> contourDrawables; - contourDrawables.reserve(contourPolygons.size()); - for (size_t i = 0; i < contourPolygons.size(); ++i) + for (size_t i = 1; i < m_contourLinePolygons.size(); ++i) { - cvf::ref vertexArray = contourPolygons[i]; - std::vector indices; - indices.reserve(contourPolygons[i]->size()); - for (cvf::uint j = 0; j < contourPolygons[i]->size(); ++j) + std::vector> contourDrawables; + + for (size_t j = 0; j < m_contourLinePolygons[i].size(); ++j) { - indices.push_back(j); + if (m_contourLinePolygons[i][j].vertices.empty()) continue; + + cvf::String labelText(m_contourLinePolygons[i][j].value); + + size_t nVertices = m_contourLinePolygons[i][j].vertices.size(); + + std::vector displayLines; displayLines.reserve(nVertices * 2); + for (size_t v = 0; v < nVertices; ++v) + { + cvf::Vec3d globalVertex1 = m_contourLinePolygons[i][j].vertices[v] + m_contourMapProjection->origin3d(); + cvf::Vec3d displayVertex1 = displayCoordTransform->transformToDisplayCoord(globalVertex1); + + cvf::Vec3d globalVertex2; + if (v < nVertices - 1) + globalVertex2 = m_contourLinePolygons[i][j].vertices[v + 1] + m_contourMapProjection->origin3d(); + else + globalVertex2 = m_contourLinePolygons[i][j].vertices[0] + m_contourMapProjection->origin3d(); + + cvf::Vec3d displayVertex2 = displayCoordTransform->transformToDisplayCoord(globalVertex2); + + cvf::BoundingBox lineBBox; + lineBBox.add(displayVertex1); + lineBBox.add(displayVertex2); + + bool addOriginalSegment = true; + for (const cvf::BoundingBox& existingBBox : labelBBoxes[i]) + { + if (lineBBox.intersects(existingBBox)) + { + if (existingBBox.contains(displayVertex1) && existingBBox.contains(displayVertex2)) + { + addOriginalSegment = false; + } + else + { + cvf::Vec3d dir = displayVertex2 - displayVertex1; + + cvf::Ray ray; + ray.setOrigin(displayVertex1); + ray.setDirection(dir.getNormalized()); + ray.setMaximumDistance(dir.length()); + + if (!existingBBox.contains(displayVertex1)) + { + cvf::Vec3d intersection; + bool hit = ray.boxIntersect(existingBBox, &intersection); + if (hit) + { + displayLines.push_back(cvf::Vec3f(displayVertex1)); + displayLines.push_back(cvf::Vec3f(intersection)); + addOriginalSegment = false; + } + } + + if (!existingBBox.contains(displayVertex2)) + { + ray.setOrigin(displayVertex2); + ray.setDirection(-ray.direction()); + cvf::Vec3d intersection; + bool hit = ray.boxIntersect(existingBBox, &intersection); + if (hit) + { + displayLines.push_back(cvf::Vec3f(intersection)); + displayLines.push_back(cvf::Vec3f(displayVertex2)); + addOriginalSegment = false; + } + } + } + } + } + if (addOriginalSegment) + { + displayLines.push_back(cvf::Vec3f(displayVertex1)); + displayLines.push_back(cvf::Vec3f(displayVertex2)); + } + } + + cvf::ref vertexArray = new cvf::Vec3fArray(displayLines); + + std::vector indices; + indices.reserve(vertexArray->size()); + for (cvf::uint k = 0; k < vertexArray->size(); ++k) + { + indices.push_back(k); + } + + cvf::ref indexedUInt = new cvf::PrimitiveSetIndexedUInt(cvf::PrimitiveType::PT_LINES); + cvf::ref indexArray = new cvf::UIntArray(indices); + indexedUInt->setIndices(indexArray.p()); + + cvf::ref geo = new cvf::DrawableGeo; + + geo->addPrimitiveSet(indexedUInt.p()); + geo->setVertexArray(vertexArray.p()); + contourDrawables.push_back(geo); + } + if (!contourDrawables.empty()) + { + contourDrawablesForAllLevels[i] = contourDrawables; } + } + return contourDrawablesForAllLevels; +} - cvf::ref indexedUInt = new cvf::PrimitiveSetIndexedUInt(cvf::PrimitiveType::PT_LINES); - cvf::ref indexArray = new cvf::UIntArray(indices); - indexedUInt->setIndices(indexArray.p()); +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector> + RivContourMapProjectionPartMgr::createContourLabels(const cvf::Camera* camera, + const caf::DisplayCoordTransform* displayCoordTransform, + std::vector>* labelBBoxes) const +{ + CVF_ASSERT(camera && displayCoordTransform && labelBBoxes); - cvf::ref geo = new cvf::DrawableGeo; + std::vector> labelDrawables; + labelBBoxes->clear(); + labelBBoxes->resize(m_contourLinePolygons.size()); - geo->addPrimitiveSet(indexedUInt.p()); - geo->setVertexArray(vertexArray.p()); - contourDrawables.push_back(geo); + const cvf::ScalarMapper* mapper = m_contourMapProjection->legendConfig()->scalarMapper(); + if (dynamic_cast(mapper) != nullptr) + return labelDrawables; + + std::vector tickValues; + mapper->majorTickValues(&tickValues); + + const RimContourMapProjection::ContourPolygons* previousLevel = nullptr; + for (int64_t i = (int64_t)m_contourLinePolygons.size() - 1; i > 0; --i) + { + cvf::Color3f backgroundColor(mapper->mapToColor(tickValues[i])); + cvf::Color3f textColor = RiaColorTools::contrastColor(backgroundColor); + cvf::ref label = createTextLabel(textColor, backgroundColor); + + for (size_t j = 0; j < m_contourLinePolygons[i].size(); ++j) + { + if (m_contourLinePolygons[i][j].vertices.empty()) continue; + + cvf::String labelText(m_contourLinePolygons[i][j].value); + + size_t nVertices = m_contourLinePolygons[i][j].vertices.size(); + size_t nLabels = nVertices; + double distanceSinceLastLabel = std::numeric_limits::infinity(); + for (size_t l = 0; l < nLabels; ++l) + { + size_t nVertex = (nVertices * l) / nLabels; + size_t nextVertex = (nVertex + 1) % nVertices; + + const cvf::Vec3d& localVertex1 = m_contourLinePolygons[i][j].vertices[nVertex]; + const cvf::Vec3d& localVertex2 = m_contourLinePolygons[i][j].vertices[nextVertex]; + + cvf::Vec3d lineCenter = (localVertex1 + localVertex2) * 0.5; + if (previousLevel && lineOverlapsWithPreviousContourLevel(lineCenter, previousLevel)) + { + continue; + } + + cvf::Vec3d globalVertex1 = localVertex1 + m_contourMapProjection->origin3d(); + cvf::Vec3d globalVertex2 = localVertex2 + m_contourMapProjection->origin3d(); + + cvf::Vec3d globalVertex = 0.5 * (globalVertex1 + globalVertex2); + + cvf::Vec3d segment = globalVertex2 - globalVertex1; + cvf::Vec3d displayVertex = displayCoordTransform->transformToDisplayCoord(globalVertex); + cvf::Vec3d windowVertex; + camera->project(displayVertex, &windowVertex); + CVF_ASSERT(!windowVertex.isUndefined()); + displayVertex.z() += 10.0f; + cvf::BoundingBox windowBBox = label->textBoundingBox(labelText, cvf::Vec3f::ZERO, cvf::Vec3f(segment.getNormalized())); + cvf::Vec3d displayBBoxMin, displayBBoxMax; + camera->unproject(windowBBox.min() + windowVertex, &displayBBoxMin); + camera->unproject(windowBBox.max() + windowVertex, &displayBBoxMax); + + CVF_ASSERT(!displayBBoxMin.isUndefined()); + CVF_ASSERT(!displayBBoxMax.isUndefined()); + + cvf::BoundingBox displayBBox(displayBBoxMin - cvf::Vec3d::Z_AXIS * 20.0, displayBBoxMax + cvf::Vec3d::Z_AXIS * 20.0); + + cvf::Vec3d currentExtent = displayBBoxMax - displayBBoxMin; + + bool overlaps = false; + if (distanceSinceLastLabel < currentExtent.length() * 10.0) + { + overlaps = true; + } + + if (!overlaps) + { + for (auto boxVector : *labelBBoxes) + { + for (const cvf::BoundingBox& existingBBox : boxVector) + { + double dist = (displayBBox.center() - existingBBox.center()).length(); + if (dist < segment.length() || existingBBox.intersects(displayBBox)) + { + overlaps = true; + break; + } + } + } + } + + if (!overlaps) + { + cvf::Vec3f displayVertexV(displayVertex); + CVF_ASSERT(!displayVertex.isUndefined()); + label->addText(labelText, displayVertexV, cvf::Vec3f(segment.getNormalized())); + labelBBoxes->at(i).push_back(displayBBox); + distanceSinceLastLabel = 0.0; + } + else + { + distanceSinceLastLabel += segment.length(); + } + } + } + if (label->numberOfTexts() != 0u) + { + labelDrawables.push_back(label); + } + + previousLevel = &m_contourLinePolygons[i]; } - return contourDrawables; + return labelDrawables; } + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- cvf::ref RivContourMapProjectionPartMgr::createPickPointVisDrawable(const caf::DisplayCoordTransform* displayCoordTransform) const { - cvf::ref geo = nullptr; + std::vector pickPointPolygon = m_contourMapProjection->generatePickPointPolygon(); + if (pickPointPolygon.empty()) + { + return nullptr; + } + cvf::ref vertexArray = new cvf::Vec3fArray(pickPointPolygon.size()); + + for (size_t i = 0; i < pickPointPolygon.size(); ++i) + { + cvf::Vec3d globalPoint = pickPointPolygon[i] + m_contourMapProjection->origin3d(); + cvf::Vec3f displayPoint(displayCoordTransform->transformToDisplayCoord(globalPoint)); + (*vertexArray)[i] = displayPoint; + } - cvf::ref pickPointPolygon = m_contourMapProjection->generatePickPointPolygon(displayCoordTransform); - if (pickPointPolygon.notNull() && pickPointPolygon->size() > 0u) + cvf::ref geo = nullptr; + if (vertexArray->size() > 0u) { std::vector indices; - indices.reserve(pickPointPolygon->size()); - for (cvf::uint j = 0; j < pickPointPolygon->size(); ++j) + indices.reserve(vertexArray->size()); + for (cvf::uint j = 0; j < vertexArray->size(); ++j) { indices.push_back(j); } @@ -226,7 +514,48 @@ cvf::ref geo = new cvf::DrawableGeo; geo->addPrimitiveSet(indexedUInt.p()); - geo->setVertexArray(pickPointPolygon.p()); + geo->setVertexArray(vertexArray.p()); } return geo; } + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RivContourMapProjectionPartMgr::lineOverlapsWithPreviousContourLevel( + const cvf::Vec3d& lineCenter, + const RimContourMapProjection::ContourPolygons* previousLevel) const +{ + const int64_t jump = 50; + CVF_ASSERT(previousLevel); + double tolerance = 1.0e-2 * m_contourMapProjection->sampleSpacing(); + for (const RimContourMapProjection::ContourPolygon& edgePolygon : *previousLevel) + { + std::pair closestIndex(0, std::numeric_limits::infinity()); + for (int64_t i = 0; i < (int64_t) edgePolygon.vertices.size(); i += jump) + { + const cvf::Vec3d& edgeVertex1 = edgePolygon.vertices[i]; + const cvf::Vec3d& edgeVertex2 = edgePolygon.vertices[(i + 1) % edgePolygon.vertices.size()]; + double dist1 = cvf::GeometryTools::linePointSquareDist(edgeVertex1, edgeVertex2, lineCenter); + if (dist1 < tolerance) + { + return true; + } + if (dist1 < closestIndex.second) + { + closestIndex = std::make_pair(i, dist1); + } + } + for (int64_t i = std::max((int64_t)1, closestIndex.first - jump + 1); i < std::min((int64_t)edgePolygon.vertices.size(), closestIndex.first + jump); ++i) + { + const cvf::Vec3d& edgeVertex1 = edgePolygon.vertices[i]; + const cvf::Vec3d& edgeVertex2 = edgePolygon.vertices[(i + 1) % edgePolygon.vertices.size()]; + double dist1 = cvf::GeometryTools::linePointSquareDist(edgeVertex1, edgeVertex2, lineCenter); + if (dist1 < tolerance) + { + return true; + } + } + } + return false; +} diff --git a/ApplicationCode/ModelVisualization/RivContourMapProjectionPartMgr.h b/ApplicationCode/ModelVisualization/RivContourMapProjectionPartMgr.h index af580e391f..8eaf61ddea 100644 --- a/ApplicationCode/ModelVisualization/RivContourMapProjectionPartMgr.h +++ b/ApplicationCode/ModelVisualization/RivContourMapProjectionPartMgr.h @@ -18,35 +18,56 @@ #pragma once +#include "RimEclipseContourMapProjection.h" + #include "cafPdmPointer.h" #include "cafDisplayCoordTransform.h" #include "cvfBase.h" #include "cvfDrawableGeo.h" +#include "cvfDrawableText.h" #include "cvfModelBasicList.h" #include "cvfObject.h" +#include "cvfVector4.h" + +class RimEclipseContourMapView; -class RimContourMapView; -class RimContourMapProjection; +namespace cvf +{ + class Effect; +} class RivContourMapProjectionPartMgr : public cvf::Object { public: - RivContourMapProjectionPartMgr(RimContourMapProjection* contourMapProjection, RimContourMapView* contourMap); + RivContourMapProjectionPartMgr(RimContourMapProjection* contourMapProjection, RimGridView* contourMap); + void createProjectionGeometry(); void appendProjectionToModel(cvf::ModelBasicList* model, const caf::DisplayCoordTransform* displayCoordTransform) const; + void appendContourLinesToModel(const cvf::Camera* camera, cvf::ModelBasicList* model, const caf::DisplayCoordTransform* displayCoordTransform); void appendPickPointVisToModel(cvf::ModelBasicList* model, const caf::DisplayCoordTransform* displayCoordTransform) const; - cvf::ref createTextureCoords() const; + cvf::ref createTextureCoords(const std::vector& values) const; + private: - cvf::ref createProjectionMapDrawable(const caf::DisplayCoordTransform* displayCoordTransform) const; - std::vector> createContourPolygons(const caf::DisplayCoordTransform* displayCoordTransform) const; - cvf::ref createPickPointVisDrawable(const caf::DisplayCoordTransform* displayCoordTransform) const; + static cvf::ref createTextLabel(const cvf::Color3f& textColor, const cvf::Color3f& backgroundColor); + cvf::ref createProjectionMapPart(const caf::DisplayCoordTransform* displayCoordTransform) const; + std::vector>> createContourPolygons(const caf::DisplayCoordTransform* displayCoordTransform, const std::vector>& labelBBoxes) const; + std::vector> createContourLabels(const cvf::Camera* camera, const caf::DisplayCoordTransform* displayCoordTransform, std::vector>* labelBBoxes) const; + cvf::ref createPickPointVisDrawable(const caf::DisplayCoordTransform* displayCoordTransform) const; + bool lineOverlapsWithPreviousContourLevel(const cvf::Vec3d& lineCenter, + const RimContourMapProjection::ContourPolygons* previousLevel) const; + private: - caf::PdmPointer m_contourMapProjection; - caf::PdmPointer m_parentContourMap; + caf::PdmPointer m_contourMapProjection; + caf::PdmPointer m_parentContourMap; + + std::vector m_contourLinePolygons; + std::vector m_contourMapTriangles; + std::vector> m_labelBoundingBoxes; + cvf::ref m_labelEffect; }; diff --git a/ApplicationCode/ModelVisualization/RivFaultPartMgr.cpp b/ApplicationCode/ModelVisualization/RivFaultPartMgr.cpp index 39f054b7ea..c165a4badd 100644 --- a/ApplicationCode/ModelVisualization/RivFaultPartMgr.cpp +++ b/ApplicationCode/ModelVisualization/RivFaultPartMgr.cpp @@ -35,6 +35,7 @@ #include "RimTernaryLegendConfig.h" #include "RivFaultGeometryGenerator.h" +#include "RivMeshLinesSourceInfo.h" #include "RivNNCGeometryGenerator.h" #include "RivPartPriority.h" #include "RivResultToTextureMapper.h" @@ -42,9 +43,9 @@ #include "RivSourceInfo.h" #include "RivTernaryScalarMapper.h" #include "RivTernaryTextureCoordsCreator.h" +#include "RivTextLabelSourceInfo.h" #include "RivTextureCoordsCreator.h" -#include "RivMeshLinesSourceInfo.h" #include "cvfDrawableGeo.h" #include "cvfDrawableText.h" #include "cvfModelBasicList.h" @@ -64,6 +65,7 @@ RivFaultPartMgr::RivFaultPartMgr(const RigGridBase* grid, , m_opacityLevel(1.0f) , m_defaultColor(cvf::Color3::WHITE) { + CVF_ASSERT(rimFault->faultGeometry()); cvf::ref> connIdxes = new cvf::Array; connIdxes->assign(rimFault->faultGeometry()->connectionIndices()); @@ -480,7 +482,7 @@ void RivFaultPartMgr::createLabelWithAnchorLine(const cvf::Part* part) // Fault label if (!m_rimFault->name().isEmpty()) { - cvf::Font* font = RiaApplication::instance()->customFont(); + cvf::Font* font = RiaApplication::instance()->defaultWellLabelFont(); cvf::ref drawableText = new cvf::DrawableText; drawableText->setFont(font); @@ -520,6 +522,8 @@ void RivFaultPartMgr::createLabelWithAnchorLine(const cvf::Part* part) labelPart->setEffect(eff.p()); labelPart->setPriority(RivPartPriority::PartType::Text); + labelPart->setSourceInfo(new RivTextLabelSourceInfo(m_rimFault, cvfString, textCoord)); + m_faultLabelPart = labelPart; } @@ -688,9 +692,9 @@ void RivFaultPartMgr::updateNNCColors(size_t timeStepIndex, RimEclipseCellColors if (cellResultColors) { - size_t scalarSetIndex = cellResultColors->scalarResultIndex(); + RigEclipseResultAddress eclResAddr = cellResultColors->eclipseResultAddress(); - if (m_grid->mainGrid()->nncData()->hasScalarValues(scalarSetIndex)) + if (m_grid->mainGrid()->nncData()->hasScalarValues(eclResAddr)) { showNncsWithScalarMappedColor = true; } @@ -699,8 +703,8 @@ void RivFaultPartMgr::updateNNCColors(size_t timeStepIndex, RimEclipseCellColors if (showNncsWithScalarMappedColor) { - size_t scalarSetIndex = cellResultColors->scalarResultIndex(); - RiaDefines::ResultCatType resultType = cellResultColors->resultType(); + RigEclipseResultAddress eclResAddr = cellResultColors->eclipseResultAddress(); + RiaDefines::ResultCatType resultType = cellResultColors->resultType(); const cvf::ScalarMapper* mapper = cellResultColors->legendConfig()->scalarMapper(); @@ -711,7 +715,7 @@ void RivFaultPartMgr::updateNNCColors(size_t timeStepIndex, RimEclipseCellColors { size_t nativeTimeStepIndex = eclipseCase->uiToNativeTimeStepIndex(timeStepIndex); m_NNCGenerator->textureCoordinates( - m_NNCTextureCoords.p(), mapper, resultType, scalarSetIndex, nativeTimeStepIndex); + m_NNCTextureCoords.p(), mapper, resultType, eclResAddr, nativeTimeStepIndex); } } diff --git a/ApplicationCode/ModelVisualization/RivFishbonesSubsPartMgr.cpp b/ApplicationCode/ModelVisualization/RivFishbonesSubsPartMgr.cpp index 6bbc396072..f3313c6621 100644 --- a/ApplicationCode/ModelVisualization/RivFishbonesSubsPartMgr.cpp +++ b/ApplicationCode/ModelVisualization/RivFishbonesSubsPartMgr.cpp @@ -95,11 +95,7 @@ void RivFishbonesSubsPartMgr::buildParts(const caf::DisplayCoordTransform* displ { std::vector lateralDomainCoords = m_rimFishbonesSubs->coordsForLateral(sub.subIndex, lateralIndex); - std::vector displayCoords; - for (auto domainCoord : lateralDomainCoords) - { - displayCoords.push_back(displayCoordTransform->transformToDisplayCoord(domainCoord)); - } + std::vector displayCoords = displayCoordTransform->transformToDisplayCoords(lateralDomainCoords); geoGenerator.cylinderWithCenterLineParts(&m_parts, displayCoords, m_rimFishbonesSubs->fishbonesColor(), wellPath->combinedScaleFactor() * characteristicCellSize * 0.5); } diff --git a/ApplicationCode/ModelVisualization/RivMeasurementPartMgr.cpp b/ApplicationCode/ModelVisualization/RivMeasurementPartMgr.cpp new file mode 100644 index 0000000000..968d25c131 --- /dev/null +++ b/ApplicationCode/ModelVisualization/RivMeasurementPartMgr.cpp @@ -0,0 +1,248 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2011- Statoil ASA +// Copyright (C) 2013- Ceetron Solutions AS +// Copyright (C) 2011-2012 Ceetron AS +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "RivMeasurementPartMgr.h" + +#include "RiaApplication.h" +#include "RiaBoundingBoxTools.h" +#include "RiaColorTools.h" +#include "RiaFontCache.h" +#include "RiaPreferences.h" + +#include "Rim3dView.h" +#include "RimAnnotationInViewCollection.h" +#include "RimMeasurement.h" +#include "RimPolylinesFromFileAnnotationInView.h" +#include "RimProject.h" +#include "RimUserDefinedPolylinesAnnotationInView.h" + +#include "RivPartPriority.h" +#include "RivPolylineAnnotationPartMgr.h" +#include "RivPolylineGenerator.h" +#include "RivReachCircleAnnotationPartMgr.h" +#include "RivTextAnnotationPartMgr.h" + +#include "cafDisplayCoordTransform.h" +#include "cafEffectGenerator.h" +#include "cafFixedAtlasFont.h" + +#include "cvfBoundingBox.h" +#include "cvfCamera.h" +#include "cvfDrawableGeo.h" +#include "cvfDrawableText.h" +#include "cvfModelBasicList.h" +#include "cvfPart.h" +#include "cvfRenderStateDepth.h" +#include "cvfRenderStatePoint.h" +#include "cvfqtUtils.h" + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RivMeasurementPartMgr::RivMeasurementPartMgr(Rim3dView* view) + : m_rimView(view) + , m_measurement(nullptr) +{ +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RivMeasurementPartMgr::~RivMeasurementPartMgr() {} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RivMeasurementPartMgr::appendGeometryPartsToModel(const cvf::Camera* camera, + cvf::ModelBasicList* model, + const caf::DisplayCoordTransform* displayCoordTransform, + const cvf::BoundingBox& boundingBox) +{ + if (m_measurement.isNull()) + { + m_measurement = RiaApplication::instance()->project()->measurement(); + } + + if (m_measurement.isNull()) return; + if (m_measurement->pointsInDomainCoords().empty()) return; + + // Check bounding box + if (!isPolylinesInBoundingBox(boundingBox)) return; + + buildPolyLineParts(camera, displayCoordTransform); + + if (m_linePart.notNull()) + { + model->addPart(m_linePart.p()); + } + + if (m_pointPart.notNull()) + { + model->addPart(m_pointPart.p()); + } + + if (m_labelPart.notNull()) + { + model->addPart(m_labelPart.p()); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RivMeasurementPartMgr::clearGeometryCache() +{ + m_linePart = nullptr; + m_pointPart = nullptr; + m_labelPart = nullptr; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RivMeasurementPartMgr::buildPolyLineParts(const cvf::Camera* camera, + const caf::DisplayCoordTransform* displayCoordTransform) +{ + auto pointsInDisplay = displayCoordTransform->transformToDisplayCoords(m_measurement->pointsInDomainCoords()); + + // Measurement lines + { + cvf::ref polylineGeo = RivPolylineGenerator::createLineAlongPolylineDrawable(pointsInDisplay); + if (polylineGeo.notNull()) + { + cvf::ref part = new cvf::Part; + part->setName("Cross Section Polyline"); + part->setDrawable(polylineGeo.p()); + + part->updateBoundingBox(); + part->setPriority(RivPartPriority::PartType::Highlight); + + cvf::ref eff; + caf::MeshEffectGenerator lineEffGen(cvf::Color3::MAGENTA); + eff = lineEffGen.generateUnCachedEffect(); + + cvf::ref depth = new cvf::RenderStateDepth; + depth->enableDepthTest(false); + eff->setRenderState(depth.p()); + + part->setEffect(eff.p()); + + m_linePart = part; + } + } + + // Measurement points + cvf::ref polylinePointsGeo = RivPolylineGenerator::createPointsFromPolylineDrawable(pointsInDisplay); + if (polylinePointsGeo.notNull()) + { + cvf::ref part = new cvf::Part; + part->setName("Cross Section Polyline"); + part->setDrawable(polylinePointsGeo.p()); + + part->updateBoundingBox(); + part->setPriority(RivPartPriority::PartType::Highlight); + + cvf::ref eff; + caf::MeshEffectGenerator lineEffGen(cvf::Color3::MAGENTA); + eff = lineEffGen.generateUnCachedEffect(); + + cvf::ref depth = new cvf::RenderStateDepth; + depth->enableDepthTest(false); + eff->setRenderState(depth.p()); + + cvf::ref pointRendState = new cvf::RenderStatePoint(cvf::RenderStatePoint::FIXED_SIZE); + pointRendState->setSize(5.0f); + eff->setRenderState(pointRendState.p()); + + part->setEffect(eff.p()); + + m_pointPart = part; + } + + // Text label + if (pointsInDisplay.size() > 1) + { + bool negativeXDir = false; + cvf::Vec3d lastV = pointsInDisplay[pointsInDisplay.size() - 1] - pointsInDisplay[pointsInDisplay.size() - 2]; + if (lastV.x() < 0.0) + { + negativeXDir = true; + } + + auto backgroundColor = RiaApplication::instance()->preferences()->defaultViewerBackgroundColor; + auto fontColor = cvf::Color3f::BLACK; + QString text = m_measurement->label(); + auto labelPosition = pointsInDisplay.back(); + auto font = RiaApplication::instance()->defaultWellLabelFont(); + + cvf::ref drawableText = new cvf::DrawableText; + drawableText->setFont(font); + drawableText->setCheckPosVisible(false); + drawableText->setDrawBorder(true); + drawableText->setDrawBackground(true); + drawableText->setVerticalAlignment(cvf::TextDrawer::BASELINE); + drawableText->setBackgroundColor(backgroundColor); + drawableText->setBorderColor(RiaColorTools::computeOffsetColor(backgroundColor, 0.3f)); + drawableText->setTextColor(fontColor); + + cvf::String cvfString = cvfqt::Utils::toString(text); + + cvf::Vec3d windowLabelPosition; + camera->project(labelPosition, &windowLabelPosition); + + cvf::BoundingBox oneCharBB = drawableText->textBoundingBox(cvf::String("A"), cvf::Vec3f(labelPosition)); + if (negativeXDir) + { + cvf::BoundingBox textBB = drawableText->textBoundingBox(cvfString, cvf::Vec3f(labelPosition)); + windowLabelPosition.x() -= textBB.extent().x() + oneCharBB.extent().x(); + } + else + { + windowLabelPosition.x() += oneCharBB.extent().x(); + } + camera->unproject(windowLabelPosition, &labelPosition); + + cvf::Vec3f textCoord(labelPosition); + drawableText->addText(cvfString, textCoord); + + cvf::ref part = new cvf::Part; + part->setName("RivMeasurementPartMgr: " + cvfString); + part->setDrawable(drawableText.p()); + + cvf::ref eff = new cvf::Effect(); + part->setEffect(eff.p()); + part->setPriority(RivPartPriority::PartType::Text); + + m_labelPart = part; + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RivMeasurementPartMgr::isPolylinesInBoundingBox(const cvf::BoundingBox& boundingBox) +{ + auto effectiveBoundingBox = RiaBoundingBoxTools::inflate(boundingBox, 3); + for (const auto& pt : m_measurement->pointsInDomainCoords()) + { + if (effectiveBoundingBox.contains(pt)) return true; + } + return false; +} diff --git a/ApplicationCode/ModelVisualization/RivMeasurementPartMgr.h b/ApplicationCode/ModelVisualization/RivMeasurementPartMgr.h new file mode 100644 index 0000000000..f624e8fc1e --- /dev/null +++ b/ApplicationCode/ModelVisualization/RivMeasurementPartMgr.h @@ -0,0 +1,72 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2011-2012 Statoil ASA, Ceetron AS +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "cvfBase.h" +#include "cvfAssert.h" +#include "cvfCollection.h" +#include "cvfObject.h" +#include "cafPdmPointer.h" +#include "cvfVector3.h" + +namespace cvf +{ + class BoundingBox; + class Camera; + class Part; + class ModelBasicList; + class Transform; + class Font; +} +namespace caf +{ + class DisplayCoordTransform; +} + +class Rim3dView; +class RimMeasurement; + + +class RivMeasurementPartMgr : public cvf::Object +{ + using Vec3d = cvf::Vec3d; + +public: + RivMeasurementPartMgr(Rim3dView* view); + ~RivMeasurementPartMgr() override; + + void appendGeometryPartsToModel(const cvf::Camera* camera, + cvf::ModelBasicList* model, + const caf::DisplayCoordTransform* displayCoordTransform, + const cvf::BoundingBox& boundingBox); + + void clearGeometryCache(); + +private: + void buildPolyLineParts(const cvf::Camera* camera, const caf::DisplayCoordTransform* displayCoordTransform); + + bool isPolylinesInBoundingBox(const cvf::BoundingBox& boundingBox); + +private: + caf::PdmPointer m_rimView; + caf::PdmPointer m_measurement; + cvf::ref m_linePart; + cvf::ref m_pointPart; + cvf::ref m_labelPart; +}; diff --git a/ApplicationCode/ModelVisualization/RivNNCGeometryGenerator.cpp b/ApplicationCode/ModelVisualization/RivNNCGeometryGenerator.cpp index e233b02813..825e322902 100644 --- a/ApplicationCode/ModelVisualization/RivNNCGeometryGenerator.cpp +++ b/ApplicationCode/ModelVisualization/RivNNCGeometryGenerator.cpp @@ -148,7 +148,7 @@ void RivNNCGeometryGenerator::computeArrays() void RivNNCGeometryGenerator::textureCoordinates(cvf::Vec2fArray* textureCoords, const cvf::ScalarMapper* mapper, RiaDefines::ResultCatType resultType, - size_t scalarResultIndex, + const RigEclipseResultAddress& resVarAddr, size_t nativeTimeStepIndex) const { size_t numVertices = m_vertices->size(); @@ -158,15 +158,15 @@ void RivNNCGeometryGenerator::textureCoordinates(cvf::Vec2fArray* textureCoords, const std::vector* nncResultVals = nullptr; if (resultType == RiaDefines::STATIC_NATIVE) { - nncResultVals = m_nncData->staticConnectionScalarResult(scalarResultIndex); + nncResultVals = m_nncData->staticConnectionScalarResult(resVarAddr); } else if (resultType == RiaDefines::DYNAMIC_NATIVE) { - nncResultVals = m_nncData->dynamicConnectionScalarResult(scalarResultIndex, nativeTimeStepIndex); + nncResultVals = m_nncData->dynamicConnectionScalarResult(resVarAddr, nativeTimeStepIndex); } else if (resultType == RiaDefines::GENERATED) { - nncResultVals = m_nncData->generatedConnectionScalarResult(scalarResultIndex, nativeTimeStepIndex); + nncResultVals = m_nncData->generatedConnectionScalarResult(resVarAddr, nativeTimeStepIndex); } if (!nncResultVals || nncResultVals->size() == 0) diff --git a/ApplicationCode/ModelVisualization/RivNNCGeometryGenerator.h b/ApplicationCode/ModelVisualization/RivNNCGeometryGenerator.h index bbad9decdd..cb24bc489e 100644 --- a/ApplicationCode/ModelVisualization/RivNNCGeometryGenerator.h +++ b/ApplicationCode/ModelVisualization/RivNNCGeometryGenerator.h @@ -33,6 +33,7 @@ namespace cvf class RigNNCData; class RigGridBase; +class RigEclipseResultAddress; //================================================================================================== /// @@ -50,7 +51,7 @@ class RivNNCGeometryGenerator : public cvf::Object void textureCoordinates(cvf::Vec2fArray* textureCoords, const cvf::ScalarMapper* mapper, RiaDefines::ResultCatType resultType, - size_t scalarResultIndex, + const RigEclipseResultAddress& resVarAddr, size_t nativeTimeStepIndex) const; // Mapping between cells and geometry diff --git a/ApplicationCode/ModelVisualization/RivPipeGeometryGenerator.cpp b/ApplicationCode/ModelVisualization/RivPipeGeometryGenerator.cpp index 17e937a895..824e0004f9 100644 --- a/ApplicationCode/ModelVisualization/RivPipeGeometryGenerator.cpp +++ b/ApplicationCode/ModelVisualization/RivPipeGeometryGenerator.cpp @@ -384,8 +384,6 @@ cvf::ref RivPipeGeometryGenerator::generateVariableRadiusTube( const cvf::Vec3dArray* cylinderCenterCoords, const std::vector& radii) { - const double epsilon = 1.0e-8; - CVF_ASSERT(cylinderCenterCoords != nullptr); // Calculate first valid pipe direction, to be able to handle centerNodes in the same place diff --git a/ApplicationCode/ModelVisualization/RivPipeQuadToSegmentMapper.h b/ApplicationCode/ModelVisualization/RivPipeQuadToSegmentMapper.h index 8e36942029..cb3b9b64bf 100644 --- a/ApplicationCode/ModelVisualization/RivPipeQuadToSegmentMapper.h +++ b/ApplicationCode/ModelVisualization/RivPipeQuadToSegmentMapper.h @@ -20,7 +20,7 @@ #pragma once #include -#include +#include //================================================================================================== diff --git a/ApplicationCode/ModelVisualization/RivPolylineAnnotationPartMgr.cpp b/ApplicationCode/ModelVisualization/RivPolylineAnnotationPartMgr.cpp new file mode 100644 index 0000000000..b23c0ba61e --- /dev/null +++ b/ApplicationCode/ModelVisualization/RivPolylineAnnotationPartMgr.cpp @@ -0,0 +1,285 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2018- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "RivPolylineAnnotationPartMgr.h" + +#include "RiaApplication.h" +#include "RiaBoundingBoxTools.h" + +#include "Rim3dView.h" +#include "RimAnnotationCollection.h" +#include "RimPolylinesAnnotation.h" +#include "RimPolylinesAnnotationInView.h" +#include "RimAnnotationInViewCollection.h" +#include "RimAnnotationLineAppearance.h" +#include "RimEclipseView.h" + +#include "RigMainGrid.h" +#include "RigPolyLinesData.h" + +#include "RivPolylineGenerator.h" +#include "RivPartPriority.h" +#include "RivPolylinesAnnotationSourceInfo.h" + + +#include "cafEffectGenerator.h" + +#include "cvfDrawableGeo.h" +#include "cvfDrawableText.h" +#include "cvfModelBasicList.h" +#include "cvfPart.h" +#include "cvfTransform.h" +#include "cafDisplayCoordTransform.h" +#include "cvfGeometryBuilderTriangles.h" +#include "cvfGeometryUtils.h" +#include "cvfDrawableVectors.h" + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RivPolylineAnnotationPartMgr::RivPolylineAnnotationPartMgr(Rim3dView* view, RimPolylinesAnnotationInView* annotationInView) +: m_rimView(view), m_rimAnnotationInView(annotationInView) +{ +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RivPolylineAnnotationPartMgr::~RivPolylineAnnotationPartMgr() +{ + +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RivPolylineAnnotationPartMgr::buildPolylineAnnotationParts(const caf::DisplayCoordTransform* displayXf) +{ + clearAllGeometry(); + + auto rimAnnotation = m_rimAnnotationInView->sourceAnnotation(); + if (!rimAnnotation->isEmpty() && rimAnnotation->isActive()) + { + auto lineColor = rimAnnotation->appearance()->color(); + auto isDashedLine = rimAnnotation->appearance()->isDashed(); + auto lineThickness = rimAnnotation->appearance()->thickness(); + + auto* collection = annotationCollection(); + if (!collection) return; + + auto linesInDomain = getPolylinesPointsInDomain(collection->snapAnnotations(), collection->annotationPlaneZ()); + auto linesInDisplay = transformPolylinesPointsToDisplay(linesInDomain, displayXf); + + // Line part + if(rimAnnotation->showLines()) + { + cvf::ref drawableGeo = RivPolylineGenerator::createLineAlongPolylineDrawable(linesInDisplay, rimAnnotation->closePolyline()); + cvf::ref part = new cvf::Part; + part->setName("RivPolylineAnnotationPartMgr"); + part->setDrawable(drawableGeo.p()); + + caf::MeshEffectGenerator effgen(lineColor); + effgen.setLineWidth(lineThickness); + if (isDashedLine) effgen.setLineStipple(true); + cvf::ref eff = effgen.generateCachedEffect(); + + part->setEffect(eff.p()); + part->setPriority(RivPartPriority::PartType::MeshLines); + + cvf::ref sourceInfo = new RivPolylinesAnnotationSourceInfo(rimAnnotation); + part->setSourceInfo(sourceInfo.p()); + + m_linePart = part; + } + + // Sphere part + if(rimAnnotation->showSpheres()) + { + auto sphereColor = rimAnnotation->appearance()->sphereColor(); + double sphereRadiusFactor = rimAnnotation->appearance()->sphereRadiusFactor(); + + cvf::ref vertices = new cvf::Vec3fArray; + cvf::ref vecRes = new cvf::Vec3fArray; + cvf::ref colors = new cvf::Color3fArray; + + size_t pointCount = 0; + for (const auto& line : linesInDisplay) pointCount += line.size(); + vertices->reserve(pointCount); + vecRes->reserve(pointCount); + colors->reserve(pointCount); + + for (const auto& line : linesInDisplay) + { + for (const auto& v : line) + { + vertices->add(cvf::Vec3f(v)); + vecRes->add(cvf::Vec3f::X_AXIS); + colors->add(sphereColor); + } + } + + cvf::ref vectorDrawable; + if (RiaApplication::instance()->useShaders()) + { + // NOTE: Drawable vectors must be rendered using shaders when the rest of the application is rendered using + // shaders Drawing vectors using fixed function when rest of the application uses shaders causes visual artifacts + vectorDrawable = new cvf::DrawableVectors("u_transformationMatrix", "u_color"); + } + else + { + vectorDrawable = new cvf::DrawableVectors(); + } + + vectorDrawable->setVectors(vertices.p(), vecRes.p()); + vectorDrawable->setColors(colors.p()); + + cvf::GeometryBuilderTriangles builder; + double cellRadius = 15.0; + auto eclipseView = dynamic_cast(m_rimView.p()); + if (eclipseView) + { + double characteristicCellSize = eclipseView->mainGrid()->characteristicIJCellSize(); + cellRadius = sphereRadiusFactor * characteristicCellSize; + } + + cvf::GeometryUtils::createSphere(cellRadius, 15, 15, &builder); + vectorDrawable->setGlyph(builder.trianglesUShort().p(), builder.vertices().p()); + + cvf::ref part = new cvf::Part; + part->setName("RivPolylineAnnotationPartMgr"); + part->setDrawable(vectorDrawable.p()); + + part->setEffect(new cvf::Effect()); + part->setPriority(RivPartPriority::PartType::MeshLines); + + cvf::ref sourceInfo = new RivPolylinesAnnotationSourceInfo(rimAnnotation); + part->setSourceInfo(sourceInfo.p()); + + m_spherePart = part; + } + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector> + RivPolylineAnnotationPartMgr::getPolylinesPointsInDomain(bool snapToPlaneZ, double planeZ) +{ + auto polylines = m_rimAnnotationInView->sourceAnnotation()->polyLinesData()->polyLines(); + if (!snapToPlaneZ) return polylines; + + std::vector> polylinesInDisplay; + for (const auto& pts : polylines) + { + std::vector polyline; + for (const auto& pt : pts) + { + auto ptInDisp = pt; + ptInDisp.z() = planeZ; + polyline.push_back(ptInDisp); + } + polylinesInDisplay.push_back(polyline); + } + return polylinesInDisplay; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector> RivPolylineAnnotationPartMgr::transformPolylinesPointsToDisplay( + const std::vector>& pointsInDomain, + const caf::DisplayCoordTransform* displayXf) +{ + std::vector> pointsInDisplay; + for (const auto& pts : pointsInDomain) + { + std::vector displayCoords = displayXf->transformToDisplayCoords(pts); + + pointsInDisplay.push_back(displayCoords); + + } + return pointsInDisplay; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RivPolylineAnnotationPartMgr::isPolylinesInBoundingBox(const cvf::BoundingBox& boundingBox) +{ + auto coll = annotationCollection(); + if (!coll) return false; + + auto effectiveBoundingBox = RiaBoundingBoxTools::inflate(boundingBox, 3); + for (const auto& pts : getPolylinesPointsInDomain(coll->snapAnnotations(), coll->annotationPlaneZ())) + { + for (const auto& pt : pts) + { + if (effectiveBoundingBox.contains(pt)) return true; + } + } + return false; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RivPolylineAnnotationPartMgr::clearAllGeometry() +{ + m_linePart = nullptr; + m_spherePart = nullptr; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimAnnotationInViewCollection* RivPolylineAnnotationPartMgr::annotationCollection() const +{ + std::vector colls; + m_rimView->descendantsIncludingThisOfType(colls); + return !colls.empty() ? colls.front() : nullptr; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RivPolylineAnnotationPartMgr::appendDynamicGeometryPartsToModel(cvf::ModelBasicList* model, + const caf::DisplayCoordTransform * displayXf, + const cvf::BoundingBox& boundingBox) +{ + auto rimAnnotation = m_rimAnnotationInView->sourceAnnotation(); + if (!rimAnnotation) return; + if (rimAnnotation->isEmpty()) return; + if (!m_rimAnnotationInView->isVisible()) return; + + // Check bounding box + if (!isPolylinesInBoundingBox(boundingBox)) return; + + buildPolylineAnnotationParts(displayXf); + + if ( m_linePart.notNull() ) + { + model->addPart(m_linePart.p()); + } + + if (m_spherePart.notNull()) + { + model->addPart(m_spherePart.p()); + } +} + diff --git a/ApplicationCode/ModelVisualization/RivPolylineAnnotationPartMgr.h b/ApplicationCode/ModelVisualization/RivPolylineAnnotationPartMgr.h new file mode 100644 index 0000000000..d319870627 --- /dev/null +++ b/ApplicationCode/ModelVisualization/RivPolylineAnnotationPartMgr.h @@ -0,0 +1,75 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2018 equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "cvfBase.h" +#include "cvfAssert.h" +#include "cvfObject.h" +#include "cvfVector3.h" + +#include "cafPdmPointer.h" + +#include + +namespace cvf +{ + class BoundingBox; + class Part; + class ModelBasicList; + class Transform; + class Font; +} +namespace caf +{ + class DisplayCoordTransform; +} + +class Rim3dView; +class RimPolylinesAnnotationInView; +class RimAnnotationInViewCollection; + + +class RivPolylineAnnotationPartMgr : public cvf::Object +{ + using Vec3d = cvf::Vec3d; + +public: + RivPolylineAnnotationPartMgr(Rim3dView* view, RimPolylinesAnnotationInView* annotation); + ~RivPolylineAnnotationPartMgr() override; + + void appendDynamicGeometryPartsToModel(cvf::ModelBasicList* model, + const caf::DisplayCoordTransform * displayXf, + const cvf::BoundingBox& boundingBox); +private: + void buildPolylineAnnotationParts(const caf::DisplayCoordTransform* displayXf); + + std::vector> getPolylinesPointsInDomain(bool snapToPlaneZ, double planeZ); + std::vector> transformPolylinesPointsToDisplay(const std::vector>& pointsInDomain, + const caf::DisplayCoordTransform* displayXf); + + bool isPolylinesInBoundingBox(const cvf::BoundingBox& boundingBox); + + void clearAllGeometry(); + RimAnnotationInViewCollection* annotationCollection() const; + + caf::PdmPointer m_rimView; + caf::PdmPointer m_rimAnnotationInView; + cvf::ref m_linePart; + cvf::ref m_spherePart; +}; diff --git a/ApplicationCode/ModelVisualization/RivPolylineGenerator.cpp b/ApplicationCode/ModelVisualization/RivPolylineGenerator.cpp new file mode 100644 index 0000000000..8e930eb0f8 --- /dev/null +++ b/ApplicationCode/ModelVisualization/RivPolylineGenerator.cpp @@ -0,0 +1,124 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2018- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "RivPolylineGenerator.h" + +#include "cvfDrawableGeo.h" +#include "cvfPrimitiveSetDirect.h" +#include "cvfPrimitiveSetIndexedUInt.h" + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +cvf::ref RivPolylineGenerator::createLineAlongPolylineDrawable(const std::vector& polyLine, bool closeLine) +{ + std::vector> polyLines; + polyLines.push_back(polyLine); + return createLineAlongPolylineDrawable(polyLines, closeLine); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +cvf::ref + RivPolylineGenerator::createLineAlongPolylineDrawable(const std::vector>& polyLines, bool closeLine) +{ + std::vector lineIndices; + std::vector vertices; + + for (const std::vector& polyLine : polyLines) + { + if (polyLine.size() < 2) continue; + + size_t verticesCount = vertices.size(); + + for (size_t i = 0; i < polyLine.size(); ++i) + { + vertices.emplace_back(polyLine[i]); + if (i < polyLine.size() - 1) + { + lineIndices.push_back(static_cast(verticesCount + i)); + lineIndices.push_back(static_cast(verticesCount + i + 1)); + } + } + + if (closeLine && vertices.front() != vertices.back()) + { + lineIndices.push_back(static_cast(verticesCount + polyLine.size() - 1)); + lineIndices.push_back(static_cast(verticesCount)); + } + } + + if (vertices.empty()) return nullptr; + + cvf::ref vx = new cvf::Vec3fArray; + vx->assign(vertices); + cvf::ref idxes = new cvf::UIntArray; + idxes->assign(lineIndices); + + cvf::ref prim = new cvf::PrimitiveSetIndexedUInt(cvf::PT_LINES); + prim->setIndices(idxes.p()); + + cvf::ref polylineGeo = new cvf::DrawableGeo; + polylineGeo->setVertexArray(vx.p()); + polylineGeo->addPrimitiveSet(prim.p()); + + return polylineGeo; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +cvf::ref RivPolylineGenerator::createPointsFromPolylineDrawable(const std::vector& polyLine) +{ + std::vector> polyLines; + polyLines.push_back(polyLine); + return createPointsFromPolylineDrawable( polyLines ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +cvf::ref + RivPolylineGenerator::createPointsFromPolylineDrawable(const std::vector>& polyLines) +{ + std::vector vertices; + + for (const std::vector& polyLine : polyLines) + { + for (const auto& pl : polyLine) + { + vertices.emplace_back(pl); + } + } + + if (vertices.empty()) return nullptr; + + cvf::ref primSet = new cvf::PrimitiveSetDirect(cvf::PT_POINTS); + primSet->setStartIndex(0); + primSet->setIndexCount(vertices.size()); + + cvf::ref geo = new cvf::DrawableGeo; + + cvf::ref vx = new cvf::Vec3fArray(vertices); + geo->setVertexArray(vx.p()); + geo->addPrimitiveSet(primSet.p()); + + return geo; +} diff --git a/ApplicationCode/ModelVisualization/RivPolylineGenerator.h b/ApplicationCode/ModelVisualization/RivPolylineGenerator.h new file mode 100644 index 0000000000..354ef4b87b --- /dev/null +++ b/ApplicationCode/ModelVisualization/RivPolylineGenerator.h @@ -0,0 +1,43 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2018- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "cvfBase.h" +#include "cvfObject.h" + +#include +#include + +namespace cvf +{ + class DrawableGeo; +} + +//================================================================================================== +/// +//================================================================================================== +class RivPolylineGenerator : public cvf::Object +{ +public: + static cvf::ref createLineAlongPolylineDrawable(const std::vector& polyLine, bool closeLine = false); + static cvf::ref createLineAlongPolylineDrawable(const std::vector>& polyLines, bool closeLine = false); + + static cvf::ref createPointsFromPolylineDrawable(const std::vector& polyLine); + static cvf::ref createPointsFromPolylineDrawable(const std::vector>& polyLines); +}; diff --git a/ApplicationCode/ModelVisualization/RivPolylinesAnnotationSourceInfo.cpp b/ApplicationCode/ModelVisualization/RivPolylinesAnnotationSourceInfo.cpp new file mode 100644 index 0000000000..732213249e --- /dev/null +++ b/ApplicationCode/ModelVisualization/RivPolylinesAnnotationSourceInfo.cpp @@ -0,0 +1,40 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2015- Statoil ASA +// Copyright (C) 2015- Ceetron Solutions AS +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "RivPolylinesAnnotationSourceInfo.h" + +#include "RimEclipseView.h" +#include "RimAnnotationInViewCollection.h" +#include "RimPolylinesAnnotation.h" + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RivPolylinesAnnotationSourceInfo::RivPolylinesAnnotationSourceInfo(RimPolylinesAnnotation* annotation) + : m_annotation(annotation) +{ +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimPolylinesAnnotation* RivPolylinesAnnotationSourceInfo::annotation() const +{ + return m_annotation.p(); +} diff --git a/ApplicationCode/ModelVisualization/RivPolylinesAnnotationSourceInfo.h b/ApplicationCode/ModelVisualization/RivPolylinesAnnotationSourceInfo.h new file mode 100644 index 0000000000..82b0c7b847 --- /dev/null +++ b/ApplicationCode/ModelVisualization/RivPolylinesAnnotationSourceInfo.h @@ -0,0 +1,37 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2015- Statoil ASA +// Copyright (C) 2015- Ceetron Solutions AS +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "cvfBase.h" +#include "cvfObject.h" +#include "cafPdmPointer.h" + +class RimPolylinesAnnotation; + +class RivPolylinesAnnotationSourceInfo : public cvf::Object +{ +public: + RivPolylinesAnnotationSourceInfo(RimPolylinesAnnotation* annotation); + + RimPolylinesAnnotation* annotation() const; + +private: + caf::PdmPointer m_annotation; +}; diff --git a/ApplicationCode/ModelVisualization/RivReachCircleAnnotationPartMgr.cpp b/ApplicationCode/ModelVisualization/RivReachCircleAnnotationPartMgr.cpp new file mode 100644 index 0000000000..6d993d41ce --- /dev/null +++ b/ApplicationCode/ModelVisualization/RivReachCircleAnnotationPartMgr.cpp @@ -0,0 +1,219 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2011- Statoil ASA +// Copyright (C) 2013- Ceetron Solutions AS +// Copyright (C) 2011-2012 Ceetron AS +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + + + +#include "RivReachCircleAnnotationPartMgr.h" + +#include "RiaBoundingBoxTools.h" + +#include "Rim3dView.h" +#include "RimAnnotationInViewCollection.h" +#include "RimReachCircleAnnotation.h" +#include "RimReachCircleAnnotationInView.h" + +#include "RivPolylineGenerator.h" +#include "RivPartPriority.h" +#include "RivReachCircleAnnotationSourceInfo.h" + +#include "cafEffectGenerator.h" + +#include "cvfDrawableGeo.h" +#include "cvfModelBasicList.h" +#include "cvfPart.h" +#include "cafDisplayCoordTransform.h" + +#include + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RivReachCircleAnnotationPartMgr::RivReachCircleAnnotationPartMgr(Rim3dView* view, RimReachCircleAnnotationInView* annotationInView) +: m_rimView(view), m_rimAnnotationInView(annotationInView) +{ +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RivReachCircleAnnotationPartMgr::~RivReachCircleAnnotationPartMgr() +{ + +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RivReachCircleAnnotationPartMgr::buildParts(const caf::DisplayCoordTransform* displayXf, bool doFlatten, double xOffset) +{ + auto rimAnnotation = m_rimAnnotationInView->sourceAnnotation(); + clearAllGeometry(); + + cvf::ref sourceInfo = new RivReachCircleAnnotationSourceInfo(rimAnnotation); + + Vec3d centerPositionInDomain = rimAnnotation->centerPoint(); + + auto lineColor = rimAnnotation->appearance()->color(); + auto isDashedLine = rimAnnotation->appearance()->isDashed(); + auto lineThickness = rimAnnotation->appearance()->thickness(); + + // Circle part + auto* collection = annotationCollection(); + if(collection) + { + std::vector pointsInDomain = computeCirclePointsInDomain(collection->snapAnnotations(), collection->annotationPlaneZ()); + std::vector points = displayXf->transformToDisplayCoords(pointsInDomain); + + cvf::ref drawableGeo = RivPolylineGenerator::createLineAlongPolylineDrawable(points); + + cvf::ref part = new cvf::Part; + part->setDrawable(drawableGeo.p()); + + caf::MeshEffectGenerator effgen(lineColor); + effgen.setLineWidth(lineThickness); + if (isDashedLine) effgen.setLineStipple(true); // Currently, dashed lines are not supported + cvf::ref eff = effgen.generateUnCachedEffect(); + + part->setEffect(eff.p()); + part->setPriority(RivPartPriority::PartType::MeshLines); + part->setSourceInfo(sourceInfo.p()); + + m_circlePart = part; + } + + // Center point part + { + auto centerPos = displayXf->transformToDisplayCoord(rimAnnotation->centerPoint()); + double symbolSize = 20; + double xMin = centerPos.x() - symbolSize / 2.0; + double xMax = xMin + symbolSize; + double yMin = centerPos.y() - symbolSize / 2.0; + double yMax = yMin + symbolSize; + double z = centerPos.z(); + std::vector line1 = { {xMin, yMin, z}, {xMax, yMax, z} }; + std::vector line2 = { {xMax, yMin, z}, {xMin, yMax, z} }; + std::vector> symbol = { line1, line2 }; + cvf::ref drawableGeo = RivPolylineGenerator::createLineAlongPolylineDrawable(symbol); + + cvf::ref part = new cvf::Part; + part->setDrawable(drawableGeo.p()); + + caf::MeshEffectGenerator effgen(lineColor); + effgen.setLineWidth(2); + cvf::ref eff = effgen.generateUnCachedEffect(); + + part->setEffect(eff.p()); + part->setPriority(RivPartPriority::PartType::MeshLines); + part->setSourceInfo(sourceInfo.p()); + + m_centerPointPart = part; + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RivReachCircleAnnotationPartMgr::clearAllGeometry() +{ + m_circlePart = nullptr; + m_centerPointPart = nullptr; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RivReachCircleAnnotationPartMgr::appendDynamicGeometryPartsToModel(cvf::ModelBasicList* model, + const caf::DisplayCoordTransform* displayXf, + const cvf::BoundingBox& boundingBox) +{ + if (m_rimAnnotationInView.isNull() || !m_rimAnnotationInView->sourceAnnotation()) return; + if (!m_rimAnnotationInView->isVisible()) return; + + // Check bounding box + if (!isCircleInBoundingBox(boundingBox)) return; + + if (!validateAnnotation(m_rimAnnotationInView->sourceAnnotation())) return; + + buildParts(displayXf, false, 0.0); + model->addPart(m_circlePart.p()); + model->addPart(m_centerPointPart.p()); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RivReachCircleAnnotationPartMgr::validateAnnotation(const RimReachCircleAnnotation* annotation) const +{ + auto a = m_rimAnnotationInView->sourceAnnotation(); + return a->centerPoint() != cvf::Vec3d::ZERO && a->radius() > 0.0; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RivReachCircleAnnotationPartMgr::isCircleInBoundingBox(const cvf::BoundingBox& boundingBox) +{ + auto coll = annotationCollection(); + if (!coll) return false; + + auto effectiveBoundingBox = RiaBoundingBoxTools::inflate(boundingBox, 3); + auto points = computeCirclePointsInDomain(coll->snapAnnotations(), coll->annotationPlaneZ()); + for (const auto& pt : points) + { + if (effectiveBoundingBox.contains(pt)) return true; + } + return false; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector RivReachCircleAnnotationPartMgr::computeCirclePointsInDomain(bool snapToPlaneZ, double planeZ) +{ + int numPoints = 36; + auto centerPos = m_rimAnnotationInView->sourceAnnotation()->centerPoint(); + auto radius = m_rimAnnotationInView->sourceAnnotation()->radius(); + + if (snapToPlaneZ) + { + centerPos.z() = planeZ; + } + + std::vector points; + for (int i = 0; i < numPoints; i++) + { + double rad = 2 * cvf::PI_D * (double)i / (double)numPoints; + Vec3d pt(centerPos.x() + cos(rad) * radius, centerPos.y() + sin(rad) * radius, centerPos.z()); + points.push_back(pt); + } + points.push_back(points.front()); + return points; +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimAnnotationInViewCollection* RivReachCircleAnnotationPartMgr::annotationCollection() const +{ + std::vector colls; + m_rimView->descendantsIncludingThisOfType(colls); + return !colls.empty() ? colls.front() : nullptr; +} diff --git a/ApplicationCode/ModelVisualization/RivReachCircleAnnotationPartMgr.h b/ApplicationCode/ModelVisualization/RivReachCircleAnnotationPartMgr.h new file mode 100644 index 0000000000..0c4891c130 --- /dev/null +++ b/ApplicationCode/ModelVisualization/RivReachCircleAnnotationPartMgr.h @@ -0,0 +1,75 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2011-2012 Statoil ASA, Ceetron AS +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "cvfBase.h" +#include "cvfAssert.h" +#include "cvfObject.h" +#include "cafPdmPointer.h" + +#include "cvfVector3.h" + +#include + +namespace cvf +{ + class BoundingBox; + class Part; + class ModelBasicList; + class Transform; + class Font; +} +namespace caf +{ + class DisplayCoordTransform; +} + +class Rim3dView; +class RimReachCircleAnnotation; +class RimReachCircleAnnotationInView; +class RimAnnotationInViewCollection; + +class RivReachCircleAnnotationPartMgr : public cvf::Object +{ + using Vec3d = cvf::Vec3d; + +public: + RivReachCircleAnnotationPartMgr(Rim3dView* view, RimReachCircleAnnotationInView* annotationInView); + ~RivReachCircleAnnotationPartMgr() override; + + void appendDynamicGeometryPartsToModel(cvf::ModelBasicList* model, + const caf::DisplayCoordTransform* displayXf, + const cvf::BoundingBox& boundingBox); + +private: + void buildParts(const caf::DisplayCoordTransform* displayXf, bool doFlatten, double xOffset); + + void clearAllGeometry(); + bool validateAnnotation(const RimReachCircleAnnotation* annotation) const; + bool isCircleInBoundingBox(const cvf::BoundingBox& boundingBox); + + std::vector computeCirclePointsInDomain(bool snapToPlaneZ, double planeZ); + + RimAnnotationInViewCollection* annotationCollection() const; + + caf::PdmPointer m_rimView; + caf::PdmPointer m_rimAnnotationInView; + cvf::ref m_circlePart; + cvf::ref m_centerPointPart; +}; diff --git a/ApplicationCode/ModelVisualization/RivReachCircleAnnotationSourceInfo.cpp b/ApplicationCode/ModelVisualization/RivReachCircleAnnotationSourceInfo.cpp new file mode 100644 index 0000000000..32dc41eea8 --- /dev/null +++ b/ApplicationCode/ModelVisualization/RivReachCircleAnnotationSourceInfo.cpp @@ -0,0 +1,40 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2015- Statoil ASA +// Copyright (C) 2015- Ceetron Solutions AS +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "RivReachCircleAnnotationSourceInfo.h" + +#include "RimEclipseView.h" +#include "RimAnnotationInViewCollection.h" +#include "RimReachCircleAnnotation.h" + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RivReachCircleAnnotationSourceInfo::RivReachCircleAnnotationSourceInfo(RimReachCircleAnnotation* annotation) + : m_annotation(annotation) +{ +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimReachCircleAnnotation* RivReachCircleAnnotationSourceInfo::annotation() const +{ + return m_annotation.p(); +} diff --git a/ApplicationCode/ModelVisualization/RivReachCircleAnnotationSourceInfo.h b/ApplicationCode/ModelVisualization/RivReachCircleAnnotationSourceInfo.h new file mode 100644 index 0000000000..95bd34948a --- /dev/null +++ b/ApplicationCode/ModelVisualization/RivReachCircleAnnotationSourceInfo.h @@ -0,0 +1,37 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2015- Statoil ASA +// Copyright (C) 2015- Ceetron Solutions AS +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "cvfBase.h" +#include "cvfObject.h" +#include "cafPdmPointer.h" + +class RimReachCircleAnnotation; + +class RivReachCircleAnnotationSourceInfo : public cvf::Object +{ +public: + RivReachCircleAnnotationSourceInfo(RimReachCircleAnnotation* annotation); + + RimReachCircleAnnotation* annotation() const; + +private: + caf::PdmPointer m_annotation; +}; diff --git a/ApplicationCode/ModelVisualization/RivReservoirFaultsPartMgr.cpp b/ApplicationCode/ModelVisualization/RivReservoirFaultsPartMgr.cpp index a030ad9664..cbcf669dbf 100644 --- a/ApplicationCode/ModelVisualization/RivReservoirFaultsPartMgr.cpp +++ b/ApplicationCode/ModelVisualization/RivReservoirFaultsPartMgr.cpp @@ -159,18 +159,18 @@ void RivReservoirFaultsPartMgr::appendPartsToModel(cvf::ModelBasicList* model) bool showNncs = true; if (faultCollection->hideNncsWhenNoResultIsAvailable()) { - size_t scalarResultIndex = cvf::UNDEFINED_SIZE_T; + RigEclipseResultAddress eclipseResultAddress; if (faultResultColors->showCustomFaultResult()) { - scalarResultIndex = faultResultColors->customFaultResult()->scalarResultIndex(); + eclipseResultAddress = faultResultColors->customFaultResult()->eclipseResultAddress(); } else { - scalarResultIndex = cellResultColors->scalarResultIndex(); + eclipseResultAddress = cellResultColors->eclipseResultAddress(); } RigMainGrid* mainGrid = m_reservoirView->mainGrid(); - if (!(mainGrid && mainGrid->nncData()->hasScalarValues(scalarResultIndex))) + if (!(mainGrid && mainGrid->nncData()->hasScalarValues(eclipseResultAddress))) { showNncs = false; } diff --git a/ApplicationCode/ModelVisualization/RivReservoirViewPartMgr.cpp b/ApplicationCode/ModelVisualization/RivReservoirViewPartMgr.cpp index 3d54d14c3a..7ee05f2981 100644 --- a/ApplicationCode/ModelVisualization/RivReservoirViewPartMgr.cpp +++ b/ApplicationCode/ModelVisualization/RivReservoirViewPartMgr.cpp @@ -3,17 +3,17 @@ // Copyright (C) 2011- Statoil ASA // Copyright (C) 2013- Ceetron Solutions AS // Copyright (C) 2011-2012 Ceetron AS -// +// // ResInsight 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 3 of the License, or // (at your option) any later version. -// +// // ResInsight 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 at +// +// See the GNU General Public License at // for more details. // ///////////////////////////////////////////////////////////////////////////////// @@ -22,9 +22,9 @@ #include "RigActiveCellInfo.h" #include "RigCaseCellResultsData.h" -#include "RigEclipseCaseData.h" #include "RigCaseToCaseCellMapper.h" #include "RigCell.h" +#include "RigEclipseCaseData.h" #include "RigGridBase.h" #include "RigResultAccessorFactory.h" @@ -49,16 +49,15 @@ #include //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- -RivReservoirViewPartMgr::RivReservoirViewPartMgr(RimEclipseView * resv) : -m_reservoirView(resv) +RivReservoirViewPartMgr::RivReservoirViewPartMgr(RimEclipseView* resv) + : m_reservoirView(resv) { m_scaleTransform = new cvf::Transform(); clearGeometryCache(); } - //-------------------------------------------------------------------------------------------------- /// Clears the geometry cache for the given, and the dependent geometryTypes (from a visibility standpoint) //-------------------------------------------------------------------------------------------------- @@ -66,87 +65,87 @@ void RivReservoirViewPartMgr::scheduleGeometryRegen(RivCellSetEnum geometryType) { switch (geometryType) { - case OVERRIDDEN_CELL_VISIBILITY: - clearGeometryCache(OVERRIDDEN_CELL_VISIBILITY); - case INACTIVE: - clearGeometryCache(INACTIVE); - clearGeometryCache(RANGE_FILTERED_INACTIVE); - break; - case RANGE_FILTERED_INACTIVE: - clearGeometryCache(RANGE_FILTERED_INACTIVE); - break; - case ACTIVE: - clearGeometryCache(ACTIVE); - clearGeometryCache(ALL_WELL_CELLS); - clearGeometryCache(VISIBLE_WELL_CELLS); - clearGeometryCache(VISIBLE_WELL_FENCE_CELLS); - clearGeometryCache(RANGE_FILTERED); - clearGeometryCache(RANGE_FILTERED_WELL_CELLS); - clearGeometryCache(VISIBLE_WELL_CELLS_OUTSIDE_RANGE_FILTER); - clearGeometryCache(VISIBLE_WELL_FENCE_CELLS_OUTSIDE_RANGE_FILTER); - clearGeometryCache(PROPERTY_FILTERED); - clearGeometryCache(PROPERTY_FILTERED_WELL_CELLS); - break; - case ALL_WELL_CELLS: - clearGeometryCache(ALL_WELL_CELLS); - clearGeometryCache(VISIBLE_WELL_CELLS); - clearGeometryCache(VISIBLE_WELL_FENCE_CELLS); - clearGeometryCache(RANGE_FILTERED); - clearGeometryCache(RANGE_FILTERED_WELL_CELLS); - clearGeometryCache(VISIBLE_WELL_CELLS_OUTSIDE_RANGE_FILTER); - clearGeometryCache(VISIBLE_WELL_FENCE_CELLS_OUTSIDE_RANGE_FILTER); - clearGeometryCache(PROPERTY_FILTERED_WELL_CELLS); - break; - case VISIBLE_WELL_CELLS: - clearGeometryCache(VISIBLE_WELL_CELLS); - clearGeometryCache(VISIBLE_WELL_FENCE_CELLS); - clearGeometryCache(VISIBLE_WELL_CELLS_OUTSIDE_RANGE_FILTER); - clearGeometryCache(VISIBLE_WELL_FENCE_CELLS_OUTSIDE_RANGE_FILTER); - clearGeometryCache(PROPERTY_FILTERED); - clearGeometryCache(PROPERTY_FILTERED_WELL_CELLS); - break; - case VISIBLE_WELL_FENCE_CELLS: - clearGeometryCache(VISIBLE_WELL_FENCE_CELLS); - clearGeometryCache(VISIBLE_WELL_FENCE_CELLS_OUTSIDE_RANGE_FILTER); - clearGeometryCache(PROPERTY_FILTERED_WELL_CELLS); - break; - case RANGE_FILTERED: - clearGeometryCache(RANGE_FILTERED); - clearGeometryCache(RANGE_FILTERED_INACTIVE); - clearGeometryCache(RANGE_FILTERED_WELL_CELLS); - clearGeometryCache(VISIBLE_WELL_CELLS_OUTSIDE_RANGE_FILTER); - clearGeometryCache(VISIBLE_WELL_FENCE_CELLS_OUTSIDE_RANGE_FILTER); - clearGeometryCache(PROPERTY_FILTERED); - clearGeometryCache(PROPERTY_FILTERED_WELL_CELLS); - break; - case RANGE_FILTERED_WELL_CELLS: - clearGeometryCache(RANGE_FILTERED_WELL_CELLS); - clearGeometryCache(RANGE_FILTERED); - clearGeometryCache(VISIBLE_WELL_CELLS_OUTSIDE_RANGE_FILTER); - clearGeometryCache(VISIBLE_WELL_FENCE_CELLS_OUTSIDE_RANGE_FILTER); - clearGeometryCache(PROPERTY_FILTERED_WELL_CELLS); - break; - case VISIBLE_WELL_CELLS_OUTSIDE_RANGE_FILTER: - clearGeometryCache(VISIBLE_WELL_CELLS_OUTSIDE_RANGE_FILTER); - clearGeometryCache(VISIBLE_WELL_FENCE_CELLS_OUTSIDE_RANGE_FILTER); - clearGeometryCache(PROPERTY_FILTERED_WELL_CELLS); - break; - case VISIBLE_WELL_FENCE_CELLS_OUTSIDE_RANGE_FILTER: - clearGeometryCache(VISIBLE_WELL_FENCE_CELLS_OUTSIDE_RANGE_FILTER); - clearGeometryCache(PROPERTY_FILTERED_WELL_CELLS); - break; - case PROPERTY_FILTERED: - clearGeometryCache(PROPERTY_FILTERED); - clearGeometryCache(PROPERTY_FILTERED_WELL_CELLS); - break; - case PROPERTY_FILTERED_WELL_CELLS: - clearGeometryCache(PROPERTY_FILTERED_WELL_CELLS); - break; + case OVERRIDDEN_CELL_VISIBILITY: + clearGeometryCache(OVERRIDDEN_CELL_VISIBILITY); + case INACTIVE: + clearGeometryCache(INACTIVE); + clearGeometryCache(RANGE_FILTERED_INACTIVE); + break; + case RANGE_FILTERED_INACTIVE: + clearGeometryCache(RANGE_FILTERED_INACTIVE); + break; + case ACTIVE: + clearGeometryCache(ACTIVE); + clearGeometryCache(ALL_WELL_CELLS); + clearGeometryCache(VISIBLE_WELL_CELLS); + clearGeometryCache(VISIBLE_WELL_FENCE_CELLS); + clearGeometryCache(RANGE_FILTERED); + clearGeometryCache(RANGE_FILTERED_WELL_CELLS); + clearGeometryCache(VISIBLE_WELL_CELLS_OUTSIDE_RANGE_FILTER); + clearGeometryCache(VISIBLE_WELL_FENCE_CELLS_OUTSIDE_RANGE_FILTER); + clearGeometryCache(PROPERTY_FILTERED); + clearGeometryCache(PROPERTY_FILTERED_WELL_CELLS); + break; + case ALL_WELL_CELLS: + clearGeometryCache(ALL_WELL_CELLS); + clearGeometryCache(VISIBLE_WELL_CELLS); + clearGeometryCache(VISIBLE_WELL_FENCE_CELLS); + clearGeometryCache(RANGE_FILTERED); + clearGeometryCache(RANGE_FILTERED_WELL_CELLS); + clearGeometryCache(VISIBLE_WELL_CELLS_OUTSIDE_RANGE_FILTER); + clearGeometryCache(VISIBLE_WELL_FENCE_CELLS_OUTSIDE_RANGE_FILTER); + clearGeometryCache(PROPERTY_FILTERED_WELL_CELLS); + break; + case VISIBLE_WELL_CELLS: + clearGeometryCache(VISIBLE_WELL_CELLS); + clearGeometryCache(VISIBLE_WELL_FENCE_CELLS); + clearGeometryCache(VISIBLE_WELL_CELLS_OUTSIDE_RANGE_FILTER); + clearGeometryCache(VISIBLE_WELL_FENCE_CELLS_OUTSIDE_RANGE_FILTER); + clearGeometryCache(PROPERTY_FILTERED); + clearGeometryCache(PROPERTY_FILTERED_WELL_CELLS); + break; + case VISIBLE_WELL_FENCE_CELLS: + clearGeometryCache(VISIBLE_WELL_FENCE_CELLS); + clearGeometryCache(VISIBLE_WELL_FENCE_CELLS_OUTSIDE_RANGE_FILTER); + clearGeometryCache(PROPERTY_FILTERED_WELL_CELLS); + break; + case RANGE_FILTERED: + clearGeometryCache(RANGE_FILTERED); + clearGeometryCache(RANGE_FILTERED_INACTIVE); + clearGeometryCache(RANGE_FILTERED_WELL_CELLS); + clearGeometryCache(VISIBLE_WELL_CELLS_OUTSIDE_RANGE_FILTER); + clearGeometryCache(VISIBLE_WELL_FENCE_CELLS_OUTSIDE_RANGE_FILTER); + clearGeometryCache(PROPERTY_FILTERED); + clearGeometryCache(PROPERTY_FILTERED_WELL_CELLS); + break; + case RANGE_FILTERED_WELL_CELLS: + clearGeometryCache(RANGE_FILTERED_WELL_CELLS); + clearGeometryCache(RANGE_FILTERED); + clearGeometryCache(VISIBLE_WELL_CELLS_OUTSIDE_RANGE_FILTER); + clearGeometryCache(VISIBLE_WELL_FENCE_CELLS_OUTSIDE_RANGE_FILTER); + clearGeometryCache(PROPERTY_FILTERED_WELL_CELLS); + break; + case VISIBLE_WELL_CELLS_OUTSIDE_RANGE_FILTER: + clearGeometryCache(VISIBLE_WELL_CELLS_OUTSIDE_RANGE_FILTER); + clearGeometryCache(VISIBLE_WELL_FENCE_CELLS_OUTSIDE_RANGE_FILTER); + clearGeometryCache(PROPERTY_FILTERED_WELL_CELLS); + break; + case VISIBLE_WELL_FENCE_CELLS_OUTSIDE_RANGE_FILTER: + clearGeometryCache(VISIBLE_WELL_FENCE_CELLS_OUTSIDE_RANGE_FILTER); + clearGeometryCache(PROPERTY_FILTERED_WELL_CELLS); + break; + case PROPERTY_FILTERED: + clearGeometryCache(PROPERTY_FILTERED); + clearGeometryCache(PROPERTY_FILTERED_WELL_CELLS); + break; + case PROPERTY_FILTERED_WELL_CELLS: + clearGeometryCache(PROPERTY_FILTERED_WELL_CELLS); + break; } } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RivReservoirViewPartMgr::clearGeometryCache(RivCellSetEnum geomType) { @@ -190,7 +189,7 @@ void RivReservoirViewPartMgr::clearGeometryCache(RivCellSetEnum geomType) } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RivReservoirViewPartMgr::clearGeometryCache() { @@ -210,10 +209,11 @@ void RivReservoirViewPartMgr::clearGeometryCache() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- -void RivReservoirViewPartMgr::appendStaticGeometryPartsToModel(cvf::ModelBasicList* model, RivCellSetEnum geometryType, - const std::vector& gridIndices) +void RivReservoirViewPartMgr::appendStaticGeometryPartsToModel(cvf::ModelBasicList* model, + RivCellSetEnum geometryType, + const std::vector& gridIndices) { ensureStaticGeometryPartsCreated(geometryType); @@ -221,21 +221,23 @@ void RivReservoirViewPartMgr::appendStaticGeometryPartsToModel(cvf::ModelBasicLi } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RivReservoirViewPartMgr::ensureStaticGeometryPartsCreated(RivCellSetEnum geometryType) { if (geometryType < PROPERTY_FILTERED && m_geometriesNeedsRegen[geometryType]) { - createGeometry( geometryType); + createGeometry(geometryType); } } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- -void RivReservoirViewPartMgr::appendDynamicGeometryPartsToModel(cvf::ModelBasicList* model, RivCellSetEnum geometryType, - size_t frameIndex, const std::vector& gridIndices) +void RivReservoirViewPartMgr::appendDynamicGeometryPartsToModel(cvf::ModelBasicList* model, + RivCellSetEnum geometryType, + size_t frameIndex, + const std::vector& gridIndices) { ensureDynamicGeometryPartsCreated(geometryType, frameIndex); @@ -250,7 +252,7 @@ void RivReservoirViewPartMgr::appendDynamicGeometryPartsToModel(cvf::ModelBasicL } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RivReservoirViewPartMgr::ensureDynamicGeometryPartsCreated(RivCellSetEnum geometryType, size_t frameIndex) { @@ -263,7 +265,8 @@ void RivReservoirViewPartMgr::ensureDynamicGeometryPartsCreated(RivCellSetEnum g } else if (geometryType == PROPERTY_FILTERED_WELL_CELLS) { - if (frameIndex >= m_propFilteredWellGeometryFramesNeedsRegen.size() || m_propFilteredWellGeometryFramesNeedsRegen[frameIndex]) + if (frameIndex >= m_propFilteredWellGeometryFramesNeedsRegen.size() || + m_propFilteredWellGeometryFramesNeedsRegen[frameIndex]) { createPropertyFilteredWellGeometry(frameIndex); } @@ -271,7 +274,7 @@ void RivReservoirViewPartMgr::ensureDynamicGeometryPartsCreated(RivCellSetEnum g } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RivReservoirViewPartMgr::createGeometry(RivCellSetEnum geometryType) { @@ -279,15 +282,15 @@ void RivReservoirViewPartMgr::createGeometry(RivCellSetEnum geometryType) m_geometries[geometryType].clearAndSetReservoir(geometryType, m_reservoirView->eclipseCase(), m_reservoirView); m_geometries[geometryType].setTransform(m_scaleTransform.p()); - + std::vector grids; res->allGrids(&grids); for (size_t i = 0; i < grids.size(); ++i) { - cvf::ref cellVisibility = m_geometries[geometryType].cellVisibility(i); + cvf::ref cellVisibility = m_geometries[geometryType].cellVisibility(i); computeVisibility(cellVisibility.p(), geometryType, grids[i], i); - + m_geometries[geometryType].setCellVisibility(i, cellVisibility.p()); } @@ -295,25 +298,29 @@ void RivReservoirViewPartMgr::createGeometry(RivCellSetEnum geometryType) } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- -void RivReservoirViewPartMgr::computeVisibility(cvf::UByteArray* cellVisibility, RivCellSetEnum geometryType, RigGridBase* grid, size_t gridIdx) +void RivReservoirViewPartMgr::computeVisibility(cvf::UByteArray* cellVisibility, + RivCellSetEnum geometryType, + RigGridBase* grid, + size_t gridIdx) { - RigEclipseCaseData* eclipseCase = m_reservoirView->eclipseCase()->eclipseCaseData(); - auto activeCellInfo = m_reservoirView->currentActiveCellInfo(); + RigEclipseCaseData* eclipseCase = m_reservoirView->eclipseCase()->eclipseCaseData(); + auto activeCellInfo = m_reservoirView->currentActiveCellInfo(); switch (geometryType) { - case OVERRIDDEN_CELL_VISIBILITY: - computeOverriddenCellVisibility(cellVisibility, grid); - break; - case ACTIVE: - computeNativeVisibility(cellVisibility, grid, activeCellInfo, eclipseCase->wellCellsInGrid(gridIdx), false, false, true); - break; - case ALL_WELL_CELLS: - copyByteArray(cellVisibility, eclipseCase->wellCellsInGrid(gridIdx)); - break; - case VISIBLE_WELL_CELLS: + case OVERRIDDEN_CELL_VISIBILITY: + computeOverriddenCellVisibility(cellVisibility, grid); + break; + case ACTIVE: + computeNativeVisibility( + cellVisibility, grid, activeCellInfo, eclipseCase->wellCellsInGrid(gridIdx), false, false, true); + break; + case ALL_WELL_CELLS: + copyByteArray(cellVisibility, eclipseCase->wellCellsInGrid(gridIdx)); + break; + case VISIBLE_WELL_CELLS: { cvf::ref allWellCellsVisibility; ensureStaticGeometryPartsCreated(ALL_WELL_CELLS); @@ -329,7 +336,7 @@ void RivReservoirViewPartMgr::computeVisibility(cvf::UByteArray* cellVisibility, } } break; - case VISIBLE_WELL_FENCE_CELLS: + case VISIBLE_WELL_FENCE_CELLS: { cvf::ref allWellCellsVisibility; ensureStaticGeometryPartsCreated(ALL_WELL_CELLS); @@ -345,37 +352,46 @@ void RivReservoirViewPartMgr::computeVisibility(cvf::UByteArray* cellVisibility, } } break; - case INACTIVE: - computeNativeVisibility(cellVisibility, grid, activeCellInfo, eclipseCase->wellCellsInGrid(gridIdx), m_reservoirView->showInvalidCells(), true, false); - break; - case RANGE_FILTERED: + case INACTIVE: + computeNativeVisibility(cellVisibility, + grid, + activeCellInfo, + eclipseCase->wellCellsInGrid(gridIdx), + m_reservoirView->showInvalidCells(), + true, + false); + break; + case RANGE_FILTERED: { cvf::ref nativeVisibility; ensureStaticGeometryPartsCreated(ACTIVE); nativeVisibility = m_geometries[ACTIVE].cellVisibility(gridIdx); - computeRangeVisibility(geometryType, cellVisibility, grid, nativeVisibility.p(), m_reservoirView->rangeFilterCollection()); + computeRangeVisibility( + geometryType, cellVisibility, grid, nativeVisibility.p(), m_reservoirView->rangeFilterCollection()); } break; - case RANGE_FILTERED_INACTIVE: + case RANGE_FILTERED_INACTIVE: { cvf::ref nativeVisibility; ensureStaticGeometryPartsCreated(INACTIVE); nativeVisibility = m_geometries[INACTIVE].cellVisibility(gridIdx); - computeRangeVisibility(geometryType, cellVisibility, grid, nativeVisibility.p(), m_reservoirView->rangeFilterCollection()); + computeRangeVisibility( + geometryType, cellVisibility, grid, nativeVisibility.p(), m_reservoirView->rangeFilterCollection()); } break; - case RANGE_FILTERED_WELL_CELLS: + case RANGE_FILTERED_WELL_CELLS: { cvf::ref nativeVisibility; ensureStaticGeometryPartsCreated(ALL_WELL_CELLS); nativeVisibility = m_geometries[ALL_WELL_CELLS].cellVisibility(gridIdx); - computeRangeVisibility(geometryType, cellVisibility, grid, nativeVisibility.p(), m_reservoirView->rangeFilterCollection()); + computeRangeVisibility( + geometryType, cellVisibility, grid, nativeVisibility.p(), m_reservoirView->rangeFilterCollection()); } break; - case VISIBLE_WELL_CELLS_OUTSIDE_RANGE_FILTER: + case VISIBLE_WELL_CELLS_OUTSIDE_RANGE_FILTER: { cvf::ref visibleWellCells; cvf::ref rangeFilteredWellCells; @@ -383,7 +399,7 @@ void RivReservoirViewPartMgr::computeVisibility(cvf::UByteArray* cellVisibility, ensureStaticGeometryPartsCreated(VISIBLE_WELL_CELLS); ensureStaticGeometryPartsCreated(RANGE_FILTERED_WELL_CELLS); - visibleWellCells = m_geometries[VISIBLE_WELL_CELLS].cellVisibility(gridIdx); + visibleWellCells = m_geometries[VISIBLE_WELL_CELLS].cellVisibility(gridIdx); rangeFilteredWellCells = m_geometries[RANGE_FILTERED_WELL_CELLS].cellVisibility(gridIdx); cellVisibility->resize(visibleWellCells->size()); @@ -395,7 +411,7 @@ void RivReservoirViewPartMgr::computeVisibility(cvf::UByteArray* cellVisibility, } } break; - case VISIBLE_WELL_FENCE_CELLS_OUTSIDE_RANGE_FILTER: + case VISIBLE_WELL_FENCE_CELLS_OUTSIDE_RANGE_FILTER: { cvf::ref visibleWellCells; cvf::ref rangeFilteredWellCells; @@ -403,7 +419,7 @@ void RivReservoirViewPartMgr::computeVisibility(cvf::UByteArray* cellVisibility, ensureStaticGeometryPartsCreated(VISIBLE_WELL_FENCE_CELLS); ensureStaticGeometryPartsCreated(RANGE_FILTERED); - visibleWellCells = m_geometries[VISIBLE_WELL_FENCE_CELLS].cellVisibility(gridIdx); + visibleWellCells = m_geometries[VISIBLE_WELL_FENCE_CELLS].cellVisibility(gridIdx); rangeFilteredWellCells = m_geometries[RANGE_FILTERED].cellVisibility(gridIdx); cellVisibility->resize(visibleWellCells->size()); @@ -415,41 +431,42 @@ void RivReservoirViewPartMgr::computeVisibility(cvf::UByteArray* cellVisibility, } } break; - default: - CVF_ASSERT(false); // Call special function for property filtered stuff - break; + default: + CVF_ASSERT(false); // Call special function for property filtered stuff + break; } } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RivReservoirViewPartMgr::createPropertyFilteredNoneWellCellGeometry(size_t frameIndex) { RigEclipseCaseData* res = m_reservoirView->eclipseCase()->eclipseCaseData(); - if ( frameIndex >= m_propFilteredGeometryFrames.size()) - { + if (frameIndex >= m_propFilteredGeometryFrames.size()) + { m_propFilteredGeometryFrames.resize(frameIndex + 1); m_propFilteredGeometryFramesNeedsRegen.resize(frameIndex + 1, true); } - if ( m_propFilteredGeometryFrames[frameIndex].isNull()) m_propFilteredGeometryFrames[frameIndex] = new RivReservoirPartMgr; + if (m_propFilteredGeometryFrames[frameIndex].isNull()) m_propFilteredGeometryFrames[frameIndex] = new RivReservoirPartMgr; - m_propFilteredGeometryFrames[frameIndex]->clearAndSetReservoir(PROPERTY_FILTERED, m_reservoirView->eclipseCase(), m_reservoirView); + m_propFilteredGeometryFrames[frameIndex]->clearAndSetReservoir( + PROPERTY_FILTERED, m_reservoirView->eclipseCase(), m_reservoirView); m_propFilteredGeometryFrames[frameIndex]->setTransform(m_scaleTransform.p()); std::vector grids; res->allGrids(&grids); bool hasActiveRangeFilters = m_reservoirView->rangeFilterCollection()->hasActiveFilters(); - bool hasVisibleWellCells = m_reservoirView->wellCollection()->hasVisibleWellCells(); + bool hasVisibleWellCells = m_reservoirView->wellCollection()->hasVisibleWellCells(); for (size_t gIdx = 0; gIdx < grids.size(); ++gIdx) { - cvf::ref cellVisibility = m_propFilteredGeometryFrames[frameIndex]->cellVisibility(gIdx); - cvf::ref rangeVisibility; - cvf::ref fenceVisibility; + cvf::ref cellVisibility = m_propFilteredGeometryFrames[frameIndex]->cellVisibility(gIdx); + cvf::ref rangeVisibility; + cvf::ref fenceVisibility; if (hasActiveRangeFilters && hasVisibleWellCells) { @@ -489,44 +506,47 @@ void RivReservoirViewPartMgr::createPropertyFilteredNoneWellCellGeometry(size_t (*cellVisibility)[cellIdx] = (*rangeVisibility)[cellIdx] || (*fenceVisibility)[cellIdx]; } - computePropertyVisibility(cellVisibility.p(), grids[gIdx], frameIndex, cellVisibility.p(), m_reservoirView->eclipsePropertyFilterCollection()); + computePropertyVisibility( + cellVisibility.p(), grids[gIdx], frameIndex, cellVisibility.p(), m_reservoirView->eclipsePropertyFilterCollection()); m_propFilteredGeometryFrames[frameIndex]->setCellVisibility(gIdx, cellVisibility.p()); - } + } m_propFilteredGeometryFramesNeedsRegen[frameIndex] = false; } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RivReservoirViewPartMgr::createPropertyFilteredWellGeometry(size_t frameIndex) { RigEclipseCaseData* res = m_reservoirView->eclipseCase()->eclipseCaseData(); - if ( frameIndex >= m_propFilteredWellGeometryFrames.size()) - { + if (frameIndex >= m_propFilteredWellGeometryFrames.size()) + { m_propFilteredWellGeometryFrames.resize(frameIndex + 1); m_propFilteredWellGeometryFramesNeedsRegen.resize(frameIndex + 1, true); } - if ( m_propFilteredWellGeometryFrames[frameIndex].isNull()) m_propFilteredWellGeometryFrames[frameIndex] = new RivReservoirPartMgr; + if (m_propFilteredWellGeometryFrames[frameIndex].isNull()) + m_propFilteredWellGeometryFrames[frameIndex] = new RivReservoirPartMgr; - m_propFilteredWellGeometryFrames[frameIndex]->clearAndSetReservoir(PROPERTY_FILTERED_WELL_CELLS, m_reservoirView->eclipseCase(), m_reservoirView); + m_propFilteredWellGeometryFrames[frameIndex]->clearAndSetReservoir( + PROPERTY_FILTERED_WELL_CELLS, m_reservoirView->eclipseCase(), m_reservoirView); m_propFilteredWellGeometryFrames[frameIndex]->setTransform(m_scaleTransform.p()); std::vector grids; res->allGrids(&grids); bool hasActiveRangeFilters = m_reservoirView->rangeFilterCollection()->hasActiveFilters(); - bool hasVisibleWellCells = m_reservoirView->wellCollection()->hasVisibleWellCells(); + bool hasVisibleWellCells = m_reservoirView->wellCollection()->hasVisibleWellCells(); for (size_t gIdx = 0; gIdx < grids.size(); ++gIdx) { - cvf::ref cellVisibility = m_propFilteredWellGeometryFrames[frameIndex]->cellVisibility(gIdx); - cvf::ref rangeVisibility; - cvf::ref wellCellsOutsideRange; - cvf::ref wellFenceCells; + cvf::ref cellVisibility = m_propFilteredWellGeometryFrames[frameIndex]->cellVisibility(gIdx); + cvf::ref rangeVisibility; + cvf::ref wellCellsOutsideRange; + cvf::ref wellFenceCells; if (hasActiveRangeFilters && hasVisibleWellCells) { @@ -538,14 +558,13 @@ void RivReservoirViewPartMgr::createPropertyFilteredWellGeometry(size_t frameInd ensureStaticGeometryPartsCreated(VISIBLE_WELL_FENCE_CELLS_OUTSIDE_RANGE_FILTER); wellFenceCells = m_geometries[VISIBLE_WELL_FENCE_CELLS_OUTSIDE_RANGE_FILTER].cellVisibility(gIdx); - } else if (hasActiveRangeFilters && !hasVisibleWellCells) { ensureStaticGeometryPartsCreated(RANGE_FILTERED_WELL_CELLS); - rangeVisibility = m_geometries[RANGE_FILTERED_WELL_CELLS].cellVisibility(gIdx); + rangeVisibility = m_geometries[RANGE_FILTERED_WELL_CELLS].cellVisibility(gIdx); wellCellsOutsideRange = rangeVisibility; - wellFenceCells = rangeVisibility; + wellFenceCells = rangeVisibility; } else if (!hasActiveRangeFilters && hasVisibleWellCells) { @@ -560,9 +579,9 @@ void RivReservoirViewPartMgr::createPropertyFilteredWellGeometry(size_t frameInd else if (!hasActiveRangeFilters && !hasVisibleWellCells) { ensureStaticGeometryPartsCreated(ALL_WELL_CELLS); - wellFenceCells = m_geometries[ALL_WELL_CELLS].cellVisibility(gIdx); + wellFenceCells = m_geometries[ALL_WELL_CELLS].cellVisibility(gIdx); wellCellsOutsideRange = wellFenceCells; - rangeVisibility = wellFenceCells; + rangeVisibility = wellFenceCells; } cellVisibility->resize(rangeVisibility->size()); @@ -570,10 +589,12 @@ void RivReservoirViewPartMgr::createPropertyFilteredWellGeometry(size_t frameInd #pragma omp parallel for for (int cellIdx = 0; cellIdx < static_cast(cellVisibility->size()); ++cellIdx) { - (*cellVisibility)[cellIdx] = (*wellFenceCells)[cellIdx] || (*rangeVisibility)[cellIdx] || (*wellCellsOutsideRange)[cellIdx]; + (*cellVisibility)[cellIdx] = + (*wellFenceCells)[cellIdx] || (*rangeVisibility)[cellIdx] || (*wellCellsOutsideRange)[cellIdx]; } - computePropertyVisibility(cellVisibility.p(), grids[gIdx], frameIndex, cellVisibility.p(), m_reservoirView->eclipsePropertyFilterCollection()); + computePropertyVisibility( + cellVisibility.p(), grids[gIdx], frameIndex, cellVisibility.p(), m_reservoirView->eclipsePropertyFilterCollection()); m_propFilteredWellGeometryFrames[frameIndex]->setCellVisibility(gIdx, cellVisibility.p()); } @@ -584,10 +605,13 @@ void RivReservoirViewPartMgr::createPropertyFilteredWellGeometry(size_t frameInd //-------------------------------------------------------------------------------------------------- /// Evaluate visibility based on cell state //-------------------------------------------------------------------------------------------------- -void RivReservoirViewPartMgr::computeNativeVisibility(cvf::UByteArray* cellVisibility, const RigGridBase* grid, const RigActiveCellInfo* activeCellInfo, const cvf::UByteArray* cellIsInWellStatuses, - bool invalidCellsIsVisible, - bool inactiveCellsIsVisible, - bool activeCellsIsVisible) +void RivReservoirViewPartMgr::computeNativeVisibility(cvf::UByteArray* cellVisibility, + const RigGridBase* grid, + const RigActiveCellInfo* activeCellInfo, + const cvf::UByteArray* cellIsInWellStatuses, + bool invalidCellsIsVisible, + bool inactiveCellsIsVisible, + bool activeCellsIsVisible) { CVF_ASSERT(cellVisibility != nullptr); CVF_ASSERT(grid != nullptr); @@ -597,17 +621,15 @@ void RivReservoirViewPartMgr::computeNativeVisibility(cvf::UByteArray* cellVisib cellVisibility->resize(grid->cellCount()); -#pragma omp parallel for +#pragma omp parallel for for (int cellIndex = 0; cellIndex < static_cast(grid->cellCount()); cellIndex++) { - const RigCell& cell = grid->cell(cellIndex); - size_t reservoirCellIndex = cell.mainGridCellIndex(); - - if ( !invalidCellsIsVisible && cell.isInvalid() - || !inactiveCellsIsVisible && !activeCellInfo->isActive(reservoirCellIndex) - || !activeCellsIsVisible && activeCellInfo->isActive(reservoirCellIndex) - || (*cellIsInWellStatuses)[cellIndex] - ) + const RigCell& cell = grid->cell(cellIndex); + size_t reservoirCellIndex = cell.mainGridCellIndex(); + + if (!invalidCellsIsVisible && cell.isInvalid() || + !inactiveCellsIsVisible && !activeCellInfo->isActive(reservoirCellIndex) || + !activeCellsIsVisible && activeCellInfo->isActive(reservoirCellIndex) || (*cellIsInWellStatuses)[cellIndex]) { (*cellVisibility)[cellIndex] = false; } @@ -619,25 +641,25 @@ void RivReservoirViewPartMgr::computeNativeVisibility(cvf::UByteArray* cellVisib } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RivReservoirViewPartMgr::computeOverriddenCellVisibility(cvf::UByteArray* cellVisibility, const RigGridBase* grid) { - RimViewController* masterViewLink = m_reservoirView->viewController(); - + CVF_ASSERT(masterViewLink); RimGridView* masterView = masterViewLink->ownerViewLinker()->masterView(); - // get cell visibility - #if 1 - cvf::ref totCellVisibility = masterView->currentTotalCellVisibility(); - #else - // Could get something more like - std::vector > gridsWithCellSetVisibility = masterView->getAllGridsCurrentCellSetsCellVisibility(); - #endif - +// get cell visibility +#if 1 + cvf::ref totCellVisibility = masterView->currentTotalCellVisibility(); +#else + // Could get something more like + std::vector> gridsWithCellSetVisibility = + masterView->getAllGridsCurrentCellSetsCellVisibility(); +#endif + CVF_ASSERT(cellVisibility != nullptr); CVF_ASSERT(grid != nullptr); @@ -649,40 +671,38 @@ void RivReservoirViewPartMgr::computeOverriddenCellVisibility(cvf::UByteArray* c for (size_t lcIdx = 0; lcIdx < gridCellCount; ++lcIdx) { - #if 1 - int reservoirCellIdx = static_cast(grid->reservoirCellIndex(lcIdx)); - int cellCount = 0; +#if 1 + int reservoirCellIdx = static_cast(grid->reservoirCellIndex(lcIdx)); + int cellCount = 0; const int* cellIndicesInMasterCase = cellMapper->masterCaseCellIndices(reservoirCellIdx, &cellCount); - + for (int mcIdx = 0; mcIdx < cellCount; ++mcIdx) { - (*cellVisibility)[lcIdx] |= (*totCellVisibility)[cellIndicesInMasterCase[mcIdx]]; // If any is visible, show + (*cellVisibility)[lcIdx] |= (*totCellVisibility)[cellIndicesInMasterCase[mcIdx]]; // If any is visible, show } - #else - +#else + const RigGridCells& masterCaseCells = cellMapper->masterCaseGridAndLocalCellIndex(grid->gridIndex, lcIdx); for (int mcIdx = 0; mcIdx < masterCaseCells.cellCount(); ++mcIdx) { - int cellSetCount = gridsWithCellSetVisibility[ masterCaseCells.gridIndex[mcIdx] ].size(); + int cellSetCount = gridsWithCellSetVisibility[masterCaseCells.gridIndex[mcIdx]].size(); for (int csIdx = 0; csIdx < cellSetCount; ++csIdx) { - (*cellVisibility)[lcIdx] |= gridsWithCellSetVisibility[masterCaseCells.gridIndex[mcIdx]][masterCaseCells.cellIndex[mcIdx]]; + (*cellVisibility)[lcIdx] |= + gridsWithCellSetVisibility[masterCaseCells.gridIndex[mcIdx]][masterCaseCells.cellIndex[mcIdx]]; } } - #endif +#endif } } - - - //-------------------------------------------------------------------------------------------------- /// Copy the data from source into destination. This is not trivial to do using cvf::Array ... -/// using parallelized operator [] and not memcopy. Do not know what is faster. +/// using parallelized operator [] and not memcopy. Do not know what is faster. //-------------------------------------------------------------------------------------------------- -void RivReservoirViewPartMgr::copyByteArray(cvf::UByteArray* destination, const cvf::UByteArray* source ) +void RivReservoirViewPartMgr::copyByteArray(cvf::UByteArray* destination, const cvf::UByteArray* source) { CVF_ASSERT(destination != nullptr); CVF_ASSERT(source != nullptr); @@ -692,22 +712,21 @@ void RivReservoirViewPartMgr::copyByteArray(cvf::UByteArray* destination, const destination->resize(source->size()); } -#pragma omp parallel for +#pragma omp parallel for for (int cellIndex = 0; cellIndex < static_cast(source->size()); cellIndex++) { (*destination)[cellIndex] = (*source)[cellIndex]; } } - //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- -void RivReservoirViewPartMgr::computeRangeVisibility(RivCellSetEnum geometryType, - cvf::UByteArray* cellVisibility, - const RigGridBase* grid, - const cvf::UByteArray* nativeVisibility, - const RimCellRangeFilterCollection* rangeFilterColl) +void RivReservoirViewPartMgr::computeRangeVisibility(RivCellSetEnum geometryType, + cvf::UByteArray* cellVisibility, + const RigGridBase* grid, + const cvf::UByteArray* nativeVisibility, + const RimCellRangeFilterCollection* rangeFilterColl) { CVF_ASSERT(cellVisibility != nullptr); CVF_ASSERT(nativeVisibility != nullptr); @@ -725,7 +744,7 @@ void RivReservoirViewPartMgr::computeRangeVisibility(RivCellSetEnum geometryType cvf::CellRangeFilter gridCellRangeFilter; rangeFilterColl->compoundCellRangeFilter(&gridCellRangeFilter, grid->gridIndex()); - const RigLocalGrid* lgr = nullptr; + const RigLocalGrid* lgr = nullptr; cvf::ref parentGridVisibilities; if (!grid->isMainGrid()) @@ -737,7 +756,8 @@ void RivReservoirViewPartMgr::computeRangeVisibility(RivCellSetEnum geometryType if (geometryType == RANGE_FILTERED_WELL_CELLS) { - geometryType = RANGE_FILTERED; // Use the range filtering in the parent grid, not the well cells in the parent grid + geometryType = + RANGE_FILTERED; // Use the range filtering in the parent grid, not the well cells in the parent grid } RivReservoirPartMgr* reservoirGridPartMgr = &m_geometries[geometryType]; @@ -745,19 +765,20 @@ void RivReservoirViewPartMgr::computeRangeVisibility(RivCellSetEnum geometryType parentGridVisibilities = reservoirGridPartMgr->cellVisibility(parentGridIndex); } - bool hasAdditiveRangeFilters = rangeFilterColl->hasActiveIncludeFilters() || m_reservoirView->wellCollection()->hasVisibleWellCells(); + bool hasAdditiveRangeFilters = + rangeFilterColl->hasActiveIncludeFilters() || m_reservoirView->wellCollection()->hasVisibleWellCells(); -#pragma omp parallel for +#pragma omp parallel for for (int cellIndex = 0; cellIndex < static_cast(grid->cellCount()); cellIndex++) { - if ( (*nativeVisibility)[cellIndex] ) + if ((*nativeVisibility)[cellIndex]) { - const RigCell& cell = grid->cell(cellIndex); - bool visibleDueToParentGrid = false; + const RigCell& cell = grid->cell(cellIndex); + bool visibleDueToParentGrid = false; if (lgr) { size_t parentGridCellIndex = cell.parentCellIndex(); - visibleDueToParentGrid = parentGridVisibilities->get(parentGridCellIndex); + visibleDueToParentGrid = parentGridVisibilities->get(parentGridCellIndex); } // Normal grid visibility @@ -767,31 +788,35 @@ void RivReservoirViewPartMgr::computeRangeVisibility(RivCellSetEnum geometryType bool isInSubGridArea = cell.subGrid() != nullptr; grid->ijkFromCellIndex(cellIndex, &mainGridI, &mainGridJ, &mainGridK); - + bool nativeRangeVisibility = false; - + if (hasAdditiveRangeFilters) { nativeRangeVisibility = gridCellRangeFilter.isCellVisible(mainGridI, mainGridJ, mainGridK, isInSubGridArea); } else { - // Special handling when no include filters are present. Use native visibility + // Special handling when no include filters are present. Use native visibility nativeRangeVisibility = (*nativeVisibility)[cellIndex]; } - - (*cellVisibility)[cellIndex] = (visibleDueToParentGrid || nativeRangeVisibility) - && !gridCellRangeFilter.isCellExcluded(mainGridI, mainGridJ, mainGridK, isInSubGridArea); + + (*cellVisibility)[cellIndex] = + (visibleDueToParentGrid || nativeRangeVisibility) && + !gridCellRangeFilter.isCellExcluded(mainGridI, mainGridJ, mainGridK, isInSubGridArea); } } } } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- -void RivReservoirViewPartMgr::computePropertyVisibility(cvf::UByteArray* cellVisibility, const RigGridBase* grid, size_t timeStepIndex, - const cvf::UByteArray* rangeFilterVisibility, RimEclipsePropertyFilterCollection* propFilterColl) +void RivReservoirViewPartMgr::computePropertyVisibility(cvf::UByteArray* cellVisibility, + const RigGridBase* grid, + size_t timeStepIndex, + const cvf::UByteArray* rangeFilterVisibility, + RimEclipsePropertyFilterCollection* propFilterColl) { CVF_ASSERT(cellVisibility != nullptr); CVF_ASSERT(rangeFilterVisibility != nullptr); @@ -801,7 +826,7 @@ void RivReservoirViewPartMgr::computePropertyVisibility(cvf::UByteArray* cellVis CVF_ASSERT(rangeFilterVisibility->size() == grid->cellCount()); // Copy if not equal - if (cellVisibility != rangeFilterVisibility ) (*cellVisibility) = *rangeFilterVisibility; + if (cellVisibility != rangeFilterVisibility) (*cellVisibility) = *rangeFilterVisibility; if (propFilterColl->hasActiveFilters()) { @@ -809,20 +834,21 @@ void RivReservoirViewPartMgr::computePropertyVisibility(cvf::UByteArray* cellVis { RimEclipsePropertyFilter* propertyFilter = propFilterColl->propertyFilters()[i]; - if (propertyFilter->isActive() && propertyFilter->resultDefinition->hasResult()) + if (propertyFilter->isActive() && propertyFilter->resultDefinition()->hasResult()) { const RimCellFilter::FilterModeType filterType = propertyFilter->filterMode(); RigEclipseCaseData* eclipseCase = propFilterColl->reservoirView()->eclipseCase()->eclipseCaseData(); - cvf::ref resultAccessor = RigResultAccessorFactory::createFromResultDefinition(eclipseCase, grid->gridIndex(), timeStepIndex, propertyFilter->resultDefinition); + cvf::ref resultAccessor = RigResultAccessorFactory::createFromResultDefinition( + eclipseCase, grid->gridIndex(), timeStepIndex, propertyFilter->resultDefinition()); CVF_ASSERT(resultAccessor.notNull()); if (propertyFilter->isCategorySelectionActive()) { std::vector integerVector = propertyFilter->selectedCategoryValues(); - std::set integerSet; + std::set integerSet; for (auto val : integerVector) { integerSet.insert(val); @@ -888,56 +914,65 @@ void RivReservoirViewPartMgr::computePropertyVisibility(cvf::UByteArray* cellVis } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RivReservoirViewPartMgr::updateCellColor(RivCellSetEnum geometryType, size_t timeStepIndex, cvf::Color4f color) { - RivReservoirPartMgr * pmgr = reservoirPartManager( geometryType, timeStepIndex ); + RivReservoirPartMgr* pmgr = reservoirPartManager(geometryType, timeStepIndex); pmgr->updateCellColor(color); } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- -void RivReservoirViewPartMgr::updateCellResultColor(RivCellSetEnum geometryType, size_t timeStepIndex, RimEclipseCellColors* cellResultColors) +void RivReservoirViewPartMgr::updateCellResultColor(RivCellSetEnum geometryType, + size_t timeStepIndex, + RimEclipseCellColors* cellResultColors) { - RivReservoirPartMgr * pmgr = reservoirPartManager( geometryType, timeStepIndex ); + RivReservoirPartMgr* pmgr = reservoirPartManager(geometryType, timeStepIndex); pmgr->updateCellResultColor(timeStepIndex, cellResultColors); } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- -void RivReservoirViewPartMgr::updateCellEdgeResultColor(RivCellSetEnum geometryType, size_t timeStepIndex, RimEclipseCellColors* cellResultColors, RimCellEdgeColors* cellEdgeResultColors) +void RivReservoirViewPartMgr::updateCellEdgeResultColor(RivCellSetEnum geometryType, + size_t timeStepIndex, + RimEclipseCellColors* cellResultColors, + RimCellEdgeColors* cellEdgeResultColors) { - RivReservoirPartMgr * pmgr = reservoirPartManager( geometryType, timeStepIndex ); + RivReservoirPartMgr* pmgr = reservoirPartManager(geometryType, timeStepIndex); pmgr->updateCellEdgeResultColor(timeStepIndex, cellResultColors, cellEdgeResultColors); } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- -void RivReservoirViewPartMgr::updateFaultCellEdgeResultColor(RivCellSetEnum geometryType, size_t timeStepIndex, RimEclipseCellColors* cellResultColors, RimCellEdgeColors* cellEdgeResultColors) +void RivReservoirViewPartMgr::updateFaultCellEdgeResultColor(RivCellSetEnum geometryType, + size_t timeStepIndex, + RimEclipseCellColors* cellResultColors, + RimCellEdgeColors* cellEdgeResultColors) { - RivReservoirPartMgr * pmgr = reservoirPartManager(geometryType, timeStepIndex); + RivReservoirPartMgr* pmgr = reservoirPartManager(geometryType, timeStepIndex); pmgr->updateFaultCellEdgeResultColor(timeStepIndex, cellResultColors, cellEdgeResultColors); } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- -const cvf::UByteArray* RivReservoirViewPartMgr::cellVisibility(RivCellSetEnum geometryType, size_t gridIndex, size_t timeStepIndex) +const cvf::UByteArray* + RivReservoirViewPartMgr::cellVisibility(RivCellSetEnum geometryType, size_t gridIndex, size_t timeStepIndex) { ensureDynamicGeometryPartsCreated(geometryType, timeStepIndex); ensureStaticGeometryPartsCreated(geometryType); - RivReservoirPartMgr * pmgr = (const_cast(this))->reservoirPartManager( geometryType, timeStepIndex ); - + RivReservoirPartMgr* pmgr = (const_cast(this))->reservoirPartManager(geometryType, timeStepIndex); + return pmgr->cellVisibility(gridIndex).p(); } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- RivReservoirPartMgr* RivReservoirViewPartMgr::reservoirPartManager(RivCellSetEnum geometryType, size_t timeStepIndex) { @@ -956,9 +991,11 @@ RivReservoirPartMgr* RivReservoirViewPartMgr::reservoirPartManager(RivCellSetEnu } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- -void RivReservoirViewPartMgr::updateFaultColors(RivCellSetEnum geometryType, size_t timeStepIndex, RimEclipseCellColors* cellResultColors) +void RivReservoirViewPartMgr::updateFaultColors(RivCellSetEnum geometryType, + size_t timeStepIndex, + RimEclipseCellColors* cellResultColors) { if (geometryType == PROPERTY_FILTERED && timeStepIndex >= m_propFilteredGeometryFrames.size()) { @@ -975,7 +1012,7 @@ void RivReservoirViewPartMgr::updateFaultColors(RivCellSetEnum geometryType, siz } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RivReservoirViewPartMgr::appendFaultsStaticGeometryPartsToModel(cvf::ModelBasicList* model, RivCellSetEnum geometryType) { @@ -983,85 +1020,88 @@ void RivReservoirViewPartMgr::appendFaultsStaticGeometryPartsToModel(cvf::ModelB ensureStaticGeometryPartsCreated(geometryType); -/* - QString text; - switch (geometryType) - { - case OVERRIDDEN_CELL_VISIBILITY: - text = "OVERRIDDEN_CELL_VISIBILITY"; - break; - case ALL_CELLS: - text = "ALL_CELLS"; - break; - case ACTIVE: - text = "ACTIVE"; - break; - case ALL_WELL_CELLS: - text = "ALL_WELL_CELLS"; - break; - case VISIBLE_WELL_CELLS: - text = "VISIBLE_WELL_CELLS"; - break; - case VISIBLE_WELL_FENCE_CELLS: - text = "VISIBLE_WELL_FENCE_CELLS"; - break; - case INACTIVE: - text = "INACTIVE"; - break; - case RANGE_FILTERED: - text = "RANGE_FILTERED"; - break; - case RANGE_FILTERED_INACTIVE: - text = "RANGE_FILTERED_INACTIVE"; - break; - case RANGE_FILTERED_WELL_CELLS: - text = "RANGE_FILTERED_WELL_CELLS"; - break; - case VISIBLE_WELL_CELLS_OUTSIDE_RANGE_FILTER: - text = "VISIBLE_WELL_CELLS_OUTSIDE_RANGE_FILTER"; - break; - case VISIBLE_WELL_FENCE_CELLS_OUTSIDE_RANGE_FILTER: - text = "VISIBLE_WELL_FENCE_CELLS_OUTSIDE_RANGE_FILTER"; - break; - case PROPERTY_FILTERED: - text = "PROPERTY_FILTERED"; - break; - case PROPERTY_FILTERED_WELL_CELLS: - text = "PROPERTY_FILTERED_WELL_CELLS"; - break; - default: - break; - } + /* + QString text; + switch (geometryType) + { + case OVERRIDDEN_CELL_VISIBILITY: + text = "OVERRIDDEN_CELL_VISIBILITY"; + break; + case ALL_CELLS: + text = "ALL_CELLS"; + break; + case ACTIVE: + text = "ACTIVE"; + break; + case ALL_WELL_CELLS: + text = "ALL_WELL_CELLS"; + break; + case VISIBLE_WELL_CELLS: + text = "VISIBLE_WELL_CELLS"; + break; + case VISIBLE_WELL_FENCE_CELLS: + text = "VISIBLE_WELL_FENCE_CELLS"; + break; + case INACTIVE: + text = "INACTIVE"; + break; + case RANGE_FILTERED: + text = "RANGE_FILTERED"; + break; + case RANGE_FILTERED_INACTIVE: + text = "RANGE_FILTERED_INACTIVE"; + break; + case RANGE_FILTERED_WELL_CELLS: + text = "RANGE_FILTERED_WELL_CELLS"; + break; + case VISIBLE_WELL_CELLS_OUTSIDE_RANGE_FILTER: + text = "VISIBLE_WELL_CELLS_OUTSIDE_RANGE_FILTER"; + break; + case VISIBLE_WELL_FENCE_CELLS_OUTSIDE_RANGE_FILTER: + text = "VISIBLE_WELL_FENCE_CELLS_OUTSIDE_RANGE_FILTER"; + break; + case PROPERTY_FILTERED: + text = "PROPERTY_FILTERED"; + break; + case PROPERTY_FILTERED_WELL_CELLS: + text = "PROPERTY_FILTERED_WELL_CELLS"; + break; + default: + break; + } - qDebug() << text; -*/ + qDebug() << text; + */ m_geometries[geometryType].appendFaultPartsToModel(model); } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- -void RivReservoirViewPartMgr::appendFaultsDynamicGeometryPartsToModel(cvf::ModelBasicList* model, RivCellSetEnum geometryType, size_t frameIndex) +void RivReservoirViewPartMgr::appendFaultsDynamicGeometryPartsToModel(cvf::ModelBasicList* model, + RivCellSetEnum geometryType, + size_t frameIndex) { if (geometryType == PROPERTY_FILTERED) { - //qDebug() << "PROPERTY_FILTERED"; + // qDebug() << "PROPERTY_FILTERED"; m_propFilteredGeometryFrames[frameIndex]->appendFaultPartsToModel(model); } else if (geometryType == PROPERTY_FILTERED_WELL_CELLS) { - //qDebug() << "PROPERTY_FILTERED_WELL_CELLS"; + // qDebug() << "PROPERTY_FILTERED_WELL_CELLS"; m_propFilteredWellGeometryFrames[frameIndex]->appendFaultPartsToModel(model); } } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- -RivCellSetEnum RivReservoirViewPartMgr::geometryTypeForFaultLabels(const std::set& geometryTypes, bool showFaultsOutsideFilters) const +RivCellSetEnum RivReservoirViewPartMgr::geometryTypeForFaultLabels(const std::set& geometryTypes, + bool showFaultsOutsideFilters) const { for (RivCellSetEnum cellSetType : geometryTypes) { @@ -1083,7 +1123,7 @@ RivCellSetEnum RivReservoirViewPartMgr::geometryTypeForFaultLabels(const std::se } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RivReservoirViewPartMgr::appendFaultLabelsStaticGeometryPartsToModel(cvf::ModelBasicList* model, RivCellSetEnum geometryType) { @@ -1092,15 +1132,17 @@ void RivReservoirViewPartMgr::appendFaultLabelsStaticGeometryPartsToModel(cvf::M } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- -void RivReservoirViewPartMgr::appendFaultLabelsDynamicGeometryPartsToModel(cvf::ModelBasicList* model, RivCellSetEnum geometryType, size_t frameIndex) +void RivReservoirViewPartMgr::appendFaultLabelsDynamicGeometryPartsToModel(cvf::ModelBasicList* model, + RivCellSetEnum geometryType, + size_t frameIndex) { m_propFilteredGeometryFrames[frameIndex]->appendFaultLabelPartsToModel(model); } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RivReservoirViewPartMgr::forceWatertightGeometryOnForType(RivCellSetEnum geometryType) { @@ -1126,7 +1168,7 @@ void RivReservoirViewPartMgr::forceWatertightGeometryOnForType(RivCellSetEnum ge } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RivReservoirViewPartMgr::clearWatertightGeometryFlags() { diff --git a/ApplicationCode/ModelVisualization/RivSimWellConnectionSourceInfo.cpp b/ApplicationCode/ModelVisualization/RivSimWellConnectionSourceInfo.cpp index 0018a16497..0d252cdf52 100644 --- a/ApplicationCode/ModelVisualization/RivSimWellConnectionSourceInfo.cpp +++ b/ApplicationCode/ModelVisualization/RivSimWellConnectionSourceInfo.cpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018 Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by diff --git a/ApplicationCode/ModelVisualization/RivSimWellConnectionSourceInfo.h b/ApplicationCode/ModelVisualization/RivSimWellConnectionSourceInfo.h index 464e90a81b..f2a879ffce 100644 --- a/ApplicationCode/ModelVisualization/RivSimWellConnectionSourceInfo.h +++ b/ApplicationCode/ModelVisualization/RivSimWellConnectionSourceInfo.h @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018 Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by diff --git a/ApplicationCode/ModelVisualization/RivSimWellPipesPartMgr.cpp b/ApplicationCode/ModelVisualization/RivSimWellPipesPartMgr.cpp index 1a9759c4ca..40b8ea5d54 100644 --- a/ApplicationCode/ModelVisualization/RivSimWellPipesPartMgr.cpp +++ b/ApplicationCode/ModelVisualization/RivSimWellPipesPartMgr.cpp @@ -287,7 +287,7 @@ void RivSimWellPipesPartMgr::buildWellPipeParts(const caf::DisplayCoordTransform for (const auto& intersectionInfo : wellPathCellIntersections) { size_t globalCellIndex = intersectionInfo.globCellIndex; - const RigWellResultPoint* wResCell = wResFrame.findResultCell(0, globalCellIndex); + const RigWellResultPoint* wResCell = wResFrame.findResultCellWellHeadIncluded(0, globalCellIndex); if (!wResCell || !wResCell->isValid()) { @@ -415,7 +415,7 @@ void RivSimWellPipesPartMgr::updatePipeResultColor(size_t frameIndex) if (cellIds[wcIdx].isCell()) { - wResCell = wResFrame.findResultCell(cellIds[wcIdx].m_gridIndex, cellIds[wcIdx].m_gridCellIndex); + wResCell = wResFrame.findResultCellWellHeadExcluded(cellIds[wcIdx].m_gridIndex, cellIds[wcIdx].m_gridCellIndex); } if (wResCell) diff --git a/ApplicationCode/ModelVisualization/RivTensorResultPartMgr.cpp b/ApplicationCode/ModelVisualization/RivTensorResultPartMgr.cpp index bd301d520c..0807084778 100644 --- a/ApplicationCode/ModelVisualization/RivTensorResultPartMgr.cpp +++ b/ApplicationCode/ModelVisualization/RivTensorResultPartMgr.cpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018- Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -219,29 +219,6 @@ void RivTensorResultPartMgr::calculateElementTensors(const RigFemPart& (*elmTensors)[elmIdx] = tensorSumOfElmNodes * (1.0 / 8.0); } } - - std::array, 3> elmPrincipals; - std::vector> elmPrincipalDirections; - - elmPrincipals[0].resize(elmCount); - elmPrincipals[1].resize(elmCount); - elmPrincipals[2].resize(elmCount); - - elmPrincipalDirections.resize(elmCount); - - for (size_t nIdx = 0; nIdx < elmCount; ++nIdx) - { - cvf::Vec3f principalDirs[3]; - cvf::Vec3f principalValues = (*elmTensors)[nIdx].calculatePrincipals(principalDirs); - - elmPrincipals[0][nIdx] = principalValues[0]; - elmPrincipals[1][nIdx] = principalValues[1]; - elmPrincipals[2][nIdx] = principalValues[2]; - - elmPrincipalDirections[nIdx][0] = principalDirs[0]; - elmPrincipalDirections[nIdx][1] = principalDirs[1]; - elmPrincipalDirections[nIdx][2] = principalDirs[2]; - } } //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/ModelVisualization/RivTensorResultPartMgr.h b/ApplicationCode/ModelVisualization/RivTensorResultPartMgr.h index 5b7c513939..f990efd46e 100644 --- a/ApplicationCode/ModelVisualization/RivTensorResultPartMgr.h +++ b/ApplicationCode/ModelVisualization/RivTensorResultPartMgr.h @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018- Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by diff --git a/ApplicationCode/ModelVisualization/RivTernaryTextureCoordsCreator.cpp b/ApplicationCode/ModelVisualization/RivTernaryTextureCoordsCreator.cpp index 526572e32f..0455385dce 100644 --- a/ApplicationCode/ModelVisualization/RivTernaryTextureCoordsCreator.cpp +++ b/ApplicationCode/ModelVisualization/RivTernaryTextureCoordsCreator.cpp @@ -57,9 +57,9 @@ RivTernaryTextureCoordsCreator::RivTernaryTextureCoordsCreator( RiaDefines::PorosityModelType porosityModel = cellResultColors->porosityModel(); - cvf::ref soil = RigResultAccessorFactory::createFromUiResultName(eclipseCase, gridIndex, porosityModel, resTimeStepIdx, "SOIL"); - cvf::ref sgas = RigResultAccessorFactory::createFromUiResultName(eclipseCase, gridIndex, porosityModel, resTimeStepIdx, "SGAS"); - cvf::ref swat = RigResultAccessorFactory::createFromUiResultName(eclipseCase, gridIndex, porosityModel, resTimeStepIdx, "SWAT"); + cvf::ref soil = RigResultAccessorFactory::createFromResultAddress(eclipseCase, gridIndex, porosityModel, resTimeStepIdx, RigEclipseResultAddress("SOIL")); + cvf::ref sgas = RigResultAccessorFactory::createFromResultAddress(eclipseCase, gridIndex, porosityModel, resTimeStepIdx, RigEclipseResultAddress("SGAS")); + cvf::ref swat = RigResultAccessorFactory::createFromResultAddress(eclipseCase, gridIndex, porosityModel, resTimeStepIdx, RigEclipseResultAddress("SWAT")); m_resultAccessor = new RigTernaryResultAccessor(); m_resultAccessor->setTernaryResultAccessors(soil.p(), sgas.p(), swat.p()); @@ -92,9 +92,9 @@ RivTernaryTextureCoordsCreator::RivTernaryTextureCoordsCreator( RiaDefines::PorosityModelType porosityModel = cellResultColors->porosityModel(); size_t gridIndex = 0; - cvf::ref soil = RigResultAccessorFactory::createFromUiResultName(eclipseCase, gridIndex, porosityModel, resTimeStepIdx, "SOIL"); - cvf::ref sgas = RigResultAccessorFactory::createFromUiResultName(eclipseCase, gridIndex, porosityModel, resTimeStepIdx, "SGAS"); - cvf::ref swat = RigResultAccessorFactory::createFromUiResultName(eclipseCase, gridIndex, porosityModel, resTimeStepIdx, "SWAT"); + cvf::ref soil = RigResultAccessorFactory::createFromResultAddress(eclipseCase, gridIndex, porosityModel, resTimeStepIdx, RigEclipseResultAddress("SOIL")); + cvf::ref sgas = RigResultAccessorFactory::createFromResultAddress(eclipseCase, gridIndex, porosityModel, resTimeStepIdx, RigEclipseResultAddress("SGAS")); + cvf::ref swat = RigResultAccessorFactory::createFromResultAddress(eclipseCase, gridIndex, porosityModel, resTimeStepIdx, RigEclipseResultAddress("SWAT")); m_resultAccessor = new RigTernaryResultAccessor(); m_resultAccessor->setTernaryResultAccessors(soil.p(), sgas.p(), swat.p()); diff --git a/ApplicationCode/ModelVisualization/RivTextAnnotationPartMgr.cpp b/ApplicationCode/ModelVisualization/RivTextAnnotationPartMgr.cpp new file mode 100644 index 0000000000..96a0e2c54d --- /dev/null +++ b/ApplicationCode/ModelVisualization/RivTextAnnotationPartMgr.cpp @@ -0,0 +1,260 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2011- Statoil ASA +// Copyright (C) 2013- Ceetron Solutions AS +// Copyright (C) 2011-2012 Ceetron AS +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + + + +#include "RivTextAnnotationPartMgr.h" + +#include "RiaApplication.h" +#include "RiaBoundingBoxTools.h" +#include "RiaColorTools.h" +#include "RiaFontCache.h" +#include "RiaPreferences.h" + +#include "Rim3dView.h" +#include "RimAnnotationInViewCollection.h" +#include "RimAnnotationTextAppearance.h" +#include "RimTextAnnotation.h" +#include "RimTextAnnotationInView.h" + +#include "RivObjectSourceInfo.h" +#include "RivPartPriority.h" +#include "RivPolylineGenerator.h" + +#include "cafEffectGenerator.h" +#include "cafDisplayCoordTransform.h" +#include "cafFixedAtlasFont.h" + +#include "cvfDrawableGeo.h" +#include "cvfDrawableText.h" +#include "cvfModelBasicList.h" +#include "cvfPart.h" +#include "cvfqtUtils.h" + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RivTextAnnotationPartMgr::RivTextAnnotationPartMgr(Rim3dView* view, RimTextAnnotation* annotationLocal) +: m_rimView(view), m_rimAnnotationLocal(annotationLocal), m_rimAnnotationInView(nullptr) +{ +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RivTextAnnotationPartMgr::RivTextAnnotationPartMgr(Rim3dView* view, RimTextAnnotationInView* annotationInView) + : m_rimView(view) + , m_rimAnnotationLocal(nullptr) + , m_rimAnnotationInView(annotationInView) +{ +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RivTextAnnotationPartMgr::~RivTextAnnotationPartMgr() +{ + +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RivTextAnnotationPartMgr::buildParts(const caf::DisplayCoordTransform * displayXf, + bool doFlatten, + double xOffset) +{ + clearAllGeometry(); + + auto collection = annotationCollection(); + if (!collection) return; + + cvf::Vec3d anchorPositionInDomain = getAnchorPointInDomain(collection->snapAnnotations(), collection->annotationPlaneZ()); + cvf::Vec3d labelPositionInDomain = getLabelPointInDomain(collection->snapAnnotations(), collection->annotationPlaneZ()); + + cvf::Vec3d anchorPosition = displayXf->transformToDisplayCoord(anchorPositionInDomain); + cvf::Vec3d labelPosition = displayXf->transformToDisplayCoord(labelPositionInDomain); + QString text = rimAnnotation()->text(); + + auto fontSize = rimAnnotation()->appearance()->fontSize(); + auto fontColor = rimAnnotation()->appearance()->fontColor(); + auto backgroundColor = rimAnnotation()->appearance()->backgroundColor(); + auto anchorLineColor = rimAnnotation()->appearance()->anchorLineColor(); + + // Line part + { + std::vector points = { anchorPosition, labelPosition }; + + cvf::ref drawableGeo = RivPolylineGenerator::createLineAlongPolylineDrawable(points); + + cvf::ref part = new cvf::Part; + part->setDrawable(drawableGeo.p()); + + caf::MeshEffectGenerator colorEffgen(anchorLineColor); + cvf::ref eff = colorEffgen.generateUnCachedEffect(); + + part->setEffect(eff.p()); + part->setPriority(RivPartPriority::PartType::MeshLines); + part->setSourceInfo(new RivObjectSourceInfo(rimAnnotation())); + + m_linePart = part; + } + + // Text part + { + auto font = RiaFontCache::getFont(fontSize); + cvf::ref drawableText = new cvf::DrawableText; + drawableText->setFont(font.p()); + drawableText->setCheckPosVisible(false); + drawableText->setUseDepthBuffer(true); + drawableText->setDrawBorder(true); + drawableText->setDrawBackground(true); + drawableText->setVerticalAlignment(cvf::TextDrawer::BASELINE); + drawableText->setBackgroundColor(backgroundColor); + drawableText->setBorderColor(RiaColorTools::computeOffsetColor(backgroundColor, 0.3f)); + drawableText->setTextColor(fontColor); + + cvf::String cvfString = cvfqt::Utils::toString(text); + + cvf::Vec3f textCoord(labelPosition); + drawableText->addText(cvfString, textCoord); + + cvf::ref part = new cvf::Part; + part->setName("RivTextAnnotationPartMgr: " + cvfString); + part->setDrawable(drawableText.p()); + + cvf::ref eff = new cvf::Effect(); + part->setEffect(eff.p()); + part->setPriority(RivPartPriority::PartType::MeshLines); + + m_labelPart = part; + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RivTextAnnotationPartMgr::Vec3d RivTextAnnotationPartMgr::getAnchorPointInDomain(bool snapToPlaneZ, double planeZ) +{ + auto pt = rimAnnotation()->anchorPoint(); + + if (snapToPlaneZ) + { + pt.z() = planeZ; + } + return pt; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RivTextAnnotationPartMgr::Vec3d RivTextAnnotationPartMgr::getLabelPointInDomain(bool snapToPlaneZ, double planeZ) +{ + auto pt = rimAnnotation()->labelPoint(); + + if (snapToPlaneZ) + { + pt.z() = planeZ; + } + return pt; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RivTextAnnotationPartMgr::isTextInBoundingBox(const cvf::BoundingBox& boundingBox) +{ + auto coll = annotationCollection(); + if (!coll) return false; + + auto effectiveBoundingBox = RiaBoundingBoxTools::inflate(boundingBox, 3); + if (effectiveBoundingBox.contains(getAnchorPointInDomain(coll->snapAnnotations(), coll->annotationPlaneZ())) || + effectiveBoundingBox.contains(getLabelPointInDomain(coll->snapAnnotations(), coll->annotationPlaneZ()))) return true; + return false; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RivTextAnnotationPartMgr::clearAllGeometry() +{ + m_linePart = nullptr; + m_labelPart = nullptr; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RivTextAnnotationPartMgr::appendDynamicGeometryPartsToModel(cvf::ModelBasicList* model, + const caf::DisplayCoordTransform * displayXf, + const cvf::BoundingBox& boundingBox) +{ + if (!rimAnnotation() || !isAnnotationVisible()) return; + + // Check bounding box + if (!isTextInBoundingBox(boundingBox)) return; + + if (!validateAnnotation(rimAnnotation())) return; + + buildParts(displayXf, false, 0.0); + model->addPart(m_linePart.p()); + model->addPart(m_labelPart.p()); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RivTextAnnotationPartMgr::validateAnnotation(const RimTextAnnotation* annotation) const +{ + return rimAnnotation()->anchorPoint() != cvf::Vec3d::ZERO && !rimAnnotation()->text().isEmpty(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimAnnotationInViewCollection* RivTextAnnotationPartMgr::annotationCollection() const +{ + std::vector colls; + m_rimView->descendantsIncludingThisOfType(colls); + return !colls.empty() ? colls.front() : nullptr; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimTextAnnotation* RivTextAnnotationPartMgr::rimAnnotation() const +{ + if (m_rimAnnotationLocal) return m_rimAnnotationLocal; + + return m_rimAnnotationInView->sourceAnnotation(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RivTextAnnotationPartMgr::isAnnotationVisible() const +{ + if (m_rimAnnotationLocal) + return m_rimAnnotationLocal->isVisible(); + if(m_rimAnnotationInView) + return m_rimAnnotationInView->isVisible(); + return false; +} diff --git a/ApplicationCode/ModelVisualization/RivTextAnnotationPartMgr.h b/ApplicationCode/ModelVisualization/RivTextAnnotationPartMgr.h new file mode 100644 index 0000000000..84439117e7 --- /dev/null +++ b/ApplicationCode/ModelVisualization/RivTextAnnotationPartMgr.h @@ -0,0 +1,82 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2011-2012 Statoil ASA, Ceetron AS +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "cvfBase.h" +#include "cvfAssert.h" +#include "cvfObject.h" +#include "cafPdmPointer.h" + +#include + +namespace cvf +{ + class BoundingBox; + class Part; + class ModelBasicList; + class Transform; + class Font; +} +namespace caf +{ + class DisplayCoordTransform; +} + +class Rim3dView; +class RimAnnotationInViewCollection; +class RimTextAnnotation; +class RimTextAnnotationInView; + +class RivTextAnnotationPartMgr : public cvf::Object +{ + using Vec3d = cvf::Vec3d; + +public: + RivTextAnnotationPartMgr(Rim3dView* view, RimTextAnnotation* annotationLocal); + RivTextAnnotationPartMgr(Rim3dView* view, RimTextAnnotationInView* annotationInView); + ~RivTextAnnotationPartMgr() override; + + void appendDynamicGeometryPartsToModel(cvf::ModelBasicList* model, + const caf::DisplayCoordTransform * displayXf, + const cvf::BoundingBox& boundingBox); + +private: + void buildParts(const caf::DisplayCoordTransform * displayXf, + bool doFlatten, + double xOffset); + + Vec3d getAnchorPointInDomain(bool snapToPlaneZ, double planeZ); + Vec3d getLabelPointInDomain(bool snapToPlaneZ, double planeZ); + + bool isTextInBoundingBox(const cvf::BoundingBox& boundingBox); + + void clearAllGeometry(); + bool validateAnnotation(const RimTextAnnotation* annotation) const; + + RimAnnotationInViewCollection* annotationCollection() const; + + RimTextAnnotation* rimAnnotation() const; + bool isAnnotationVisible() const; + + caf::PdmPointer m_rimView; + caf::PdmPointer m_rimAnnotationLocal; + caf::PdmPointer m_rimAnnotationInView; + cvf::ref m_linePart; + cvf::ref< cvf::Part > m_labelPart; +}; diff --git a/ApplicationCode/ModelVisualization/RivTextLabelSourceInfo.cpp b/ApplicationCode/ModelVisualization/RivTextLabelSourceInfo.cpp new file mode 100644 index 0000000000..6e3d6b1e14 --- /dev/null +++ b/ApplicationCode/ModelVisualization/RivTextLabelSourceInfo.cpp @@ -0,0 +1,46 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2019- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "RivTextLabelSourceInfo.h" + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RivTextLabelSourceInfo::RivTextLabelSourceInfo(caf::PdmObject* pdmObject, const cvf::String& text, const cvf::Vec3f& position) + : RivObjectSourceInfo(pdmObject) + , m_text(text) + , m_positionDisplayCoord(position) + +{ +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +cvf::String RivTextLabelSourceInfo::text() const +{ + return m_text; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +cvf::Vec3f RivTextLabelSourceInfo::textPositionDisplayCoord() const +{ + return m_positionDisplayCoord; +} diff --git a/ApplicationCode/ModelVisualization/RivTextLabelSourceInfo.h b/ApplicationCode/ModelVisualization/RivTextLabelSourceInfo.h new file mode 100644 index 0000000000..9d5c338c1a --- /dev/null +++ b/ApplicationCode/ModelVisualization/RivTextLabelSourceInfo.h @@ -0,0 +1,44 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2019- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "RivObjectSourceInfo.h" + +#include "cvfArray.h" +#include "cvfBase.h" +#include "cvfObject.h" +#include "cvfString.h" + + +//================================================================================================== +/// +/// +//================================================================================================== +class RivTextLabelSourceInfo : public RivObjectSourceInfo +{ +public: + explicit RivTextLabelSourceInfo(caf::PdmObject* pdmObject, const cvf::String& text, const cvf::Vec3f& positionDisplayCoord); + + cvf::String text() const; + cvf::Vec3f textPositionDisplayCoord() const; + +private: + cvf::String m_text; + cvf::Vec3f m_positionDisplayCoord; +}; diff --git a/ApplicationCode/ModelVisualization/RivWellConnectionFactorGeometryGenerator.cpp b/ApplicationCode/ModelVisualization/RivWellConnectionFactorGeometryGenerator.cpp index c28f0b8a3b..3e33a6536c 100644 --- a/ApplicationCode/ModelVisualization/RivWellConnectionFactorGeometryGenerator.cpp +++ b/ApplicationCode/ModelVisualization/RivWellConnectionFactorGeometryGenerator.cpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018 Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by diff --git a/ApplicationCode/ModelVisualization/RivWellConnectionFactorGeometryGenerator.h b/ApplicationCode/ModelVisualization/RivWellConnectionFactorGeometryGenerator.h index 2ac0ff01cc..15dfbe95f0 100644 --- a/ApplicationCode/ModelVisualization/RivWellConnectionFactorGeometryGenerator.h +++ b/ApplicationCode/ModelVisualization/RivWellConnectionFactorGeometryGenerator.h @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018 Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by diff --git a/ApplicationCode/ModelVisualization/RivWellConnectionFactorPartMgr.cpp b/ApplicationCode/ModelVisualization/RivWellConnectionFactorPartMgr.cpp index b7dc4a96cf..799cde54c3 100644 --- a/ApplicationCode/ModelVisualization/RivWellConnectionFactorPartMgr.cpp +++ b/ApplicationCode/ModelVisualization/RivWellConnectionFactorPartMgr.cpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018 Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by diff --git a/ApplicationCode/ModelVisualization/RivWellConnectionFactorPartMgr.h b/ApplicationCode/ModelVisualization/RivWellConnectionFactorPartMgr.h index 107addb91d..2a1e50828b 100644 --- a/ApplicationCode/ModelVisualization/RivWellConnectionFactorPartMgr.h +++ b/ApplicationCode/ModelVisualization/RivWellConnectionFactorPartMgr.h @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018 Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by diff --git a/ApplicationCode/ModelVisualization/RivWellConnectionSourceInfo.cpp b/ApplicationCode/ModelVisualization/RivWellConnectionSourceInfo.cpp index 6d534fb247..066e9a0ac5 100644 --- a/ApplicationCode/ModelVisualization/RivWellConnectionSourceInfo.cpp +++ b/ApplicationCode/ModelVisualization/RivWellConnectionSourceInfo.cpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018 Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by diff --git a/ApplicationCode/ModelVisualization/RivWellConnectionSourceInfo.h b/ApplicationCode/ModelVisualization/RivWellConnectionSourceInfo.h index b37bf837c0..36166ba817 100644 --- a/ApplicationCode/ModelVisualization/RivWellConnectionSourceInfo.h +++ b/ApplicationCode/ModelVisualization/RivWellConnectionSourceInfo.h @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018 Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by diff --git a/ApplicationCode/ModelVisualization/RivWellFracturePartMgr.cpp b/ApplicationCode/ModelVisualization/RivWellFracturePartMgr.cpp index 5a0596d61a..2b6cd22761 100644 --- a/ApplicationCode/ModelVisualization/RivWellFracturePartMgr.cpp +++ b/ApplicationCode/ModelVisualization/RivWellFracturePartMgr.cpp @@ -950,14 +950,8 @@ void RivWellFracturePartMgr::appendFracturePerforationLengthParts(const RimEclip } } - std::vector displayCoords; - { - std::vector perforationLengthCoord = m_rimFracture->perforationLengthCenterLineCoords(); - for (const cvf::Vec3d& point : perforationLengthCoord) - { - displayCoords.push_back(displayCoordTransform->transformToDisplayCoord(point)); - } - } + std::vector displayCoords = + displayCoordTransform->transformToDisplayCoords(m_rimFracture->perforationLengthCenterLineCoords()); if (!displayCoords.empty()) { diff --git a/ApplicationCode/ModelVisualization/RivWellHeadPartMgr.cpp b/ApplicationCode/ModelVisualization/RivWellHeadPartMgr.cpp index 21c5404f3c..5e5572c7bf 100644 --- a/ApplicationCode/ModelVisualization/RivWellHeadPartMgr.cpp +++ b/ApplicationCode/ModelVisualization/RivWellHeadPartMgr.cpp @@ -35,11 +35,14 @@ #include "RimSimWellInViewCollection.h" #include "RimSimWellInView.h" -#include "RivPipeGeometryGenerator.h" #include "RivPartPriority.h" +#include "RivPipeGeometryGenerator.h" +#include "RivSectionFlattner.h" #include "RivSimWellPipeSourceInfo.h" +#include "RivTextLabelSourceInfo.h" #include "cafEffectGenerator.h" +#include "cafDisplayCoordTransform.h" #include "cvfArrowGenerator.h" #include "cvfDrawableGeo.h" @@ -49,8 +52,6 @@ #include "cvfPart.h" #include "cvfTransform.h" #include "cvfqtUtils.h" -#include "cafDisplayCoordTransform.h" -#include "RivSectionFlattner.h" @@ -296,7 +297,7 @@ void RivWellHeadPartMgr::buildWellHeadParts(size_t frameIndex, if (well->showWellLabel() && !well->name().isEmpty()) { - cvf::Font* font = RiaApplication::instance()->customFont(); + cvf::Font* font = RiaApplication::instance()->defaultWellLabelFont(); cvf::ref drawableText = new cvf::DrawableText; drawableText->setFont(font); @@ -319,7 +320,8 @@ void RivWellHeadPartMgr::buildWellHeadParts(size_t frameIndex, part->setEffect(eff.p()); part->setPriority(RivPartPriority::PartType::Text); - part->setSourceInfo(sourceInfo.p()); + + part->setSourceInfo(new RivTextLabelSourceInfo(m_rimWell, cvfString, textCoord)); m_wellHeadLabelPart = part; } diff --git a/ApplicationCode/ModelVisualization/RivWellPathPartMgr.cpp b/ApplicationCode/ModelVisualization/RivWellPathPartMgr.cpp index 235348e9c6..dafe176eca 100644 --- a/ApplicationCode/ModelVisualization/RivWellPathPartMgr.cpp +++ b/ApplicationCode/ModelVisualization/RivWellPathPartMgr.cpp @@ -56,6 +56,7 @@ #include "RivWellFracturePartMgr.h" #include "RivWellPathPartMgr.h" #include "RivWellPathSourceInfo.h" +#include "RivTextLabelSourceInfo.h" #include "RiuViewer.h" @@ -255,11 +256,7 @@ void RivWellPathPartMgr::appendImportedFishbonesToModel(cvf::ModelBasicList* mod { if (!fbWellPath->isChecked()) continue; - std::vector displayCoords; - for (const auto& lateralDomainCoords : fbWellPath->coordinates()) - { - displayCoords.push_back(displayCoordTransform->transformToDisplayCoord(lateralDomainCoords)); - } + std::vector displayCoords = displayCoordTransform->transformToDisplayCoords(fbWellPath->coordinates()); cvf::ref objectSourceInfo = new RivObjectSourceInfo(fbWellPath); @@ -615,7 +612,7 @@ void RivWellPathPartMgr::buildWellPathParts(const caf::DisplayCoordTransform* di if (wellPathCollection->showWellPathLabel() && m_rimWellPath->showWellPathLabel() && !m_rimWellPath->name().isEmpty()) { - cvf::Font* font = RiaApplication::instance()->customFont(); + cvf::Font* font = RiaApplication::instance()->defaultWellLabelFont(); cvf::ref drawableText = new cvf::DrawableText; drawableText->setFont(font); @@ -639,6 +636,8 @@ void RivWellPathPartMgr::buildWellPathParts(const caf::DisplayCoordTransform* di part->setEffect(eff.p()); part->setPriority(RivPartPriority::Text); + part->setSourceInfo(new RivTextLabelSourceInfo(m_rimWellPath, cvfString, textCoord)); + m_wellLabelPart = part; } diff --git a/ApplicationCode/ModelVisualization/RivWellPathsPartMgr.cpp b/ApplicationCode/ModelVisualization/RivWellPathsPartMgr.cpp index bd026d013a..5ad9f40b25 100644 --- a/ApplicationCode/ModelVisualization/RivWellPathsPartMgr.cpp +++ b/ApplicationCode/ModelVisualization/RivWellPathsPartMgr.cpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018 Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by diff --git a/ApplicationCode/ModelVisualization/RivWellPathsPartMgr.h b/ApplicationCode/ModelVisualization/RivWellPathsPartMgr.h index 6df0845eb8..dcbdece5e7 100644 --- a/ApplicationCode/ModelVisualization/RivWellPathsPartMgr.h +++ b/ApplicationCode/ModelVisualization/RivWellPathsPartMgr.h @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018 Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by diff --git a/ApplicationCode/ModelVisualization/WindowEdgeAxesOverlayItem/RivWindowEdgeAxesOverlayItem.cpp b/ApplicationCode/ModelVisualization/WindowEdgeAxesOverlayItem/RivWindowEdgeAxesOverlayItem.cpp index df91fe269e..03c7158f98 100644 --- a/ApplicationCode/ModelVisualization/WindowEdgeAxesOverlayItem/RivWindowEdgeAxesOverlayItem.cpp +++ b/ApplicationCode/ModelVisualization/WindowEdgeAxesOverlayItem/RivWindowEdgeAxesOverlayItem.cpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018- Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by diff --git a/ApplicationCode/ProjectDataModel/Annotations/CMakeLists_files.cmake b/ApplicationCode/ProjectDataModel/Annotations/CMakeLists_files.cmake new file mode 100644 index 0000000000..b32f471b2d --- /dev/null +++ b/ApplicationCode/ProjectDataModel/Annotations/CMakeLists_files.cmake @@ -0,0 +1,55 @@ + +set (SOURCE_GROUP_HEADER_FILES +${CMAKE_CURRENT_LIST_DIR}/RimAnnotationCollectionBase.h +${CMAKE_CURRENT_LIST_DIR}/RimAnnotationCollection.h +${CMAKE_CURRENT_LIST_DIR}/RimPolylinesAnnotation.h +${CMAKE_CURRENT_LIST_DIR}/RimPolylinesFromFileAnnotation.h +${CMAKE_CURRENT_LIST_DIR}/RimUserDefinedPolylinesAnnotation.h +${CMAKE_CURRENT_LIST_DIR}/RimReachCircleAnnotation.h +${CMAKE_CURRENT_LIST_DIR}/RimTextAnnotation.h +${CMAKE_CURRENT_LIST_DIR}/RimAnnotationInViewCollection.h +${CMAKE_CURRENT_LIST_DIR}/RimAnnotationLineAppearance.h +${CMAKE_CURRENT_LIST_DIR}/RimAnnotationTextAppearance.h +${CMAKE_CURRENT_LIST_DIR}/RimPolylinesFromFileAnnotationInView.h +${CMAKE_CURRENT_LIST_DIR}/RimUserDefinedPolylinesAnnotationInView.h +${CMAKE_CURRENT_LIST_DIR}/RimPolylinesAnnotationInView.h +${CMAKE_CURRENT_LIST_DIR}/RimReachCircleAnnotationInView.h +${CMAKE_CURRENT_LIST_DIR}/RimTextAnnotationInView.h +${CMAKE_CURRENT_LIST_DIR}/RimAnnotationGroupCollection.h +${CMAKE_CURRENT_LIST_DIR}/RimPolylineTarget.h +) + +set (SOURCE_GROUP_SOURCE_FILES +${CMAKE_CURRENT_LIST_DIR}/RimAnnotationCollectionBase.cpp +${CMAKE_CURRENT_LIST_DIR}/RimAnnotationCollection.cpp +${CMAKE_CURRENT_LIST_DIR}/RimPolylinesAnnotation.cpp +${CMAKE_CURRENT_LIST_DIR}/RimPolylinesFromFileAnnotation.cpp +${CMAKE_CURRENT_LIST_DIR}/RimUserDefinedPolylinesAnnotation.cpp +${CMAKE_CURRENT_LIST_DIR}/RimReachCircleAnnotation.cpp +${CMAKE_CURRENT_LIST_DIR}/RimTextAnnotation.cpp +${CMAKE_CURRENT_LIST_DIR}/RimAnnotationInViewCollection.cpp +${CMAKE_CURRENT_LIST_DIR}/RimAnnotationLineAppearance.cpp +${CMAKE_CURRENT_LIST_DIR}/RimAnnotationTextAppearance.cpp +${CMAKE_CURRENT_LIST_DIR}/RimPolylinesFromFileAnnotationInView.cpp +${CMAKE_CURRENT_LIST_DIR}/RimUserDefinedPolylinesAnnotationInView.cpp +${CMAKE_CURRENT_LIST_DIR}/RimPolylinesAnnotationInView.cpp +${CMAKE_CURRENT_LIST_DIR}/RimReachCircleAnnotationInView.cpp +${CMAKE_CURRENT_LIST_DIR}/RimTextAnnotationInView.cpp +${CMAKE_CURRENT_LIST_DIR}/RimAnnotationGroupCollection.cpp +${CMAKE_CURRENT_LIST_DIR}/RimPolylineTarget.cpp +) + +list(APPEND CODE_HEADER_FILES +${SOURCE_GROUP_HEADER_FILES} +) + +list(APPEND CODE_SOURCE_FILES +${SOURCE_GROUP_SOURCE_FILES} +) + +set (QT_MOC_HEADERS +${QT_MOC_HEADERS} +) + + +source_group( "ProjectDataModel\\Annotations" FILES ${SOURCE_GROUP_HEADER_FILES} ${SOURCE_GROUP_SOURCE_FILES} ${CMAKE_CURRENT_LIST_DIR}/CMakeLists_files.cmake ) diff --git a/ApplicationCode/ProjectDataModel/Annotations/RimAnnotationCollection.cpp b/ApplicationCode/ProjectDataModel/Annotations/RimAnnotationCollection.cpp new file mode 100644 index 0000000000..539ef7056f --- /dev/null +++ b/ApplicationCode/ProjectDataModel/Annotations/RimAnnotationCollection.cpp @@ -0,0 +1,281 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2018- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "RimAnnotationCollection.h" + +#include "RiaApplication.h" +#include "RiaColorTables.h" + +#include "RimAnnotationGroupCollection.h" +#include "RimTextAnnotation.h" +#include "RimReachCircleAnnotation.h" +#include "RimPolylinesFromFileAnnotation.h" +#include "RimUserDefinedPolylinesAnnotation.h" +#include "RimAnnotationLineAppearance.h" + +#include "RimProject.h" +#include "RimGridView.h" +#include "RimAnnotationInViewCollection.h" + +#include "QMessageBox" +#include +#include "RiaColorTables.h" + + +CAF_PDM_SOURCE_INIT(RimAnnotationCollection, "RimAnnotationCollection"); + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimAnnotationCollection::RimAnnotationCollection() +{ + CAF_PDM_InitObject("Annotations", ":/Annotations16x16.png", "", ""); + + CAF_PDM_InitFieldNoDefault(&m_reachCircleAnnotations, "ReachCircleAnnotations", "Reach Circle Annotations", "", "", ""); + CAF_PDM_InitFieldNoDefault(&m_userDefinedPolylineAnnotations, "UserDefinedPolylineAnnotations", "User Defined Polyline Annotations", "", "", ""); + CAF_PDM_InitFieldNoDefault(&m_polylineFromFileAnnotations, "PolylineFromFileAnnotations", "Polylines From File", "", "", ""); + + m_reachCircleAnnotations.uiCapability()->setUiHidden(true); + m_userDefinedPolylineAnnotations.uiCapability()->setUiHidden(true); + m_polylineFromFileAnnotations.uiCapability()->setUiHidden(true); + + m_reachCircleAnnotations = new RimAnnotationGroupCollection(); + m_userDefinedPolylineAnnotations = new RimAnnotationGroupCollection(); + m_polylineFromFileAnnotations = new RimAnnotationGroupCollection(); + + m_reachCircleAnnotations->uiCapability()->setUiName(RimAnnotationGroupCollection::REACH_CIRCLE_ANNOTATION_UI_NAME); + m_userDefinedPolylineAnnotations->uiCapability()->setUiName(RimAnnotationGroupCollection::USED_DEFINED_POLYLINE_ANNOTATION_UI_NAME); + m_polylineFromFileAnnotations->uiCapability()->setUiName(RimAnnotationGroupCollection::POLYLINE_FROM_FILE_ANNOTATION_UI_NAME); + + m_reachCircleAnnotations->uiCapability()->setUiIcon(QIcon(":/ReachCircle16x16.png")); + m_userDefinedPolylineAnnotations->uiCapability()->setUiIcon(QIcon(":/PolylinesFromFile16x16.png")); + m_polylineFromFileAnnotations->uiCapability()->setUiIcon(QIcon(":/PolylinesFromFile16x16.png")); + +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimAnnotationCollection::~RimAnnotationCollection() +{ +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimAnnotationCollection::addAnnotation(RimReachCircleAnnotation* annotation) +{ + m_reachCircleAnnotations->addAnnotation(annotation); + updateViewAnnotationCollections(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimAnnotationCollection::addAnnotation(RimUserDefinedPolylinesAnnotation* annotation) +{ + + m_userDefinedPolylineAnnotations->addAnnotation(annotation); + updateViewAnnotationCollections(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimAnnotationCollection::addAnnotation(RimPolylinesFromFileAnnotation* annotation) +{ + m_polylineFromFileAnnotations->addAnnotation(annotation); + updateViewAnnotationCollections(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector RimAnnotationCollection::reachCircleAnnotations() const +{ + std::vector annotations; + for (auto& a : m_reachCircleAnnotations->annotations()) + { + annotations.push_back(dynamic_cast(a)); + } + return annotations; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector RimAnnotationCollection::userDefinedPolylineAnnotations() const +{ + std::vector annotations; + for (auto& a : m_userDefinedPolylineAnnotations->annotations()) + { + annotations.push_back(dynamic_cast(a)); + } + return annotations; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector RimAnnotationCollection::polylinesFromFileAnnotations() const +{ + std::vector annotations; + for (auto& a : m_polylineFromFileAnnotations->annotations()) + { + annotations.push_back(dynamic_cast(a)); + } + return annotations; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimPolylinesFromFileAnnotation* RimAnnotationCollection::importOrUpdatePolylinesFromFile(const QStringList& fileNames) +{ + QStringList newFileNames; + std::vector polyLinesObjsToReload; + + for(const QString& newFileName : fileNames) + { + bool isFound = false; + for(RimPolylinesFromFileAnnotation* polyLinesAnnot: polylinesFromFileAnnotations()) + { + if(polyLinesAnnot->fileName() == newFileName) + { + polyLinesObjsToReload.push_back(polyLinesAnnot); + isFound = true; + break; + } + } + + if(!isFound) + { + newFileNames.push_back(newFileName); + } + } + + size_t newLinesIdx = 0; + for(const QString& newFileName : newFileNames) + { + RimPolylinesFromFileAnnotation* newPolyLinesAnnot = new RimPolylinesFromFileAnnotation; + + auto newColor = RiaColorTables::categoryPaletteColors().cycledColor3f(lineBasedAnnotationsCount()); + + newPolyLinesAnnot->setFileName(newFileName); + newPolyLinesAnnot->setDescriptionFromFileName(); + newPolyLinesAnnot->appearance()->setColor(newColor); + + m_polylineFromFileAnnotations->addAnnotation(newPolyLinesAnnot); + polyLinesObjsToReload.push_back(newPolyLinesAnnot); + + ++newLinesIdx; + } + + updateViewAnnotationCollections(); + + reloadPolylinesFromFile(polyLinesObjsToReload); + + if (!newFileNames.empty()) + { + return polylinesFromFileAnnotations().back(); + } + else + { + return nullptr; + } + +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +size_t RimAnnotationCollection::lineBasedAnnotationsCount() const +{ + return m_reachCircleAnnotations->annotations().size() + + m_userDefinedPolylineAnnotations->annotations().size() + + m_polylineFromFileAnnotations->annotations().size(); +} + +//-------------------------------------------------------------------------------------------------- +/// Update view-local annotation collections, to mirror the state in the global collection (this collection) +//-------------------------------------------------------------------------------------------------- +void RimAnnotationCollection::updateViewAnnotationCollections() +{ + auto views = gridViewsContainingAnnotations(); + + for (const auto* view : views) + { + view->annotationCollection()->onGlobalCollectionChanged(this); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimAnnotationCollection::onAnnotationDeleted() +{ + updateViewAnnotationCollections(); + RimAnnotationCollectionBase::onAnnotationDeleted(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector RimAnnotationCollection::allPdmAnnotations() const +{ + std::vector all; + all.insert(all.end(), m_textAnnotations->m_annotations.begin(), m_textAnnotations->m_annotations.end()); + all.insert(all.end(), m_reachCircleAnnotations->m_annotations.begin(), m_reachCircleAnnotations->m_annotations.end()); + all.insert(all.end(), m_userDefinedPolylineAnnotations->m_annotations.begin(), m_userDefinedPolylineAnnotations->m_annotations.end()); + all.insert(all.end(), m_polylineFromFileAnnotations->m_annotations.begin(), m_polylineFromFileAnnotations->m_annotations.end()); + return all; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimAnnotationCollection::reloadPolylinesFromFile(const std::vector& polyLinesObjsToReload) +{ + QString totalErrorMessage; + + for ( RimPolylinesFromFileAnnotation* polyLinesAnnot: polyLinesObjsToReload ) + { + QString errormessage; + + polyLinesAnnot->readPolyLinesFile(&errormessage); + if ( !errormessage.isEmpty() ) + { + totalErrorMessage += "\nError in: " + polyLinesAnnot->fileName() + + "\n\t" + errormessage; + } + } + + if ( !totalErrorMessage.isEmpty() ) + { + QMessageBox::warning(nullptr, "Import Polylines", totalErrorMessage); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimAnnotationCollection::loadDataAndUpdate() +{ + reloadPolylinesFromFile(polylinesFromFileAnnotations()); +} diff --git a/ApplicationCode/ProjectDataModel/Annotations/RimAnnotationCollection.h b/ApplicationCode/ProjectDataModel/Annotations/RimAnnotationCollection.h new file mode 100644 index 0000000000..c39df37acf --- /dev/null +++ b/ApplicationCode/ProjectDataModel/Annotations/RimAnnotationCollection.h @@ -0,0 +1,76 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2018- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "RiaEclipseUnitTools.h" + +#include "RimAnnotationCollectionBase.h" + +#include "cafPdmChildArrayField.h" +#include "cafPdmField.h" +#include "cafPdmChildField.h" +#include "cafPdmObject.h" +#include "cafPdmPointer.h" + +class QString; +class RimAnnotationGroupCollection; +class RimTextAnnotation; +class RimReachCircleAnnotation; +class RimUserDefinedPolylinesAnnotation; +class RimPolylinesFromFileAnnotation; +class RimGridView; + +//================================================================================================== +/// +/// +//================================================================================================== +class RimAnnotationCollection : public RimAnnotationCollectionBase +{ + CAF_PDM_HEADER_INIT; +public: + RimAnnotationCollection(); + ~RimAnnotationCollection() override; + + void loadDataAndUpdate(); + + void addAnnotation(RimReachCircleAnnotation* annotation); + void addAnnotation(RimUserDefinedPolylinesAnnotation* annotation); + void addAnnotation(RimPolylinesFromFileAnnotation* annotation); + + std::vector reachCircleAnnotations() const; + std::vector userDefinedPolylineAnnotations() const; + std::vector polylinesFromFileAnnotations() const; + + RimPolylinesFromFileAnnotation* importOrUpdatePolylinesFromFile(const QStringList& fileNames ); + + size_t lineBasedAnnotationsCount() const; + + void updateViewAnnotationCollections() override; + void onAnnotationDeleted() override; + + // Used by sync code + std::vector allPdmAnnotations() const; + +private: + void reloadPolylinesFromFile(const std::vector& polyLinesObjsToReload); + + caf::PdmChildField m_reachCircleAnnotations; + caf::PdmChildField m_userDefinedPolylineAnnotations; + caf::PdmChildField m_polylineFromFileAnnotations; +}; diff --git a/ApplicationCode/ProjectDataModel/Annotations/RimAnnotationCollectionBase.cpp b/ApplicationCode/ProjectDataModel/Annotations/RimAnnotationCollectionBase.cpp new file mode 100644 index 0000000000..b97bfeb79f --- /dev/null +++ b/ApplicationCode/ProjectDataModel/Annotations/RimAnnotationCollectionBase.cpp @@ -0,0 +1,169 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2018- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "RimAnnotationCollectionBase.h" + +#include "RiaApplication.h" + +#include "RimTextAnnotation.h" +#include "RimReachCircleAnnotation.h" +#include "RimPolylinesAnnotation.h" + +#include "RimProject.h" +#include "RimGridView.h" +#include "RimAnnotationInViewCollection.h" +#include "RimAnnotationGroupCollection.h" + +#include "QMessageBox" +#include +#include "RiaColorTables.h" + + +CAF_PDM_SOURCE_INIT(RimAnnotationCollectionBase, "RimAnnotationCollectionBase"); + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimAnnotationCollectionBase::RimAnnotationCollectionBase() +{ + CAF_PDM_InitObject("Annotations", ":/WellCollection.png", "", ""); + + CAF_PDM_InitField(&m_isActive, "IsActive", true, "Is Active", "", "", ""); + m_isActive.uiCapability()->setUiHidden(true); + + CAF_PDM_InitFieldNoDefault(&m_textAnnotations, "TextAnnotations", "Text Annotations", "", "", ""); + + m_textAnnotations.uiCapability()->setUiHidden(true); + m_textAnnotations = new RimAnnotationGroupCollection(); + m_textAnnotations->uiCapability()->setUiName(RimAnnotationGroupCollection::TEXT_ANNOTATION_UI_NAME); + m_textAnnotations->uiCapability()->setUiIcon(QIcon(":/TextAnnotation16x16.png")); +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimAnnotationCollectionBase::~RimAnnotationCollectionBase() +{ +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RimAnnotationCollectionBase::isActive() const +{ + return m_isActive(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimAnnotationCollectionBase::addAnnotation(RimTextAnnotation* annotation) +{ + m_textAnnotations->addAnnotation(annotation); + updateViewAnnotationCollections(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector RimAnnotationCollectionBase::textAnnotations() const +{ + std::vector annotations; + for (auto& a : m_textAnnotations->annotations()) + { + annotations.push_back(dynamic_cast(a)); + } + return annotations; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimAnnotationCollectionBase::updateViewAnnotationCollections() +{ + // Default implementation: No op +} + +//-------------------------------------------------------------------------------------------------- +/// At least one annotation have been deleted. Typically by the generic delete command +//-------------------------------------------------------------------------------------------------- +void RimAnnotationCollectionBase::onAnnotationDeleted() +{ + scheduleRedrawOfRelevantViews(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimAnnotationCollectionBase::scheduleRedrawOfRelevantViews() +{ + // Todo: Do a Bounding Box check to see if this annotation actually is relevant for the view + + auto views = gridViewsContainingAnnotations(); + if ( !views.empty() ) + { + for ( auto& view : views ) + { + view->scheduleCreateDisplayModelAndRedraw(); + } + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector RimAnnotationCollectionBase::gridViewsContainingAnnotations() const +{ + std::vector views; + RimProject* project = nullptr; + this->firstAncestorOrThisOfType(project); + + if (!project) return views; + + std::vector visibleGridViews; + project->allVisibleGridViews(visibleGridViews); + + for (auto& gridView : visibleGridViews) + { + /*if (gridView->annotationCollection()->annotationsCount() > 0)*/ views.push_back(gridView); + } + return views; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimAnnotationCollectionBase::fieldChangedByUi(const caf::PdmFieldHandle* changedField, + const QVariant& oldValue, + const QVariant& newValue) +{ + if (changedField == &m_isActive) + { + updateUiIconFromToggleField(); + scheduleRedrawOfRelevantViews(); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +caf::PdmFieldHandle* RimAnnotationCollectionBase::objectToggleField() +{ + return &m_isActive; +} diff --git a/ApplicationCode/ProjectDataModel/Annotations/RimAnnotationCollectionBase.h b/ApplicationCode/ProjectDataModel/Annotations/RimAnnotationCollectionBase.h new file mode 100644 index 0000000000..22cd547a6e --- /dev/null +++ b/ApplicationCode/ProjectDataModel/Annotations/RimAnnotationCollectionBase.h @@ -0,0 +1,64 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2018- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "RiaEclipseUnitTools.h" + +#include "cafPdmChildArrayField.h" +#include "cafPdmField.h" +#include "cafPdmChildField.h" +#include "cafPdmObject.h" +#include "cafPdmPointer.h" + +class QString; +class RimTextAnnotation; +class RimAnnotationGroupCollection; +class RimGridView; + +//================================================================================================== +/// +/// +//================================================================================================== +class RimAnnotationCollectionBase : public caf::PdmObject +{ + CAF_PDM_HEADER_INIT; +public: + RimAnnotationCollectionBase(); + ~RimAnnotationCollectionBase() override; + + bool isActive() const; + + void addAnnotation(RimTextAnnotation* annotation); + + std::vector textAnnotations() const; + + virtual void updateViewAnnotationCollections(); + virtual void onAnnotationDeleted(); + + void scheduleRedrawOfRelevantViews(); + std::vector gridViewsContainingAnnotations() const; + +protected: + void fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue) override; + caf::PdmFieldHandle* objectToggleField() override; + +protected: + caf::PdmField m_isActive; + caf::PdmChildField m_textAnnotations; +}; diff --git a/ApplicationCode/ProjectDataModel/Annotations/RimAnnotationGroupCollection.cpp b/ApplicationCode/ProjectDataModel/Annotations/RimAnnotationGroupCollection.cpp new file mode 100644 index 0000000000..8bd38621a8 --- /dev/null +++ b/ApplicationCode/ProjectDataModel/Annotations/RimAnnotationGroupCollection.cpp @@ -0,0 +1,128 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2018- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "RimAnnotationGroupCollection.h" + +#include "RiaApplication.h" + +#include "RimTextAnnotation.h" +#include "RimReachCircleAnnotation.h" +#include "RimPolylinesAnnotation.h" + +#include "RimProject.h" +#include "RimGridView.h" +#include "RimAnnotationInViewCollection.h" + +#include "QMessageBox" +#include +#include "RiaColorTables.h" + + +CAF_PDM_SOURCE_INIT(RimAnnotationGroupCollection, "RimAnnotationGroupCollection"); + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +const QString RimAnnotationGroupCollection::TEXT_ANNOTATION_UI_NAME = "Text Annotations"; +const QString RimAnnotationGroupCollection::REACH_CIRCLE_ANNOTATION_UI_NAME = "Reach Circle Annotations"; +const QString RimAnnotationGroupCollection::USED_DEFINED_POLYLINE_ANNOTATION_UI_NAME = "User Defined Polyline Annotations"; +const QString RimAnnotationGroupCollection::POLYLINE_FROM_FILE_ANNOTATION_UI_NAME = "Polylines From File"; + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimAnnotationGroupCollection::RimAnnotationGroupCollection() +{ + CAF_PDM_InitObject("Annotations", ":/WellCollection.png", "", ""); + + CAF_PDM_InitField(&m_isActive, "IsActive", true, "Is Active", "", "", ""); + CAF_PDM_InitFieldNoDefault(&m_annotations, "Annotations", "Annotations", "", "", ""); + + m_isActive.uiCapability()->setUiHidden(true); + m_annotations.uiCapability()->setUiHidden(true); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimAnnotationGroupCollection::~RimAnnotationGroupCollection() +{ +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RimAnnotationGroupCollection::isActive() const +{ + return m_isActive(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RimAnnotationGroupCollection::isVisible() const +{ + RimAnnotationCollectionBase* coll; + firstAncestorOrThisOfType(coll); + + bool visible = true; + if (coll) visible = coll->isActive(); + if (visible) visible = m_isActive; + return visible; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimAnnotationGroupCollection::addAnnotation(caf::PdmObject* annotation) +{ + m_annotations.push_back(annotation); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector RimAnnotationGroupCollection::annotations() const +{ + return m_annotations.childObjects(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimAnnotationGroupCollection::fieldChangedByUi(const caf::PdmFieldHandle* changedField, + const QVariant& oldValue, + const QVariant& newValue) +{ + if (changedField == &m_isActive) + { + updateUiIconFromToggleField(); + + RimAnnotationCollectionBase* coll; + firstAncestorOrThisOfType(coll); + if(coll) coll->scheduleRedrawOfRelevantViews(); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +caf::PdmFieldHandle* RimAnnotationGroupCollection::objectToggleField() +{ + return &m_isActive; +} diff --git a/ApplicationCode/ProjectDataModel/Annotations/RimAnnotationGroupCollection.h b/ApplicationCode/ProjectDataModel/Annotations/RimAnnotationGroupCollection.h new file mode 100644 index 0000000000..c23a68379a --- /dev/null +++ b/ApplicationCode/ProjectDataModel/Annotations/RimAnnotationGroupCollection.h @@ -0,0 +1,66 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2018- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "RiaEclipseUnitTools.h" + +#include "cafPdmChildArrayField.h" +#include "cafPdmField.h" +#include "cafPdmObject.h" +#include "cafPdmPointer.h" + +class QString; +class RimTextAnnotation; +class RimGridView; + +//================================================================================================== +/// +/// +//================================================================================================== +class RimAnnotationGroupCollection : public caf::PdmObject +{ + friend class RimAnnotationCollection; + friend class RimAnnotationInViewCollection; + + CAF_PDM_HEADER_INIT; + +public: + const static QString TEXT_ANNOTATION_UI_NAME; + const static QString REACH_CIRCLE_ANNOTATION_UI_NAME; + const static QString USED_DEFINED_POLYLINE_ANNOTATION_UI_NAME; + const static QString POLYLINE_FROM_FILE_ANNOTATION_UI_NAME; + +public: + RimAnnotationGroupCollection(); + ~RimAnnotationGroupCollection() override; + + bool isActive() const; + bool isVisible() const; + + void addAnnotation(caf::PdmObject* annotation); + std::vector annotations() const; + +protected: + void fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue) override; + caf::PdmFieldHandle* objectToggleField() override; + +protected: + caf::PdmField m_isActive; + caf::PdmChildArrayField m_annotations; +}; diff --git a/ApplicationCode/ProjectDataModel/Annotations/RimAnnotationInViewCollection.cpp b/ApplicationCode/ProjectDataModel/Annotations/RimAnnotationInViewCollection.cpp new file mode 100644 index 0000000000..25749f21f6 --- /dev/null +++ b/ApplicationCode/ProjectDataModel/Annotations/RimAnnotationInViewCollection.cpp @@ -0,0 +1,420 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2018- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "RimAnnotationInViewCollection.h" + +#include "RimAnnotationCollection.h" +#include "RimAnnotationGroupCollection.h" +#include "RimAnnotationTextAppearance.h" +#include "RimCase.h" +#include "RimProject.h" +#include "RimGridView.h" +#include "RimTextAnnotation.h" +#include "RimReachCircleAnnotation.h" +#include "RimUserDefinedPolylinesAnnotation.h" +#include "RimPolylinesFromFileAnnotation.h" +#include "RimTextAnnotationInView.h" +#include "RimReachCircleAnnotationInView.h" +#include "RimUserDefinedPolylinesAnnotationInView.h" +#include "RimPolylinesFromFileAnnotationInView.h" + +#include + +#include + +//-------------------------------------------------------------------------------------------------- +/// Internal function +//-------------------------------------------------------------------------------------------------- +caf::PdmObject* sourcePdmAnnotation(const caf::PdmObject* annotationInView) +{ + auto t = dynamic_cast(annotationInView); + if (t) + { + return t->sourceAnnotation(); + } + + auto c = dynamic_cast(annotationInView); + if (c) + { + return c->sourceAnnotation(); + } + + auto up = dynamic_cast(annotationInView); + if (up) + { + return up->sourceAnnotation(); + } + + auto pf = dynamic_cast(annotationInView); + if (pf) + { + return pf->sourceAnnotation(); + } + + return nullptr; +} + + +CAF_PDM_SOURCE_INIT(RimAnnotationInViewCollection, "Annotations"); + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimAnnotationInViewCollection::RimAnnotationInViewCollection() +{ + CAF_PDM_InitObject("Annotations", ":/Annotations16x16.png", "", ""); + + CAF_PDM_InitField(&m_annotationPlaneDepth, "AnnotationPlaneDepth", 0.0, "Annotation Plane Depth", "", "", ""); + CAF_PDM_InitField(&m_snapAnnotations, "SnapAnnotations", false, "Snap Annotations to Plane", "", "", ""); + + m_annotationPlaneDepth.uiCapability()->setUiEditorTypeName(caf::PdmUiDoubleSliderEditor::uiEditorTypeName()); + m_annotationPlaneDepth.uiCapability()->setUiLabelPosition(caf::PdmUiItemInfo::LabelPosType::TOP); + + CAF_PDM_InitFieldNoDefault(&m_globalTextAnnotations, "TextAnnotationsInView", "Global Text Annotations", "", "", ""); + CAF_PDM_InitFieldNoDefault(&m_globalReachCircleAnnotations, "ReachCircleAnnotationsInView", "Global Reach Circle Annotations", "", "", ""); + CAF_PDM_InitFieldNoDefault(&m_globalUserDefinedPolylineAnnotations, "UserDefinedPolylinesAnnotationsInView", "Global User Defined Polylines Annotations", "", "", ""); + CAF_PDM_InitFieldNoDefault(&m_globalPolylineFromFileAnnotations, "PolylinesFromFileAnnotationsInView", "Global Polylines From File Annotations", "", "", ""); + + m_globalTextAnnotations.uiCapability()->setUiHidden(true); + m_globalReachCircleAnnotations.uiCapability()->setUiHidden(true); + m_globalUserDefinedPolylineAnnotations.uiCapability()->setUiHidden(true); + m_globalPolylineFromFileAnnotations.uiCapability()->setUiHidden(true); + + m_globalTextAnnotations = new RimAnnotationGroupCollection(); + m_globalReachCircleAnnotations = new RimAnnotationGroupCollection(); + m_globalUserDefinedPolylineAnnotations = new RimAnnotationGroupCollection(); + m_globalPolylineFromFileAnnotations = new RimAnnotationGroupCollection(); + + m_globalTextAnnotations->uiCapability()->setUiName("Global Text Annotations"); + m_globalReachCircleAnnotations->uiCapability()->setUiName("Global Reach Circle Annotations"); + m_globalUserDefinedPolylineAnnotations->uiCapability()->setUiName("Global User Defined Polylines Annotations"); + m_globalPolylineFromFileAnnotations->uiCapability()->setUiName("Global Polylines From File Annotations"); + + m_globalTextAnnotations->uiCapability()->setUiIcon(QIcon(":/TextAnnotation16x16.png")); + m_globalReachCircleAnnotations->uiCapability()->setUiIcon(QIcon(":/ReachCircle16x16.png")); + m_globalUserDefinedPolylineAnnotations->uiCapability()->setUiIcon(QIcon(":/PolylinesFromFile16x16.png")); + m_globalPolylineFromFileAnnotations->uiCapability()->setUiIcon(QIcon(":/PolylinesFromFile16x16.png")); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimAnnotationInViewCollection::~RimAnnotationInViewCollection() +{ +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +double RimAnnotationInViewCollection::annotationPlaneZ() const +{ + return -m_annotationPlaneDepth(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RimAnnotationInViewCollection::snapAnnotations() const +{ + return m_snapAnnotations; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector RimAnnotationInViewCollection::globalTextAnnotations() const +{ + std::vector annotations; + for (auto& a : m_globalTextAnnotations->annotations()) + { + annotations.push_back(dynamic_cast(a)); + } + return annotations; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector RimAnnotationInViewCollection::globalReachCircleAnnotations() const +{ + std::vector annotations; + for (auto& a : m_globalReachCircleAnnotations->annotations()) + { + annotations.push_back(dynamic_cast(a)); + } + return annotations; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector RimAnnotationInViewCollection::globalUserDefinedPolylineAnnotations() const +{ + std::vector annotations; + for (auto& a : m_globalUserDefinedPolylineAnnotations->annotations()) + { + annotations.push_back(dynamic_cast(a)); + } + return annotations; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector RimAnnotationInViewCollection::globalPolylineFromFileAnnotations() const +{ + std::vector annotations; + for (auto& a : m_globalPolylineFromFileAnnotations->annotations()) + { + annotations.push_back(dynamic_cast(a)); + } + return annotations; +} + +//-------------------------------------------------------------------------------------------------- +/// Called when the global annotation collection has changed +//-------------------------------------------------------------------------------------------------- +void RimAnnotationInViewCollection::onGlobalCollectionChanged(const RimAnnotationCollection* globalCollection) +{ + // Sync annotations from global annotation collection + auto globals = globalCollection->allPdmAnnotations(); + auto locals = allGlobalPdmAnnotations(); + std::vector globalAnnotationsToDelete; + std::set globalsSet(globals.begin(), globals.end()); + + for(const auto local : locals) + { + auto sourceAnnotation = sourcePdmAnnotation(local); + if (globalsSet.count(sourceAnnotation) > 0) + { + globalsSet.erase(sourceAnnotation); + } + else + { + globalAnnotationsToDelete.push_back(local); + } + } + + // Remove deleted global annotations + for(auto a : globalAnnotationsToDelete) + { + deleteGlobalAnnotation(a); + } + + // Add newly added global annotations + for (const auto& global : globalsSet) + { + addGlobalAnnotation(global); + } + + updateConnectedEditors(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RimAnnotationInViewCollection::hasTextAnnotationsWithCustomFontSize(RiaFontCache::FontSize defaultFontSize) const +{ + for (auto annotation : textAnnotations()) + { + if (annotation->appearance()->fontSize() != defaultFontSize) + { + return true; + } + } + + for (auto annotationInView : globalTextAnnotations()) + { + if (annotationInView->sourceAnnotation()->appearance()->fontSize() != defaultFontSize) + { + return true; + } + } + + return false; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RimAnnotationInViewCollection::applyFontSizeToAllTextAnnotations(RiaFontCache::FontSize oldFontSize, + RiaFontCache::FontSize fontSize, + bool forceChange) +{ + bool anyChange = false; + for (auto annotation : textAnnotations()) + { + if (forceChange || annotation->appearance()->fontSize() == oldFontSize) + { + annotation->appearance()->setFontSize(fontSize); + annotation->updateConnectedEditors(); + anyChange = true; + } + } + + for (auto annotationInView : globalTextAnnotations()) + { + if (forceChange || annotationInView->sourceAnnotation()->appearance()->fontSize() == oldFontSize) + { + annotationInView->sourceAnnotation()->appearance()->setFontSize(fontSize); + annotationInView->updateConnectedEditors(); + anyChange = true; + } + } + return anyChange; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimAnnotationInViewCollection::defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering) +{ + uiOrdering.add(&m_snapAnnotations); + if(m_snapAnnotations()) + uiOrdering.add(&m_annotationPlaneDepth); + + uiOrdering.skipRemainingFields(true); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimAnnotationInViewCollection::fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue) +{ + scheduleRedrawOfRelevantViews(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimAnnotationInViewCollection::defineEditorAttribute(const caf::PdmFieldHandle* field, + QString uiConfigName, + caf::PdmUiEditorAttribute* attribute) +{ + if (field == &m_annotationPlaneDepth) + { + auto* attr = dynamic_cast(attribute); + + if (attr) + { + RimCase* rimCase; + firstAncestorOrThisOfType(rimCase); + + if (rimCase) + { + auto bb = rimCase->allCellsBoundingBox(); + attr->m_minimum = -bb.max().z(); + attr->m_maximum = -bb.min().z(); + } + else + { + attr->m_minimum = 0; + attr->m_maximum = 10000; + } + } + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector RimAnnotationInViewCollection::allGlobalPdmAnnotations() const +{ + std::vector all; + all.insert(all.end(), m_globalTextAnnotations->m_annotations.begin(), m_globalTextAnnotations->m_annotations.end()); + all.insert(all.end(), m_globalReachCircleAnnotations->m_annotations.begin(), m_globalReachCircleAnnotations->m_annotations.end()); + all.insert(all.end(), m_globalUserDefinedPolylineAnnotations->m_annotations.begin(), m_globalUserDefinedPolylineAnnotations->m_annotations.end()); + all.insert(all.end(), m_globalPolylineFromFileAnnotations->m_annotations.begin(), m_globalPolylineFromFileAnnotations->m_annotations.end()); + return all; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimAnnotationInViewCollection::addGlobalAnnotation(caf::PdmObject* annotation) +{ + auto t = dynamic_cast(annotation); + if (t) + { + m_globalTextAnnotations->addAnnotation(new RimTextAnnotationInView(t)); + return; + } + + auto c = dynamic_cast< RimReachCircleAnnotation*>(annotation); + if (c) + { + m_globalReachCircleAnnotations->addAnnotation(new RimReachCircleAnnotationInView(c)); + return; + } + + auto up = dynamic_cast(annotation); + if (up) + { + m_globalUserDefinedPolylineAnnotations->addAnnotation(new RimUserDefinedPolylinesAnnotationInView(up)); + return; + } + + auto pf = dynamic_cast(annotation); + if (pf) + { + m_globalPolylineFromFileAnnotations->addAnnotation(new RimPolylinesFromFileAnnotationInView(pf)); + return; + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimAnnotationInViewCollection::deleteGlobalAnnotation(const caf::PdmObject* annotation) +{ + for(size_t i = 0; i < m_globalTextAnnotations->m_annotations.size(); i++) + { + if (m_globalTextAnnotations->m_annotations[i] == annotation) + { + m_globalTextAnnotations->m_annotations.erase(i); + return; + } + } + + for (size_t i = 0; i < m_globalReachCircleAnnotations->m_annotations.size(); i++) + { + if (m_globalReachCircleAnnotations->m_annotations[i] == annotation) + { + m_globalReachCircleAnnotations->m_annotations.erase(i); + return; + } + } + + for (size_t i = 0; i < m_globalUserDefinedPolylineAnnotations->m_annotations.size(); i++) + { + if (m_globalUserDefinedPolylineAnnotations->m_annotations[i] == annotation) + { + m_globalUserDefinedPolylineAnnotations->m_annotations.erase(i); + return; + } + } + + for (size_t i = 0; i < m_globalPolylineFromFileAnnotations->m_annotations.size(); i++) + { + if (m_globalPolylineFromFileAnnotations->m_annotations[i] == annotation) + { + m_globalPolylineFromFileAnnotations->m_annotations.erase(i); + return; + } + } +} diff --git a/ApplicationCode/ProjectDataModel/Annotations/RimAnnotationInViewCollection.h b/ApplicationCode/ProjectDataModel/Annotations/RimAnnotationInViewCollection.h new file mode 100644 index 0000000000..28c123ed26 --- /dev/null +++ b/ApplicationCode/ProjectDataModel/Annotations/RimAnnotationInViewCollection.h @@ -0,0 +1,86 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2018- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "RiaFontCache.h" +#include "RimAnnotationCollectionBase.h" + +#include "cafAppEnum.h" +#include "cafPdmChildArrayField.h" +#include "cafPdmField.h" +#include "cafPdmChildField.h" +#include "cafPdmObject.h" +#include "cafPdmPointer.h" +#include "cafTristate.h" + +class RimAnnotationCollection; +class RimAnnotationGroupCollection; +class RimTextAnnotation; +class RimTextAnnotationInView; +class RimReachCircleAnnotationInView; +class RimUserDefinedPolylinesAnnotationInView; +class RimPolylinesFromFileAnnotationInView; + +//================================================================================================== +/// +/// +//================================================================================================== +class RimAnnotationInViewCollection : public RimAnnotationCollectionBase +{ + CAF_PDM_HEADER_INIT; +public: + + RimAnnotationInViewCollection(); + ~RimAnnotationInViewCollection() override; + + double annotationPlaneZ() const; + bool snapAnnotations() const; + + std::vector globalTextAnnotations() const; + std::vector globalReachCircleAnnotations() const; + std::vector globalUserDefinedPolylineAnnotations() const; + std::vector globalPolylineFromFileAnnotations() const; + + void onGlobalCollectionChanged(const RimAnnotationCollection* globalCollection); + + bool hasTextAnnotationsWithCustomFontSize(RiaFontCache::FontSize defaultFontSize) const; + bool applyFontSizeToAllTextAnnotations(RiaFontCache::FontSize oldFontSize, RiaFontCache::FontSize fontSize, bool forceSizeChange = false); + +protected: + void defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering) override; + void fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue) override; + void defineEditorAttribute(const caf::PdmFieldHandle* field, + QString uiConfigName, + caf::PdmUiEditorAttribute* attribute) override; +private: + std::vector allGlobalPdmAnnotations() const; + void addGlobalAnnotation(caf::PdmObject* annotation); + void deleteGlobalAnnotation(const caf::PdmObject* annotation); + +private: + caf::PdmField m_annotationPlaneDepth; + caf::PdmField m_snapAnnotations; + + caf::PdmChildField m_globalTextAnnotations; + caf::PdmChildField m_globalReachCircleAnnotations; + caf::PdmChildField m_globalUserDefinedPolylineAnnotations; + caf::PdmChildField m_globalPolylineFromFileAnnotations; + + +}; diff --git a/ApplicationCode/ProjectDataModel/Annotations/RimAnnotationLineAppearance.cpp b/ApplicationCode/ProjectDataModel/Annotations/RimAnnotationLineAppearance.cpp new file mode 100644 index 0000000000..67502f5a54 --- /dev/null +++ b/ApplicationCode/ProjectDataModel/Annotations/RimAnnotationLineAppearance.cpp @@ -0,0 +1,236 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2018- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "RimAnnotationLineAppearance.h" +#include "RimAnnotationCollection.h" + +#include "RiaStdStringTools.h" + +#include + +#include "cafPdmUiLineEditor.h" + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +class ThicknessValidator : public QValidator +{ +public: + State validate(QString &input, int &pos) const override + { + if (input.isEmpty()) return State::Intermediate; + + int val = RiaStdStringTools::toInt(input.toStdString()); + if (val > 0 && val < 8) return State::Acceptable; + else return State::Invalid; + } +}; + + +namespace caf +{ +template<> +void RimAnnotationLineAppearance::LineStyle::setUp() +{ + addItem(RimAnnotationLineAppearance::STYLE_SOLID, "STYLE_SOLID", "Solid"); + addItem(RimAnnotationLineAppearance::STYLE_DASH, "STYLE_DASH", "Dashes"); + + setDefault(RimAnnotationLineAppearance::STYLE_SOLID); +} +} + + +CAF_PDM_SOURCE_INIT(RimAnnotationLineAppearance, "RimAnnotationLineAppearance"); + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimAnnotationLineAppearance::RimAnnotationLineAppearance() +{ + CAF_PDM_InitObject("AnnotationLineAppearance", ":/WellCollection.png", "", ""); + + CAF_PDM_InitField(&m_lineFieldsHidden, "LineFieldsHidden", false, "Line Fields Hidden", "", "", ""); + CAF_PDM_InitField(&m_color, "Color", cvf::Color3f(cvf::Color3f::BLACK), "Line Color", "", "", ""); + CAF_PDM_InitField(&m_thickness, "Thickness", 2, "Line Thickness", "", "", ""); + + // Stippling not yet supported. Needs new stuff in VizFwk + CAF_PDM_InitField(&m_style, "Style", LineStyle(), "Style", "", "", ""); + m_style.uiCapability()->setUiHidden(true); + m_style.xmlCapability()->disableIO(); + + m_lineFieldsHidden.uiCapability()->setUiHidden(true); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimAnnotationLineAppearance::setLineFieldsHidden(bool hidden) +{ + m_lineFieldsHidden = hidden; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimAnnotationLineAppearance::setColor(const cvf::Color3f& newColor) +{ + m_color = newColor; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +cvf::Color3f RimAnnotationLineAppearance::color() const +{ + return m_color(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RimAnnotationLineAppearance::isDashed() const +{ + return m_style() == STYLE_DASH; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +int RimAnnotationLineAppearance::thickness() const +{ + return m_thickness(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimAnnotationLineAppearance::defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering) +{ + if (!m_lineFieldsHidden()) + { + uiOrdering.add(&m_color); + uiOrdering.add(&m_style); + uiOrdering.add(&m_thickness); + } + + uiOrdering.skipRemainingFields(true); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimAnnotationLineAppearance::fieldChangedByUi(const caf::PdmFieldHandle* changedField, + const QVariant& oldValue, + const QVariant& newValue) +{ + RimAnnotationCollection* annColl = nullptr; + this->firstAncestorOrThisOfTypeAsserted(annColl); + annColl->scheduleRedrawOfRelevantViews(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimAnnotationLineAppearance::defineEditorAttribute(const caf::PdmFieldHandle* field, + QString uiConfigName, + caf::PdmUiEditorAttribute* attribute) +{ + if (field == &m_thickness) + { + auto myAttr = dynamic_cast(attribute); + if (myAttr) + { + myAttr->validator = new ThicknessValidator(); + } + } +} + +CAF_PDM_SOURCE_INIT(RimPolylineAppearance, "RimPolylineAppearance"); + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimPolylineAppearance::RimPolylineAppearance() +{ + CAF_PDM_InitObject("PolylineAppearance", ":/WellCollection.png", "", ""); + + CAF_PDM_InitField(&m_sphereFieldsHidden, "SphereFieldsHidden", false, "Sphere Fields Hidden", "", "", ""); + CAF_PDM_InitField(&m_sphereColor, "SphereColor", cvf::Color3f(cvf::Color3f::BLACK), "Sphere Color", "", "", ""); + CAF_PDM_InitField(&m_sphereRadiusFactor, "SphereRadiusFactor", 0.1, "Sphere Radius Factor", "", "", ""); + + m_sphereFieldsHidden.uiCapability()->setUiHidden(true); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimPolylineAppearance::setSphereFieldsHidden(bool hidden) +{ + m_sphereFieldsHidden = hidden; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimPolylineAppearance::setSphereColor(const cvf::Color3f& color) +{ + m_sphereColor = color; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +cvf::Color3f RimPolylineAppearance::sphereColor() const +{ + return m_sphereColor(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +double RimPolylineAppearance::sphereRadiusFactor() const +{ + return m_sphereRadiusFactor(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimPolylineAppearance::defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering) +{ + RimAnnotationLineAppearance::defineUiOrdering(uiConfigName, uiOrdering); + + if (!m_sphereFieldsHidden) + { + uiOrdering.add(&m_sphereColor); + uiOrdering.add(&m_sphereRadiusFactor); + } + + uiOrdering.skipRemainingFields(true); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimPolylineAppearance::fieldChangedByUi(const caf::PdmFieldHandle* changedField, + const QVariant& oldValue, + const QVariant& newValue) +{ + RimAnnotationLineAppearance::fieldChangedByUi(changedField, oldValue, newValue); +} diff --git a/ApplicationCode/ProjectDataModel/Annotations/RimAnnotationLineAppearance.h b/ApplicationCode/ProjectDataModel/Annotations/RimAnnotationLineAppearance.h new file mode 100644 index 0000000000..ae2ef9fdb4 --- /dev/null +++ b/ApplicationCode/ProjectDataModel/Annotations/RimAnnotationLineAppearance.h @@ -0,0 +1,106 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2018- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "cafPdmObject.h" + +#include "cafPdmField.h" +#include "cafAppEnum.h" + +#include "cafPdmFieldCvfColor.h" + + +//================================================================================================== +/// +/// +//================================================================================================== +class RimAnnotationLineAppearance : public caf::PdmObject +{ + CAF_PDM_HEADER_INIT; + +public: + enum LineStyleEnum + { + STYLE_SOLID, + STYLE_DASH + }; + using LineStyle = caf::AppEnum; + +public: + RimAnnotationLineAppearance(); + + void setLineFieldsHidden(bool hidden); + + void setColor(const cvf::Color3f& newColor); + cvf::Color3f color() const; + bool isDashed() const; + int thickness() const; + +protected: + void defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering) override; + void fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue) override; + void defineEditorAttribute(const caf::PdmFieldHandle* field, + QString uiConfigName, + caf::PdmUiEditorAttribute* attribute) override; + +private: + caf::PdmField m_lineFieldsHidden; + caf::PdmField m_color; + caf::PdmField m_style; + caf::PdmField m_thickness; + +}; + + +//================================================================================================== +/// +/// +//================================================================================================== +class RimReachCircleLineAppearance : public RimAnnotationLineAppearance +{ + +}; + + +//================================================================================================== +/// +/// +//================================================================================================== +class RimPolylineAppearance : public RimAnnotationLineAppearance +{ + CAF_PDM_HEADER_INIT; + +public: + RimPolylineAppearance(); + + void setSphereFieldsHidden(bool hidden); + + void setSphereColor(const cvf::Color3f& color); + cvf::Color3f sphereColor() const; + double sphereRadiusFactor() const; + +protected: + void defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering) override; + void fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue) override; + +private: + caf::PdmField m_sphereFieldsHidden; + caf::PdmField m_sphereColor; + caf::PdmField m_sphereRadiusFactor; +}; diff --git a/ApplicationCode/ProjectDataModel/Annotations/RimAnnotationTextAppearance.cpp b/ApplicationCode/ProjectDataModel/Annotations/RimAnnotationTextAppearance.cpp new file mode 100644 index 0000000000..4d1ef9b3c5 --- /dev/null +++ b/ApplicationCode/ProjectDataModel/Annotations/RimAnnotationTextAppearance.cpp @@ -0,0 +1,123 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2018- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "RimAnnotationTextAppearance.h" + +#include "RiaApplication.h" +#include "RiaPreferences.h" + +#include "RimAnnotationCollection.h" +#include "RimAnnotationInViewCollection.h" + + +CAF_PDM_SOURCE_INIT(RimAnnotationTextAppearance, "RimAnnotationTextAppearance"); + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimAnnotationTextAppearance::RimAnnotationTextAppearance() +{ + CAF_PDM_InitObject("TextAnnotation", ":/WellCollection.png", "", ""); + + auto prefs = RiaApplication::instance()->preferences(); + auto defaultBackgroundColor = prefs->defaultViewerBackgroundColor(); + + CAF_PDM_InitFieldNoDefault(&m_fontSize, "FontSize", "Font Size", "", "", ""); + m_fontSize = prefs->defaultAnnotationFontSize(); + + CAF_PDM_InitField(&m_fontColor, "FontColor", cvf::Color3f(cvf::Color3f::BLACK), "Font Color", "", "", ""); + CAF_PDM_InitField(&m_backgroundColor, "BackgroundColor", defaultBackgroundColor , "Background Color", "", "", ""); + CAF_PDM_InitField(&m_anchorLineColor, "AnchorLineColor", cvf::Color3f(cvf::Color3f::BLACK), "Anchor Line Color", "", "", ""); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimAnnotationTextAppearance::setFontSize(FontSize size) +{ + m_fontSize = size; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimAnnotationTextAppearance::setBackgroundColor(const cvf::Color3f& newColor) +{ + m_backgroundColor = newColor; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimAnnotationTextAppearance::FontSize RimAnnotationTextAppearance::fontSize() const +{ + return m_fontSize; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +cvf::Color3f RimAnnotationTextAppearance::fontColor() const +{ + return m_fontColor; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +cvf::Color3f RimAnnotationTextAppearance::backgroundColor() const +{ + return m_backgroundColor; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +cvf::Color3f RimAnnotationTextAppearance::anchorLineColor() const +{ + return m_anchorLineColor; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimAnnotationTextAppearance::defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering) +{ + uiOrdering.add(&m_fontSize); + uiOrdering.add(&m_fontColor); + uiOrdering.add(&m_backgroundColor); + uiOrdering.add(&m_anchorLineColor); + + uiOrdering.skipRemainingFields(true); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimAnnotationTextAppearance::fieldChangedByUi(const caf::PdmFieldHandle* changedField, + const QVariant& oldValue, + const QVariant& newValue) +{ + RimAnnotationCollectionBase* annColl = nullptr; + this->firstAncestorOrThisOfTypeAsserted(annColl); + + if (annColl) + { + annColl->scheduleRedrawOfRelevantViews(); + } +} diff --git a/ApplicationCode/ProjectDataModel/Annotations/RimAnnotationTextAppearance.h b/ApplicationCode/ProjectDataModel/Annotations/RimAnnotationTextAppearance.h new file mode 100644 index 0000000000..9193b18ee7 --- /dev/null +++ b/ApplicationCode/ProjectDataModel/Annotations/RimAnnotationTextAppearance.h @@ -0,0 +1,63 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2018- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "RiaFontCache.h" + +#include "cafPdmObject.h" + +#include "cafPdmField.h" +#include "cafAppEnum.h" + +#include "cafPdmFieldCvfColor.h" + + +//================================================================================================== +/// +/// +//================================================================================================== +class RimAnnotationTextAppearance : public caf::PdmObject +{ + CAF_PDM_HEADER_INIT; + +public: + using FontSize = caf::AppEnum; + + RimAnnotationTextAppearance(); + + void setFontSize(FontSize size); + void setBackgroundColor(const cvf::Color3f& newColor); + + FontSize fontSize() const; + cvf::Color3f fontColor() const; + cvf::Color3f backgroundColor() const; + cvf::Color3f anchorLineColor() const; + +protected: + void defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering) override; + void fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue) override; + +private: + caf::PdmField m_fontSize; + caf::PdmField m_fontColor; + caf::PdmField m_backgroundColor; + caf::PdmField m_anchorLineColor; + +}; + diff --git a/ApplicationCode/ProjectDataModel/Annotations/RimPolylineTarget.cpp b/ApplicationCode/ProjectDataModel/Annotations/RimPolylineTarget.cpp new file mode 100644 index 0000000000..d42a2123d2 --- /dev/null +++ b/ApplicationCode/ProjectDataModel/Annotations/RimPolylineTarget.cpp @@ -0,0 +1,104 @@ +#include "RimPolylineTarget.h" +#include "RimModeledWellPath.h" + +#include +#include "RimUserDefinedPolylinesAnnotation.h" +#include "cafPdmUiCheckBoxEditor.h" + +CAF_PDM_SOURCE_INIT(RimPolylineTarget, "PolylineTarget"); + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimPolylineTarget::RimPolylineTarget() + : m_isFullUpdateEnabled(true) +{ + + CAF_PDM_InitField(&m_isEnabled, "IsEnabled", true, "", "", "", ""); + CAF_PDM_InitFieldNoDefault(&m_targetPointXyd, "TargetPointXyd", "Point", "", "", ""); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimPolylineTarget::~RimPolylineTarget() +{ + +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RimPolylineTarget::isEnabled() const +{ + return m_isEnabled; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimPolylineTarget::setAsPointTargetXYD(const cvf::Vec3d& point) +{ + m_targetPointXyd = point; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimPolylineTarget::setAsPointXYZ(const cvf::Vec3d& point) +{ + m_targetPointXyd = cvf::Vec3d(point.x(), point.y(), -point.z()); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +cvf::Vec3d RimPolylineTarget::targetPointXYZ() const +{ + cvf::Vec3d xyzPoint(m_targetPointXyd()); + xyzPoint.z() = -xyzPoint.z(); + return xyzPoint; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +caf::PdmUiFieldHandle* RimPolylineTarget::targetPointUiCapability() +{ + return m_targetPointXyd.uiCapability(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimPolylineTarget::enableFullUpdate(bool enable) +{ + m_isFullUpdateEnabled = enable; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QList RimPolylineTarget::calculateValueOptions(const caf::PdmFieldHandle* fieldNeedingOptions, bool* useOptionsOnly) +{ + QList options; + return options; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimPolylineTarget::fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue) +{ + RimUserDefinedPolylinesAnnotation* polyline; + firstAncestorOrThisOfTypeAsserted(polyline); + polyline->updateVisualization(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimPolylineTarget::defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering) +{ + m_targetPointXyd.uiCapability()->setUiReadOnly(m_isEnabled()); +} diff --git a/ApplicationCode/ProjectDataModel/Annotations/RimPolylineTarget.h b/ApplicationCode/ProjectDataModel/Annotations/RimPolylineTarget.h new file mode 100644 index 0000000000..3403aa38f1 --- /dev/null +++ b/ApplicationCode/ProjectDataModel/Annotations/RimPolylineTarget.h @@ -0,0 +1,56 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2018 - Equinor +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once +#include "cafPdmObject.h" + +#include "cvfBase.h" +#include "cvfVector3.h" +#include "cafAppEnum.h" +#include "cafPdmField.h" +#include "cafPdmCoreVec3d.h" +#include "RiaLineArcWellPathCalculator.h" + +class RimPolylineTarget : public caf::PdmObject +{ + CAF_PDM_HEADER_INIT; +public: + RimPolylineTarget(); + ~RimPolylineTarget() override; + + bool isEnabled() const; + + void setAsPointTargetXYD(const cvf::Vec3d& point); + void setAsPointXYZ(const cvf::Vec3d& point); + + cvf::Vec3d targetPointXYZ() const; + caf::PdmUiFieldHandle* targetPointUiCapability(); + void enableFullUpdate(bool enable); + +private: + QList calculateValueOptions(const caf::PdmFieldHandle* fieldNeedingOptions, bool* useOptionsOnly) override; + void fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue) override; + void defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering) override; + +private: + bool m_isFullUpdateEnabled; + caf::PdmField m_isEnabled; + caf::PdmField m_targetPointXyd; + +}; + diff --git a/ApplicationCode/ProjectDataModel/Annotations/RimPolylinesAnnotation.cpp b/ApplicationCode/ProjectDataModel/Annotations/RimPolylinesAnnotation.cpp new file mode 100644 index 0000000000..163f3c3adb --- /dev/null +++ b/ApplicationCode/ProjectDataModel/Annotations/RimPolylinesAnnotation.cpp @@ -0,0 +1,121 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2018- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "RimPolylinesAnnotation.h" + +#include "RimAnnotationInViewCollection.h" +#include "RimGridView.h" +#include "RimProject.h" +#include "RimTools.h" +#include "QFile" +#include "RimAnnotationCollection.h" +#include "RimAnnotationLineAppearance.h" + +#include "QFileInfo" + +CAF_PDM_ABSTRACT_SOURCE_INIT(RimPolylinesAnnotation, "RimPolylinesAnnotation"); + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimPolylinesAnnotation::RimPolylinesAnnotation() +{ + CAF_PDM_InitObject("PolylineAnnotation", ":/WellCollection.png", "", ""); + + CAF_PDM_InitField(&m_isActive, "IsActive", true, "Is Active", "", "", ""); + m_isActive.uiCapability()->setUiHidden(true); + + CAF_PDM_InitField(&m_closePolyline, "ClosePolyline", false, "Close Polyline", "", "", ""); + CAF_PDM_InitField(&m_showLines, "ShowLines", true, "Show Lines", "", "", ""); + CAF_PDM_InitField(&m_showSpheres, "ShowSpheres", false, "Show Spheres", "", "", ""); + + CAF_PDM_InitFieldNoDefault(&m_appearance, "Appearance", "Appearance", "", "", ""); + + m_appearance = new RimPolylineAppearance(); + m_appearance.uiCapability()->setUiTreeHidden(true); + m_appearance.uiCapability()->setUiTreeChildrenHidden(true); + +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimPolylinesAnnotation::~RimPolylinesAnnotation() +{ + +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RimPolylinesAnnotation::isActive() +{ + return m_isActive(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RimPolylinesAnnotation::isVisible() +{ + RimAnnotationCollectionBase* coll; + firstAncestorOrThisOfType(coll); + + return coll && coll->isActive() && m_isActive; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RimPolylinesAnnotation::closePolyline() const +{ + return m_closePolyline; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RimPolylinesAnnotation::showLines() const +{ + return m_showLines; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RimPolylinesAnnotation::showSpheres() const +{ + return m_showSpheres; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimPolylineAppearance* RimPolylinesAnnotation::appearance() const +{ + return m_appearance; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +caf::PdmFieldHandle* RimPolylinesAnnotation::objectToggleField() +{ + return &m_isActive; +} + diff --git a/ApplicationCode/ProjectDataModel/Annotations/RimPolylinesAnnotation.h b/ApplicationCode/ProjectDataModel/Annotations/RimPolylinesAnnotation.h new file mode 100644 index 0000000000..132e2f6625 --- /dev/null +++ b/ApplicationCode/ProjectDataModel/Annotations/RimPolylinesAnnotation.h @@ -0,0 +1,66 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2018- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once +#include "cafPdmChildField.h" +#include "cafPdmField.h" +#include "cafPdmObject.h" + +// Include to make Pdm work for cvf::Color +#include "cvfBase.h" +#include "cvfObject.h" + +class RigPolyLinesData; +class RimPolylineAppearance; + +//================================================================================================== +/// +/// +//================================================================================================== +class RimPolylinesAnnotation : public caf::PdmObject +{ + CAF_PDM_HEADER_INIT; + +public: + RimPolylinesAnnotation(); + ~RimPolylinesAnnotation() override; + + virtual cvf::ref polyLinesData() = 0; + virtual bool isEmpty() = 0; + + bool isActive(); + bool isVisible(); + + bool closePolyline() const; + bool showLines() const; + bool showSpheres() const; + + RimPolylineAppearance* appearance() const; + +protected: + caf::PdmFieldHandle* objectToggleField() override; + +protected: + caf::PdmField m_isActive; + + caf::PdmField m_closePolyline; + caf::PdmField m_showLines; + caf::PdmField m_showSpheres; + + caf::PdmChildField m_appearance; +}; diff --git a/ApplicationCode/ProjectDataModel/Annotations/RimPolylinesAnnotationInView.cpp b/ApplicationCode/ProjectDataModel/Annotations/RimPolylinesAnnotationInView.cpp new file mode 100644 index 0000000000..4966371844 --- /dev/null +++ b/ApplicationCode/ProjectDataModel/Annotations/RimPolylinesAnnotationInView.cpp @@ -0,0 +1,127 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2018- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "RimPolylinesAnnotationInView.h" +#include "RimPolylinesAnnotation.h" +#include "RimAnnotationCollectionBase.h" +#include "RimAnnotationGroupCollection.h" + + +CAF_PDM_SOURCE_INIT(RimPolylinesAnnotationInView, "RimPolylinesAnnotationInView"); + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimPolylinesAnnotationInView::RimPolylinesAnnotationInView() +{ + CAF_PDM_InitObject("PolyLinesAnnotationInView", ":/WellCollection.png", "", ""); + + CAF_PDM_InitField(&m_isActive, "IsActive", true, "Is Active", "", "", ""); + CAF_PDM_InitFieldNoDefault(&m_sourceAnnotation, "SourceAnnotation", "Source Annotation", "", "", ""); + + m_isActive.uiCapability()->setUiHidden(true); + m_sourceAnnotation.uiCapability()->setUiHidden(true); + m_sourceAnnotation = nullptr; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimPolylinesAnnotationInView::RimPolylinesAnnotationInView(RimPolylinesAnnotation* sourceAnnotation) + : RimPolylinesAnnotationInView() +{ + CVF_ASSERT(sourceAnnotation); + + m_isActive = sourceAnnotation->isActive(); + m_sourceAnnotation = sourceAnnotation; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RimPolylinesAnnotationInView::isActive() const +{ + return m_isActive(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimPolylinesAnnotation* RimPolylinesAnnotationInView::sourceAnnotation() const +{ + return m_sourceAnnotation; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RimPolylinesAnnotationInView::isVisible() const +{ + RimAnnotationGroupCollection* coll; + firstAncestorOrThisOfType(coll); + + bool visible = true; + if (coll) visible = coll->isVisible(); + if (visible && m_sourceAnnotation) + { + visible = m_sourceAnnotation->isVisible(); + + if (visible) + { + RimAnnotationGroupCollection* globalColl; + m_sourceAnnotation->firstAncestorOrThisOfType(globalColl); + if (globalColl) visible = globalColl->isVisible(); + } + } + if (visible) visible = m_isActive; + return visible; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimPolylinesAnnotationInView::fieldChangedByUi(const caf::PdmFieldHandle* changedField, + const QVariant& oldValue, + const QVariant& newValue) +{ + if (changedField == &m_isActive) + { + RimAnnotationCollectionBase* coll; + firstAncestorOrThisOfType(coll); + + if (coll) coll->scheduleRedrawOfRelevantViews(); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +caf::PdmFieldHandle* RimPolylinesAnnotationInView::objectToggleField() +{ + return &m_isActive; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +caf::PdmFieldHandle* RimPolylinesAnnotationInView::userDescriptionField() +{ + return m_sourceAnnotation ? m_sourceAnnotation->userDescriptionField() : nullptr; +} + diff --git a/ApplicationCode/ProjectDataModel/Annotations/RimPolylinesAnnotationInView.h b/ApplicationCode/ProjectDataModel/Annotations/RimPolylinesAnnotationInView.h new file mode 100644 index 0000000000..b5076185b1 --- /dev/null +++ b/ApplicationCode/ProjectDataModel/Annotations/RimPolylinesAnnotationInView.h @@ -0,0 +1,71 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2018- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "RimAnnotationLineAppearance.h" + +#include "cafPdmChildArrayField.h" +#include "cafPdmField.h" +#include "cafPdmObject.h" +#include "cafPdmPointer.h" +#include "cafAppEnum.h" +#include "cafPdmUiOrdering.h" +#include "cafPdmPtrField.h" + +// Include to make Pdm work for cvf::Color +#include "cafPdmFieldCvfColor.h" +#include "cafPdmChildField.h" +#include "cafPdmFieldCvfVec3d.h" + +#include "cvfObject.h" +#include "cvfVector3.h" + +#include + +class QString; +class RimGridView; +class RimPolylinesAnnotation; + +//================================================================================================== +/// +/// +//================================================================================================== +class RimPolylinesAnnotationInView : public caf::PdmObject +{ + CAF_PDM_HEADER_INIT; + +public: + RimPolylinesAnnotationInView(); + RimPolylinesAnnotationInView(RimPolylinesAnnotation* sourceAnnotation); + ~RimPolylinesAnnotationInView() override {} + + bool isActive() const; + RimPolylinesAnnotation* sourceAnnotation() const; + + bool isVisible() const; + +protected: + void fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue) override; + caf::PdmFieldHandle* objectToggleField() override; + caf::PdmFieldHandle* userDescriptionField() override; + +private: + caf::PdmField m_isActive; + caf::PdmPtrField m_sourceAnnotation; +}; diff --git a/ApplicationCode/ProjectDataModel/Annotations/RimPolylinesFromFileAnnotation.cpp b/ApplicationCode/ProjectDataModel/Annotations/RimPolylinesFromFileAnnotation.cpp new file mode 100644 index 0000000000..5586ee1a96 --- /dev/null +++ b/ApplicationCode/ProjectDataModel/Annotations/RimPolylinesFromFileAnnotation.cpp @@ -0,0 +1,236 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2018- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "RimPolylinesFromFileAnnotation.h" + +#include "RimAnnotationCollection.h" +#include "RimAnnotationLineAppearance.h" +#include "RigPolyLinesData.h" + +#include "cafPdmUiFilePathEditor.h" + +#include +#include +#include + + +CAF_PDM_SOURCE_INIT(RimPolylinesFromFileAnnotation, "PolylinesFromFileAnnotation"); + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimPolylinesFromFileAnnotation::RimPolylinesFromFileAnnotation() +{ + CAF_PDM_InitObject("PolyLines Annotation", ":/PolylinesFromFile16x16.png", "", ""); + + CAF_PDM_InitFieldNoDefault(&m_polyLinesFileName, "PolyLineFilePath", "File", "", "", ""); + CAF_PDM_InitField(&m_userDescription, "PolyLineDescription", QString(""), "Name", "", "", ""); + +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimPolylinesFromFileAnnotation::~RimPolylinesFromFileAnnotation() +{ + +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimPolylinesFromFileAnnotation::setFileName(const QString& fileName) +{ + m_polyLinesFileName = fileName; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RimPolylinesFromFileAnnotation::fileName() const +{ + return m_polyLinesFileName().path(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimPolylinesFromFileAnnotation::readPolyLinesFile(QString * errorMessage) +{ + QFile dataFile(m_polyLinesFileName().path()); + + if (!dataFile.open(QFile::ReadOnly)) + { + if (errorMessage) (*errorMessage) += "Could not open the File: " + (m_polyLinesFileName().path()) + "\n"; + return; + } + + m_polyLinesData = new RigPolyLinesData; + + std::vector< std::vector< cvf::Vec3d > > polylines(1); + + QTextStream stream(&dataFile); + int lineNumber = 1; + while (!stream.atEnd()) + { + QString line = stream.readLine(); + QStringList commentLineSegs = line.split("#", QString::KeepEmptyParts); + if(commentLineSegs.size() == 0) continue; // Empty line + + + QStringList lineSegs = commentLineSegs[0].split(QRegExp("\\s+"), QString::SkipEmptyParts); + + if(lineSegs.size() == 0) continue; // No data + if(lineSegs.size() != 3) + { + if (errorMessage) (*errorMessage) += "Unexpected number of words on line: " + QString::number(lineNumber) + "\n"; + continue; + } + + if (lineSegs.size() == 3) // Normal case + { + bool isNumberParsingOk = true; + bool isOk = true; + double x = lineSegs[0].toDouble(&isOk); isNumberParsingOk &= isOk; + double y = lineSegs[1].toDouble(&isOk); isNumberParsingOk &= isOk; + double z = lineSegs[2].toDouble(&isOk); isNumberParsingOk &= isOk; + + if (!isNumberParsingOk) + { + if (errorMessage) (*errorMessage) += "Could not read the point at line: " + QString::number(lineNumber) + "\n"; + continue; + } + + if (x == 999.0 && y == 999.0 && z == 999.0) // New PolyLine + { + polylines.push_back(std::vector()); + continue; + } + + cvf::Vec3d point(x, y, -z); + polylines.back().push_back(point); + + } + + ++lineNumber; + } + + if ( polylines.back().empty() ) + { + polylines.pop_back(); + } + + m_polyLinesData->setPolyLines(polylines); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +cvf::ref RimPolylinesFromFileAnnotation::polyLinesData() +{ + return m_polyLinesData; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RimPolylinesFromFileAnnotation::isEmpty() +{ + if (m_polyLinesData.isNull()) return true; + + for (const std::vector & line :m_polyLinesData->polyLines()) + { + if (!line.empty()) return false; + } + + return true; +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimPolylinesFromFileAnnotation::setDescriptionFromFileName() +{ + QFileInfo fileInfo(m_polyLinesFileName().path()); + m_userDescription = fileInfo.fileName(); + +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimPolylinesFromFileAnnotation::defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering) +{ + appearance()->setLineFieldsHidden(!m_showLines()); + appearance()->setSphereFieldsHidden(!m_showSpheres()); + + uiOrdering.add(&m_polyLinesFileName); + + auto appearanceGroup = uiOrdering.addNewGroup("Appearance"); + appearanceGroup->add(&m_closePolyline); + appearanceGroup->add(&m_showLines); + appearanceGroup->add(&m_showSpheres); + + appearance()->uiOrdering(uiConfigName, *appearanceGroup); + + uiOrdering.skipRemainingFields(true); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimPolylinesFromFileAnnotation::fieldChangedByUi(const caf::PdmFieldHandle* changedField, + const QVariant& oldValue, + const QVariant& newValue) +{ + if (changedField == &m_polyLinesFileName) + { + QString errorMessage; + this->readPolyLinesFile(&errorMessage); + if (!errorMessage.isEmpty()) + { + QString totalError = "\nError in: " + this->fileName() + + "\n\t" + errorMessage; + QMessageBox::warning(nullptr, "Import Polylines", totalError); + } + } + else if (changedField == &m_showLines) + { + appearance()->setLineFieldsHidden(!m_showLines()); + } + else if (changedField == &m_showSpheres) + { + appearance()->setSphereFieldsHidden(!m_showSpheres()); + } + + RimAnnotationCollection* annColl = nullptr; + this->firstAncestorOrThisOfTypeAsserted(annColl); + + annColl->scheduleRedrawOfRelevantViews(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +caf::PdmFieldHandle* RimPolylinesFromFileAnnotation::userDescriptionField() +{ + return &m_userDescription; +} + + diff --git a/ApplicationCode/ProjectDataModel/Annotations/RimPolylinesFromFileAnnotation.h b/ApplicationCode/ProjectDataModel/Annotations/RimPolylinesFromFileAnnotation.h new file mode 100644 index 0000000000..2d45f02ceb --- /dev/null +++ b/ApplicationCode/ProjectDataModel/Annotations/RimPolylinesFromFileAnnotation.h @@ -0,0 +1,56 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2018 equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "RimPolylinesAnnotation.h" + + +class RimPolylinesFromFileAnnotation : public RimPolylinesAnnotation +{ + friend class RimPolylinesFromFileAnnotationInView; + + CAF_PDM_HEADER_INIT; + +public: + RimPolylinesFromFileAnnotation(); + ~RimPolylinesFromFileAnnotation() override; + + void setFileName(const QString& fileName); + QString fileName() const; + void readPolyLinesFile(QString * errorMessage); + + cvf::ref polyLinesData() override; + bool isEmpty() override; + + void setDescriptionFromFileName(); + +protected: + void defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering) override; + void fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue) override; + +private: + caf::PdmFieldHandle* userDescriptionField() override; + + caf::PdmField m_userDescription; + caf::PdmField m_polyLinesFileName; + cvf::ref m_polyLinesData; +}; + + + diff --git a/ApplicationCode/ProjectDataModel/Annotations/RimPolylinesFromFileAnnotationInView.cpp b/ApplicationCode/ProjectDataModel/Annotations/RimPolylinesFromFileAnnotationInView.cpp new file mode 100644 index 0000000000..efe4e3eed2 --- /dev/null +++ b/ApplicationCode/ProjectDataModel/Annotations/RimPolylinesFromFileAnnotationInView.cpp @@ -0,0 +1,41 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2018- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "RimPolylinesFromFileAnnotationInView.h" +#include "RimPolylinesFromFileAnnotation.h" + + +CAF_PDM_SOURCE_INIT(RimPolylinesFromFileAnnotationInView, "RimPolylinesFromFileAnnotationInView"); + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimPolylinesFromFileAnnotationInView::RimPolylinesFromFileAnnotationInView() +{ + CAF_PDM_InitObject("PolyLines Annotation", ":/PolylinesFromFile16x16.png", "", ""); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimPolylinesFromFileAnnotationInView::RimPolylinesFromFileAnnotationInView(RimPolylinesFromFileAnnotation* sourceAnnotation) + : RimPolylinesAnnotationInView(sourceAnnotation) +{ + CAF_PDM_InitObject("PolyLines Annotation", ":/PolylinesFromFile16x16.png", "", ""); +} diff --git a/ApplicationCode/ProjectDataModel/Annotations/RimPolylinesFromFileAnnotationInView.h b/ApplicationCode/ProjectDataModel/Annotations/RimPolylinesFromFileAnnotationInView.h new file mode 100644 index 0000000000..c88717afa8 --- /dev/null +++ b/ApplicationCode/ProjectDataModel/Annotations/RimPolylinesFromFileAnnotationInView.h @@ -0,0 +1,55 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2018- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "RimPolylinesAnnotationInView.h" + +#include "cafPdmChildArrayField.h" +#include "cafPdmField.h" +#include "cafPdmObject.h" +#include "cafPdmPointer.h" +#include "cafAppEnum.h" +#include "cafPdmUiOrdering.h" +#include "cafPdmPtrField.h" + +// Include to make Pdm work for cvf::Color +#include "cafPdmFieldCvfColor.h" +#include "cafPdmChildField.h" +#include "cafPdmFieldCvfVec3d.h" + +#include "cvfObject.h" +#include "cvfVector3.h" + +#include + +class RimPolylinesFromFileAnnotation; + +//================================================================================================== +/// +/// +//================================================================================================== +class RimPolylinesFromFileAnnotationInView : public RimPolylinesAnnotationInView +{ + CAF_PDM_HEADER_INIT; + +public: + RimPolylinesFromFileAnnotationInView(); + RimPolylinesFromFileAnnotationInView(RimPolylinesFromFileAnnotation* sourceAnnotation); + ~RimPolylinesFromFileAnnotationInView() override {} +}; diff --git a/ApplicationCode/ProjectDataModel/Annotations/RimReachCircleAnnotation.cpp b/ApplicationCode/ProjectDataModel/Annotations/RimReachCircleAnnotation.cpp new file mode 100644 index 0000000000..393cff6c2f --- /dev/null +++ b/ApplicationCode/ProjectDataModel/Annotations/RimReachCircleAnnotation.cpp @@ -0,0 +1,216 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2018- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "RimReachCircleAnnotation.h" + +#include "RimAnnotationInViewCollection.h" +#include "RimAnnotationLineAppearance.h" +#include "RimGridView.h" +#include "RimProject.h" +#include "RimAnnotationCollection.h" + +#include "RicVec3dPickEventHandler.h" + +#include "cafPdmUiPushButtonEditor.h" +#include "cafPdmUiPickableLineEditor.h" + +CAF_PDM_SOURCE_INIT(RimReachCircleAnnotation, "RimReachCircleAnnotation"); + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimReachCircleAnnotation::RimReachCircleAnnotation() +{ + CAF_PDM_InitObject("CircleAnnotation", ":/ReachCircle16x16.png", "", ""); + + CAF_PDM_InitField(&m_isActive, "IsActive", true, "Is Active", "", "", ""); + m_isActive.uiCapability()->setUiHidden(true); + + CAF_PDM_InitField(&m_centerPointXyd, "CenterPointXyd", Vec3d::ZERO, "Center Point", "", "", ""); + m_centerPointXyd.uiCapability()->setUiEditorTypeName(caf::PdmUiPickableLineEditor::uiEditorTypeName()); + CAF_PDM_InitField(&m_centerPointPickEnabled, "AnchorPointPick", false, "", "", "", ""); + caf::PdmUiPushButtonEditor::configureEditorForField(&m_centerPointPickEnabled); + m_centerPointPickEnabled.uiCapability()->setUiLabelPosition(caf::PdmUiItemInfo::LabelPosType::HIDDEN); + + CAF_PDM_InitField(&m_radius, "Radius", 100.0, "Radius", "", "", ""); + CAF_PDM_InitField(&m_name, "Name", QString("Circle Annotation"), "Name", "", "", ""); + + CAF_PDM_InitFieldNoDefault(&m_appearance, "Appearance", "Appearance", "", "", ""); + + m_appearance = new RimReachCircleLineAppearance(); + m_appearance.uiCapability()->setUiTreeHidden(true); + m_appearance.uiCapability()->setUiTreeChildrenHidden(true); + + m_centerPointEventHandler.reset(new RicVec3dPickEventHandler(&m_centerPointXyd)); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RimReachCircleAnnotation::isActive() +{ + return m_isActive(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RimReachCircleAnnotation::isVisible() +{ + RimAnnotationCollectionBase* coll; + firstAncestorOrThisOfType(coll); + + return coll && coll->isActive() && m_isActive; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimReachCircleAnnotation::enablePicking(bool enable) +{ + m_centerPointPickEnabled = enable; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +cvf::Vec3d RimReachCircleAnnotation::centerPoint() const +{ + auto pos = m_centerPointXyd(); + pos.z() = -pos.z(); + return pos; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +double RimReachCircleAnnotation::radius() const +{ + return m_radius; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RimReachCircleAnnotation::name() const +{ + return m_name; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimReachCircleLineAppearance* RimReachCircleAnnotation::appearance() const +{ + return m_appearance; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimReachCircleAnnotation::defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering) +{ + uiOrdering.add(&m_name); + uiOrdering.add(&m_centerPointXyd); + uiOrdering.add(&m_centerPointPickEnabled, false); + uiOrdering.add(&m_radius); + + auto appearanceGroup = uiOrdering.addNewGroup("Appearance"); + appearance()->uiOrdering(uiConfigName, *appearanceGroup); + + uiOrdering.skipRemainingFields(true); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimReachCircleAnnotation::fieldChangedByUi(const caf::PdmFieldHandle* changedField, + const QVariant& oldValue, + const QVariant& newValue) +{ + if (changedField == &m_centerPointXyd) + { + m_centerPointPickEnabled = false; + this->updateConnectedEditors(); + } + if (changedField == &m_centerPointPickEnabled) + { + this->updateConnectedEditors(); + } + RimAnnotationCollection* annColl = nullptr; + this->firstAncestorOrThisOfTypeAsserted(annColl); + + annColl->scheduleRedrawOfRelevantViews(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +caf::PdmFieldHandle* RimReachCircleAnnotation::userDescriptionField() +{ + return &m_name; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +caf::PdmFieldHandle* RimReachCircleAnnotation::objectToggleField() +{ + return &m_isActive; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimReachCircleAnnotation::defineEditorAttribute(const caf::PdmFieldHandle* field, + QString uiConfigName, + caf::PdmUiEditorAttribute* attribute) +{ + if (field == &m_centerPointXyd) + { + auto* attr = dynamic_cast(attribute); + if (attr) + { + attr->pickEventHandler = m_centerPointEventHandler; + attr->enablePicking = m_centerPointPickEnabled; + if (m_centerPointXyd().isZero()) + { + attr->enablePicking = true; + } + } + } + + if (field == &m_centerPointPickEnabled) + { + auto* attr = dynamic_cast(attribute); + if (attr) + { + if (m_centerPointPickEnabled) + { + attr->m_buttonText = "Stop"; + } + else + { + attr->m_buttonText = "Pick"; + } + } + } + +} + diff --git a/ApplicationCode/ProjectDataModel/Annotations/RimReachCircleAnnotation.h b/ApplicationCode/ProjectDataModel/Annotations/RimReachCircleAnnotation.h new file mode 100644 index 0000000000..38ff201733 --- /dev/null +++ b/ApplicationCode/ProjectDataModel/Annotations/RimReachCircleAnnotation.h @@ -0,0 +1,86 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2018- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "cafPdmChildArrayField.h" +#include "cafPdmField.h" +#include "cafPdmObject.h" +#include "cafPdmPointer.h" +#include "cafAppEnum.h" +#include "cafPdmUiOrdering.h" + +// Include to make Pdm work for cvf::Color +#include "cafPdmFieldCvfColor.h" +#include "cafPdmChildField.h" +#include "cafPdmFieldCvfVec3d.h" +#include "cafPdmObject.h" + +#include "cvfObject.h" +#include "cvfVector3.h" + +#include + +class QString; +class RicVec3dPickEventHandler; +class RimGridView; +class RimReachCircleLineAppearance; + +//================================================================================================== +/// +/// +//================================================================================================== +class RimReachCircleAnnotation : public caf::PdmObject +{ + friend class RimReachCircleAnnotationInView; + + using Vec3d = cvf::Vec3d; + + CAF_PDM_HEADER_INIT; + +public: + RimReachCircleAnnotation(); + ~RimReachCircleAnnotation() override {} + + bool isActive(); + bool isVisible(); + void enablePicking(bool enable); + + Vec3d centerPoint() const; + double radius() const; + QString name() const; + RimReachCircleLineAppearance* appearance() const; + +protected: + void defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering) override; + void fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue) override; + caf::PdmFieldHandle* userDescriptionField() override; + caf::PdmFieldHandle* objectToggleField() override; + virtual void defineEditorAttribute(const caf::PdmFieldHandle* field, QString uiConfigName, caf::PdmUiEditorAttribute* attribute) override; + +private: + caf::PdmField m_isActive; + + caf::PdmField m_centerPointXyd; + caf::PdmField m_centerPointPickEnabled; + caf::PdmField m_radius; + caf::PdmField m_name; + caf::PdmChildField m_appearance; + + std::shared_ptr m_centerPointEventHandler; +}; diff --git a/ApplicationCode/ProjectDataModel/Annotations/RimReachCircleAnnotationInView.cpp b/ApplicationCode/ProjectDataModel/Annotations/RimReachCircleAnnotationInView.cpp new file mode 100644 index 0000000000..f03ad39a53 --- /dev/null +++ b/ApplicationCode/ProjectDataModel/Annotations/RimReachCircleAnnotationInView.cpp @@ -0,0 +1,135 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2018- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "RimReachCircleAnnotationInView.h" +#include "RimReachCircleAnnotation.h" +#include "RimAnnotationCollectionBase.h" +#include "RimAnnotationGroupCollection.h" + + +CAF_PDM_SOURCE_INIT(RimReachCircleAnnotationInView, "RimReachCircleAnnotationInView"); + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimReachCircleAnnotationInView::RimReachCircleAnnotationInView() +{ + CAF_PDM_InitObject("ReachCircleAnnotationInView", ":/ReachCircle16x16.png", "", ""); + + CAF_PDM_InitField(&m_isActive, "IsActive", true, "Is Active", "", "", ""); + CAF_PDM_InitFieldNoDefault(&m_sourceAnnotation, "SourceAnnotation", "Source Annotation", "", "", ""); + + m_isActive.uiCapability()->setUiHidden(true); + m_sourceAnnotation.uiCapability()->setUiHidden(true); + m_sourceAnnotation = nullptr; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimReachCircleAnnotationInView::RimReachCircleAnnotationInView(RimReachCircleAnnotation* sourceAnnotation) + : RimReachCircleAnnotationInView() +{ + CVF_ASSERT(sourceAnnotation); + + m_isActive = sourceAnnotation->isActive(); + m_sourceAnnotation = sourceAnnotation; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RimReachCircleAnnotationInView::isActive() const +{ + return m_isActive(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimReachCircleAnnotationInView::setSourceAnnotation(RimReachCircleAnnotation* annotation) +{ + m_sourceAnnotation = annotation; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimReachCircleAnnotation* RimReachCircleAnnotationInView::sourceAnnotation() const +{ + return m_sourceAnnotation; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RimReachCircleAnnotationInView::isVisible() const +{ + RimAnnotationGroupCollection* coll; + firstAncestorOrThisOfType(coll); + + bool visible = true; + if (coll) visible = coll->isVisible(); + if (visible && m_sourceAnnotation) + { + visible = m_sourceAnnotation->isVisible(); + + if (visible) + { + RimAnnotationGroupCollection* globalColl; + m_sourceAnnotation->firstAncestorOrThisOfType(globalColl); + if (globalColl) visible = globalColl->isVisible(); + } + } + if (visible) visible = m_isActive; + return visible; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimReachCircleAnnotationInView::fieldChangedByUi(const caf::PdmFieldHandle* changedField, + const QVariant& oldValue, + const QVariant& newValue) +{ + if (changedField == &m_isActive) + { + RimAnnotationCollectionBase* coll; + firstAncestorOrThisOfType(coll); + + if (coll) coll->scheduleRedrawOfRelevantViews(); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +caf::PdmFieldHandle* RimReachCircleAnnotationInView::objectToggleField() +{ + return &m_isActive; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +caf::PdmFieldHandle* RimReachCircleAnnotationInView::userDescriptionField() +{ + return m_sourceAnnotation ? m_sourceAnnotation->userDescriptionField() : nullptr; +} + diff --git a/ApplicationCode/ProjectDataModel/Annotations/RimReachCircleAnnotationInView.h b/ApplicationCode/ProjectDataModel/Annotations/RimReachCircleAnnotationInView.h new file mode 100644 index 0000000000..86aa6f45d0 --- /dev/null +++ b/ApplicationCode/ProjectDataModel/Annotations/RimReachCircleAnnotationInView.h @@ -0,0 +1,72 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2018- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "RimAnnotationLineAppearance.h" + +#include "cafPdmChildArrayField.h" +#include "cafPdmField.h" +#include "cafPdmObject.h" +#include "cafPdmPointer.h" +#include "cafAppEnum.h" +#include "cafPdmUiOrdering.h" +#include "cafPdmPtrField.h" + +// Include to make Pdm work for cvf::Color +#include "cafPdmFieldCvfColor.h" +#include "cafPdmChildField.h" +#include "cafPdmFieldCvfVec3d.h" + +#include "cvfObject.h" +#include "cvfVector3.h" + +#include + +class QString; +class RimGridView; +class RimReachCircleAnnotation; + +//================================================================================================== +/// +/// +//================================================================================================== +class RimReachCircleAnnotationInView : public caf::PdmObject +{ + CAF_PDM_HEADER_INIT; + +public: + RimReachCircleAnnotationInView(); + RimReachCircleAnnotationInView(RimReachCircleAnnotation* sourceAnnotation); + ~RimReachCircleAnnotationInView() override {} + + bool isActive() const; + void setSourceAnnotation(RimReachCircleAnnotation* annotation); + RimReachCircleAnnotation* sourceAnnotation() const; + + bool isVisible() const; + +protected: + void fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue) override; + caf::PdmFieldHandle* objectToggleField() override; + caf::PdmFieldHandle* userDescriptionField() override; + +private: + caf::PdmField m_isActive; + caf::PdmPtrField m_sourceAnnotation; +}; diff --git a/ApplicationCode/ProjectDataModel/Annotations/RimTextAnnotation.cpp b/ApplicationCode/ProjectDataModel/Annotations/RimTextAnnotation.cpp new file mode 100644 index 0000000000..521c0c5793 --- /dev/null +++ b/ApplicationCode/ProjectDataModel/Annotations/RimTextAnnotation.cpp @@ -0,0 +1,298 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2018- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "RimTextAnnotation.h" + +#include "RimAnnotationInViewCollection.h" +#include "RimGridView.h" +#include "RimProject.h" +#include "RimAnnotationCollection.h" +#include "RimAnnotationGroupCollection.h" +#include "RimAnnotationTextAppearance.h" + +#include "RicVec3dPickEventHandler.h" +#include "AnnotationCommands/RicTextAnnotation3dEditor.h" + +#include "cafCmdFeatureManager.h" +#include "cafPdmUiPushButtonEditor.h" +#include "cafPdmUiTextEditor.h" +#include "cafPdmUiTreeOrdering.h" +#include "cafPdmUiPickableLineEditor.h" + +#include +#include + +CAF_PDM_SOURCE_INIT(RimTextAnnotation, "RimTextAnnotation"); + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimTextAnnotation::RimTextAnnotation() +{ + CAF_PDM_InitObject("TextAnnotation", ":/TextAnnotation16x16.png", "", ""); + this->setUi3dEditorTypeName(RicTextAnnotation3dEditor::uiEditorTypeName()); + + CAF_PDM_InitField(&m_anchorPointXyd, "AnchorPointXyd", Vec3d::ZERO, "Anchor Point", "", "", ""); + m_anchorPointXyd.uiCapability()->setUiEditorTypeName(caf::PdmUiPickableLineEditor::uiEditorTypeName()); + CAF_PDM_InitField(&m_anchorPointPickEnabledButtonField, "AnchorPointPick", false, "", "", "", ""); + caf::PdmUiPushButtonEditor::configureEditorForField(&m_anchorPointPickEnabledButtonField); + m_anchorPointPickEnabledButtonField.uiCapability()->setUiLabelPosition(caf::PdmUiItemInfo::LabelPosType::HIDDEN); + + CAF_PDM_InitField(&m_labelPointXyd, "LabelPointXyd", Vec3d::ZERO, "Label Point", "", "", ""); + m_labelPointXyd.uiCapability()->setUiEditorTypeName(caf::PdmUiPickableLineEditor::uiEditorTypeName()); + CAF_PDM_InitField(&m_labelPointPickEnabledButtonField, "LabelPointPick", false, "", "", "", ""); + caf::PdmUiPushButtonEditor::configureEditorForField(&m_labelPointPickEnabledButtonField); + m_labelPointPickEnabledButtonField.uiCapability()->setUiLabelPosition(caf::PdmUiItemInfo::LabelPosType::HIDDEN); + + CAF_PDM_InitField(&m_text, "Text", QString("(New text)"), "Text", "", "", ""); + m_text.uiCapability()->setUiEditorTypeName(caf::PdmUiTextEditor::uiEditorTypeName()); + + CAF_PDM_InitField(&m_isActive, "IsActive", true, "Is Active", "", "", ""); + m_isActive.uiCapability()->setUiHidden(true); + + CAF_PDM_InitFieldNoDefault(&m_textAppearance, "TextAppearance", "Text Appearance", "", "", ""); + m_textAppearance = new RimAnnotationTextAppearance(); + m_textAppearance.uiCapability()->setUiTreeHidden(true); + m_textAppearance.uiCapability()->setUiTreeChildrenHidden(true); + + CAF_PDM_InitFieldNoDefault(&m_nameProxy, "NameProxy", "Name Proxy", "", "", ""); + m_nameProxy.registerGetMethod(this, &RimTextAnnotation::extractNameFromText); + m_nameProxy.uiCapability()->setUiReadOnly(true); + m_nameProxy.xmlCapability()->disableIO(); + + m_anchorPointPickEventHandler.reset(new RicVec3dPickEventHandler(&m_anchorPointXyd)); + m_labelPointPickEventHandler.reset(new RicVec3dPickEventHandler(&m_labelPointXyd, 0.1)); + +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimTextAnnotation::~RimTextAnnotation() +{ + +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +cvf::Vec3d RimTextAnnotation::anchorPoint() const +{ + auto pos = m_anchorPointXyd(); + pos.z() = -pos.z(); + return pos; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimTextAnnotation::setAnchorPoint(const Vec3d & pointXyz) +{ + m_anchorPointXyd = pointXyz; + m_anchorPointXyd.v().z() *= -1; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +cvf::Vec3d RimTextAnnotation::labelPoint() const +{ + auto pos = m_labelPointXyd(); + pos.z() = -pos.z(); + return pos; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimTextAnnotation::setLabelPoint(const Vec3d & pointXyz) +{ + m_labelPointXyd = pointXyz; + m_labelPointXyd.v().z() *= -1; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimTextAnnotation::setText(const QString& text) +{ + m_text = text; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +const QString& RimTextAnnotation::text() const +{ + return m_text(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimTextAnnotation::defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering) +{ + uiOrdering.add(&m_anchorPointXyd); + uiOrdering.add(&m_anchorPointPickEnabledButtonField, false); + uiOrdering.add(&m_labelPointXyd); + uiOrdering.add(&m_labelPointPickEnabledButtonField, false); + + uiOrdering.add(&m_text); + + auto appearanceGroup = uiOrdering.addNewGroup("Text Appearance"); + m_textAppearance->uiOrdering(uiConfigName, *appearanceGroup); + + uiOrdering.skipRemainingFields(true); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimTextAnnotation::fieldChangedByUi(const caf::PdmFieldHandle* changedField, + const QVariant& oldValue, + const QVariant& newValue) +{ + if (changedField == &m_anchorPointXyd) + { + m_anchorPointPickEnabledButtonField = false; + if (m_labelPointXyd().isZero()) + { + m_labelPointXyd = m_anchorPointXyd; + } + this->updateConnectedEditors(); + } + if (changedField == &m_labelPointXyd) + { + m_labelPointPickEnabledButtonField = false; + this->updateConnectedEditors(); + } + if (changedField == &m_anchorPointPickEnabledButtonField || changedField == &m_labelPointPickEnabledButtonField) + { + this->updateConnectedEditors(); + } + + RimAnnotationCollectionBase* annColl = nullptr; + this->firstAncestorOrThisOfTypeAsserted(annColl); + + if(annColl) annColl->scheduleRedrawOfRelevantViews(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +caf::PdmFieldHandle* RimTextAnnotation::userDescriptionField() +{ + return &m_nameProxy; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RimTextAnnotation::isActive() +{ + return m_isActive(); +} + +//-------------------------------------------------------------------------------------------------- +/// Returns true if annotation can be displayed due to all toggles that affect this annotation +//-------------------------------------------------------------------------------------------------- +bool RimTextAnnotation::isVisible() const +{ + RimAnnotationGroupCollection* coll; + firstAncestorOrThisOfType(coll); + + bool visible = true; + if (coll) visible = coll->isVisible(); + if(visible) visible = m_isActive; + + return visible; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimTextAnnotation::enablePicking(bool enable) +{ + m_anchorPointPickEnabledButtonField = enable; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimAnnotationTextAppearance* RimTextAnnotation::appearance() const +{ + return m_textAppearance(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +caf::PdmFieldHandle* RimTextAnnotation::objectToggleField() +{ + return &m_isActive; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimTextAnnotation::defineEditorAttribute(const caf::PdmFieldHandle* field, + QString uiConfigName, + caf::PdmUiEditorAttribute* attribute) +{ + caf::PdmUiPickableLineEditorAttribute* attr = dynamic_cast(attribute); + + if (attr && field == &m_anchorPointXyd) + { + attr->pickEventHandler = m_anchorPointPickEventHandler; + attr->enablePicking = m_anchorPointPickEnabledButtonField; + } + else if (attr && field == &m_labelPointXyd) + { + attr->pickEventHandler = m_labelPointPickEventHandler; + attr->enablePicking = m_labelPointPickEnabledButtonField; + } + + if (field == &m_anchorPointPickEnabledButtonField || field == &m_labelPointPickEnabledButtonField) + { + auto* pbAttribute = dynamic_cast(attribute); + if (pbAttribute) + { + auto boolField = static_cast*>(field); + if (boolField->v()) + { + pbAttribute->m_buttonText = "Stop"; + } + else + { + pbAttribute->m_buttonText = "Pick"; + } + } + } + +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RimTextAnnotation::extractNameFromText() const +{ + return m_text().split("\n").front(); +} + + diff --git a/ApplicationCode/ProjectDataModel/Annotations/RimTextAnnotation.h b/ApplicationCode/ProjectDataModel/Annotations/RimTextAnnotation.h new file mode 100644 index 0000000000..9ef512845b --- /dev/null +++ b/ApplicationCode/ProjectDataModel/Annotations/RimTextAnnotation.h @@ -0,0 +1,102 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2018- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "cafPdmChildArrayField.h" +#include "cafPdmField.h" +#include "cafPdmObject.h" +#include "cafPdmPointer.h" +#include "cafAppEnum.h" +#include "cafPdmUiOrdering.h" + +// Include to make Pdm work for cvf::Color +#include "cafPdmFieldCvfColor.h" +#include "cafPdmChildField.h" +#include "cafPdmFieldCvfVec3d.h" +#include "cafPdmProxyValueField.h" + +#include "cvfObject.h" +#include "cvfVector3.h" + +#include +#include + +class QString; +class RicVec3dPickEventHandler; +class RimGridView; +class RimAnnotationTextAppearance; + +//================================================================================================== +/// +/// +//================================================================================================== +class RimTextAnnotation : public caf::PdmObject +{ + friend class RimTextAnnotationInView; + + using Vec3d = cvf::Vec3d; + + CAF_PDM_HEADER_INIT; + +public: + RimTextAnnotation(); + ~RimTextAnnotation() override; + + Vec3d anchorPoint() const; + void setAnchorPoint(const Vec3d & pointXyz) ; + Vec3d labelPoint() const; + void setLabelPoint(const Vec3d & pointXyz) ; + void setText(const QString& text); + const QString& text() const; + bool isActive(); + bool isVisible() const; + void enablePicking(bool enable); + + RimAnnotationTextAppearance* appearance() const; + +protected: + void defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering) override; + void fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue) override; + caf::PdmFieldHandle* userDescriptionField() override; + caf::PdmFieldHandle* objectToggleField() override; + void defineEditorAttribute(const caf::PdmFieldHandle* field, + QString uiConfigName, + caf::PdmUiEditorAttribute* attribute) override; + +private: + friend class RicTextAnnotation3dEditor; + + QString extractNameFromText() const; + + caf::PdmField m_anchorPointXyd; + caf::PdmField m_anchorPointPickEnabledButtonField; + caf::PdmField m_labelPointXyd; + caf::PdmField m_labelPointPickEnabledButtonField; + caf::PdmField m_text; + caf::PdmField m_isActive; + + caf::PdmChildField m_textAppearance; + + caf::PdmProxyValueField m_nameProxy; + + std::shared_ptr m_anchorPointPickEventHandler; + std::shared_ptr m_labelPointPickEventHandler; + +}; + diff --git a/ApplicationCode/ProjectDataModel/Annotations/RimTextAnnotationInView.cpp b/ApplicationCode/ProjectDataModel/Annotations/RimTextAnnotationInView.cpp new file mode 100644 index 0000000000..65c54889cf --- /dev/null +++ b/ApplicationCode/ProjectDataModel/Annotations/RimTextAnnotationInView.cpp @@ -0,0 +1,135 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2018- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "RimTextAnnotationInView.h" +#include "RimTextAnnotation.h" +#include "RimAnnotationCollectionBase.h" +#include "RimAnnotationGroupCollection.h" + + +CAF_PDM_SOURCE_INIT(RimTextAnnotationInView, "RimTextAnnotationInView"); + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimTextAnnotationInView::RimTextAnnotationInView() +{ + CAF_PDM_InitObject("TextAnnotationInView", ":/TextAnnotation16x16.png", "", ""); + + CAF_PDM_InitField(&m_isActive, "IsActive", true, "Is Active", "", "", ""); + CAF_PDM_InitFieldNoDefault(&m_sourceAnnotation, "SourceAnnotation", "Source Annotation", "", "", ""); + + m_isActive.uiCapability()->setUiHidden(true); + m_sourceAnnotation.uiCapability()->setUiHidden(true); + m_sourceAnnotation = nullptr; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimTextAnnotationInView::RimTextAnnotationInView(RimTextAnnotation* sourceAnnotation) + : RimTextAnnotationInView() +{ + CVF_ASSERT(sourceAnnotation); + + m_isActive = sourceAnnotation->isActive(); + m_sourceAnnotation = sourceAnnotation; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RimTextAnnotationInView::isActive() const +{ + return m_isActive(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimTextAnnotationInView::setSourceAnnotation(RimTextAnnotation* annotation) +{ + m_sourceAnnotation = annotation; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimTextAnnotation* RimTextAnnotationInView::sourceAnnotation() const +{ + return m_sourceAnnotation; +} + +//-------------------------------------------------------------------------------------------------- +/// Returns true if annotation can be displayed due to all toggles that affect this annotation +//-------------------------------------------------------------------------------------------------- +bool RimTextAnnotationInView::isVisible() const +{ + RimAnnotationGroupCollection* coll; + firstAncestorOrThisOfType(coll); + + bool visible = true; + if (coll) visible = coll->isVisible(); + if (visible && m_sourceAnnotation) + { + visible = m_sourceAnnotation->isVisible(); + + if (visible) + { + RimAnnotationGroupCollection* globalColl; + m_sourceAnnotation->firstAncestorOrThisOfType(globalColl); + if (globalColl) visible = globalColl->isVisible(); + } + } + if (visible) visible = m_isActive; + return visible; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimTextAnnotationInView::fieldChangedByUi(const caf::PdmFieldHandle* changedField, + const QVariant& oldValue, + const QVariant& newValue) +{ + if (changedField == &m_isActive) + { + RimAnnotationCollectionBase* coll; + firstAncestorOrThisOfType(coll); + + if (coll) coll->scheduleRedrawOfRelevantViews(); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +caf::PdmFieldHandle* RimTextAnnotationInView::objectToggleField() +{ + return &m_isActive; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +caf::PdmFieldHandle* RimTextAnnotationInView::userDescriptionField() +{ + return m_sourceAnnotation ? m_sourceAnnotation->userDescriptionField() : nullptr; +} + diff --git a/ApplicationCode/ProjectDataModel/Annotations/RimTextAnnotationInView.h b/ApplicationCode/ProjectDataModel/Annotations/RimTextAnnotationInView.h new file mode 100644 index 0000000000..535eef561b --- /dev/null +++ b/ApplicationCode/ProjectDataModel/Annotations/RimTextAnnotationInView.h @@ -0,0 +1,68 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2018- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "cafPdmChildArrayField.h" +#include "cafPdmField.h" +#include "cafPdmObject.h" +#include "cafPdmPointer.h" +#include "cafAppEnum.h" +#include "cafPdmUiOrdering.h" +#include "cafPdmPtrField.h" + +// Include to make Pdm work for cvf::Color +#include "cafPdmFieldCvfColor.h" +#include "cafPdmChildField.h" +#include "cafPdmFieldCvfVec3d.h" + +#include "cvfObject.h" +#include "cvfVector3.h" + +#include + +class RimTextAnnotation; + +//================================================================================================== +/// +/// +//================================================================================================== +class RimTextAnnotationInView : public caf::PdmObject +{ + CAF_PDM_HEADER_INIT; + +public: + RimTextAnnotationInView(); + RimTextAnnotationInView(RimTextAnnotation* sourceAnnotation); + ~RimTextAnnotationInView() override {} + + bool isActive() const; + void setSourceAnnotation(RimTextAnnotation* annotation); + RimTextAnnotation* sourceAnnotation() const; + + bool isVisible() const; + +protected: + void fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue) override; + caf::PdmFieldHandle* objectToggleField() override; + caf::PdmFieldHandle* userDescriptionField() override; + +private: + caf::PdmField m_isActive; + caf::PdmPtrField m_sourceAnnotation; +}; diff --git a/ApplicationCode/ProjectDataModel/Annotations/RimUserDefinedPolylinesAnnotation.cpp b/ApplicationCode/ProjectDataModel/Annotations/RimUserDefinedPolylinesAnnotation.cpp new file mode 100644 index 0000000000..98fd260929 --- /dev/null +++ b/ApplicationCode/ProjectDataModel/Annotations/RimUserDefinedPolylinesAnnotation.cpp @@ -0,0 +1,325 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2018- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "RimUserDefinedPolylinesAnnotation.h" + +#include "WellPathCommands/PointTangentManipulator/RicPolyline3dEditor.h" +#include "WellPathCommands/RicPolylineTargetsPickEventHandler.h" + +#include "RimAnnotationCollection.h" +#include "RimAnnotationLineAppearance.h" +#include "RimPolylineTarget.h" + +#include "RigPolyLinesData.h" + +#include "RiuViewerCommands.h" + +#include "cvfBoundingBox.h" + +#include "cafPdmUiTableViewEditor.h" +#include "cafCmdFeatureMenuBuilder.h" +#include "cafPdmUiPushButtonEditor.h" +#include "cafPdmUiTreeOrdering.h" + +CAF_PDM_SOURCE_INIT(RimUserDefinedPolylinesAnnotation, "UserDefinedPolylinesAnnotation"); + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimUserDefinedPolylinesAnnotation::RimUserDefinedPolylinesAnnotation() + : m_pickTargetsEventHandler(new RicPolylineTargetsPickEventHandler(this)) +{ + CAF_PDM_InitObject("PolyLines Annotation", ":/PolylinesFromFile16x16.png", "", ""); + + CAF_PDM_InitField(&m_name, "Name", QString("User Defined Polyline"), "Name", "", "", ""); + + CAF_PDM_InitField(&m_enablePicking, "EnablePicking", false, "", "", "", ""); + caf::PdmUiPushButtonEditor::configureEditorForField(&m_enablePicking); + m_enablePicking.uiCapability()->setUiLabelPosition(caf::PdmUiItemInfo::LabelPosType::HIDDEN); + + CAF_PDM_InitFieldNoDefault(&m_targets, "Targets", "Targets", "", "", ""); + m_targets.uiCapability()->setUiEditorTypeName(caf::PdmUiTableViewEditor::uiEditorTypeName()); + //m_targets.uiCapability()->setUiTreeHidden(true); + m_targets.uiCapability()->setUiTreeChildrenHidden(true); + m_targets.uiCapability()->setUiLabelPosition(caf::PdmUiItemInfo::TOP); + m_targets.uiCapability()->setCustomContextMenuEnabled(true); + + this->setUi3dEditorTypeName(RicPolyline3dEditor::uiEditorTypeName()); + +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimUserDefinedPolylinesAnnotation::~RimUserDefinedPolylinesAnnotation() +{ + +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +cvf::ref RimUserDefinedPolylinesAnnotation::polyLinesData() +{ + cvf::ref pld = new RigPolyLinesData; + std::vector line; + for (const RimPolylineTarget* target : m_targets) + { + line.push_back(target->targetPointXYZ()); + } + pld->setPolyLines({ line }); + + return pld; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector RimUserDefinedPolylinesAnnotation::activeTargets() const +{ + return m_targets.childObjects(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RimUserDefinedPolylinesAnnotation::isEmpty() +{ + return m_targets.empty(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimUserDefinedPolylinesAnnotation::appendTarget(const cvf::Vec3d& defaultPos) +{ + RimPolylineTarget* target = nullptr; + + auto targets = m_targets.childObjects(); + if (targets.empty()) + { + target = new RimPolylineTarget(); + target->setAsPointXYZ(defaultPos); + } + else + { + target = dynamic_cast( + targets.back()->xmlCapability()->copyByXmlSerialization(caf::PdmDefaultObjectFactory::instance())); + } + + if (target) + { + m_targets.push_back(target); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimUserDefinedPolylinesAnnotation::insertTarget(const RimPolylineTarget* targetToInsertBefore, + RimPolylineTarget* targetToInsert) +{ + size_t index = m_targets.index(targetToInsertBefore); + if (index < m_targets.size()) + m_targets.insert(index, targetToInsert); + else + m_targets.push_back(targetToInsert); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimUserDefinedPolylinesAnnotation::deleteTarget(RimPolylineTarget* targetTodelete) +{ + m_targets.removeChildObject(targetTodelete); + delete targetTodelete; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::pair + RimUserDefinedPolylinesAnnotation::findActiveTargetsAroundInsertionPoint(const RimPolylineTarget* targetToInsertBefore) +{ + RimPolylineTarget* before = nullptr; + RimPolylineTarget* after = nullptr; + + bool foundTarget = false; + for (const auto& wt : m_targets) + { + if (wt == targetToInsertBefore) + { + foundTarget = true; + } + + if (wt->isEnabled() && !after && foundTarget) after = wt; + + if (wt->isEnabled() && !foundTarget) before = wt; + } + + return {before, after}; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimUserDefinedPolylinesAnnotation::updateVisualization() +{ + RimAnnotationCollection* annColl = nullptr; + this->firstAncestorOrThisOfTypeAsserted(annColl); + + annColl->scheduleRedrawOfRelevantViews(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimUserDefinedPolylinesAnnotation::enablePicking(bool enable) +{ + m_enablePicking = enable; + updateConnectedEditors(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimUserDefinedPolylinesAnnotation::defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering) +{ + appearance()->setLineFieldsHidden(!m_showLines); + appearance()->setSphereFieldsHidden(!m_showSpheres); + + uiOrdering.add(&m_name); + uiOrdering.add(&m_targets); + uiOrdering.add(&m_enablePicking); + + auto appearanceGroup = uiOrdering.addNewGroup("Appearance"); + appearanceGroup->add(&m_closePolyline); + appearanceGroup->add(&m_showLines); + appearanceGroup->add(&m_showSpheres); + + appearance()->uiOrdering(uiConfigName, *appearanceGroup); + + uiOrdering.skipRemainingFields(true); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimUserDefinedPolylinesAnnotation::defineUiTreeOrdering(caf::PdmUiTreeOrdering& uiTreeOrdering, QString uiConfigName) +{ + uiTreeOrdering.skipRemainingChildren(true); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimUserDefinedPolylinesAnnotation::fieldChangedByUi(const caf::PdmFieldHandle* changedField, + const QVariant& oldValue, + const QVariant& newValue) +{ + if (changedField == &m_enablePicking) + { + this->updateConnectedEditors(); + } + else if (changedField == &m_showLines) + { + appearance()->setLineFieldsHidden(!m_showLines()); + } + else if (changedField == &m_showSpheres) + { + appearance()->setSphereFieldsHidden(!m_showSpheres()); + } + + updateVisualization(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimUserDefinedPolylinesAnnotation::defineObjectEditorAttribute(QString uiConfigName, caf::PdmUiEditorAttribute* attribute) +{ + RicPolyline3dEditorAttribute* attrib = dynamic_cast(attribute); + if (attrib) + { + attrib->pickEventHandler = m_pickTargetsEventHandler; + attrib->enablePicking = m_enablePicking; + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimUserDefinedPolylinesAnnotation::defineCustomContextMenu(const caf::PdmFieldHandle* fieldNeedingMenu, + QMenu* menu, + QWidget* fieldEditorWidget) +{ + caf::CmdFeatureMenuBuilder menuBuilder; + + menuBuilder << "RicNewPolylineTargetFeature"; + menuBuilder << "Separator"; + menuBuilder << "RicDeletePolylineTargetFeature"; + + menuBuilder.appendToMenu(menu); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimUserDefinedPolylinesAnnotation::defineEditorAttribute(const caf::PdmFieldHandle* field, + QString uiConfigName, + caf::PdmUiEditorAttribute* attribute) +{ + if (field == &m_enablePicking) + { + auto* pbAttribute = dynamic_cast(attribute); + if (pbAttribute) + { + if (!m_enablePicking) + { + pbAttribute->m_buttonText = "Start Picking Points"; + } + else + { + pbAttribute->m_buttonText = "Stop Picking Points"; + } + } + } + + if (field == &m_targets) + { + auto tvAttribute = dynamic_cast(attribute); + if (tvAttribute) + { + tvAttribute->resizePolicy = caf::PdmUiTableViewEditorAttribute::RESIZE_TO_FIT_CONTENT; + + if (m_enablePicking) + { + tvAttribute->baseColor.setRgb(255, 220, 255); + tvAttribute->alwaysEnforceResizePolicy = true; + } + } + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +caf::PdmFieldHandle* RimUserDefinedPolylinesAnnotation::userDescriptionField() +{ + return &m_name; +} diff --git a/ApplicationCode/ProjectDataModel/Annotations/RimUserDefinedPolylinesAnnotation.h b/ApplicationCode/ProjectDataModel/Annotations/RimUserDefinedPolylinesAnnotation.h new file mode 100644 index 0000000000..2920cbe2f9 --- /dev/null +++ b/ApplicationCode/ProjectDataModel/Annotations/RimUserDefinedPolylinesAnnotation.h @@ -0,0 +1,81 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2018 equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once +#include "RimPolylinesAnnotation.h" + +#include "cafPdmFieldCvfVec3d.h" +#include "cafPdmChildArrayField.h" + +#include + +class RicPolylineTargetsPickEventHandler; +class RimPolylineTarget; + +//================================================================================================== +/// +/// +//================================================================================================== + +class RimUserDefinedPolylinesAnnotation : public RimPolylinesAnnotation +{ + friend class RimUserDefinedPolylinesAnnotationInView; + + using Vec3d = cvf::Vec3d; + + CAF_PDM_HEADER_INIT; +public: + RimUserDefinedPolylinesAnnotation(); + ~RimUserDefinedPolylinesAnnotation() override; + + cvf::ref polyLinesData() override; + std::vector activeTargets() const; + bool isEmpty() override; + + void appendTarget(const cvf::Vec3d& defaultPos = cvf::Vec3d::ZERO); + void insertTarget(const RimPolylineTarget* targetToInsertBefore, RimPolylineTarget* targetToInsert); + void deleteTarget(RimPolylineTarget* targetTodelete); + + std::pair + findActiveTargetsAroundInsertionPoint(const RimPolylineTarget* targetToInsertBefore); + void updateVisualization(); + + void enablePicking(bool enable); + +protected: + void defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering) override; + void defineUiTreeOrdering(caf::PdmUiTreeOrdering& uiTreeOrdering, QString uiConfigName) override; + void fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue) override; + void defineObjectEditorAttribute(QString uiConfigName, caf::PdmUiEditorAttribute* attribute) override; + +private: + void defineCustomContextMenu(const caf::PdmFieldHandle* fieldNeedingMenu, QMenu* menu, QWidget* fieldEditorWidget) override; + void defineEditorAttribute(const caf::PdmFieldHandle* field, + QString uiConfigName, + caf::PdmUiEditorAttribute* attribute) override; + caf::PdmFieldHandle* userDescriptionField() override; + +private: + caf::PdmField m_name; + caf::PdmField m_enablePicking; + caf::PdmChildArrayField m_targets; + + std::shared_ptr m_pickTargetsEventHandler; +}; + + diff --git a/ApplicationCode/ProjectDataModel/Annotations/RimUserDefinedPolylinesAnnotationInView.cpp b/ApplicationCode/ProjectDataModel/Annotations/RimUserDefinedPolylinesAnnotationInView.cpp new file mode 100644 index 0000000000..b7f1a59205 --- /dev/null +++ b/ApplicationCode/ProjectDataModel/Annotations/RimUserDefinedPolylinesAnnotationInView.cpp @@ -0,0 +1,41 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2018- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "RimUserDefinedPolylinesAnnotationInView.h" +#include "RimUserDefinedPolylinesAnnotation.h" + + +CAF_PDM_SOURCE_INIT(RimUserDefinedPolylinesAnnotationInView, "RimUserDefinedPolylinesAnnotationInView"); + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimUserDefinedPolylinesAnnotationInView::RimUserDefinedPolylinesAnnotationInView() +{ + CAF_PDM_InitObject("PolyLinesAnnotationInView", ":/WellCollection.png", "", ""); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimUserDefinedPolylinesAnnotationInView::RimUserDefinedPolylinesAnnotationInView(RimUserDefinedPolylinesAnnotation* sourceAnnotation) + : RimPolylinesAnnotationInView(sourceAnnotation) +{ + CAF_PDM_InitObject("PolyLinesAnnotationInView", ":/WellCollection.png", "", ""); +} diff --git a/ApplicationCode/ProjectDataModel/Annotations/RimUserDefinedPolylinesAnnotationInView.h b/ApplicationCode/ProjectDataModel/Annotations/RimUserDefinedPolylinesAnnotationInView.h new file mode 100644 index 0000000000..0e8d2c6273 --- /dev/null +++ b/ApplicationCode/ProjectDataModel/Annotations/RimUserDefinedPolylinesAnnotationInView.h @@ -0,0 +1,56 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2018- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "RimPolylinesAnnotationInView.h" + +#include "cafPdmChildArrayField.h" +#include "cafPdmField.h" +#include "cafPdmObject.h" +#include "cafPdmPointer.h" +#include "cafAppEnum.h" +#include "cafPdmUiOrdering.h" +#include "cafPdmPtrField.h" + +// Include to make Pdm work for cvf::Color +#include "cafPdmFieldCvfColor.h" +#include "cafPdmChildField.h" +#include "cafPdmFieldCvfVec3d.h" + +#include "cvfObject.h" +#include "cvfVector3.h" + +#include + +class QString; +class RimGridView; +class RimUserDefinedPolylinesAnnotation; + +//================================================================================================== +/// +/// +//================================================================================================== +class RimUserDefinedPolylinesAnnotationInView : public RimPolylinesAnnotationInView +{ + CAF_PDM_HEADER_INIT; +public: + RimUserDefinedPolylinesAnnotationInView(); + RimUserDefinedPolylinesAnnotationInView(RimUserDefinedPolylinesAnnotation* sourceAnnotation); + ~RimUserDefinedPolylinesAnnotationInView() override {} +}; diff --git a/ApplicationCode/ProjectDataModel/CMakeLists_files.cmake b/ApplicationCode/ProjectDataModel/CMakeLists_files.cmake index afcdda6189..475fa10379 100644 --- a/ApplicationCode/ProjectDataModel/CMakeLists_files.cmake +++ b/ApplicationCode/ProjectDataModel/CMakeLists_files.cmake @@ -88,7 +88,7 @@ ${CMAKE_CURRENT_LIST_DIR}/RimContextCommandBuilder.h ${CMAKE_CURRENT_LIST_DIR}/RimGridCollection.h ${CMAKE_CURRENT_LIST_DIR}/RimPlotCurve.h ${CMAKE_CURRENT_LIST_DIR}/RimIntersectionBox.h -${CMAKE_CURRENT_LIST_DIR}/RimMultiSnapshotDefinition.h +${CMAKE_CURRENT_LIST_DIR}/RimAdvancedSnapshotExportDefinition.h ${CMAKE_CURRENT_LIST_DIR}/RimMdiWindowController.h ${CMAKE_CURRENT_LIST_DIR}/RimPropertyFilter.h ${CMAKE_CURRENT_LIST_DIR}/RimNamedObject.h @@ -118,9 +118,19 @@ ${CMAKE_CURRENT_LIST_DIR}/RimWellLogRftCurveNameConfig.h ${CMAKE_CURRENT_LIST_DIR}/RimDataSourceSteppingTools.h ${CMAKE_CURRENT_LIST_DIR}/RimWellLogCurveCommonDataSource.h ${CMAKE_CURRENT_LIST_DIR}/RimContourMapProjection.h -${CMAKE_CURRENT_LIST_DIR}/RimContourMapView.h -${CMAKE_CURRENT_LIST_DIR}/RimContourMapViewCollection.h -${CMAKE_CURRENT_LIST_DIR}/RimContourMapNameConfig.h +${CMAKE_CURRENT_LIST_DIR}/RimEclipseContourMapProjection.h +${CMAKE_CURRENT_LIST_DIR}/RimEclipseContourMapView.h +${CMAKE_CURRENT_LIST_DIR}/RimEclipseContourMapViewCollection.h +${CMAKE_CURRENT_LIST_DIR}/RimGeoMechContourMapProjection.h +${CMAKE_CURRENT_LIST_DIR}/RimGeoMechContourMapView.h +${CMAKE_CURRENT_LIST_DIR}/RimGeoMechContourMapViewCollection.h +${CMAKE_CURRENT_LIST_DIR}/RimViewNameConfig.h +${CMAKE_CURRENT_LIST_DIR}/RimScaleLegendConfig.h +${CMAKE_CURRENT_LIST_DIR}/RimReloadCaseTools.h +${CMAKE_CURRENT_LIST_DIR}/RimRiuQwtPlotOwnerInterface.h +${CMAKE_CURRENT_LIST_DIR}/RimPlotAxisPropertiesInterface.h +${CMAKE_CURRENT_LIST_DIR}/RimPlotAxisProperties.h +${CMAKE_CURRENT_LIST_DIR}/RimPlotAxisAnnotation.h ) @@ -213,7 +223,7 @@ ${CMAKE_CURRENT_LIST_DIR}/RimContextCommandBuilder.cpp ${CMAKE_CURRENT_LIST_DIR}/RimGridCollection.cpp ${CMAKE_CURRENT_LIST_DIR}/RimPlotCurve.cpp ${CMAKE_CURRENT_LIST_DIR}/RimIntersectionBox.cpp -${CMAKE_CURRENT_LIST_DIR}/RimMultiSnapshotDefinition.cpp +${CMAKE_CURRENT_LIST_DIR}/RimAdvancedSnapshotExportDefinition.cpp ${CMAKE_CURRENT_LIST_DIR}/RimMdiWindowController.cpp ${CMAKE_CURRENT_LIST_DIR}/RimPropertyFilter.cpp ${CMAKE_CURRENT_LIST_DIR}/RimNamedObject.cpp @@ -243,9 +253,18 @@ ${CMAKE_CURRENT_LIST_DIR}/RimWellLogRftCurveNameConfig.cpp ${CMAKE_CURRENT_LIST_DIR}/RimDataSourceSteppingTools.cpp ${CMAKE_CURRENT_LIST_DIR}/RimWellLogCurveCommonDataSource.cpp ${CMAKE_CURRENT_LIST_DIR}/RimContourMapProjection.cpp -${CMAKE_CURRENT_LIST_DIR}/RimContourMapView.cpp -${CMAKE_CURRENT_LIST_DIR}/RimContourMapViewCollection.cpp -${CMAKE_CURRENT_LIST_DIR}/RimContourMapNameConfig.cpp +${CMAKE_CURRENT_LIST_DIR}/RimEclipseContourMapProjection.cpp +${CMAKE_CURRENT_LIST_DIR}/RimEclipseContourMapView.cpp +${CMAKE_CURRENT_LIST_DIR}/RimEclipseContourMapViewCollection.cpp +${CMAKE_CURRENT_LIST_DIR}/RimGeoMechContourMapProjection.cpp +${CMAKE_CURRENT_LIST_DIR}/RimGeoMechContourMapView.cpp +${CMAKE_CURRENT_LIST_DIR}/RimGeoMechContourMapViewCollection.cpp +${CMAKE_CURRENT_LIST_DIR}/RimViewNameConfig.cpp +${CMAKE_CURRENT_LIST_DIR}/RimScaleLegendConfig.cpp +${CMAKE_CURRENT_LIST_DIR}/RimReloadCaseTools.cpp +${CMAKE_CURRENT_LIST_DIR}/RimPlotAxisPropertiesInterface.cpp +${CMAKE_CURRENT_LIST_DIR}/RimPlotAxisProperties.cpp +${CMAKE_CURRENT_LIST_DIR}/RimPlotAxisAnnotation.cpp ) list(APPEND CODE_HEADER_FILES diff --git a/ApplicationCode/ProjectDataModel/Completions/CMakeLists_files.cmake b/ApplicationCode/ProjectDataModel/Completions/CMakeLists_files.cmake index 318f8f01be..461fb14803 100644 --- a/ApplicationCode/ProjectDataModel/Completions/CMakeLists_files.cmake +++ b/ApplicationCode/ProjectDataModel/Completions/CMakeLists_files.cmake @@ -15,7 +15,10 @@ ${CMAKE_CURRENT_LIST_DIR}/RimFractureContainment.h ${CMAKE_CURRENT_LIST_DIR}/RimFractureContainmentTools.h ${CMAKE_CURRENT_LIST_DIR}/RimFractureExportSettings.h ${CMAKE_CURRENT_LIST_DIR}/RimFractureTemplate.h +${CMAKE_CURRENT_LIST_DIR}/RimCompletionTemplateCollection.h ${CMAKE_CURRENT_LIST_DIR}/RimFractureTemplateCollection.h +${CMAKE_CURRENT_LIST_DIR}/RimValveTemplateCollection.h +${CMAKE_CURRENT_LIST_DIR}/RimValveTemplate.h ${CMAKE_CURRENT_LIST_DIR}/RimSimWellFracture.h ${CMAKE_CURRENT_LIST_DIR}/RimSimWellFractureCollection.h ${CMAKE_CURRENT_LIST_DIR}/RimStimPlanFractureTemplate.h @@ -27,6 +30,8 @@ ${CMAKE_CURRENT_LIST_DIR}/RimNonDarcyPerforationParameters.h ${CMAKE_CURRENT_LIST_DIR}/RimWellPathComponentInterface.h ${CMAKE_CURRENT_LIST_DIR}/RimWellPathValve.h ${CMAKE_CURRENT_LIST_DIR}/RimMultipleValveLocations.h +${CMAKE_CURRENT_LIST_DIR}/RimWellPathAicdParameters.h + ) @@ -46,7 +51,10 @@ ${CMAKE_CURRENT_LIST_DIR}/RimFractureContainment.cpp ${CMAKE_CURRENT_LIST_DIR}/RimFractureContainmentTools.cpp ${CMAKE_CURRENT_LIST_DIR}/RimFractureExportSettings.cpp ${CMAKE_CURRENT_LIST_DIR}/RimFractureTemplate.cpp +${CMAKE_CURRENT_LIST_DIR}/RimCompletionTemplateCollection.cpp ${CMAKE_CURRENT_LIST_DIR}/RimFractureTemplateCollection.cpp +${CMAKE_CURRENT_LIST_DIR}/RimValveTemplateCollection.cpp +${CMAKE_CURRENT_LIST_DIR}/RimValveTemplate.cpp ${CMAKE_CURRENT_LIST_DIR}/RimSimWellFracture.cpp ${CMAKE_CURRENT_LIST_DIR}/RimSimWellFractureCollection.cpp ${CMAKE_CURRENT_LIST_DIR}/RimStimPlanFractureTemplate.cpp @@ -57,6 +65,7 @@ ${CMAKE_CURRENT_LIST_DIR}/RimMswCompletionParameters.cpp ${CMAKE_CURRENT_LIST_DIR}/RimNonDarcyPerforationParameters.cpp ${CMAKE_CURRENT_LIST_DIR}/RimWellPathValve.cpp ${CMAKE_CURRENT_LIST_DIR}/RimMultipleValveLocations.cpp +${CMAKE_CURRENT_LIST_DIR}/RimWellPathAicdParameters.cpp ) list(APPEND CODE_HEADER_FILES diff --git a/ApplicationCode/ProjectDataModel/Completions/Rim3dWellLogCurveCollection.cpp b/ApplicationCode/ProjectDataModel/Completions/Rim3dWellLogCurveCollection.cpp index 68ec1f8a14..1361e6b85d 100644 --- a/ApplicationCode/ProjectDataModel/Completions/Rim3dWellLogCurveCollection.cpp +++ b/ApplicationCode/ProjectDataModel/Completions/Rim3dWellLogCurveCollection.cpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018- Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by diff --git a/ApplicationCode/ProjectDataModel/Completions/Rim3dWellLogCurveCollection.h b/ApplicationCode/ProjectDataModel/Completions/Rim3dWellLogCurveCollection.h index c4d4a60a53..e0fecd6ee9 100644 --- a/ApplicationCode/ProjectDataModel/Completions/Rim3dWellLogCurveCollection.h +++ b/ApplicationCode/ProjectDataModel/Completions/Rim3dWellLogCurveCollection.h @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018- Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by diff --git a/ApplicationCode/ProjectDataModel/Completions/RimCompletionTemplateCollection.cpp b/ApplicationCode/ProjectDataModel/Completions/RimCompletionTemplateCollection.cpp new file mode 100644 index 0000000000..7918882629 --- /dev/null +++ b/ApplicationCode/ProjectDataModel/Completions/RimCompletionTemplateCollection.cpp @@ -0,0 +1,110 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2018- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "RimCompletionTemplateCollection.h" + +#include "RimFractureTemplateCollection.h" +#include "RimValveTemplateCollection.h" + +#include "cafPdmUiTreeOrdering.h" + +#include "cvfAssert.h" + +CAF_PDM_SOURCE_INIT(RimCompletionTemplateCollection, "CompletionTemplateCollection"); + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimCompletionTemplateCollection::RimCompletionTemplateCollection() +{ + CAF_PDM_InitObject("Completion Templates", ":/CompletionsSymbol16x16.png", "", ""); + + CAF_PDM_InitFieldNoDefault(&m_fractureTemplates, "FractureTemplates", "", "", "", ""); + m_fractureTemplates = new RimFractureTemplateCollection; + m_fractureTemplates->addDefaultEllipseTemplate(); + CAF_PDM_InitFieldNoDefault(&m_valveTemplates, "ValveTemplates", "", "", "", ""); + m_valveTemplates = new RimValveTemplateCollection; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimCompletionTemplateCollection::~RimCompletionTemplateCollection() +{ + +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimFractureTemplateCollection* RimCompletionTemplateCollection::fractureTemplateCollection() +{ + return m_fractureTemplates; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +const RimFractureTemplateCollection* RimCompletionTemplateCollection::fractureTemplateCollection() const +{ + return m_fractureTemplates; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimValveTemplateCollection* RimCompletionTemplateCollection::valveTemplateCollection() +{ + return m_valveTemplates; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +const RimValveTemplateCollection* RimCompletionTemplateCollection::valveTemplateCollection() const +{ + return m_valveTemplates; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimCompletionTemplateCollection::setDefaultUnitSystemBasedOnLoadedCases() +{ + m_fractureTemplates->setDefaultUnitSystemBasedOnLoadedCases(); + m_valveTemplates->setDefaultUnitSystemBasedOnLoadedCases(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimCompletionTemplateCollection::setFractureTemplateCollection(RimFractureTemplateCollection* fractureTemplateCollection) +{ + CVF_ASSERT(!m_fractureTemplates->fractureTemplates().empty()); + m_fractureTemplates = fractureTemplateCollection; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimCompletionTemplateCollection::defineUiTreeOrdering(caf::PdmUiTreeOrdering& uiTreeOrdering, QString uiConfigName /*= ""*/) +{ + uiTreeOrdering.add(m_fractureTemplates); + uiTreeOrdering.add(m_valveTemplates); + uiTreeOrdering.skipRemainingChildren(true); +} diff --git a/ApplicationCode/ProjectDataModel/Completions/RimCompletionTemplateCollection.h b/ApplicationCode/ProjectDataModel/Completions/RimCompletionTemplateCollection.h new file mode 100644 index 0000000000..ea61683123 --- /dev/null +++ b/ApplicationCode/ProjectDataModel/Completions/RimCompletionTemplateCollection.h @@ -0,0 +1,51 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2018- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "cafPdmChildField.h" +#include "cafPdmObject.h" + +class RimOilField; +class RimValveTemplateCollection; +class RimFractureTemplateCollection; + +class RimCompletionTemplateCollection : public caf::PdmObject +{ + CAF_PDM_HEADER_INIT; +public: + RimCompletionTemplateCollection(); + ~RimCompletionTemplateCollection() override; + + RimFractureTemplateCollection* fractureTemplateCollection(); + const RimFractureTemplateCollection* fractureTemplateCollection() const; + RimValveTemplateCollection* valveTemplateCollection(); + const RimValveTemplateCollection* valveTemplateCollection() const; + void setDefaultUnitSystemBasedOnLoadedCases(); + +private: + friend class RimOilField; + void setFractureTemplateCollection(RimFractureTemplateCollection* fractureTemplateCollection); + + caf::PdmChildField m_fractureTemplates; + caf::PdmChildField m_valveTemplates; + +protected: + void defineUiTreeOrdering(caf::PdmUiTreeOrdering& uiTreeOrdering, QString uiConfigName = "") override; + +}; diff --git a/ApplicationCode/ProjectDataModel/Completions/RimEllipseFractureTemplate.cpp b/ApplicationCode/ProjectDataModel/Completions/RimEllipseFractureTemplate.cpp index ca3adbec10..d6c75ce038 100644 --- a/ApplicationCode/ProjectDataModel/Completions/RimEllipseFractureTemplate.cpp +++ b/ApplicationCode/ProjectDataModel/Completions/RimEllipseFractureTemplate.cpp @@ -394,7 +394,7 @@ void RimEllipseFractureTemplate::convertToUnitSystem(RiaEclipseUnitTools::UnitSy { if (m_fractureTemplateUnit() == neededUnit) return; - setFractureTemplateUnit(neededUnit); + setUnitSystem(neededUnit); RimFractureTemplate::convertToUnitSystem(neededUnit); if (neededUnit == RiaEclipseUnitTools::UNITS_FIELD) diff --git a/ApplicationCode/ProjectDataModel/Completions/RimFishbonesCollection.cpp b/ApplicationCode/ProjectDataModel/Completions/RimFishbonesCollection.cpp index a7afc5bc6d..9ab1610a30 100644 --- a/ApplicationCode/ProjectDataModel/Completions/RimFishbonesCollection.cpp +++ b/ApplicationCode/ProjectDataModel/Completions/RimFishbonesCollection.cpp @@ -56,7 +56,7 @@ RimFishbonesCollection::RimFishbonesCollection() CAF_PDM_InitField(&m_mainBoreDiameter, "MainBoreDiameter", 0.216, "Main Bore Diameter", "", "", ""); CAF_PDM_InitField(&m_skinFactor, "MainBoreSkinFactor", 0., "Main Bore Skin Factor [0..1]", "", "", ""); CAF_PDM_InitFieldNoDefault(&m_mswParameters, "MswParameters", "Multi Segment Well Parameters", "", "", ""); - m_mswParameters = new RimMswCompletionParameters; + m_mswParameters = new RimMswCompletionParameters(false); m_mswParameters.uiCapability()->setUiTreeHidden(true); m_mswParameters.uiCapability()->setUiTreeChildrenHidden(true); manuallyModifiedStartMD = false; diff --git a/ApplicationCode/ProjectDataModel/Completions/RimFishbonesMultipleSubs.cpp b/ApplicationCode/ProjectDataModel/Completions/RimFishbonesMultipleSubs.cpp index 5ccae742ff..ec34468ef1 100644 --- a/ApplicationCode/ProjectDataModel/Completions/RimFishbonesMultipleSubs.cpp +++ b/ApplicationCode/ProjectDataModel/Completions/RimFishbonesMultipleSubs.cpp @@ -25,6 +25,7 @@ #include "RimWellPath.h" #include "RimFishbonesCollection.h" #include "RimMultipleValveLocations.h" +#include "RimWellPathValve.h" #include "cafPdmUiDoubleValueEditor.h" #include "cafPdmUiListEditor.h" @@ -273,32 +274,25 @@ double RimFishbonesMultipleSubs::icdOrificeDiameter(RiaEclipseUnitTools::UnitSys { RimWellPath* wellPath; firstAncestorOrThisOfTypeAsserted(wellPath); - if (unitSystem == RiaEclipseUnitTools::UNITS_METRIC) - { - if (wellPath->unitSystem() == RiaEclipseUnitTools::UNITS_FIELD) - { - return RiaEclipseUnitTools::inchToMeter(m_icdOrificeDiameter()); - } - else - { - return m_icdOrificeDiameter() / 1000; - } - } - else if (unitSystem == RiaEclipseUnitTools::UNITS_FIELD) - { - if (wellPath->unitSystem() == RiaEclipseUnitTools::UNITS_METRIC) - { - return RiaEclipseUnitTools::meterToFeet(m_icdOrificeDiameter() / 1000); - } - else - { - return RiaEclipseUnitTools::inchToFeet(m_icdOrificeDiameter()); - } - } - CVF_ASSERT(false); - return 0.0; + return RimWellPathValve::convertOrificeDiameter(m_icdOrificeDiameter(), wellPath->unitSystem(), unitSystem); +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +double RimFishbonesMultipleSubs::icdFlowCoefficient() const +{ + return m_icdFlowCoefficient(); } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +size_t RimFishbonesMultipleSubs::icdCount() const +{ + return m_icdCount(); +} //-------------------------------------------------------------------------------------------------- /// diff --git a/ApplicationCode/ProjectDataModel/Completions/RimFishbonesMultipleSubs.h b/ApplicationCode/ProjectDataModel/Completions/RimFishbonesMultipleSubs.h index d43a556003..93c96d9f51 100644 --- a/ApplicationCode/ProjectDataModel/Completions/RimFishbonesMultipleSubs.h +++ b/ApplicationCode/ProjectDataModel/Completions/RimFishbonesMultipleSubs.h @@ -93,8 +93,8 @@ class RimFishbonesMultipleSubs : public caf::PdmObject, public Rim3dPropertiesIn double skinFactor() const { return m_pipeProperties()->skinFactor(); } double openHoleRoughnessFactor(RiaEclipseUnitTools::UnitSystem unitSystem) const; double icdOrificeDiameter(RiaEclipseUnitTools::UnitSystem unitSystem) const; - double icdFlowCoefficient() const { return m_icdFlowCoefficient(); } - size_t icdCount() const { return m_icdCount(); } + double icdFlowCoefficient() const; + size_t icdCount() const; std::vector lateralLengths() const; void geometryUpdated(); diff --git a/ApplicationCode/ProjectDataModel/Completions/RimFracture.cpp b/ApplicationCode/ProjectDataModel/Completions/RimFracture.cpp index 126f076068..817fc2e66b 100644 --- a/ApplicationCode/ProjectDataModel/Completions/RimFracture.cpp +++ b/ApplicationCode/ProjectDataModel/Completions/RimFracture.cpp @@ -1,6 +1,7 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2017 Statoil ASA +// Copyright (C) 2017-2018 Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -24,6 +25,8 @@ #include "RiaEclipseUnitTools.h" #include "RiaLogging.h" +#include "Riu3DMainWindowTools.h" + #include "RigMainGrid.h" #include "Rim3dView.h" @@ -39,13 +42,17 @@ #include "RimReservoirCellResultsStorage.h" #include "RimStimPlanColors.h" #include "RimStimPlanFractureTemplate.h" -#include "RimWellPathFractureCollection.h" #include "RivWellFracturePartMgr.h" +#include "FractureCommands/RicNewEllipseFractureTemplateFeature.h" +#include "FractureCommands/RicNewStimPlanFractureTemplateFeature.h" + #include "cafHexGridIntersectionTools/cafHexGridIntersectionTools.h" #include "cafPdmUiDoubleSliderEditor.h" +#include "cafPdmUiPushButtonEditor.h" +#include "cafPdmUiToolButtonEditor.h" #include "cafPdmUiTreeOrdering.h" #include "cvfBoundingBox.h" @@ -57,7 +64,7 @@ #include #include -#include +#include CAF_PDM_XML_ABSTRACT_SOURCE_INIT(RimFracture, "Fracture"); @@ -94,6 +101,17 @@ RimFracture::RimFracture() CAF_PDM_InitObject("Fracture", "", "", ""); CAF_PDM_InitFieldNoDefault(&m_fractureTemplate, "FractureDef", "Fracture Template", "", "", ""); + CAF_PDM_InitField(&m_editFractureTemplate, "EditTemplate", false, "Edit", "", "", ""); + m_editFractureTemplate.uiCapability()->setUiEditorTypeName(caf::PdmUiToolButtonEditor::uiEditorTypeName()); + m_editFractureTemplate.uiCapability()->setUiLabelPosition(caf::PdmUiItemInfo::HIDDEN); + + CAF_PDM_InitField(&m_createEllipseFractureTemplate, "CreateEllipseTemplate", false, "No Fracture Templates Found.", "", "", ""); + m_createEllipseFractureTemplate.uiCapability()->setUiEditorTypeName(caf::PdmUiPushButtonEditor::uiEditorTypeName()); + m_createEllipseFractureTemplate.uiCapability()->setUiLabelPosition(caf::PdmUiItemInfo::TOP); + + CAF_PDM_InitField(&m_createStimPlanFractureTemplate, "CreateStimPlanTemplate", false, "Create New Template?", "", "", ""); + m_createStimPlanFractureTemplate.uiCapability()->setUiEditorTypeName(caf::PdmUiPushButtonEditor::uiEditorTypeName()); + m_createStimPlanFractureTemplate.uiCapability()->setUiLabelPosition(caf::PdmUiItemInfo::TOP); CAF_PDM_InitFieldNoDefault(&m_anchorPosition, "AnchorPosition", "Anchor Position", "", "", ""); m_anchorPosition.uiCapability()->setUiHidden(true); @@ -210,7 +228,23 @@ void RimFracture::fieldChangedByUi(const caf::PdmFieldHandle* changedField, cons setFractureTemplate(m_fractureTemplate); setDefaultFractureColorResult(); } - + else if (changedField == &m_editFractureTemplate) + { + m_editFractureTemplate = false; + if (m_fractureTemplate != nullptr) + { + Riu3DMainWindowTools::selectAsCurrentItem(m_fractureTemplate()); + } + } + else if (changedField == &m_createEllipseFractureTemplate) + { + m_createEllipseFractureTemplate = false; + RicNewEllipseFractureTemplateFeature::createNewTemplateForFractureAndUpdate(this); + } + else if (changedField == &m_createStimPlanFractureTemplate) + { + RicNewStimPlanFractureTemplateFeature::createNewTemplateForFractureAndUpdate(this); + } if ( changedField == &m_azimuth || changedField == &m_fractureTemplate || changedField == &m_stimPlanTimeIndexToPlot @@ -287,16 +321,6 @@ void RimFracture::clearCachedNonDarcyProperties() m_cachedFractureProperties = NonDarcyData(); } -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -bool RimFracture::isEnabled() const -{ - RimWellPathFractureCollection* fractureCollection = nullptr; - this->firstAncestorOrThisOfTypeAsserted(fractureCollection); - return fractureCollection->isChecked() && isChecked(); -} - //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -537,7 +561,7 @@ QList RimFracture::calculateValueOptions(const caf::PdmF if (fieldNeedingOptions == &m_fractureTemplate) { RimOilField* oilField = proj->activeOilField(); - if (oilField && oilField->fractureDefinitionCollection) + if (oilField && oilField->fractureDefinitionCollection()) { RimFractureTemplateCollection* fracDefColl = oilField->fractureDefinitionCollection(); @@ -690,6 +714,18 @@ void RimFracture::defineEditorAttribute(const caf::PdmFieldHandle* field, myAttr->m_maximum = 1.0; } } + + if (field == &m_createEllipseFractureTemplate) + { + auto myAttr = dynamic_cast(attribute); + myAttr->m_buttonText = "Ellipse Template"; + } + + if (field == &m_createStimPlanFractureTemplate) + { + auto myAttr = dynamic_cast(attribute); + myAttr->m_buttonText = "StimPlan Template"; + } } //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/ProjectDataModel/Completions/RimFracture.h b/ApplicationCode/ProjectDataModel/Completions/RimFracture.h index 72568c69c4..973b2f4152 100644 --- a/ApplicationCode/ProjectDataModel/Completions/RimFracture.h +++ b/ApplicationCode/ProjectDataModel/Completions/RimFracture.h @@ -1,6 +1,7 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2017 Statoil ASA +// Copyright (C) 2017-2018 Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -129,7 +130,6 @@ class RimFracture : public RimCheckableNamedObject, public Rim3dPropertiesInterf friend class RimFractureTemplate; // RimWellPathCompletionsInterface overrides. - bool isEnabled() const override; RiaDefines::WellPathComponentType componentType() const override; QString componentLabel() const override; QString componentTypeLabel() const override; @@ -154,6 +154,9 @@ class RimFracture : public RimCheckableNamedObject, public Rim3dPropertiesInterf protected: caf::PdmPtrField m_fractureTemplate; + caf::PdmField m_editFractureTemplate; + caf::PdmField m_createEllipseFractureTemplate; + caf::PdmField m_createStimPlanFractureTemplate; caf::PdmProxyValueField m_uiAnchorPosition; caf::PdmField< RiaEclipseUnitTools::UnitSystemType > m_fractureUnit; diff --git a/ApplicationCode/ProjectDataModel/Completions/RimFractureContainmentTools.cpp b/ApplicationCode/ProjectDataModel/Completions/RimFractureContainmentTools.cpp index 2610d27830..556f68db7b 100644 --- a/ApplicationCode/ProjectDataModel/Completions/RimFractureContainmentTools.cpp +++ b/ApplicationCode/ProjectDataModel/Completions/RimFractureContainmentTools.cpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018 Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by diff --git a/ApplicationCode/ProjectDataModel/Completions/RimFractureContainmentTools.h b/ApplicationCode/ProjectDataModel/Completions/RimFractureContainmentTools.h index 3b7158027d..4a542a713e 100644 --- a/ApplicationCode/ProjectDataModel/Completions/RimFractureContainmentTools.h +++ b/ApplicationCode/ProjectDataModel/Completions/RimFractureContainmentTools.h @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018 Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by diff --git a/ApplicationCode/ProjectDataModel/Completions/RimFractureTemplate.cpp b/ApplicationCode/ProjectDataModel/Completions/RimFractureTemplate.cpp index d38cea8714..c6239a56c3 100644 --- a/ApplicationCode/ProjectDataModel/Completions/RimFractureTemplate.cpp +++ b/ApplicationCode/ProjectDataModel/Completions/RimFractureTemplate.cpp @@ -208,7 +208,7 @@ void RimFractureTemplate::setName(const QString& name) //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RimFractureTemplate::setFractureTemplateUnit(RiaEclipseUnitTools::UnitSystemType unitSystem) +void RimFractureTemplate::setUnitSystem(RiaEclipseUnitTools::UnitSystemType unitSystem) { m_fractureTemplateUnit = unitSystem; } diff --git a/ApplicationCode/ProjectDataModel/Completions/RimFractureTemplate.h b/ApplicationCode/ProjectDataModel/Completions/RimFractureTemplate.h index 1ea474e8a9..0cd7d79784 100644 --- a/ApplicationCode/ProjectDataModel/Completions/RimFractureTemplate.h +++ b/ApplicationCode/ProjectDataModel/Completions/RimFractureTemplate.h @@ -153,7 +153,7 @@ class RimFractureTemplate : public caf::PdmObject virtual std::vector> uiResultNamesWithUnit() const = 0; void setName(const QString& name); - void setFractureTemplateUnit(RiaEclipseUnitTools::UnitSystemType unitSystem); + void setUnitSystem(RiaEclipseUnitTools::UnitSystemType unitSystem); void setDefaultWellDiameterFromUnit(); bool isNonDarcyFlowEnabled() const; diff --git a/ApplicationCode/ProjectDataModel/Completions/RimFractureTemplateCollection.cpp b/ApplicationCode/ProjectDataModel/Completions/RimFractureTemplateCollection.cpp index 93a4ed3b47..f3afb95d29 100644 --- a/ApplicationCode/ProjectDataModel/Completions/RimFractureTemplateCollection.cpp +++ b/ApplicationCode/ProjectDataModel/Completions/RimFractureTemplateCollection.cpp @@ -99,6 +99,22 @@ std::vector RimFractureTemplateCollection::fractureTemplat return templates; } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimEllipseFractureTemplate* RimFractureTemplateCollection::addDefaultEllipseTemplate() +{ + RimEllipseFractureTemplate* ellipseFractureTemplate = new RimEllipseFractureTemplate(); + + addFractureTemplate(ellipseFractureTemplate); + + ellipseFractureTemplate->setName("Ellipse Fracture Template"); + ellipseFractureTemplate->setUnitSystem(defaultUnitSystemType()); + ellipseFractureTemplate->setDefaultValuesFromUnit(); + + return ellipseFractureTemplate; +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/ProjectDataModel/Completions/RimFractureTemplateCollection.h b/ApplicationCode/ProjectDataModel/Completions/RimFractureTemplateCollection.h index 406fa53820..b62da3e0d3 100644 --- a/ApplicationCode/ProjectDataModel/Completions/RimFractureTemplateCollection.h +++ b/ApplicationCode/ProjectDataModel/Completions/RimFractureTemplateCollection.h @@ -24,6 +24,7 @@ #include "cafPdmObject.h" #include "cafPdmChildArrayField.h" +class RimEllipseFractureTemplate; class RimFractureTemplate; //================================================================================================== @@ -40,6 +41,7 @@ class RimFractureTemplateCollection : public caf::PdmObject RimFractureTemplate* fractureTemplate(int id) const; std::vector fractureTemplates() const; + RimEllipseFractureTemplate* addDefaultEllipseTemplate(); void addFractureTemplate(RimFractureTemplate* templ); RiaEclipseUnitTools::UnitSystemType defaultUnitSystemType() const; diff --git a/ApplicationCode/ProjectDataModel/Completions/RimMswCompletionParameters.cpp b/ApplicationCode/ProjectDataModel/Completions/RimMswCompletionParameters.cpp index 459127a089..9d6e4091e5 100644 --- a/ApplicationCode/ProjectDataModel/Completions/RimMswCompletionParameters.cpp +++ b/ApplicationCode/ProjectDataModel/Completions/RimMswCompletionParameters.cpp @@ -24,6 +24,14 @@ #include namespace caf { + template<> + void RimMswCompletionParameters::ReferenceMDEnum::setUp() + { + addItem(RimMswCompletionParameters::AUTO_REFERENCE_MD, "GridIntersectionRefMD", "Grid Entry Point"); + addItem(RimMswCompletionParameters::MANUAL_REFERENCE_MD, "ManualRefMD", "User Defined"); + setDefault(RimMswCompletionParameters::AUTO_REFERENCE_MD); + } + template<> void RimMswCompletionParameters::PressureDropEnum::setUp() { @@ -47,9 +55,20 @@ CAF_PDM_SOURCE_INIT(RimMswCompletionParameters, "RimMswCompletionParameters"); //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -RimMswCompletionParameters::RimMswCompletionParameters() +RimMswCompletionParameters::RimMswCompletionParameters(bool enableReferenceDepth /* = true */) + : m_enableReferenceDepth(enableReferenceDepth) { CAF_PDM_InitObject("MSW Completion Parameters", ":/CompletionsSymbol16x16.png", "", ""); + + CAF_PDM_InitFieldNoDefault(&m_refMDType, "RefMDType", "Reference MD", "", "", ""); + CAF_PDM_InitField(&m_refMD, "RefMD", 0.0, "", "", "", ""); + + if (!m_enableReferenceDepth) + { + m_refMDType.xmlCapability()->disableIO(); + m_refMD.xmlCapability()->disableIO(); + } + CAF_PDM_InitField(&m_linerDiameter, "LinerDiameter", std::numeric_limits::infinity(), "Liner Inner Diameter", "", "", ""); CAF_PDM_InitField(&m_roughnessFactor, "RoughnessFactor", std::numeric_limits::infinity(), "Roughness Factor", "", "", ""); @@ -69,6 +88,26 @@ RimMswCompletionParameters::~RimMswCompletionParameters() } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimMswCompletionParameters::ReferenceMDType RimMswCompletionParameters::referenceMDType() const +{ + return m_refMDType(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +double RimMswCompletionParameters::manualReferenceMD() const +{ + if (m_refMDType == AUTO_REFERENCE_MD) + { + return std::numeric_limits::infinity(); + } + return m_refMD; +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -159,6 +198,22 @@ double RimMswCompletionParameters::maxSegmentLength() const return m_enforceMaxSegmentLength ? m_maxSegmentLength : std::numeric_limits::infinity(); } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimMswCompletionParameters::setReferenceMDType(ReferenceMDType refType) +{ + m_refMDType = refType; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimMswCompletionParameters::setManualReferenceMD(double manualRefMD) +{ + m_refMD = manualRefMD; +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -196,6 +251,12 @@ void RimMswCompletionParameters::setLengthAndDepth(LengthAndDepthType lengthAndD //-------------------------------------------------------------------------------------------------- void RimMswCompletionParameters::fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue) { + if (changedField == &m_refMDType) + { + m_refMD.uiCapability()->setUiHidden(m_refMDType == AUTO_REFERENCE_MD); + this->updateAllRequiredEditors(); + } + if (changedField == &m_enforceMaxSegmentLength) { m_maxSegmentLength.uiCapability()->setUiHidden(!m_enforceMaxSegmentLength()); @@ -226,6 +287,13 @@ void RimMswCompletionParameters::defineUiOrdering(QString uiConfigName, caf::Pdm } } + if (m_enableReferenceDepth) + { + uiOrdering.add(&m_refMDType); + uiOrdering.add(&m_refMD); + m_refMD.uiCapability()->setUiHidden(m_refMDType == AUTO_REFERENCE_MD); + } + uiOrdering.add(&m_linerDiameter); uiOrdering.add(&m_roughnessFactor); uiOrdering.add(&m_pressureDrop); diff --git a/ApplicationCode/ProjectDataModel/Completions/RimMswCompletionParameters.h b/ApplicationCode/ProjectDataModel/Completions/RimMswCompletionParameters.h index 2b15ab8b34..9d39ab1448 100644 --- a/ApplicationCode/ProjectDataModel/Completions/RimMswCompletionParameters.h +++ b/ApplicationCode/ProjectDataModel/Completions/RimMswCompletionParameters.h @@ -27,24 +27,32 @@ class RimMswCompletionParameters : public caf::PdmObject { CAF_PDM_HEADER_INIT; public: + enum ReferenceMDType + { + AUTO_REFERENCE_MD = 0, + MANUAL_REFERENCE_MD + }; + enum PressureDropType { HYDROSTATIC, HYDROSTATIC_FRICTION, HYDROSTATIC_FRICTION_ACCELERATION }; - typedef caf::AppEnum PressureDropEnum; - enum LengthAndDepthType { ABS, INC }; + typedef caf::AppEnum ReferenceMDEnum; + typedef caf::AppEnum PressureDropEnum; typedef caf::AppEnum LengthAndDepthEnum; - RimMswCompletionParameters(); + RimMswCompletionParameters(bool enableReferenceDepth = true); ~RimMswCompletionParameters() override; + ReferenceMDType referenceMDType() const; + double manualReferenceMD() const; double linerDiameter(RiaEclipseUnitTools::UnitSystem unitSystem) const; static double defaultLinerDiameter(RiaEclipseUnitTools::UnitSystem unitSystem); double roughnessFactor(RiaEclipseUnitTools::UnitSystem unitSystem) const; @@ -52,22 +60,27 @@ class RimMswCompletionParameters : public caf::PdmObject PressureDropEnum pressureDrop() const; LengthAndDepthEnum lengthAndDepth() const; double maxSegmentLength() const; + + void setReferenceMDType(ReferenceMDType refType); + void setManualReferenceMD(double manualRefMD); void setLinerDiameter(double diameter); void setRoughnessFactor(double roughnessFactor); void setPressureDrop(PressureDropType pressureDropType); void setLengthAndDepth(LengthAndDepthType lengthAndDepthType); - void setUnitSystemSpecificDefaults(); protected: void fieldChangedByUi(const caf::PdmFieldHandle* changedField, - const QVariant& oldValue, - const QVariant& newValue) override; - void defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering) override; + const QVariant& oldValue, + const QVariant& newValue) override; + void defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering) override; void initAfterRead() override; private: + caf::PdmField m_refMDType; + caf::PdmField m_refMD; + caf::PdmField m_linerDiameter; caf::PdmField m_roughnessFactor; @@ -76,4 +89,6 @@ class RimMswCompletionParameters : public caf::PdmObject caf::PdmField m_enforceMaxSegmentLength; caf::PdmField m_maxSegmentLength; + + bool m_enableReferenceDepth; }; diff --git a/ApplicationCode/ProjectDataModel/Completions/RimMultipleValveLocations.cpp b/ApplicationCode/ProjectDataModel/Completions/RimMultipleValveLocations.cpp index 6a351efd2f..a6167f92f1 100644 --- a/ApplicationCode/ProjectDataModel/Completions/RimMultipleValveLocations.cpp +++ b/ApplicationCode/ProjectDataModel/Completions/RimMultipleValveLocations.cpp @@ -36,7 +36,7 @@ namespace caf { template<> void AppEnum::setUp() { - addItem(RimMultipleValveLocations::VALVE_COUNT, "VALVE_COUNT", "Start/End/Number of Subs"); + addItem(RimMultipleValveLocations::VALVE_COUNT, "VALVE_COUNT", "Start/End/Number"); addItem(RimMultipleValveLocations::VALVE_SPACING, "VALVE_SPACING", "Start/End/Spacing"); addItem(RimMultipleValveLocations::VALVE_CUSTOM, "VALVE_CUSTOM", "User Specification"); setDefault(RimMultipleValveLocations::VALVE_COUNT); @@ -67,6 +67,21 @@ RimMultipleValveLocations::RimMultipleValveLocations() m_locationOfValves.uiCapability()->setUiEditorTypeName(caf::PdmUiListEditor::uiEditorTypeName()); } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimMultipleValveLocations::perforationIntervalUpdated() +{ + double existingRangeStart = m_rangeStart(); + double existingRangeEnd = m_rangeEnd(); + m_rangeStart = cvf::Math::clamp(m_rangeStart(), perforationStartMD(), perforationEndMD()); + m_rangeEnd = cvf::Math::clamp(m_rangeEnd(), perforationStartMD(), perforationEndMD()); + if (existingRangeStart != m_rangeStart() || existingRangeEnd != m_rangeEnd()) + { + computeRangesAndLocations(); + } +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -144,9 +159,13 @@ void RimMultipleValveLocations::computeRangesAndLocations() double firstWellPathMD = rigWellPathGeo->m_measuredDepths.front(); double lastWellPathMD = rigWellPathGeo->m_measuredDepths.back(); - for (auto md : locationsFromStartSpacingAndCount(m_rangeStart, m_rangeValveSpacing, m_rangeValveCount)) + double overlapStart = std::max(firstWellPathMD, m_rangeStart()); + double overlapEnd = std::min(lastWellPathMD, m_rangeEnd()); + double overlap = std::max(0.0, overlapEnd - overlapStart); + + if (overlap) { - if (md >= firstWellPathMD && md <= lastWellPathMD) + for (auto md : locationsFromStartSpacingAndCount(overlapStart, m_rangeValveSpacing, m_rangeValveCount)) { validMeasuredDepths.push_back(md); } @@ -291,8 +310,8 @@ void RimMultipleValveLocations::fieldChangedByUi(const caf::PdmFieldHandle* chan changedField == &m_rangeValveSpacing) { recomputeLocations = true; - m_rangeStart = cvf::Math::clamp(m_rangeStart(), rangeMin(), rangeMax()); - m_rangeEnd = cvf::Math::clamp(m_rangeEnd(), rangeMin(), rangeMax()); + m_rangeStart = cvf::Math::clamp(m_rangeStart(), perforationStartMD(), perforationEndMD()); + m_rangeEnd = cvf::Math::clamp(m_rangeEnd(), perforationStartMD(), perforationEndMD()); } if (changedField == &m_rangeValveSpacing) @@ -333,7 +352,7 @@ void RimMultipleValveLocations::fieldChangedByUi(const caf::PdmFieldHandle* chan } else if (valve) { - valve->geometryUpdated(); + valve->multipleValveGeometryUpdated(); } } @@ -372,7 +391,7 @@ double RimMultipleValveLocations::minimumSpacingMeters() const //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -double RimMultipleValveLocations::rangeMin() const +double RimMultipleValveLocations::perforationStartMD() const { const RimPerforationInterval* perfInterval = nullptr; this->firstAncestorOrThisOfType(perfInterval); @@ -387,7 +406,7 @@ double RimMultipleValveLocations::rangeMin() const //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -double RimMultipleValveLocations::rangeMax() const +double RimMultipleValveLocations::perforationEndMD() const { const RimPerforationInterval* perfInterval = nullptr; this->firstAncestorOrThisOfType(perfInterval); diff --git a/ApplicationCode/ProjectDataModel/Completions/RimMultipleValveLocations.h b/ApplicationCode/ProjectDataModel/Completions/RimMultipleValveLocations.h index 746d56cb23..d96b44aa90 100644 --- a/ApplicationCode/ProjectDataModel/Completions/RimMultipleValveLocations.h +++ b/ApplicationCode/ProjectDataModel/Completions/RimMultipleValveLocations.h @@ -41,6 +41,7 @@ class RimMultipleValveLocations : public caf::PdmObject public: RimMultipleValveLocations(); + void perforationIntervalUpdated(); double measuredDepth(size_t valveIndex) const; double rangeStart() const; double rangeEnd() const; @@ -56,14 +57,14 @@ class RimMultipleValveLocations : public caf::PdmObject int valveCount, const std::vector& locationOfValves); protected: - virtual void fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue) override; - virtual void defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering) override; + void fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue) override; + void defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering) override; private: int rangeCountFromSpacing() const; double minimumSpacingMeters() const; - double rangeMin() const; - double rangeMax() const; + double perforationStartMD() const; + double perforationEndMD() const; static std::vector locationsFromStartSpacingAndCount(double start, double spacing, size_t count); private: diff --git a/ApplicationCode/ProjectDataModel/Completions/RimPerforationCollection.cpp b/ApplicationCode/ProjectDataModel/Completions/RimPerforationCollection.cpp index 303e9f49f3..e7573dbc7c 100644 --- a/ApplicationCode/ProjectDataModel/Completions/RimPerforationCollection.cpp +++ b/ApplicationCode/ProjectDataModel/Completions/RimPerforationCollection.cpp @@ -35,6 +35,18 @@ #include "Riu3DMainWindowTools.h" +namespace caf +{ +template<> +void RimPerforationCollection::ReferenceMDEnum::setUp() +{ + addItem(RimPerforationCollection::AUTO_REFERENCE_MD, "GridIntersectionRefMD", "Grid Entry Point"); + addItem(RimPerforationCollection::MANUAL_REFERENCE_MD, "ManualRefMD", "User Defined"); + setDefault(RimPerforationCollection::AUTO_REFERENCE_MD); +} +} // namespace caf + + CAF_PDM_SOURCE_INIT(RimPerforationCollection, "PerforationCollection"); //-------------------------------------------------------------------------------------------------- @@ -93,35 +105,6 @@ void RimPerforationCollection::setUnitSystemSpecificDefaults() m_mswParameters->setUnitSystemSpecificDefaults(); } -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RimPerforationCollection::defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering) -{ - caf::PdmUiGroup* mswGroup = uiOrdering.addNewGroup("Multi Segment Well Options"); - m_mswParameters->uiOrdering(uiConfigName, *mswGroup); - - m_nonDarcyParameters->uiOrdering(uiConfigName, uiOrdering); - uiOrdering.skipRemainingFields(true); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RimPerforationCollection::fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue) -{ - RimProject* proj; - this->firstAncestorOrThisOfTypeAsserted(proj); - if (changedField == &m_isChecked) - { - proj->reloadCompletionTypeResultsInAllViews(); - } - else - { - proj->scheduleCreateDisplayModelAndRedrawAllViews(); - } -} - //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -185,3 +168,50 @@ std::vector RimPerforationCollection::perforation return myPerforations; } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector RimPerforationCollection::activePerforations() const +{ + std::vector myActivePerforations; + + for (const auto& perforation : m_perforations) + { + if (perforation->isChecked()) + { + myActivePerforations.push_back(perforation); + } + } + + return myActivePerforations; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimPerforationCollection::defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering) +{ + caf::PdmUiGroup* mswGroup = uiOrdering.addNewGroup("Multi Segment Well Options"); + m_mswParameters->uiOrdering(uiConfigName, *mswGroup); + m_nonDarcyParameters->uiOrdering(uiConfigName, uiOrdering); + uiOrdering.skipRemainingFields(true); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimPerforationCollection::fieldChangedByUi(const caf::PdmFieldHandle* changedField, + const QVariant& oldValue, + const QVariant& newValue) +{ + RimProject* proj; + this->firstAncestorOrThisOfTypeAsserted(proj); + if (changedField == &m_isChecked) + { + proj->reloadCompletionTypeResultsInAllViews(); + } + else + { + proj->scheduleCreateDisplayModelAndRedrawAllViews(); + } +} \ No newline at end of file diff --git a/ApplicationCode/ProjectDataModel/Completions/RimPerforationCollection.h b/ApplicationCode/ProjectDataModel/Completions/RimPerforationCollection.h index 4accf24bac..566a4cbe69 100644 --- a/ApplicationCode/ProjectDataModel/Completions/RimPerforationCollection.h +++ b/ApplicationCode/ProjectDataModel/Completions/RimPerforationCollection.h @@ -40,6 +40,13 @@ class RimPerforationCollection : public RimCheckableNamedObject CAF_PDM_HEADER_INIT; public: + enum ReferenceMDType + { + AUTO_REFERENCE_MD = 0, + MANUAL_REFERENCE_MD + }; + typedef caf::AppEnum ReferenceMDEnum; + RimPerforationCollection(); ~RimPerforationCollection() override; @@ -48,6 +55,7 @@ class RimPerforationCollection : public RimCheckableNamedObject void setUnitSystemSpecificDefaults(); void appendPerforation(RimPerforationInterval* perforation); std::vector perforations() const; + std::vector activePerforations() const; private: void defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering) override; diff --git a/ApplicationCode/ProjectDataModel/Completions/RimPerforationInterval.cpp b/ApplicationCode/ProjectDataModel/Completions/RimPerforationInterval.cpp index 8ad18b95bb..6f2fbbae8b 100644 --- a/ApplicationCode/ProjectDataModel/Completions/RimPerforationInterval.cpp +++ b/ApplicationCode/ProjectDataModel/Completions/RimPerforationInterval.cpp @@ -25,6 +25,7 @@ #include "RimPerforationCollection.h" #include "RimProject.h" +#include "RimWellLogTrack.h" #include "RimWellPath.h" #include "RimWellPathValve.h" @@ -98,14 +99,6 @@ void RimPerforationInterval::setCustomStartDate(const QDate& date) } } -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RimPerforationInterval::enableCustomEndDate(bool enable) -{ - m_useCustomEndDate = enable; -} - //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -233,6 +226,21 @@ std::vector RimPerforationInterval::valves() const return allValves; } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimPerforationInterval::updateAllReferringTracks() +{ + std::vector wellLogTracks; + + this->objectsWithReferringPtrFieldsOfType(wellLogTracks); + for (RimWellLogTrack* track : wellLogTracks) + { + track->loadDataAndUpdate(); + } + this->updateConnectedEditors(); +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -298,6 +306,17 @@ void RimPerforationInterval::fieldChangedByUi(const caf::PdmFieldHandle* changed const QVariant& oldValue, const QVariant& newValue) { + if (changedField == &m_startMD || + changedField == &m_endMD) + { + for (RimWellPathValve* valve : m_valves()) + { + valve->perforationIntervalUpdated(); + } + } + + this->updateAllReferringTracks(); + RimProject* proj = nullptr; this->firstAncestorOrThisOfTypeAsserted(proj); proj->reloadCompletionTypeResultsInAllViews(); diff --git a/ApplicationCode/ProjectDataModel/Completions/RimPerforationInterval.h b/ApplicationCode/ProjectDataModel/Completions/RimPerforationInterval.h index 3dfffc3459..24e173f4e1 100644 --- a/ApplicationCode/ProjectDataModel/Completions/RimPerforationInterval.h +++ b/ApplicationCode/ProjectDataModel/Completions/RimPerforationInterval.h @@ -52,7 +52,6 @@ class RimPerforationInterval : public RimCheckableNamedObject, void enableCustomStartDate(bool enable); void setCustomStartDate(const QDate& date); - void enableCustomEndDate(bool enable); void setCustomEndDate(const QDate& date); void setDiameter(double diameter); @@ -68,6 +67,7 @@ class RimPerforationInterval : public RimCheckableNamedObject, void addValve(RimWellPathValve* valve); std::vector valves() const; + void updateAllReferringTracks(); // RimWellPathCompletionInterface overrides bool isEnabled() const override; diff --git a/ApplicationCode/ProjectDataModel/Completions/RimSimWellFracture.cpp b/ApplicationCode/ProjectDataModel/Completions/RimSimWellFracture.cpp index ca93a9cfe7..5172ba81a0 100644 --- a/ApplicationCode/ProjectDataModel/Completions/RimSimWellFracture.cpp +++ b/ApplicationCode/ProjectDataModel/Completions/RimSimWellFracture.cpp @@ -111,16 +111,6 @@ double RimSimWellFracture::wellAzimuthAtFracturePosition() const return simWellAzimuth; } -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -double RimSimWellFracture::wellDipAtFracturePosition() -{ - computeSimWellBranchesIfRequired(); - double simWellDip = m_branchCenterLines[m_branchIndex].simWellDipAngle(fracturePosition()); - return simWellDip; -} - //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -154,6 +144,14 @@ std::vector RimSimWellFracture::perforationLengthCenterLineCoords() return coords; } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RimSimWellFracture::isEnabled() const +{ + return isChecked(); +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/ProjectDataModel/Completions/RimSimWellFracture.h b/ApplicationCode/ProjectDataModel/Completions/RimSimWellFracture.h index 64535e3332..e201022bd7 100644 --- a/ApplicationCode/ProjectDataModel/Completions/RimSimWellFracture.h +++ b/ApplicationCode/ProjectDataModel/Completions/RimSimWellFracture.h @@ -42,7 +42,6 @@ class RimSimWellFracture : public RimFracture void updateAzimuthBasedOnWellAzimuthAngle() override; double wellAzimuthAtFracturePosition() const override; - double wellDipAtFracturePosition(); double fractureMD() const override { return m_location; @@ -57,6 +56,8 @@ class RimSimWellFracture : public RimFracture std::vector perforationLengthCenterLineCoords() const override; + bool isEnabled() const override; // RimWellPathCompletionsInterface override + protected: void fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue) override; void defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering) override; diff --git a/ApplicationCode/ProjectDataModel/Completions/RimStimPlanFractureTemplate.cpp b/ApplicationCode/ProjectDataModel/Completions/RimStimPlanFractureTemplate.cpp index c5aa69e585..f97bc3049e 100644 --- a/ApplicationCode/ProjectDataModel/Completions/RimStimPlanFractureTemplate.cpp +++ b/ApplicationCode/ProjectDataModel/Completions/RimStimPlanFractureTemplate.cpp @@ -268,14 +268,14 @@ void RimStimPlanFractureTemplate::loadDataAndUpdate() if (fractureTemplateUnit() == RiaEclipseUnitTools::UNITS_UNKNOWN) { - setFractureTemplateUnit(m_stimPlanFractureDefinitionData->unitSet()); + setUnitSystem(m_stimPlanFractureDefinitionData->unitSet()); } m_readError = false; } else { - setFractureTemplateUnit(RiaEclipseUnitTools::UNITS_UNKNOWN); + setUnitSystem(RiaEclipseUnitTools::UNITS_UNKNOWN); m_readError = true; } @@ -755,7 +755,7 @@ void RimStimPlanFractureTemplate::convertToUnitSystem(RiaEclipseUnitTools::UnitS { if (m_fractureTemplateUnit() == neededUnit) return; - setFractureTemplateUnit(neededUnit); + setUnitSystem(neededUnit); RimFractureTemplate::convertToUnitSystem(neededUnit); m_readError = false; diff --git a/ApplicationCode/ProjectDataModel/Completions/RimValveTemplate.cpp b/ApplicationCode/ProjectDataModel/Completions/RimValveTemplate.cpp new file mode 100644 index 0000000000..a258489f66 --- /dev/null +++ b/ApplicationCode/ProjectDataModel/Completions/RimValveTemplate.cpp @@ -0,0 +1,270 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2018- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "RimValveTemplate.h" + +#include "RimWellPathAicdParameters.h" +#include "RimWellPathValve.h" + +#include "cafPdmUiTreeOrdering.h" + +CAF_PDM_SOURCE_INIT(RimValveTemplate, "ValveTemplate"); + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimValveTemplate::RimValveTemplate() +{ + CAF_PDM_InitObject("Valve Template", ":/ICDValve16x16.png", "", ""); + + CAF_PDM_InitField(&m_valveTemplateUnit, "UnitSystem", caf::AppEnum(RiaEclipseUnitTools::UNITS_UNKNOWN), "Units System", "", "", ""); + m_valveTemplateUnit.uiCapability()->setUiReadOnly(true); + + CAF_PDM_InitFieldNoDefault(&m_type, "CompletionType", "Type", "", "", ""); + m_type = RiaDefines::ICD; + CAF_PDM_InitField(&m_userLabel, "UserLabel", QString("Template"), "Name", "", "", ""); + + this->setName(fullLabel()); + + CAF_PDM_InitField(&m_orificeDiameter, "OrificeDiameter", 8.0, "Orifice Diameter [mm]", "", "", ""); + CAF_PDM_InitField(&m_flowCoefficient, "FlowCoefficient", 0.7, "Flow Coefficient", "", "", ""); + + CAF_PDM_InitFieldNoDefault(&m_aicdParameters, "AICDParameters", "AICD Parameters", "", "", ""); + m_aicdParameters = new RimWellPathAicdParameters; + m_aicdParameters.uiCapability()->setUiTreeHidden(true); + m_aicdParameters.uiCapability()->setUiTreeChildrenHidden(true); + +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimValveTemplate::~RimValveTemplate() +{ +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimValveTemplate::loadDataAndUpdate() +{ + +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimValveTemplate::setUnitSystem(RiaEclipseUnitTools::UnitSystemType unitSystem) +{ + m_valveTemplateUnit = unitSystem; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimValveTemplate::setDefaultValuesFromUnits() +{ + if (m_valveTemplateUnit == RiaEclipseUnitTools::UNITS_METRIC) + { + m_orificeDiameter = 8; + } + else if (m_valveTemplateUnit == RiaEclipseUnitTools::UNITS_FIELD) + { + m_orificeDiameter = 0.315; + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RiaDefines::WellPathComponentType RimValveTemplate::type() const +{ + return m_type(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimValveTemplate::setType(RiaDefines::WellPathComponentType type) +{ + CAF_ASSERT(type == RiaDefines::ICD || type == RiaDefines::AICD || RiaDefines::ICV); + + m_type = type; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RiaEclipseUnitTools::UnitSystemType RimValveTemplate::templateUnits() const +{ + return m_valveTemplateUnit; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +double RimValveTemplate::orificeDiameter() const +{ + return m_orificeDiameter; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +double RimValveTemplate::flowCoefficient() const +{ + return m_flowCoefficient; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +const RimWellPathAicdParameters* RimValveTemplate::aicdParameters() const +{ + return m_aicdParameters; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RimValveTemplate::typeLabel() const +{ + return m_type().uiText(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RimValveTemplate::fullLabel() const +{ + QString label = QString("%1: %2").arg(typeLabel()).arg(m_userLabel()); + return label; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimValveTemplate::setUserLabel(const QString& userLabel) +{ + m_userLabel = userLabel; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QList RimValveTemplate::calculateValueOptions(const caf::PdmFieldHandle* fieldNeedingOptions, + bool* useOptionsOnly) +{ + QList options; + + if (fieldNeedingOptions == &m_type) + { + std::set supportedTypes = {RiaDefines::ICD, RiaDefines::AICD, RiaDefines::ICV}; + for (RiaDefines::WellPathComponentType type : supportedTypes) + { + options.push_back(caf::PdmOptionItemInfo(CompletionTypeEnum::uiText(type), type)); + } + } + return options; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimValveTemplate::defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering) +{ + uiOrdering.add(&m_type); + uiOrdering.add(&m_userLabel); + uiOrdering.add(&m_valveTemplateUnit); + if (m_type() == RiaDefines::ICV || m_type() == RiaDefines::ICD) + { + if (m_valveTemplateUnit == RiaEclipseUnitTools::UNITS_METRIC) + { + m_orificeDiameter.uiCapability()->setUiName("Orifice Diameter [mm]"); + } + else if (m_valveTemplateUnit == RiaEclipseUnitTools::UNITS_FIELD) + { + m_orificeDiameter.uiCapability()->setUiName("Orifice Diameter [in]"); + } + } + + if (m_type() == RiaDefines::ICV || m_type() == RiaDefines::ICD) + { + caf::PdmUiGroup* group = uiOrdering.addNewGroup("MSW Valve Parameters"); + group->add(&m_orificeDiameter); + group->add(&m_flowCoefficient); + } + else + { + caf::PdmUiGroup* group = uiOrdering.addNewGroup("MSW AICD Parameters"); + m_aicdParameters->uiOrdering(uiConfigName, *group); + } + + bool readOnly = uiConfigName == QString("InsideValve"); + m_type.uiCapability()->setUiReadOnly(readOnly); + m_userLabel.uiCapability()->setUiReadOnly(readOnly); + m_orificeDiameter.uiCapability()->setUiReadOnly(readOnly); + m_flowCoefficient.uiCapability()->setUiReadOnly(readOnly); + + uiOrdering.skipRemainingFields(true); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimValveTemplate::fieldChangedByUi(const caf::PdmFieldHandle* changedField, + const QVariant& oldValue, + const QVariant& newValue) +{ + if (changedField == &m_type || changedField == &m_userLabel) + { + this->setName(fullLabel()); + } + if (changedField == &m_type) + { + std::vector referringFields; + this->referringPtrFields(referringFields); + for (caf::PdmFieldHandle* field : referringFields) + { + RimWellPathValve* valve = dynamic_cast(field->ownerObject()); + valve->templateUpdated(); + } + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimValveTemplate::defineUiTreeOrdering(caf::PdmUiTreeOrdering& uiTreeOrdering, QString uiConfigName /*= ""*/) +{ + this->setName(fullLabel()); + if (m_type() == RiaDefines::ICV) + { + this->setUiIcon(QIcon(":/ICVValve16x16.png")); + } + else if (m_type() == RiaDefines::ICD) + { + this->setUiIcon(QIcon(":/ICDValve16x16.png")); + } + else if (m_type() == RiaDefines::AICD) + { + this->setUiIcon(QIcon(":/AICDValve16x16.png")); + } + +} diff --git a/ApplicationCode/ProjectDataModel/Completions/RimValveTemplate.h b/ApplicationCode/ProjectDataModel/Completions/RimValveTemplate.h new file mode 100644 index 0000000000..e978c3424d --- /dev/null +++ b/ApplicationCode/ProjectDataModel/Completions/RimValveTemplate.h @@ -0,0 +1,72 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2018- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "RiaDefines.h" +#include "RiaEclipseUnitTools.h" + +#include "RimCheckableNamedObject.h" + +#include "cafPdmChildField.h" + +class RimWellPathAicdParameters; + +class RimValveTemplate : public RimNamedObject +{ + CAF_PDM_HEADER_INIT; +public: + + RimValveTemplate(); + ~RimValveTemplate() override; + + void loadDataAndUpdate(); + void setUnitSystem(RiaEclipseUnitTools::UnitSystemType unitSystem); + void setDefaultValuesFromUnits(); + + RiaDefines::WellPathComponentType type() const; + void setType(RiaDefines::WellPathComponentType type); + RiaEclipseUnitTools::UnitSystemType templateUnits() const; + double orificeDiameter() const; + double flowCoefficient() const; + const RimWellPathAicdParameters* aicdParameters() const; + QString typeLabel() const; + QString fullLabel() const; + void setUserLabel(const QString& userLabel); +protected: + QList calculateValueOptions(const caf::PdmFieldHandle* fieldNeedingOptions, + bool* useOptionsOnly) override; + void defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering) override; + void fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue) override; + void defineUiTreeOrdering(caf::PdmUiTreeOrdering& uiTreeOrdering, QString uiConfigName = "") override; + +private: + typedef caf::AppEnum CompletionTypeEnum; + + caf::PdmField m_valveTemplateUnit; + + caf::PdmField m_type; + caf::PdmField m_userLabel; + + // ICD and ICVs only + caf::PdmField m_orificeDiameter; + caf::PdmField m_flowCoefficient; + // AICDs + caf::PdmChildField m_aicdParameters; +}; + diff --git a/ApplicationCode/ProjectDataModel/Completions/RimValveTemplateCollection.cpp b/ApplicationCode/ProjectDataModel/Completions/RimValveTemplateCollection.cpp new file mode 100644 index 0000000000..54ecdfe785 --- /dev/null +++ b/ApplicationCode/ProjectDataModel/Completions/RimValveTemplateCollection.cpp @@ -0,0 +1,121 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2018- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "RimValveTemplateCollection.h" + +#include "RiaApplication.h" + +#include "RimProject.h" +#include "RimValveTemplate.h" + +CAF_PDM_SOURCE_INIT(RimValveTemplateCollection, "ValveTemplateCollection"); + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimValveTemplateCollection::RimValveTemplateCollection() +{ + CAF_PDM_InitObject("Valve Templates", ":/ICDValve16x16.png", "", ""); + CAF_PDM_InitFieldNoDefault(&m_valveDefinitions, "ValveDefinitions", "", "", "", ""); + CAF_PDM_InitFieldNoDefault(&m_defaultUnitsForValveTemplates, "ValveUnits", "Default unit system for valve templates", "", "", ""); + m_defaultUnitsForValveTemplates = RiaEclipseUnitTools::UNITS_METRIC; + m_valveDefinitions.uiCapability()->setUiHidden(true); + addDefaultValveTemplates(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimValveTemplateCollection::~RimValveTemplateCollection() +{ +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector RimValveTemplateCollection::valveTemplates() const +{ + std::vector templates; + for (auto& templ : m_valveDefinitions) + { + templates.push_back(templ); + } + return templates; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimValveTemplateCollection::addValveTemplate(RimValveTemplate* valveTemplate) +{ + m_valveDefinitions.push_back(valveTemplate); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimValveTemplateCollection::removeAndDeleteValveTemplate(RimValveTemplate* valveTemplate) +{ + m_valveDefinitions.removeChildObject(valveTemplate); + delete valveTemplate; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RiaEclipseUnitTools::UnitSystemType RimValveTemplateCollection::defaultUnitSystemType() const +{ + return m_defaultUnitsForValveTemplates; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimValveTemplateCollection::setDefaultUnitSystemBasedOnLoadedCases() +{ + RimProject* proj = RiaApplication::instance()->project(); + + auto commonUnitSystem = proj->commonUnitSystemForAllCases(); + if (commonUnitSystem != RiaEclipseUnitTools::UNITS_UNKNOWN) + { + m_defaultUnitsForValveTemplates = commonUnitSystem; + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimValveTemplateCollection::addDefaultValveTemplates() +{ + RimValveTemplate* aicd = new RimValveTemplate; + aicd->setType(RiaDefines::AICD); + aicd->setUserLabel("Valve Template #1"); + + RimValveTemplate* icd = new RimValveTemplate; + icd->setType(RiaDefines::ICD); + icd->setUserLabel("Valve Template #2"); + + RimValveTemplate* icv = new RimValveTemplate; + icv->setType(RiaDefines::ICV); + icv->setUserLabel("Valve Template #3"); + + addValveTemplate(aicd); + addValveTemplate(icd); + addValveTemplate(icv); +} diff --git a/ApplicationCode/ProjectDataModel/Completions/RimValveTemplateCollection.h b/ApplicationCode/ProjectDataModel/Completions/RimValveTemplateCollection.h new file mode 100644 index 0000000000..0e2c79c98b --- /dev/null +++ b/ApplicationCode/ProjectDataModel/Completions/RimValveTemplateCollection.h @@ -0,0 +1,52 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2018- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "RiaEclipseUnitTools.h" + +#include "cafPdmField.h" +#include "cafPdmObject.h" +#include "cafPdmChildArrayField.h" + +class RimValveTemplate; + +//================================================================================================== +/// +/// +//================================================================================================== +class RimValveTemplateCollection : public caf::PdmObject +{ + CAF_PDM_HEADER_INIT; + +public: + RimValveTemplateCollection(); + ~RimValveTemplateCollection() override; + + std::vector valveTemplates() const; + void addValveTemplate(RimValveTemplate* valveTemplate); + void removeAndDeleteValveTemplate(RimValveTemplate* valveTemplate); + void addDefaultValveTemplates(); + + RiaEclipseUnitTools::UnitSystemType defaultUnitSystemType() const; + void setDefaultUnitSystemBasedOnLoadedCases(); + +private: + caf::PdmChildArrayField m_valveDefinitions; + caf::PdmField m_defaultUnitsForValveTemplates; +}; diff --git a/ApplicationCode/ProjectDataModel/Completions/RimWellPathAicdParameters.cpp b/ApplicationCode/ProjectDataModel/Completions/RimWellPathAicdParameters.cpp new file mode 100644 index 0000000000..fdeb8fb238 --- /dev/null +++ b/ApplicationCode/ProjectDataModel/Completions/RimWellPathAicdParameters.cpp @@ -0,0 +1,219 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2018- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// +#include "RimWellPathAicdParameters.h" + +#include "RimPerforationInterval.h" +#include "RimWellPath.h" +#include "RimWellPathValve.h" + +#include "cafPdmUiDoubleValueEditor.h" +#include "cafPdmUiGroup.h" +#include "cafPdmUiLineEditor.h" +#include "cafPdmDoubleStringValidator.h" + +#include + +CAF_PDM_SOURCE_INIT(RimWellPathAicdParameters, "WellPathAicdParameters"); + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimWellPathAicdParameters::RimWellPathAicdParameters() +{ + // clang-format off + CAF_PDM_InitObject("RimWellPathAicdParameters", "", "", ""); + + CAF_PDM_InitField(&m_deviceOpen, "DeviceOpen", true, "Device Open?", "", "", ""); + + CAF_PDM_InitFieldNoDefault(&m_aicdParameterFields[AICD_STRENGTH], "StrengthAICD", "Strength of AICD", "", "", ""); + CAF_PDM_InitFieldNoDefault(&m_aicdParameterFields[AICD_DENSITY_CALIB_FLUID], "DensityCalibrationFluid", "Calibration Fluid Density (kg/m^3)", "", "", ""); + CAF_PDM_InitFieldNoDefault(&m_aicdParameterFields[AICD_VISCOSITY_CALIB_FLUID], "ViscosityCalibrationFluid", "Calibration Fluid Viscosity (cP)", "", "", ""); + CAF_PDM_InitFieldNoDefault(&m_aicdParameterFields[AICD_VOL_FLOW_EXP], "VolumeFlowRateExponent", "Volume Flow Rate Exponent", "", "", ""); + CAF_PDM_InitFieldNoDefault(&m_aicdParameterFields[AICD_VISOSITY_FUNC_EXP], "ViscosityFunctionExponent", "Viscosity Function Exponent", "", "", ""); + + CAF_PDM_InitField(&m_aicdParameterFields[AICD_CRITICAL_WATER_IN_LIQUID_FRAC], "CriticalWaterLiquidFractionEmul", QString("1*"), "Critical Water in Liquid Fraction for emulsions", "", "", ""); + CAF_PDM_InitField(&m_aicdParameterFields[AICD_EMULSION_VISC_TRANS_REGION], "ViscosityTransitionRegionEmul", QString("1*"), "Emulsion Viscosity Transition Region", "", "", ""); + CAF_PDM_InitField(&m_aicdParameterFields[AICD_MAX_RATIO_EMULSION_VISC], "MaxRatioOfEmulsionVisc", QString("1*"), "Max Ratio of Emulsion to Continuous Viscosity", "", "", ""); + CAF_PDM_InitField(&m_aicdParameterFields[AICD_MAX_FLOW_RATE], "MaxFlowRate", QString("1*"), "Max Flow Rate for AICD Device (m^3 / day)", "", "", ""); + CAF_PDM_InitField(&m_aicdParameterFields[AICD_EXP_OIL_FRAC_DENSITY], "ExponentOilDensity", QString("1*"), "Density Exponent of Oil Fraction", "", "", ""); + CAF_PDM_InitField(&m_aicdParameterFields[AICD_EXP_WATER_FRAC_DENSITY], "ExponentWaterDensity", QString("1*"), "Density Exponent of Water Fraction", "", "", ""); + CAF_PDM_InitField(&m_aicdParameterFields[AICD_EXP_GAS_FRAC_DENSITY], "ExponentGasDensity", QString("1*"), "Density Exponent of Gas Fraction", "", "", ""); + CAF_PDM_InitField(&m_aicdParameterFields[AICD_EXP_OIL_FRAC_VISCOSITY], "ExponentOilViscosity", QString("1*"), "Viscosity Exponent of Oil Fraction", "", "", ""); + CAF_PDM_InitField(&m_aicdParameterFields[AICD_EXP_WATER_FRAC_VISCOSITY], "ExponentWaterViscosity", QString("1*"), "Viscosity Exponent of Water Fraction", "", "", ""); + CAF_PDM_InitField(&m_aicdParameterFields[AICD_EXP_GAS_FRAC_VISCOSITY], "ExponentGasViscosity", QString("1*"), "Viscosity Exponent of Gas Fraction", "", "", ""); + + std::vector allFields; + this->fields(allFields); + for (caf::PdmFieldHandle* field : allFields) + { + caf::PdmField* stringField = dynamic_cast*>(field); + if (stringField) + { + stringField->uiCapability()->setUiEditorTypeName(caf::PdmUiLineEditor::uiEditorTypeName()); + } + } + + // clang-format on +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimWellPathAicdParameters::~RimWellPathAicdParameters() {} + +//-------------------------------------------------------------------------------------------------- +/// Requires that all the required parameters are set and a proper value +//-------------------------------------------------------------------------------------------------- +bool RimWellPathAicdParameters::isValid() const +{ + for (const caf::PdmField* stringField : stringFieldsWithNoValidDefault()) + { + if (stringField->value().isEmpty()) return false; + bool ok = true; + stringField->value().toDouble(&ok); + if (!ok) return false; + } + return true; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RimWellPathAicdParameters::isOpen() const +{ + return m_deviceOpen; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::array RimWellPathAicdParameters::doubleValues() const +{ + std::array doubleValues; + for (int i = 0; i < (int)AICD_NUM_PARAMS; ++i) + { + caf::PdmDoubleStringValidator validator(nullptr); + QString stringValue = m_aicdParameterFields[(AICDParameters)i].value(); + bool ok = true; + double doubleValue = stringValue.toDouble(&ok); + if (ok) + { + doubleValues[i] = doubleValue; + } + else + { + doubleValues[i] = std::numeric_limits::infinity(); + } + } + return doubleValues; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimWellPathAicdParameters::defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering) +{ + bool readOnly = uiConfigName == QString("InsideValve"); + + uiOrdering.add(&m_deviceOpen); + m_deviceOpen.uiCapability()->setUiReadOnly(readOnly); + for (int i = 0; i < (int)AICD_NUM_REQ_PARAMS; ++i) + { + uiOrdering.add(&m_aicdParameterFields[(AICDParameters) i]); + m_aicdParameterFields[(AICDParameters) i].uiCapability()->setUiReadOnly(readOnly); + } + + caf::PdmUiGroup* additionalGroup = uiOrdering.addNewGroup("Additional Parameters"); + for (int i = (int)AICD_NUM_REQ_PARAMS; i < (int)AICD_NUM_PARAMS; ++i) + { + additionalGroup->add(&m_aicdParameterFields[(AICDParameters) i]); + m_aicdParameterFields[(AICDParameters)i].uiCapability()->setUiReadOnly(readOnly); + } + additionalGroup->setCollapsedByDefault(true); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimWellPathAicdParameters::defineEditorAttribute(const caf::PdmFieldHandle* field, + QString uiConfigName, + caf::PdmUiEditorAttribute* attribute) +{ + const caf::PdmField* stringField = dynamic_cast*>(field); + caf::PdmUiLineEditorAttribute* lineEditorAttr = dynamic_cast(attribute); + if (stringField && lineEditorAttr) + { + if (stringFieldsWithNoValidDefault().count(stringField)) + { + lineEditorAttr->validator = new caf::PdmDoubleStringValidator(""); + } + else + { + lineEditorAttr->validator = new caf::PdmDoubleStringValidator("1*"); + } + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::set*> RimWellPathAicdParameters::stringFieldsWithNoValidDefault() const +{ + std::set*> fields; + for (int i = 0; i < (int)AICD_NUM_REQ_PARAMS; ++i) + { + fields.insert(&m_aicdParameterFields[(AICDParameters) i]); + } + return fields; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimWellPathAicdParameters::setUnitLabels() +{ + if (isMetric()) + { + m_aicdParameterFields[AICD_DENSITY_CALIB_FLUID].uiCapability()->setUiName("Calibration Fluid Density (kg / m ^ 3)"); + m_aicdParameterFields[AICD_MAX_FLOW_RATE].uiCapability()->setUiName("Max Flow Rate for AICD Device(m ^ 3 / day)"); + } + else + { + m_aicdParameterFields[AICD_DENSITY_CALIB_FLUID].uiCapability()->setUiName("Calibration Fluid Density (lb / ft ^3)"); + m_aicdParameterFields[AICD_MAX_FLOW_RATE].uiCapability()->setUiName("Max Flow Rate for AICD Device(ft ^ 3 / day)"); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RimWellPathAicdParameters::isMetric() const +{ + bool metric = false; + RimWellPath* wellPath; + firstAncestorOrThisOfType(wellPath); + if (wellPath) + { + if (wellPath->unitSystem() == RiaEclipseUnitTools::UNITS_METRIC) + { + metric = true; + } + } + return metric; +} diff --git a/ApplicationCode/ProjectDataModel/Completions/RimWellPathAicdParameters.h b/ApplicationCode/ProjectDataModel/Completions/RimWellPathAicdParameters.h new file mode 100644 index 0000000000..82fbf64233 --- /dev/null +++ b/ApplicationCode/ProjectDataModel/Completions/RimWellPathAicdParameters.h @@ -0,0 +1,72 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2018- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// +#pragma once + +#include "cafPdmBase.h" +#include "cafPdmObject.h" +#include "cafPdmField.h" + +#include + +enum AICDParameters +{ + AICD_STRENGTH = 0, + AICD_DENSITY_CALIB_FLUID, + AICD_VISCOSITY_CALIB_FLUID, + AICD_VOL_FLOW_EXP, + AICD_VISOSITY_FUNC_EXP, + AICD_NUM_REQ_PARAMS, + AICD_CRITICAL_WATER_IN_LIQUID_FRAC = AICD_NUM_REQ_PARAMS, + AICD_EMULSION_VISC_TRANS_REGION, + AICD_MAX_RATIO_EMULSION_VISC, + AICD_MAX_FLOW_RATE, + AICD_EXP_OIL_FRAC_DENSITY, + AICD_EXP_WATER_FRAC_DENSITY, + AICD_EXP_GAS_FRAC_DENSITY, + AICD_EXP_OIL_FRAC_VISCOSITY, + AICD_EXP_WATER_FRAC_VISCOSITY, + AICD_EXP_GAS_FRAC_VISCOSITY, + AICD_NUM_PARAMS +}; + +class RimWellPathAicdParameters : public caf::PdmObject +{ + CAF_PDM_HEADER_INIT; +public: + RimWellPathAicdParameters(); + ~RimWellPathAicdParameters() override; + bool isValid() const; + + bool isOpen() const; + std::array doubleValues() const; + +protected: + + void defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering) override; + void defineEditorAttribute(const caf::PdmFieldHandle* field, QString uiConfigName, caf::PdmUiEditorAttribute* attribute) override; + +private: + std::set*> stringFieldsWithNoValidDefault() const; + void setUnitLabels(); + bool isMetric() const; +private: + caf::PdmField m_deviceOpen; + + std::array, AICD_NUM_PARAMS> m_aicdParameterFields; +}; + diff --git a/ApplicationCode/ProjectDataModel/Completions/RimWellPathCompletions.cpp b/ApplicationCode/ProjectDataModel/Completions/RimWellPathCompletions.cpp index d398f88cef..d60ffaaf70 100644 --- a/ApplicationCode/ProjectDataModel/Completions/RimWellPathCompletions.cpp +++ b/ApplicationCode/ProjectDataModel/Completions/RimWellPathCompletions.cpp @@ -32,8 +32,12 @@ #include "cvfAssert.h" +#include "cafPdmDoubleStringValidator.h" +#include "cafPdmUiDoubleValueEditor.h" +#include "cafPdmUiLineEditor.h" #include "cafPdmUiTreeOrdering.h" +#include #include //-------------------------------------------------------------------------------------------------- @@ -54,7 +58,37 @@ namespace caf { setDefault(RimWellPathCompletions::OIL); } -} + + template<> + void RimWellPathCompletions::GasInflowEnum::setUp() + { + addItem(RimWellPathCompletions::STANDARD_EQ, "STD", "Standard"); + addItem(RimWellPathCompletions::RUSSELL_GOODRICH, "R-G", "Russell-Goodrich"); + addItem(RimWellPathCompletions::DRY_GAS_PSEUDO_PRESSURE, "P-P", "Dry Gas Pseudo-Pressure"); + addItem(RimWellPathCompletions::GENERALIZED_PSEUDO_PRESSURE, "GPP", "Generalized Pseudo-Pressure"); + + setDefault(RimWellPathCompletions::STANDARD_EQ); + } + + template<> + void RimWellPathCompletions::AutomaticWellShutInEnum::setUp() + { + addItem(RimWellPathCompletions::ISOLATE_FROM_FORMATION, "SHUT", "Isolate from Formation"); + addItem(RimWellPathCompletions::STOP_ABOVE_FORMATION, "STOP", "Stop above Formation"); + + setDefault(RimWellPathCompletions::STOP_ABOVE_FORMATION); + } + + template<> + void RimWellPathCompletions::HydrostaticDensityEnum::setUp() + { + addItem(RimWellPathCompletions::SEGMENTED, "SEG", "Segmented"); + addItem(RimWellPathCompletions::AVERAGED, "AVG", "Averaged"); + + setDefault(RimWellPathCompletions::SEGMENTED); + } + + } CAF_PDM_SOURCE_INIT(RimWellPathCompletions, "WellPathCompletions"); @@ -78,13 +112,19 @@ RimWellPathCompletions::RimWellPathCompletions() m_fractureCollection = new RimWellPathFractureCollection; m_fractureCollection.uiCapability()->setUiHidden(true); - CAF_PDM_InitField(&m_wellNameForExport, "WellNameForExport", QString(), "Well Name for Completion Export", "", "", ""); - - CAF_PDM_InitField(&m_wellGroupName, "WellGroupNameForExport", QString(), "Well Group Name for Completion Export", "", "", ""); - - CAF_PDM_InitField(&m_referenceDepth, "ReferenceDepthForExport", QString(), "Reference Depth for Completion Export", "", "", ""); - - CAF_PDM_InitField(&m_wellType, "WellTypeForExport", WellTypeEnum(), "Well Type for Completion Export", "", "", ""); + CAF_PDM_InitField(&m_wellNameForExport, "WellNameForExport", QString(), "Well Name", "", "", ""); + m_wellNameForExport.uiCapability()->setUiEditorTypeName(caf::PdmUiLineEditor::uiEditorTypeName()); + + CAF_PDM_InitField(&m_wellGroupName, "WellGroupNameForExport", QString(), "Well Group Name", "", "", ""); + CAF_PDM_InitField(&m_referenceDepth, "ReferenceDepthForExport", QString(), "Reference Depth for BHP", "", "", ""); + CAF_PDM_InitField(&m_preferredFluidPhase, "WellTypeForExport", WellTypeEnum(), "Preferred Fluid Phase", "", "", ""); + CAF_PDM_InitField(&m_drainageRadiusForPI, "DrainageRadiusForPI", QString("0.0"), "Drainage Radius for PI", "", "", ""); + CAF_PDM_InitFieldNoDefault(&m_gasInflowEquation, "GasInflowEq", "Gas Inflow Equation", "", "", ""); + CAF_PDM_InitFieldNoDefault(&m_automaticWellShutIn, "AutoWellShutIn", "Automatic well shut-in", "", "", ""); + CAF_PDM_InitField(&m_allowWellCrossFlow, "AllowWellCrossFlow", true, "Allow Well Cross-Flow", "", "", ""); + CAF_PDM_InitField(&m_wellBoreFluidPVTTable, "WellBoreFluidPVTTable", 0, "Wellbore Fluid PVT table", "", "", ""); + CAF_PDM_InitFieldNoDefault(&m_hydrostaticDensity, "HydrostaticDensity", "Hydrostatic Density", "", "", ""); + CAF_PDM_InitField(&m_fluidInPlaceRegion, "FluidInPlaceRegion", 0, "Fluid In-Place Region", "", "", ""); } //-------------------------------------------------------------------------------------------------- @@ -116,6 +156,17 @@ void RimWellPathCompletions::setWellNameForExport(const QString& name) m_wellNameForExport = n.remove(' '); } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimWellPathCompletions::updateWellPathNameHasChanged(const QString& newWellPathName, const QString& previousWellPathName) +{ + if (m_wellNameForExport == previousWellPathName) + { + m_wellNameForExport = newWellPathName; + } +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -150,7 +201,7 @@ QString RimWellPathCompletions::referenceDepthForExport() const //-------------------------------------------------------------------------------------------------- QString RimWellPathCompletions::wellTypeNameForExport() const { - switch (m_wellType.v()) + switch (m_preferredFluidPhase.v()) { case OIL: return "OIL"; case GAS: return "GAS"; @@ -224,6 +275,62 @@ bool RimWellPathCompletions::hasCompletions() const !perforationCollection()->perforations().empty(); } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RimWellPathCompletions::drainageRadiusForExport() const +{ + return m_drainageRadiusForPI(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RimWellPathCompletions::gasInflowEquationForExport() const +{ + return m_gasInflowEquation().text(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RimWellPathCompletions::automaticWellShutInForExport() const +{ + return m_automaticWellShutIn().text(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RimWellPathCompletions::allowWellCrossFlowForExport() const +{ + return m_allowWellCrossFlow() ? "YES" : "NO"; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RimWellPathCompletions::wellBoreFluidPVTForExport() const +{ + return QString("%1").arg(m_wellBoreFluidPVTTable()); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RimWellPathCompletions::hydrostaticDensityForExport() const +{ + return m_hydrostaticDensity().text(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RimWellPathCompletions::fluidInPlaceRegionForExport() const +{ + return QString("%1").arg(m_fluidInPlaceRegion()); +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -234,6 +341,35 @@ void RimWellPathCompletions::setUnitSystemSpecificDefaults() m_perforationCollection->setUnitSystemSpecificDefaults(); } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QRegExp RimWellPathCompletions::wellNameForExportRegExp() +{ + QRegExp rx("[\\w\\-\\_]{1,8}"); + return rx; +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimWellPathCompletions::defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering) +{ + caf::PdmUiGroup* compExportGroup = uiOrdering.addNewGroup("Completion Export Parameters"); + compExportGroup->add(&m_wellNameForExport); + compExportGroup->add(&m_wellGroupName); + compExportGroup->add(&m_referenceDepth); + compExportGroup->add(&m_preferredFluidPhase); + compExportGroup->add(&m_drainageRadiusForPI); + compExportGroup->add(&m_gasInflowEquation); + compExportGroup->add(&m_automaticWellShutIn); + compExportGroup->add(&m_allowWellCrossFlow); + compExportGroup->add(&m_wellBoreFluidPVTTable); + compExportGroup->add(&m_hydrostaticDensity); + compExportGroup->add(&m_fluidInPlaceRegion); +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -282,6 +418,40 @@ void RimWellPathCompletions::fieldChangedByUi(const caf::PdmFieldHandle* changed } } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimWellPathCompletions::defineEditorAttribute(const caf::PdmFieldHandle* field, + QString uiConfigName, + caf::PdmUiEditorAttribute* attribute) +{ + caf::PdmUiLineEditorAttribute* lineEditorAttr = dynamic_cast(attribute); + if (field == &m_wellNameForExport && lineEditorAttr) + { + QRegExpValidator* validator = new QRegExpValidator(nullptr); + validator->setRegExp(wellNameForExportRegExp()); + lineEditorAttr->validator = validator; + } + else if (field == &m_drainageRadiusForPI && lineEditorAttr) + { + caf::PdmDoubleStringValidator* validator = new caf::PdmDoubleStringValidator("1*"); + lineEditorAttr->validator = validator; + } + else if (field == &m_wellBoreFluidPVTTable && lineEditorAttr) + { + // Positive integer + QIntValidator* validator = new QIntValidator(0, std::numeric_limits::max(), nullptr); + lineEditorAttr->validator = validator; + } + else if (field == &m_fluidInPlaceRegion && lineEditorAttr) + { + // Any integer + QIntValidator* validator = new QIntValidator(-std::numeric_limits::max(), std::numeric_limits::max(), nullptr); + lineEditorAttr->validator = validator; + + } +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/ProjectDataModel/Completions/RimWellPathCompletions.h b/ApplicationCode/ProjectDataModel/Completions/RimWellPathCompletions.h index 4ccc47067e..99f317c0c3 100644 --- a/ApplicationCode/ProjectDataModel/Completions/RimWellPathCompletions.h +++ b/ApplicationCode/ProjectDataModel/Completions/RimWellPathCompletions.h @@ -39,6 +39,15 @@ class RimWellPathCompletions : public caf::PdmObject enum WellType {OIL, GAS, WATER, LIQUID}; typedef caf::AppEnum WellTypeEnum; + enum GasInflowEquation {STANDARD_EQ, RUSSELL_GOODRICH, DRY_GAS_PSEUDO_PRESSURE, GENERALIZED_PSEUDO_PRESSURE }; + typedef caf::AppEnum GasInflowEnum; + + enum AutomaticWellShutIn {ISOLATE_FROM_FORMATION, STOP_ABOVE_FORMATION }; + typedef caf::AppEnum AutomaticWellShutInEnum; + + enum HydrostaticDensity { SEGMENTED, AVERAGED }; + typedef caf::AppEnum HydrostaticDensityEnum; + public: RimWellPathCompletions(); @@ -50,17 +59,28 @@ class RimWellPathCompletions : public caf::PdmObject std::vector allCompletions() const; void setWellNameForExport(const QString& name); + void updateWellPathNameHasChanged(const QString& newWellPathName, const QString& previousWellPathName); QString wellNameForExport() const; QString wellGroupNameForExport() const; QString referenceDepthForExport() const; QString wellTypeNameForExport() const; bool hasCompletions() const; - void setUnitSystemSpecificDefaults(); + QString drainageRadiusForExport() const; + QString gasInflowEquationForExport() const; + QString automaticWellShutInForExport() const; + QString allowWellCrossFlowForExport() const; + QString wellBoreFluidPVTForExport() const; + QString hydrostaticDensityForExport() const; + QString fluidInPlaceRegionForExport() const; + void setUnitSystemSpecificDefaults(); + static QRegExp wellNameForExportRegExp(); protected: + void defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering) override; void defineUiTreeOrdering(caf::PdmUiTreeOrdering& uiTreeOrdering, QString uiConfigName) override; void fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue) override; + void defineEditorAttribute(const caf::PdmFieldHandle* field, QString uiConfigName, caf::PdmUiEditorAttribute* attribute) override; private: QString formatStringForExport(const QString& text, const QString& defaultText = "") const; @@ -74,5 +94,12 @@ class RimWellPathCompletions : public caf::PdmObject caf::PdmField m_wellGroupName; caf::PdmField m_referenceDepth; - caf::PdmField m_wellType; + caf::PdmField m_preferredFluidPhase; + caf::PdmField m_drainageRadiusForPI; + caf::PdmField m_gasInflowEquation; + caf::PdmField m_automaticWellShutIn; + caf::PdmField m_allowWellCrossFlow; + caf::PdmField m_wellBoreFluidPVTTable; + caf::PdmField m_hydrostaticDensity; + caf::PdmField m_fluidInPlaceRegion; }; diff --git a/ApplicationCode/ProjectDataModel/Completions/RimWellPathFracture.cpp b/ApplicationCode/ProjectDataModel/Completions/RimWellPathFracture.cpp index 23446e484b..88bee9b15c 100644 --- a/ApplicationCode/ProjectDataModel/Completions/RimWellPathFracture.cpp +++ b/ApplicationCode/ProjectDataModel/Completions/RimWellPathFracture.cpp @@ -1,6 +1,7 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2016- Statoil ASA +// Copyright (C) 2016-2018 Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -23,6 +24,7 @@ #include "RimEllipseFractureTemplate.h" #include "RimProject.h" #include "RimWellPath.h" +#include "RimWellPathFractureCollection.h" #include "cafPdmUiDoubleSliderEditor.h" @@ -185,6 +187,17 @@ bool RimWellPathFracture::compareByWellPathNameAndMD(const RimWellPathFracture* return lhs->fractureMD() < rhs->fractureMD(); } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RimWellPathFracture::isEnabled() const +{ + RimWellPathFractureCollection* fractureCollection = nullptr; + this->firstAncestorOrThisOfTypeAsserted(fractureCollection); + + return fractureCollection->isChecked() && isChecked(); +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -215,8 +228,29 @@ void RimWellPathFracture::defineUiOrdering(QString uiConfigName, caf::PdmUiOrder { RimFracture::defineUiOrdering(uiConfigName, uiOrdering); - uiOrdering.add(nameField()); - uiOrdering.add(&m_fractureTemplate); + if (m_fractureTemplate()) + { + uiOrdering.add(nameField(), caf::PdmUiOrdering::LayoutOptions(true, 3, 1)); + uiOrdering.add(&m_fractureTemplate, {true, 2, 1}); + uiOrdering.add(&m_editFractureTemplate, {false, 1, 0}); + } + else + { + uiOrdering.add(nameField()); + { + RimProject* project = nullptr; + this->firstAncestorOrThisOfTypeAsserted(project); + if (project->allFractureTemplates().empty()) + { + uiOrdering.add(&m_createEllipseFractureTemplate); + uiOrdering.add(&m_createStimPlanFractureTemplate, false); + } + else + { + uiOrdering.add(&m_fractureTemplate); + } + } + } caf::PdmUiGroup* locationGroup = uiOrdering.addNewGroup("Location / Orientation"); locationGroup->add(&m_measuredDepth); @@ -236,6 +270,8 @@ void RimWellPathFracture::defineUiOrdering(QString uiConfigName, caf::PdmUiOrder caf::PdmUiGroup* fractureCenterGroup = uiOrdering.addNewGroup("Fracture Center Info"); fractureCenterGroup->add(&m_uiAnchorPosition); + + uiOrdering.skipRemainingFields(true); } //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/ProjectDataModel/Completions/RimWellPathFracture.h b/ApplicationCode/ProjectDataModel/Completions/RimWellPathFracture.h index 707ddea581..6e170d43a1 100644 --- a/ApplicationCode/ProjectDataModel/Completions/RimWellPathFracture.h +++ b/ApplicationCode/ProjectDataModel/Completions/RimWellPathFracture.h @@ -1,6 +1,7 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2016- Statoil ASA +// Copyright (C) 2016-2018 Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -51,6 +52,8 @@ class RimWellPathFracture : public RimFracture static bool compareByWellPathNameAndMD(const RimWellPathFracture* lhs, const RimWellPathFracture* rhs); + bool isEnabled() const override; // RimWellPathCompletionsInterface override + protected: void defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering) override; void defineEditorAttribute(const caf::PdmFieldHandle* field, QString uiConfigName, caf::PdmUiEditorAttribute * attribute) override; @@ -60,4 +63,5 @@ class RimWellPathFracture : public RimFracture private: caf::PdmField m_measuredDepth; + }; diff --git a/ApplicationCode/ProjectDataModel/Completions/RimWellPathFractureCollection.cpp b/ApplicationCode/ProjectDataModel/Completions/RimWellPathFractureCollection.cpp index 1a7e8d9f17..36d311f999 100644 --- a/ApplicationCode/ProjectDataModel/Completions/RimWellPathFractureCollection.cpp +++ b/ApplicationCode/ProjectDataModel/Completions/RimWellPathFractureCollection.cpp @@ -23,18 +23,6 @@ #include "cafPdmObject.h" - -namespace caf { - template<> - void RimWellPathFractureCollection::ReferenceMDEnum::setUp() - { - addItem(RimWellPathFractureCollection::AUTO_REFERENCE_MD, "GridIntersectionRefMD", "Grid Entry Point"); - addItem(RimWellPathFractureCollection::MANUAL_REFERENCE_MD, "ManualRefMD", "User Defined"); - setDefault(RimWellPathFractureCollection::AUTO_REFERENCE_MD); - } -} - - CAF_PDM_SOURCE_INIT(RimWellPathFractureCollection, "WellPathFractureCollection"); //-------------------------------------------------------------------------------------------------- @@ -50,12 +38,13 @@ RimWellPathFractureCollection::RimWellPathFractureCollection(void) setName("Fractures"); nameField()->uiCapability()->setUiHidden(true); - CAF_PDM_InitFieldNoDefault(&m_refMDType, "RefMDType", "Reference MD", "", "", ""); - CAF_PDM_InitField(&m_refMD, "RefMD", 0.0, "", "", "", ""); CAF_PDM_InitFieldNoDefault(&m_mswParameters, "MswParameters", "Multi Segment Well Parameters", "", "", ""); m_mswParameters = new RimMswCompletionParameters; m_mswParameters.uiCapability()->setUiTreeHidden(true); m_mswParameters.uiCapability()->setUiTreeChildrenHidden(true); + + CAF_PDM_InitField(&m_refMDType_OBSOLETE, "RefMDType", std::numeric_limits::max(), "Reference MD", "", "", ""); + CAF_PDM_InitField(&m_refMD_OBSOLETE, "RefMD", std::numeric_limits::infinity(), "", "", "", ""); } //-------------------------------------------------------------------------------------------------- @@ -97,26 +86,6 @@ void RimWellPathFractureCollection::setUnitSystemSpecificDefaults() m_mswParameters->setUnitSystemSpecificDefaults(); } -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -RimWellPathFractureCollection::ReferenceMDType RimWellPathFractureCollection::referenceMDType() const -{ - return m_refMDType(); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -double RimWellPathFractureCollection::manualReferenceMD() const -{ - if (m_refMDType == AUTO_REFERENCE_MD) - { - return std::numeric_limits::infinity(); - } - return m_refMD; -} - //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -152,12 +121,8 @@ std::vector RimWellPathFractureCollection::activeFractures void RimWellPathFractureCollection::defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering) { caf::PdmUiGroup* mswGroup = uiOrdering.addNewGroup("Multi Segment Well Options"); - - mswGroup->add(&m_refMDType); - mswGroup->add(&m_refMD); - m_refMD.uiCapability()->setUiHidden(m_refMDType == AUTO_REFERENCE_MD); - m_mswParameters->uiOrdering(uiConfigName, *mswGroup); + uiOrdering.skipRemainingFields(true); } //-------------------------------------------------------------------------------------------------- @@ -176,3 +141,19 @@ void RimWellPathFractureCollection::fieldChangedByUi(const caf::PdmFieldHandle* proj->scheduleCreateDisplayModelAndRedrawAllViews(); } } + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimWellPathFractureCollection::initAfterRead() +{ + if (m_refMDType_OBSOLETE() != std::numeric_limits::max()) + { + m_mswParameters->setReferenceMDType((RimMswCompletionParameters::ReferenceMDType) m_refMDType_OBSOLETE()); + } + + if (m_refMD_OBSOLETE() != std::numeric_limits::infinity()) + { + m_mswParameters->setManualReferenceMD(m_refMD_OBSOLETE()); + } +} diff --git a/ApplicationCode/ProjectDataModel/Completions/RimWellPathFractureCollection.h b/ApplicationCode/ProjectDataModel/Completions/RimWellPathFractureCollection.h index 6aba1118df..edb420a60c 100644 --- a/ApplicationCode/ProjectDataModel/Completions/RimWellPathFractureCollection.h +++ b/ApplicationCode/ProjectDataModel/Completions/RimWellPathFractureCollection.h @@ -38,14 +38,6 @@ class RimWellPathFractureCollection : public RimCheckableNamedObject { CAF_PDM_HEADER_INIT; public: - enum ReferenceMDType - { - AUTO_REFERENCE_MD = 0, - MANUAL_REFERENCE_MD - }; - - typedef caf::AppEnum ReferenceMDEnum; - RimWellPathFractureCollection(void); ~RimWellPathFractureCollection(void) override; @@ -53,8 +45,6 @@ class RimWellPathFractureCollection : public RimCheckableNamedObject void addFracture(RimWellPathFracture* fracture); void deleteFractures(); void setUnitSystemSpecificDefaults(); - ReferenceMDType referenceMDType() const; - double manualReferenceMD() const; std::vector allFractures() const; std::vector activeFractures() const; @@ -62,10 +52,13 @@ class RimWellPathFractureCollection : public RimCheckableNamedObject private: void defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering) override; void fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue) override; + void initAfterRead() override; private: caf::PdmChildArrayField m_fractures; - caf::PdmField m_refMDType; - caf::PdmField m_refMD; caf::PdmChildField m_mswParameters; + + caf::PdmField m_refMDType_OBSOLETE; + caf::PdmField m_refMD_OBSOLETE; + }; diff --git a/ApplicationCode/ProjectDataModel/Completions/RimWellPathValve.cpp b/ApplicationCode/ProjectDataModel/Completions/RimWellPathValve.cpp index 8027fe538b..395f587b36 100644 --- a/ApplicationCode/ProjectDataModel/Completions/RimWellPathValve.cpp +++ b/ApplicationCode/ProjectDataModel/Completions/RimWellPathValve.cpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018 - Equinor ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -22,14 +22,20 @@ #include "RiaColorTables.h" #include "RiaEclipseUnitTools.h" +#include "Riu3DMainWindowTools.h" + #include "RigWellPath.h" #include "RimMultipleValveLocations.h" #include "RimPerforationInterval.h" #include "RimProject.h" +#include "RimValveTemplate.h" #include "RimWellPath.h" +#include "CompletionCommands/RicNewValveTemplateFeature.h" + #include "cafPdmUiDoubleSliderEditor.h" +#include "cafPdmUiToolButtonEditor.h" CAF_PDM_SOURCE_INIT(RimWellPathValve, "WellPathValve"); @@ -40,16 +46,21 @@ RimWellPathValve::RimWellPathValve() { CAF_PDM_InitObject("WellPathValve", ":/ICDValve16x16.png", "", ""); - CAF_PDM_InitFieldNoDefault(&m_type, "CompletionType", "Type ", "", "", ""); - m_type = RiaDefines::ICD; - - CAF_PDM_InitField(&m_measuredDepth, "StartMeasuredDepth", 0.0, "Start MD", "", "", ""); - m_measuredDepth.uiCapability()->setUiEditorTypeName(caf::PdmUiDoubleSliderEditor::uiEditorTypeName()); - + CAF_PDM_InitFieldNoDefault(&m_valveTemplate, "ValveTemplate", "Valve Template", "", "", ""); + CAF_PDM_InitField(&m_measuredDepth, "StartMeasuredDepth", 0.0, "Start MD", "", "", ""); CAF_PDM_InitFieldNoDefault(&m_multipleValveLocations, "ValveLocations", "Valve Locations", "", "", ""); + CAF_PDM_InitField(&m_editValveTemplate, "EditTemplate", false, "Edit", "", "", ""); + CAF_PDM_InitField(&m_createValveTemplate, "CreateTemplate", false, "Create", "", "", ""); + + m_measuredDepth.uiCapability()->setUiEditorTypeName(caf::PdmUiDoubleSliderEditor::uiEditorTypeName()); m_multipleValveLocations = new RimMultipleValveLocations; m_multipleValveLocations.uiCapability()->setUiTreeHidden(true); m_multipleValveLocations.uiCapability()->setUiTreeChildrenHidden(true); + m_editValveTemplate.uiCapability()->setUiLabelPosition(caf::PdmUiItemInfo::HIDDEN); + m_editValveTemplate.uiCapability()->setUiEditorTypeName(caf::PdmUiToolButtonEditor::uiEditorTypeName()); + m_createValveTemplate.uiCapability()->setUiLabelPosition(caf::PdmUiItemInfo::HIDDEN); + m_createValveTemplate.uiCapability()->setUiEditorTypeName(caf::PdmUiToolButtonEditor::uiEditorTypeName()); + nameField()->uiCapability()->setUiReadOnly(true); } @@ -62,6 +73,25 @@ RimWellPathValve::~RimWellPathValve() } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimWellPathValve::perforationIntervalUpdated() +{ + if (componentType() == RiaDefines::ICV) + { + const RimPerforationInterval* perfInterval = nullptr; + this->firstAncestorOrThisOfType(perfInterval); + double startMD = perfInterval->startMD(); + double endMD = perfInterval->endMD(); + m_measuredDepth = cvf::Math::clamp(m_measuredDepth(), std::min(startMD, endMD), std::max(startMD, endMD)); + } + else if (componentType() == RiaDefines::ICD || componentType() == RiaDefines::AICD) + { + m_multipleValveLocations->perforationIntervalUpdated(); + } +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -77,8 +107,10 @@ void RimWellPathValve::setMeasuredDepthAndCount(double startMD, double spacing, //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RimWellPathValve::geometryUpdated() +void RimWellPathValve::multipleValveGeometryUpdated() { + if (m_multipleValveLocations->valveLocations().empty()) return; + m_measuredDepth = m_multipleValveLocations->valveLocations().front(); RimProject* proj; @@ -92,17 +124,173 @@ void RimWellPathValve::geometryUpdated() std::vector RimWellPathValve::valveLocations() const { std::vector valveDepths; - if (m_type() == RiaDefines::ICV) + if (componentType() == RiaDefines::ICV) { valveDepths.push_back(m_measuredDepth); } - else + else if (componentType() == RiaDefines::ICD || componentType() == RiaDefines::AICD) { valveDepths = m_multipleValveLocations->valveLocations(); } return valveDepths; } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +double RimWellPathValve::orificeDiameter(RiaEclipseUnitTools::UnitSystem unitSystem) const +{ + if (m_valveTemplate()) + { + double templateDiameter = m_valveTemplate()->orificeDiameter(); + return convertOrificeDiameter(templateDiameter, m_valveTemplate()->templateUnits(), unitSystem); + } + return 0.0; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +double RimWellPathValve::flowCoefficient() const +{ + if (m_valveTemplate()) + { + double templateCoefficient = m_valveTemplate()->flowCoefficient(); + return templateCoefficient; + } + return 0.0; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimValveTemplate* RimWellPathValve::valveTemplate() const +{ + return m_valveTemplate; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimWellPathValve::setValveTemplate(RimValveTemplate* valveTemplate) +{ + m_valveTemplate = valveTemplate; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimWellPathValve::applyValveLabelAndIcon() +{ + if (componentType() == RiaDefines::ICV) + { + this->setUiIcon(QIcon(":/ICVValve16x16.png")); + QString fullName = QString("%1: %2").arg(componentLabel()).arg(m_measuredDepth()); + this->setName(fullName); + } + else if (componentType() == RiaDefines::ICD) + { + this->setUiIcon(QIcon(":/ICDValve16x16.png")); + QString fullName = QString("%1 %2: %3 - %4") + .arg(m_multipleValveLocations->valveLocations().size()) + .arg(componentLabel()) + .arg(m_multipleValveLocations->rangeStart()) + .arg(m_multipleValveLocations->rangeEnd()); + this->setName(fullName); + } + else if (componentType() == RiaDefines::AICD) + { + this->setUiIcon(QIcon(":/AICDValve16x16.png")); + QString fullName = QString("%1 %2: %3 - %4") + .arg(m_multipleValveLocations->valveLocations().size()) + .arg(componentLabel()) + .arg(m_multipleValveLocations->rangeStart()) + .arg(m_multipleValveLocations->rangeEnd()); + this->setName(fullName); + } + else + { + this->setName("Unspecified Valve"); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +const RimWellPathAicdParameters* RimWellPathValve::aicdParameters() const +{ + if (m_valveTemplate()) + { + return m_valveTemplate()->aicdParameters(); + } + return nullptr; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +double RimWellPathValve::convertOrificeDiameter(double orificeDiameterWellPathUnits, + RiaEclipseUnitTools::UnitSystem wellPathUnits, + RiaEclipseUnitTools::UnitSystem unitSystem) +{ + if (unitSystem == RiaEclipseUnitTools::UNITS_METRIC) + { + if (wellPathUnits == RiaEclipseUnitTools::UNITS_FIELD) + { + return RiaEclipseUnitTools::inchToMeter(orificeDiameterWellPathUnits); + } + else + { + return RiaEclipseUnitTools::mmToMeter(orificeDiameterWellPathUnits); + } + } + else if (unitSystem == RiaEclipseUnitTools::UNITS_FIELD) + { + if (wellPathUnits == RiaEclipseUnitTools::UNITS_METRIC) + { + return RiaEclipseUnitTools::meterToFeet(RiaEclipseUnitTools::mmToMeter(orificeDiameterWellPathUnits)); + } + else + { + return RiaEclipseUnitTools::inchToFeet(orificeDiameterWellPathUnits); + } + } + CVF_ASSERT(false); + return 0.0; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector> RimWellPathValve::valveSegments() const +{ + RimPerforationInterval* perforationInterval = nullptr; + this->firstAncestorOrThisOfType(perforationInterval); + + double startMD = perforationInterval->startMD(); + double endMD = perforationInterval->endMD(); + std::vector valveMDs = valveLocations(); + + std::vector> segments; + segments.reserve(valveMDs.size()); + + for (size_t i = 0; i < valveMDs.size(); ++i) + { + double segmentStart = startMD; + double segmentEnd = endMD; + if (i > 0) + { + segmentStart = 0.5 * (valveMDs[i - 1] + valveMDs[i]); + } + if (i < valveMDs.size() - 1u) + { + segmentEnd = 0.5 * (valveMDs[i] + valveMDs[i + 1]); + } + segments.push_back(std::make_pair(segmentStart, segmentEnd)); + } + return segments; +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -118,7 +306,11 @@ bool RimWellPathValve::isEnabled() const //-------------------------------------------------------------------------------------------------- RiaDefines::WellPathComponentType RimWellPathValve::componentType() const { - return m_type(); + if (m_valveTemplate()) + { + return m_valveTemplate()->type(); + } + return RiaDefines::UNDEFINED_COMPONENT; } //-------------------------------------------------------------------------------------------------- @@ -126,7 +318,33 @@ RiaDefines::WellPathComponentType RimWellPathValve::componentType() const //-------------------------------------------------------------------------------------------------- QString RimWellPathValve::componentLabel() const { - return m_type().uiText(); + if (componentType() == RiaDefines::ICD) + { + if (m_multipleValveLocations->valveLocations().size() > 1) + { + return "ICDs"; + } + else + { + return "ICD"; + } + } + else if (componentType() == RiaDefines::AICD) + { + if (m_multipleValveLocations->valveLocations().size() > 1) + { + return "AICDs"; + } + else + { + return "AICD"; + } + } + else if (componentType() == RiaDefines::ICV) + { + return "ICV"; + } + return "Valve"; } //-------------------------------------------------------------------------------------------------- @@ -134,7 +352,19 @@ QString RimWellPathValve::componentLabel() const //-------------------------------------------------------------------------------------------------- QString RimWellPathValve::componentTypeLabel() const { - return m_type().uiText(); + if (componentType() == RiaDefines::ICD) + { + return "ICD"; + } + else if (componentType() == RiaDefines::AICD) + { + return "AICD"; + } + else if (componentType() == RiaDefines::ICV) + { + return "ICV"; + } + return "Valve"; } //-------------------------------------------------------------------------------------------------- @@ -150,7 +380,7 @@ cvf::Color3f RimWellPathValve::defaultComponentColor() const //-------------------------------------------------------------------------------------------------- double RimWellPathValve::startMD() const { - if (m_type() == RiaDefines::ICV) + if (componentType() == RiaDefines::ICV) { return m_measuredDepth; } @@ -169,7 +399,7 @@ double RimWellPathValve::startMD() const //-------------------------------------------------------------------------------------------------- double RimWellPathValve::endMD() const { - if (m_type() == RiaDefines::ICV) + if (componentType() == RiaDefines::ICV) { return m_measuredDepth + 0.5; } @@ -183,6 +413,22 @@ double RimWellPathValve::endMD() const } } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimWellPathValve::templateUpdated() +{ + applyValveLabelAndIcon(); + + RimPerforationInterval* perfInterval; + this->firstAncestorOrThisOfTypeAsserted(perfInterval); + perfInterval->updateAllReferringTracks(); + + RimProject* proj; + this->firstAncestorOrThisOfTypeAsserted(proj); + proj->reloadCompletionTypeResultsInAllViews(); +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -190,14 +436,14 @@ QList RimWellPathValve::calculateValueOptions(const caf: { QList options; - if (fieldNeedingOptions == &m_type) + RimProject* project = nullptr; + this->firstAncestorOrThisOfTypeAsserted(project); + std::vector allTemplates = project->allValveTemplates(); + for (RimValveTemplate* valveTemplate : allTemplates) { - std::set supportedTypes = { RiaDefines::ICD, RiaDefines::AICD, RiaDefines::ICV }; - for (RiaDefines::WellPathComponentType type : supportedTypes) - { - options.push_back(caf::PdmOptionItemInfo(CompletionTypeEnum::uiText(type), type)); - } + options.push_back(caf::PdmOptionItemInfo(valveTemplate->name(), valveTemplate)); } + return options; } @@ -206,6 +452,25 @@ QList RimWellPathValve::calculateValueOptions(const caf: //-------------------------------------------------------------------------------------------------- void RimWellPathValve::fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue) { + if (changedField == &m_valveTemplate) + { + applyValveLabelAndIcon(); + this->updateConnectedEditors(); + } + else if (changedField == &m_createValveTemplate) + { + m_createValveTemplate = false; + RicNewValveTemplateFeature::createNewValveTemplateForValveAndUpdate(this); + } + else if (changedField == &m_editValveTemplate) + { + Riu3DMainWindowTools::selectAsCurrentItem(m_valveTemplate()); + } + + RimPerforationInterval* perfInterval; + this->firstAncestorOrThisOfTypeAsserted(perfInterval); + perfInterval->updateAllReferringTracks(); + RimProject* proj; this->firstAncestorOrThisOfTypeAsserted(proj); proj->reloadCompletionTypeResultsInAllViews(); @@ -216,30 +481,51 @@ void RimWellPathValve::fieldChangedByUi(const caf::PdmFieldHandle* changedField, //-------------------------------------------------------------------------------------------------- void RimWellPathValve::defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering) { - uiOrdering.add(&m_type); + uiOrdering.skipRemainingFields(true); + + uiOrdering.add(&m_valveTemplate, { true, 2, 1 }); - if (m_type() == RiaDefines::ICV) { - RimWellPath* wellPath; - firstAncestorOrThisOfType(wellPath); - if (wellPath) + if (m_valveTemplate() != nullptr) { - if (wellPath->unitSystem() == RiaEclipseUnitTools::UNITS_METRIC) - { - m_measuredDepth.uiCapability()->setUiName("Measured Depth [m]"); - } - else if (wellPath->unitSystem() == RiaEclipseUnitTools::UNITS_FIELD) + uiOrdering.add(&m_editValveTemplate, false); + } + uiOrdering.add(&m_createValveTemplate, false); + } + + if (componentType() == RiaDefines::ICV || componentType() == RiaDefines::ICD) + { + if (componentType() == RiaDefines::ICV) + { + RimWellPath* wellPath; + firstAncestorOrThisOfType(wellPath); + if (wellPath) { - m_measuredDepth.uiCapability()->setUiName("Measured Depth [ft]"); + if (wellPath->unitSystem() == RiaEclipseUnitTools::UNITS_METRIC) + { + m_measuredDepth.uiCapability()->setUiName("Measured Depth [m]"); + } + else if (wellPath->unitSystem() == RiaEclipseUnitTools::UNITS_FIELD) + { + m_measuredDepth.uiCapability()->setUiName("Measured Depth [ft]"); + } } + uiOrdering.add(&m_measuredDepth, { true, 3, 1 }); } - uiOrdering.add(&m_measuredDepth); } - else + + if (componentType() == RiaDefines::ICD || componentType() == RiaDefines::AICD) { caf::PdmUiGroup* group = uiOrdering.addNewGroup("Multiple Valve Locations"); m_multipleValveLocations->uiOrdering(uiConfigName, *group); } + + if (m_valveTemplate() != nullptr) + { + caf::PdmUiGroup* group = uiOrdering.addNewGroup("Parameters from Template"); + m_valveTemplate->uiOrdering("InsideValve", *group); + } + uiOrdering.skipRemainingFields(true); } @@ -288,19 +574,5 @@ void RimWellPathValve::defineEditorAttribute(const caf::PdmFieldHandle* field, Q //-------------------------------------------------------------------------------------------------- void RimWellPathValve::defineUiTreeOrdering(caf::PdmUiTreeOrdering& uiTreeOrdering, QString uiConfigName /*= ""*/) { - QString fullName = componentLabel() + QString(" %1").arg(m_measuredDepth()); - this->setName(fullName); - - if ( m_type() == RiaDefines::ICD ) - { - this->setUiIcon(QIcon(":/ICDValve16x16.png")); - } - else if ( m_type() == RiaDefines::ICV ) - { - this->setUiIcon(QIcon(":/ICVValve16x16.png")); - } - else if ( m_type() == RiaDefines::AICD ) - { - this->setUiIcon(QIcon(":/AICDValve16x16.png")); - } + applyValveLabelAndIcon(); } diff --git a/ApplicationCode/ProjectDataModel/Completions/RimWellPathValve.h b/ApplicationCode/ProjectDataModel/Completions/RimWellPathValve.h index a33a2403bd..d384801b05 100644 --- a/ApplicationCode/ProjectDataModel/Completions/RimWellPathValve.h +++ b/ApplicationCode/ProjectDataModel/Completions/RimWellPathValve.h @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018 - Equinor ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -17,14 +17,19 @@ ///////////////////////////////////////////////////////////////////////////////// #pragma once +#include "RiaEclipseUnitTools.h" + #include "RimCheckableNamedObject.h" +#include "RimWellPathAicdParameters.h" #include "RimWellPathComponentInterface.h" +#include "RimValveTemplate.h" #include "cafPdmObject.h" #include "cafAppEnum.h" #include "cafPdmChildField.h" #include "cafPdmField.h" +#include "cafPdmPtrField.h" #include #include @@ -35,15 +40,27 @@ class RimWellPath; class RimWellPathValve : public RimCheckableNamedObject, public RimWellPathComponentInterface { CAF_PDM_HEADER_INIT; -public: - typedef caf::AppEnum CompletionTypeEnum; - +public: RimWellPathValve(); ~RimWellPathValve() override; + void perforationIntervalUpdated(); void setMeasuredDepthAndCount(double startMD, double spacing, int valveCount); - void geometryUpdated(); + void multipleValveGeometryUpdated(); std::vector valveLocations() const; + double orificeDiameter(RiaEclipseUnitTools::UnitSystem unitSystem) const; + double flowCoefficient() const; + RimValveTemplate* valveTemplate() const; + void setValveTemplate(RimValveTemplate* valveTemplate); + void applyValveLabelAndIcon(); + const RimWellPathAicdParameters* aicdParameters() const; + + static double convertOrificeDiameter(double orificeDiameterUi, + RiaEclipseUnitTools::UnitSystem wellPathUnitSystem, + RiaEclipseUnitTools::UnitSystem wantedUnitSystem); + + std::vector> valveSegments() const; + // Overrides from RimWellPathCompletionInterface bool isEnabled() const override; @@ -53,7 +70,8 @@ class RimWellPathValve : public RimCheckableNamedObject, public RimWellPathCompo cvf::Color3f defaultComponentColor() const override; double startMD() const override; double endMD() const override; - + + void templateUpdated(); private: QList calculateValueOptions(const caf::PdmFieldHandle* fieldNeedingOptions, bool* useOptionsOnly) override; void fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue) override; @@ -62,10 +80,11 @@ class RimWellPathValve : public RimCheckableNamedObject, public RimWellPathCompo void defineUiTreeOrdering(caf::PdmUiTreeOrdering& uiTreeOrdering, QString uiConfigName = "") override; private: - caf::PdmField m_type; + caf::PdmPtrField m_valveTemplate; caf::PdmField m_measuredDepth; caf::PdmChildField m_multipleValveLocations; - + caf::PdmField m_editValveTemplate; + caf::PdmField m_createValveTemplate; }; diff --git a/ApplicationCode/ProjectDataModel/Flow/RimFlowCharacteristicsPlot.cpp b/ApplicationCode/ProjectDataModel/Flow/RimFlowCharacteristicsPlot.cpp index 0f4e84a44a..af080c629a 100644 --- a/ApplicationCode/ProjectDataModel/Flow/RimFlowCharacteristicsPlot.cpp +++ b/ApplicationCode/ProjectDataModel/Flow/RimFlowCharacteristicsPlot.cpp @@ -1,35 +1,35 @@ ///////////////////////////////////////////////////////////////////////////////// // // Copyright (C) 2017 Statoil ASA -// +// // ResInsight 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 3 of the License, or // (at your option) any later version. -// +// // ResInsight 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 at +// +// See the GNU General Public License at // for more details. // ///////////////////////////////////////////////////////////////////////////////// #include "RimFlowCharacteristicsPlot.h" -#include "RigFlowDiagResults.h" -#include "RigEclipseCaseData.h" #include "RigActiveCellInfo.h" +#include "RigEclipseCaseData.h" +#include "RigFlowDiagResults.h" -#include "RimEclipseResultCase.h" -#include "RimFlowDiagSolution.h" -#include "RimProject.h" #include "RimEclipseCellColors.h" -#include "RimEclipseView.h" #include "RimEclipsePropertyFilter.h" #include "RimEclipsePropertyFilterCollection.h" +#include "RimEclipseResultCase.h" +#include "RimEclipseView.h" #include "RimFaultInViewCollection.h" +#include "RimFlowDiagSolution.h" +#include "RimProject.h" #include "RicEclipsePropertyFilterFeatureImpl.h" #include "RicSelectOrCreateViewFeatureImpl.h" @@ -46,23 +46,21 @@ #include // Needed for HUGE_VAL on Linux - namespace caf { - template<> - void AppEnum< RimFlowCharacteristicsPlot::TimeSelectionType >::setUp() - { - addItem(RimFlowCharacteristicsPlot::ALL_AVAILABLE, "ALL_AVAILABLE", "All With Calculated Flow Diagnostics"); - addItem(RimFlowCharacteristicsPlot::SELECTED, "SELECTED", "Selected"); - setDefault(RimFlowCharacteristicsPlot::SELECTED); - } +template<> +void AppEnum::setUp() +{ + addItem(RimFlowCharacteristicsPlot::ALL_AVAILABLE, "ALL_AVAILABLE", "All With Calculated Flow Diagnostics"); + addItem(RimFlowCharacteristicsPlot::SELECTED, "SELECTED", "Selected"); + setDefault(RimFlowCharacteristicsPlot::SELECTED); } +} // namespace caf CAF_PDM_SOURCE_INIT(RimFlowCharacteristicsPlot, "FlowCharacteristicsPlot"); - //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- RimFlowCharacteristicsPlot::RimFlowCharacteristicsPlot() { @@ -79,8 +77,13 @@ RimFlowCharacteristicsPlot::RimFlowCharacteristicsPlot() CAF_PDM_InitFieldNoDefault(&m_applyTimeSteps, "ApplyTimeSteps", "", "", "", ""); caf::PdmUiPushButtonEditor::configureEditorForField(&m_applyTimeSteps); - CAF_PDM_InitField(&m_maxPvFraction, "CellPVThreshold", 0.1, "Aquifer Cell Threshold", "", "Exclude Aquifer Effects by adding a Cell Pore Volume Threshold as Fraction of Total Pore Volume.", ""); - + CAF_PDM_InitField(&m_maxPvFraction, + "CellPVThreshold", + 0.1, + "Aquifer Cell Threshold", + "", + "Exclude Aquifer Effects by adding a Cell Pore Volume Threshold as Fraction of Total Pore Volume.", + ""); CAF_PDM_InitField(&m_showLegend, "ShowLegend", true, "Legend", "", "", ""); @@ -101,24 +104,23 @@ RimFlowCharacteristicsPlot::RimFlowCharacteristicsPlot() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- RimFlowCharacteristicsPlot::~RimFlowCharacteristicsPlot() { removeMdiWindowFromMdiArea(); - + deleteViewWidget(); } - //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RimFlowCharacteristicsPlot::setFromFlowSolution(RimFlowDiagSolution* flowSolution) { - if ( !flowSolution ) + if (!flowSolution) { - m_case = nullptr; + m_case = nullptr; m_cellFilterView = nullptr; } else @@ -133,66 +135,67 @@ void RimFlowCharacteristicsPlot::setFromFlowSolution(RimFlowDiagSolution* flowSo } m_flowDiagSolution = flowSolution; - m_showWindow = true; + m_showWindow = true; onLoadDataAndUpdate(); } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RimFlowCharacteristicsPlot::deleteViewWidget() { if (m_flowCharPlotWidget) { m_flowCharPlotWidget->deleteLater(); - m_flowCharPlotWidget= nullptr; + m_flowCharPlotWidget = nullptr; } } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RimFlowCharacteristicsPlot::updateCurrentTimeStep() { if (m_timeStepSelectionType() != ALL_AVAILABLE) return; if (!m_flowDiagSolution()) return; - RigFlowDiagResults* flowResult = m_flowDiagSolution->flowDiagResults(); - std::vector calculatedTimesteps = flowResult->calculatedTimeSteps(RigFlowDiagResultAddress::PHASE_ALL); - + RigFlowDiagResults* flowResult = m_flowDiagSolution->flowDiagResults(); + std::vector calculatedTimesteps = flowResult->calculatedTimeSteps(RigFlowDiagResultAddress::PHASE_ALL); + if (m_currentlyPlottedTimeSteps == calculatedTimesteps) return; this->onLoadDataAndUpdate(); } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- -QList RimFlowCharacteristicsPlot::calculateValueOptions(const caf::PdmFieldHandle* fieldNeedingOptions, bool* useOptionsOnly) +QList RimFlowCharacteristicsPlot::calculateValueOptions(const caf::PdmFieldHandle* fieldNeedingOptions, + bool* useOptionsOnly) { QList options; - if ( fieldNeedingOptions == &m_case ) + if (fieldNeedingOptions == &m_case) { RimProject* proj = nullptr; this->firstAncestorOrThisOfType(proj); - if ( proj ) + if (proj) { std::vector cases; proj->descendantsIncludingThisOfType(cases); - for ( RimEclipseResultCase* c : cases ) + for (RimEclipseResultCase* c : cases) { - if ( c->defaultFlowDiagSolution() ) + if (c->defaultFlowDiagSolution()) { options.push_back(caf::PdmOptionItemInfo(c->caseUserDescription(), c, false, c->uiIcon())); } } } } - else if ( fieldNeedingOptions == &m_cellFilterView ) + else if (fieldNeedingOptions == &m_cellFilterView) { - if ( m_case ) + if (m_case) { for (RimEclipseView* view : m_case()->reservoirViews()) { @@ -200,28 +203,29 @@ QList RimFlowCharacteristicsPlot::calculateValueOptions( } } } - else if ( fieldNeedingOptions == &m_flowDiagSolution ) + else if (fieldNeedingOptions == &m_flowDiagSolution) { - if ( m_case ) + if (m_case) { std::vector flowSols = m_case->flowDiagSolutions(); options.push_back(caf::PdmOptionItemInfo("None", nullptr)); - for ( RimFlowDiagSolution* flowSol : flowSols ) + for (RimFlowDiagSolution* flowSol : flowSols) { options.push_back(caf::PdmOptionItemInfo(flowSol->userDescription(), flowSol, false, flowSol->uiIcon())); } } } - else if ( fieldNeedingOptions == &m_selectedTimeStepsUi ) + else if (fieldNeedingOptions == &m_selectedTimeStepsUi) { - if ( m_flowDiagSolution && m_case ) + if (m_flowDiagSolution && m_case) { - QStringList timeStepDates = m_case->timeStepStrings(); - std::vector calculatedTimeSteps = m_flowDiagSolution()->flowDiagResults()->calculatedTimeSteps(RigFlowDiagResultAddress::PHASE_ALL); + QStringList timeStepDates = m_case->timeStepStrings(); + std::vector calculatedTimeSteps = + m_flowDiagSolution()->flowDiagResults()->calculatedTimeSteps(RigFlowDiagResultAddress::PHASE_ALL); for (int tsIdx = 0; tsIdx < timeStepDates.size(); ++tsIdx) { - auto it = std::find(calculatedTimeSteps.begin(), calculatedTimeSteps.end(), tsIdx); + auto it = std::find(calculatedTimeSteps.begin(), calculatedTimeSteps.end(), tsIdx); QString itemText = timeStepDates[tsIdx]; if (it != calculatedTimeSteps.end()) { @@ -235,7 +239,7 @@ QList RimFlowCharacteristicsPlot::calculateValueOptions( { if (m_flowDiagSolution) { - std::vector tracerNames = m_flowDiagSolution->tracerNames(); + std::vector tracerNames = m_flowDiagSolution->tracerNames(); std::vector> sortedTracerNames; for (QString tracerName : tracerNames) { @@ -263,18 +267,18 @@ QList RimFlowCharacteristicsPlot::calculateValueOptions( QString prefix; switch (tracerStatus) { - case RimFlowDiagSolution::INJECTOR: - prefix = "I : "; - break; - case RimFlowDiagSolution::PRODUCER: - prefix = "P : "; - break; - case RimFlowDiagSolution::VARYING: - prefix = "I/P: "; - break; - case RimFlowDiagSolution::UNDEFINED: - prefix = "U : "; - break; + case RimFlowDiagSolution::INJECTOR: + prefix = "I : "; + break; + case RimFlowDiagSolution::PRODUCER: + prefix = "P : "; + break; + case RimFlowDiagSolution::VARYING: + prefix = "I/P: "; + break; + case RimFlowDiagSolution::UNDEFINED: + prefix = "U : "; + break; } sortedTracerNames.push_back(std::make_pair(prefix + tracerName, tracerName)); } @@ -282,10 +286,9 @@ QList RimFlowCharacteristicsPlot::calculateValueOptions( std::sort(sortedTracerNames.begin(), sortedTracerNames.end(), - [](const std::pair& a, const std::pair& b) -> bool - { - return a.first < b.first; - }); + [](const std::pair& a, const std::pair& b) -> bool { + return a.first < b.first; + }); for (auto& tracer : sortedTracerNames) { @@ -295,11 +298,10 @@ QList RimFlowCharacteristicsPlot::calculateValueOptions( } return options; - } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RimFlowCharacteristicsPlot::defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering) { @@ -321,7 +323,7 @@ void RimFlowCharacteristicsPlot::defineUiOrdering(QString uiConfigName, caf::Pdm } if (!m_case() && defaultCase) { - m_case = defaultCase; + m_case = defaultCase; m_flowDiagSolution = m_case->defaultFlowDiagSolution(); if (!m_case()->reservoirViews.empty()) { @@ -348,8 +350,7 @@ void RimFlowCharacteristicsPlot::defineUiOrdering(QString uiConfigName, caf::Pdm { caf::PdmUiGroup* regionGroup = uiOrdering.addNewGroup("Region"); regionGroup->add(&m_cellFilter); - if (m_cellFilter() == RigFlowDiagResults::CELLS_COMMUNICATION || - m_cellFilter() == RigFlowDiagResults::CELLS_DRAINED || + if (m_cellFilter() == RigFlowDiagResults::CELLS_COMMUNICATION || m_cellFilter() == RigFlowDiagResults::CELLS_DRAINED || m_cellFilter() == RigFlowDiagResults::CELLS_FLOODED) { regionGroup->add(&m_tracerFilter); @@ -365,8 +366,7 @@ void RimFlowCharacteristicsPlot::defineUiOrdering(QString uiConfigName, caf::Pdm { regionGroup->add(&m_minCommunication); } - else if (m_cellFilter() == RigFlowDiagResults::CELLS_DRAINED || - m_cellFilter() == RigFlowDiagResults::CELLS_FLOODED) + else if (m_cellFilter() == RigFlowDiagResults::CELLS_DRAINED || m_cellFilter() == RigFlowDiagResults::CELLS_FLOODED) { regionGroup->add(&m_maxTof); } @@ -384,9 +384,11 @@ void RimFlowCharacteristicsPlot::defineUiOrdering(QString uiConfigName, caf::Pdm } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- -void RimFlowCharacteristicsPlot::defineEditorAttribute(const caf::PdmFieldHandle* field, QString uiConfigName, caf::PdmUiEditorAttribute* attribute) +void RimFlowCharacteristicsPlot::defineEditorAttribute(const caf::PdmFieldHandle* field, + QString uiConfigName, + caf::PdmUiEditorAttribute* attribute) { if (field == &m_applyTimeSteps) { @@ -407,7 +409,7 @@ void RimFlowCharacteristicsPlot::defineEditorAttribute(const caf::PdmFieldHandle } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- QWidget* RimFlowCharacteristicsPlot::viewWidget() { @@ -415,7 +417,7 @@ QWidget* RimFlowCharacteristicsPlot::viewWidget() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RimFlowCharacteristicsPlot::zoomAll() { @@ -423,13 +425,15 @@ void RimFlowCharacteristicsPlot::zoomAll() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- -void RimFlowCharacteristicsPlot::fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue) +void RimFlowCharacteristicsPlot::fieldChangedByUi(const caf::PdmFieldHandle* changedField, + const QVariant& oldValue, + const QVariant& newValue) { RimViewWindow::fieldChangedByUi(changedField, oldValue, newValue); - if ( &m_case == changedField ) + if (&m_case == changedField) { m_flowDiagSolution = m_case->defaultFlowDiagSolution(); m_currentlyPlottedTimeSteps.clear(); @@ -457,7 +461,8 @@ void RimFlowCharacteristicsPlot::fieldChangedByUi(const caf::PdmFieldHandle* cha { if (m_cellFilter() != RigFlowDiagResults::CELLS_ACTIVE) { - RimEclipseView* view = RicSelectOrCreateViewFeatureImpl::showViewSelection(m_case, "FlowCharacteristicsLastUsedView", "Show Region in View"); + RimEclipseView* view = RicSelectOrCreateViewFeatureImpl::showViewSelection( + m_case, "FlowCharacteristicsLastUsedView", "RegionView", "Show Region in View"); if (view != nullptr) { @@ -480,7 +485,8 @@ void RimFlowCharacteristicsPlot::fieldChangedByUi(const caf::PdmFieldHandle* cha { if (m_flowDiagSolution) { - std::vector timeSteps = m_flowDiagSolution()->flowDiagResults()->calculatedTimeSteps(RigFlowDiagResultAddress::PHASE_ALL); + std::vector timeSteps = + m_flowDiagSolution()->flowDiagResults()->calculatedTimeSteps(RigFlowDiagResultAddress::PHASE_ALL); if (!timeSteps.empty()) { timeStep = timeSteps[0]; @@ -525,7 +531,7 @@ void RimFlowCharacteristicsPlot::fieldChangedByUi(const caf::PdmFieldHandle* cha } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- QImage RimFlowCharacteristicsPlot::snapshotWindowContent() { @@ -534,14 +540,14 @@ QImage RimFlowCharacteristicsPlot::snapshotWindowContent() if (m_flowCharPlotWidget) { QPixmap pix = QPixmap::grabWidget(m_flowCharPlotWidget); - image = pix.toImage(); + image = pix.toImage(); } return image; } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RimFlowCharacteristicsPlot::onLoadDataAndUpdate() { @@ -549,23 +555,23 @@ void RimFlowCharacteristicsPlot::onLoadDataAndUpdate() if (m_flowDiagSolution && m_flowCharPlotWidget) { - RigFlowDiagResults* flowResult = m_flowDiagSolution->flowDiagResults(); - std::vector calculatedTimesteps = flowResult->calculatedTimeSteps(RigFlowDiagResultAddress::PHASE_ALL); - + RigFlowDiagResults* flowResult = m_flowDiagSolution->flowDiagResults(); + std::vector calculatedTimesteps = flowResult->calculatedTimeSteps(RigFlowDiagResultAddress::PHASE_ALL); + if (m_timeStepSelectionType == SELECTED) { for (int tsIdx : m_selectedTimeSteps()) - { + { m_flowDiagSolution()->flowDiagResults()->maxAbsPairFlux(tsIdx); } calculatedTimesteps = m_selectedTimeSteps(); } - + m_currentlyPlottedTimeSteps = calculatedTimesteps; - std::vector timeStepDates = m_case->timeStepDates(); - QStringList timeStepStrings = m_case->timeStepStrings(); - std::vector lorenzVals(timeStepDates.size(), HUGE_VAL); + std::vector timeStepDates = m_case->timeStepDates(); + QStringList timeStepStrings = m_case->timeStepStrings(); + std::vector lorenzVals(timeStepDates.size(), HUGE_VAL); m_flowCharPlotWidget->removeAllCurves(); @@ -593,7 +599,7 @@ void RimFlowCharacteristicsPlot::onLoadDataAndUpdate() } RigActiveCellInfo* activeCellInfo = m_case()->eclipseCaseData()->activeCellInfo(RiaDefines::MATRIX_MODEL); - std::vector visibleActiveCells(activeCellInfo->reservoirActiveCellCount(), 0); + std::vector visibleActiveCells(activeCellInfo->reservoirActiveCellCount(), 0); for (size_t i = 0; i < visibleCells.size(); ++i) { @@ -609,12 +615,8 @@ void RimFlowCharacteristicsPlot::onLoadDataAndUpdate() } else { - auto flowCharResults = flowResult->flowCharacteristicsResults(timeStepIdx, - m_cellFilter(), - selectedTracerNames, - m_maxPvFraction(), - m_minCommunication(), - m_maxTof()); + auto flowCharResults = flowResult->flowCharacteristicsResults( + timeStepIdx, m_cellFilter(), selectedTracerNames, m_maxPvFraction(), m_minCommunication(), m_maxTof()); timeStepToFlowResultMap[timeStepIdx] = flowCharResults; } lorenzVals[timeStepIdx] = timeStepToFlowResultMap[timeStepIdx].m_lorenzCoefficient; @@ -622,9 +624,8 @@ void RimFlowCharacteristicsPlot::onLoadDataAndUpdate() m_flowCharPlotWidget->setLorenzCurve(timeStepStrings, timeStepDates, lorenzVals); - for ( int timeStepIdx: calculatedTimesteps ) + for (int timeStepIdx : calculatedTimesteps) { - const auto& flowCharResults = timeStepToFlowResultMap[timeStepIdx]; m_flowCharPlotWidget->addFlowCapStorageCapCurve(timeStepDates[timeStepIdx], @@ -640,7 +641,7 @@ void RimFlowCharacteristicsPlot::onLoadDataAndUpdate() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RimFlowCharacteristicsPlot::viewGeometryUpdated() { @@ -652,12 +653,10 @@ void RimFlowCharacteristicsPlot::viewGeometryUpdated() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- QWidget* RimFlowCharacteristicsPlot::createViewWidget(QWidget* mainWindowParent) { m_flowCharPlotWidget = new RiuFlowCharacteristicsPlot(this, mainWindowParent); return m_flowCharPlotWidget; } - - diff --git a/ApplicationCode/ProjectDataModel/Flow/RimWellAllocationPlot.cpp b/ApplicationCode/ProjectDataModel/Flow/RimWellAllocationPlot.cpp index b539bb7746..fae3b985bb 100644 --- a/ApplicationCode/ProjectDataModel/Flow/RimWellAllocationPlot.cpp +++ b/ApplicationCode/ProjectDataModel/Flow/RimWellAllocationPlot.cpp @@ -281,8 +281,11 @@ void RimWellAllocationPlot::updateFromWell() wfCalculator->tracerFlowPrPseudoLength(tracerName, brIdx)); } - addStackedCurve(tracerName, depthValues, *accFlow, plotTrack); - //TODO: THIs is the data to be plotted... + if (accFlow) + { + addStackedCurve(tracerName, depthValues, *accFlow, plotTrack); + // TODO: THIs is the data to be plotted... + } } } diff --git a/ApplicationCode/ProjectDataModel/Flow/RimWellPlotTools.cpp b/ApplicationCode/ProjectDataModel/Flow/RimWellPlotTools.cpp index 8a63a28a6f..b1f367950b 100644 --- a/ApplicationCode/ProjectDataModel/Flow/RimWellPlotTools.cpp +++ b/ApplicationCode/ProjectDataModel/Flow/RimWellPlotTools.cpp @@ -32,7 +32,6 @@ #include "RimEclipseResultCase.h" #include "RimOilField.h" #include "RimProject.h" -#include "RimTools.h" #include "RimWellLogExtractionCurve.h" #include "RimWellLogFile.h" #include "RimWellLogFileChannel.h" @@ -105,21 +104,20 @@ bool RimWellPlotTools::hasPressureData(RimWellPath* wellPath) //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -std::pair RimWellPlotTools::pressureResultDataInfo(const RigEclipseCaseData* eclipseCaseData) +std::pair RimWellPlotTools::pressureResultDataInfo(const RigEclipseCaseData* eclipseCaseData) { if (eclipseCaseData != nullptr) { for (const auto& pressureDataName : PRESSURE_DATA_NAMES) { - size_t index = eclipseCaseData->results(RiaDefines::MATRIX_MODEL) - ->findScalarResultIndex(RiaDefines::DYNAMIC_NATIVE, pressureDataName); - if (index != cvf::UNDEFINED_SIZE_T) + if (eclipseCaseData->results(RiaDefines::MATRIX_MODEL) + ->hasResultEntry(RigEclipseResultAddress(RiaDefines::DYNAMIC_NATIVE, pressureDataName))) { - return std::make_pair(index, pressureDataName); + return std::make_pair(RigEclipseResultAddress(RiaDefines::DYNAMIC_NATIVE, pressureDataName), pressureDataName); } } } - return std::make_pair(cvf::UNDEFINED_SIZE_T, ""); + return std::make_pair(RigEclipseResultAddress(), ""); } //-------------------------------------------------------------------------------------------------- @@ -139,7 +137,7 @@ bool RimWellPlotTools::isPressureChannel(RimWellLogFileChannel* channel) //-------------------------------------------------------------------------------------------------- bool RimWellPlotTools::hasPressureData(RimEclipseResultCase* gridCase) { - return pressureResultDataInfo(gridCase->eclipseCaseData()).first != cvf::UNDEFINED_SIZE_T; + return pressureResultDataInfo(gridCase->eclipseCaseData()).first.isValid(); } //-------------------------------------------------------------------------------------------------- /// @@ -228,10 +226,11 @@ bool RimWellPlotTools::hasFlowData(RimEclipseResultCase* gridCase) for (const QString& channelName : FLOW_DATA_NAMES) { - size_t resultIndex = - eclipseCaseData->results(RiaDefines::MATRIX_MODEL)->findScalarResultIndex(RiaDefines::DYNAMIC_NATIVE, channelName); - - if (resultIndex != cvf::UNDEFINED_SIZE_T) return true; + if (eclipseCaseData->results(RiaDefines::MATRIX_MODEL) + ->hasResultEntry(RigEclipseResultAddress(RiaDefines::DYNAMIC_NATIVE, channelName))) + { + return true; + } } return false; } @@ -412,11 +411,11 @@ std::vector RimWellPlotTools::rftCasesForWell(const QStri //-------------------------------------------------------------------------------------------------- std::map> RimWellPlotTools::timeStepsMapFromGridCase(RimEclipseCase* gridCase) { - const RigEclipseCaseData* const eclipseCaseData = gridCase->eclipseCaseData(); - std::pair resultDataInfo = pressureResultDataInfo(eclipseCaseData); + const RigEclipseCaseData* const eclipseCaseData = gridCase->eclipseCaseData(); + std::pair resultDataInfo = pressureResultDataInfo(eclipseCaseData); std::map> timeStepsMap; - if (resultDataInfo.first != cvf::UNDEFINED_SIZE_T) + if (resultDataInfo.first.isValid()) { for (const QDateTime& timeStep : eclipseCaseData->results(RiaDefines::MATRIX_MODEL)->timeStepDates(resultDataInfo.first)) { @@ -522,7 +521,7 @@ RiaRftPltCurveDefinition RimWellPlotTools::curveDefFromCurve(const RimWellLogCur } else if (wellLogFileCurve != nullptr) { - RimWellLogFile* const wellLogFile = wellLogFileCurve->wellLogFile(); + RimWellLogFile* const wellLogFile = wellLogFileCurve->wellLogFile(); if (wellLogFile != nullptr) { @@ -583,7 +582,8 @@ std::set RimWellPlotTools::curveDefsFromTimesteps(const QString& simWellName, const std::vector& selectedTimeSteps, bool firstSimWellTimeStepIsValid, - const std::vector& selectedSourcesExpanded) + const std::vector& selectedSourcesExpanded, + const std::set& interestingRFTResults) { std::set curveDefs; @@ -593,8 +593,7 @@ std::set { if (addr.rftReader()) { - std::set rftTimes = addr.rftReader()->availableTimeSteps( - simWellName, {RifEclipseRftAddress::ORAT, RifEclipseRftAddress::WRAT, RifEclipseRftAddress::GRAT}); + std::set rftTimes = addr.rftReader()->availableTimeSteps(simWellName, interestingRFTResults); for (const QDateTime& time : rftTimes) { if (selectedTimeStepSet.count(time)) @@ -937,16 +936,16 @@ void RimWellPlotTools::calculateValueOptionsForTimeSteps( { allTimeSteps.push_back(timeStepPair.first); } - dateFormatString = RimTools::createTimeFormatStringFromDates(allTimeSteps); + dateFormatString = RiaQDateTimeTools::createTimeFormatStringFromDates(allTimeSteps); } for (const std::pair>& timeStepPair : timestepsToShowWithSources) { QString optionText = RiaQDateTimeTools::toStringUsingApplicationLocale(timeStepPair.first, dateFormatString); - bool hasObs = false; - bool hasRft = false; - bool hasGrid = false; + bool hasObs = false; + bool hasRft = false; + bool hasGrid = false; for (const auto& source : timeStepPair.second) { diff --git a/ApplicationCode/ProjectDataModel/Flow/RimWellPlotTools.h b/ApplicationCode/ProjectDataModel/Flow/RimWellPlotTools.h index 5a2c1921fa..82c5b98568 100644 --- a/ApplicationCode/ProjectDataModel/Flow/RimWellPlotTools.h +++ b/ApplicationCode/ProjectDataModel/Flow/RimWellPlotTools.h @@ -18,17 +18,18 @@ #pragma once +#include "RiaEclipseUnitTools.h" +#include "RiaRftPltCurveDefinition.h" #include "RifDataSourceForRftPltQMetaType.h" -#include "RiaRftPltCurveDefinition.h" +#include "RifEclipseRftAddress.h" + +#include "RimWellLogFile.h" #include #include #include -#include "RifEclipseRftAddress.h" -#include "RimWellLogFile.h" -#include "RiaEclipseUnitTools.h" class RimEclipseCase; class RimEclipseResultCase; @@ -38,6 +39,7 @@ class RimWellLogPlot; class RimWellPath; class RiuWellRftPlot; class RigEclipseCaseData; +class RigEclipseResultAddress; //================================================================================================== /// @@ -62,7 +64,9 @@ class RimWellPlotTools static RimWellPath* wellPathByWellPathNameOrSimWellName(const QString& wellPathNameOrSimwellName); // RFT Only - static std::pair pressureResultDataInfo(const RigEclipseCaseData* eclipseCaseData); +private: + static std::pair pressureResultDataInfo(const RigEclipseCaseData* eclipseCaseData); +public: static void addTimeStepsToMap(std::map>& destMap, const std::map>& timeStepsToAdd); static std::vector wellLogFilesContainingPressure(const QString& wellPathNameOrSimWellName); @@ -71,9 +75,6 @@ class RimWellPlotTools static std::map> timeStepsMapFromGridCase(RimEclipseCase* gridCase); static RiaRftPltCurveDefinition curveDefFromCurve(const RimWellLogCurve* curve); - template - static void appendSet(std::set& destSet, const std::set& setToAppend); - // others static bool hasFlowData(const RimWellLogFile* wellLogFile); static bool hasAssociatedWellPath(const QString& wellName); @@ -96,7 +97,8 @@ class RimWellPlotTools static std::set < RiaRftPltCurveDefinition > curveDefsFromTimesteps(const QString& simWellName, const std::vector& selectedTimeStepVector, bool firstReportTimeStepIsValid, - const std::vector& selectedSourcesExpanded); + const std::vector& selectedSourcesExpanded, + const std::set& interestingRFTResults); static QString flowPlotAxisTitle(RimWellLogFile::WellFlowCondition condition, RiaEclipseUnitTools::UnitSystem unitSystem); @@ -133,12 +135,3 @@ class RimWellPlotTools }; -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -template -void RimWellPlotTools::appendSet(std::set& destSet, const std::set& setToAppend) -{ - destSet.insert(setToAppend.begin(), setToAppend.end()); -} - diff --git a/ApplicationCode/ProjectDataModel/Flow/RimWellPltPlot.cpp b/ApplicationCode/ProjectDataModel/Flow/RimWellPltPlot.cpp index 3a598cb48a..142f59cab4 100644 --- a/ApplicationCode/ProjectDataModel/Flow/RimWellPltPlot.cpp +++ b/ApplicationCode/ProjectDataModel/Flow/RimWellPltPlot.cpp @@ -1,17 +1,17 @@ ///////////////////////////////////////////////////////////////////////////////// // // Copyright (C) 2017 Statoil ASA -// +// // ResInsight 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 3 of the License, or // (at your option) any later version. -// +// // ResInsight 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 at +// +// See the GNU General Public License at // for more details. // ///////////////////////////////////////////////////////////////////////////////// @@ -35,6 +35,7 @@ #include "RigWellLogExtractor.h" #include "RigWellPath.h" +#include "RimDataSourceForRftPlt.h" #include "RimEclipseCase.h" #include "RimEclipseCaseCollection.h" #include "RimEclipseResultCase.h" @@ -43,7 +44,6 @@ #include "RimOilField.h" #include "RimProject.h" #include "RimSummaryCurveAppearanceCalculator.h" -#include "RimTools.h" #include "RimWellFlowRateCurve.h" #include "RimWellLogExtractionCurve.h" #include "RimWellLogFile.h" @@ -63,19 +63,18 @@ #include "cafPdmUiTreeSelectionEditor.h" #include "cafVecIjk.h" +#include + #include #include #include -#include "QMessageBox" - - -CAF_PDM_SOURCE_INIT(RimWellPltPlot, "WellPltPlot"); +CAF_PDM_SOURCE_INIT(RimWellPltPlot, "WellPltPlot"); namespace caf { template<> -void caf::AppEnum< FlowType>::setUp() +void caf::AppEnum::setUp() { addItem(FLOW_TYPE_PHASE_SPLIT, "PHASE_SPLIT", "Phase Split"); addItem(FLOW_TYPE_TOTAL, "TOTAL", "Total Flow"); @@ -83,22 +82,22 @@ void caf::AppEnum< FlowType>::setUp() } template<> -void caf::AppEnum< FlowPhase>::setUp() +void caf::AppEnum::setUp() { addItem(FLOW_PHASE_OIL, "PHASE_OIL", "Oil"); addItem(FLOW_PHASE_GAS, "PHASE_GAS", "Gas"); addItem(FLOW_PHASE_WATER, "PHASE_WATER", "Water"); addItem(FLOW_PHASE_TOTAL, "PHASE_TOTAL", "Total"); } -} +} // namespace caf //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- const char RimWellPltPlot::PLOT_NAME_QFORMAT_STRING[] = "PLT: %1"; //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- RimWellPltPlot::RimWellPltPlot() { @@ -135,16 +134,16 @@ RimWellPltPlot::RimWellPltPlot() CAF_PDM_InitFieldNoDefault(&m_phases, "Phases", "Phases", "", "", ""); m_phases.uiCapability()->setUiEditorTypeName(caf::PdmUiTreeSelectionEditor::uiEditorTypeName()); - m_phases = std::vector>({ FLOW_PHASE_OIL, FLOW_PHASE_GAS, FLOW_PHASE_WATER }); + m_phases = std::vector>({FLOW_PHASE_OIL, FLOW_PHASE_GAS, FLOW_PHASE_WATER}); m_phases.uiCapability()->setUiLabelPosition(caf::PdmUiItemInfo::HIDDEN); this->setAsPlotMdiWindow(); m_doInitAfterLoad = false; - m_isOnLoad = true; + m_isOnLoad = true; } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- RimWellPltPlot::~RimWellPltPlot() { @@ -154,7 +153,7 @@ RimWellPltPlot::~RimWellPltPlot() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RimWellPltPlot::deleteViewWidget() { @@ -165,13 +164,12 @@ void RimWellPltPlot::deleteViewWidget() } } - //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RimWellPltPlot::setPlotXAxisTitles(RimWellLogTrack* plotTrack) { - std::set< RiaEclipseUnitTools::UnitSystem> presentUnitSystems; + std::set presentUnitSystems; for (const RifDataSourceForRftPlt& source : m_selectedSources.v()) { if (source.eclCase()) presentUnitSystems.insert(source.eclCase()->eclipseCaseData()->unitsType()); @@ -179,27 +177,35 @@ void RimWellPltPlot::setPlotXAxisTitles(RimWellLogTrack* plotTrack) { if (source.wellLogFile()->wellLogFileData()) { - // Todo: Handle different units in the relevant las channels + // Todo: Handle different units in the relevant las channels switch (source.wellLogFile()->wellLogFileData()->depthUnit()) { - case RiaDefines::UNIT_METER: presentUnitSystems.insert(RiaEclipseUnitTools::UNITS_METRIC); - case RiaDefines::UNIT_FEET: presentUnitSystems.insert(RiaEclipseUnitTools::UNITS_FIELD); - case RiaDefines::UNIT_NONE: presentUnitSystems.insert(RiaEclipseUnitTools::UNITS_UNKNOWN); - } + case RiaDefines::UNIT_METER: + presentUnitSystems.insert(RiaEclipseUnitTools::UNITS_METRIC); + case RiaDefines::UNIT_FEET: + presentUnitSystems.insert(RiaEclipseUnitTools::UNITS_FIELD); + case RiaDefines::UNIT_NONE: + presentUnitSystems.insert(RiaEclipseUnitTools::UNITS_UNKNOWN); + } } } } - if (presentUnitSystems.size() > 1) { QMessageBox::warning(nullptr, "ResInsight PLT Plot", "Inconsistent units in PLT plot");} + if (presentUnitSystems.size() > 1) + { + QMessageBox::warning(nullptr, "ResInsight PLT Plot", "Inconsistent units in PLT plot"); + } - if (presentUnitSystems.size() <= 0 ) return; + if (presentUnitSystems.empty()) return; RiaEclipseUnitTools::UnitSystem unitSet = *presentUnitSystems.begin(); QString axisTitle; - if (m_useReservoirConditionCurves) axisTitle += RimWellPlotTools::flowPlotAxisTitle(RimWellLogFile::WELL_FLOW_COND_RESERVOIR, unitSet); + if (m_useReservoirConditionCurves) + axisTitle += RimWellPlotTools::flowPlotAxisTitle(RimWellLogFile::WELL_FLOW_COND_RESERVOIR, unitSet); if (m_useReservoirConditionCurves && m_useStandardConditionCurves) axisTitle += " | "; - if (m_useStandardConditionCurves) axisTitle += RimWellPlotTools::flowPlotAxisTitle(RimWellLogFile::WELL_FLOW_COND_STANDARD, unitSet); + if (m_useStandardConditionCurves) + axisTitle += RimWellPlotTools::flowPlotAxisTitle(RimWellLogFile::WELL_FLOW_COND_STANDARD, unitSet); plotTrack->setXAxisTitle(axisTitle); #if 0 @@ -224,39 +230,39 @@ void RimWellPltPlot::setPlotXAxisTitles(RimWellLogTrack* plotTrack) } plotTrack->setXAxisTitle("Surface Flow Rate " + unitText); - #endif +#endif } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RimWellPltPlot::updateFormationsOnPlot() const { if (m_wellLogPlot->trackCount() > 0) { - RimProject* proj = RiaApplication::instance()->project(); + RimProject* proj = RiaApplication::instance()->project(); RimWellPath* wellPath = proj->wellPathByName(m_wellPathName); RimCase* formationNamesCase = m_wellLogPlot->trackByIndex(0)->formationNamesCase(); - if ( !formationNamesCase ) + if (!formationNamesCase) { /// Set default case. Todo : Use the first of the selected cases in the plot std::vector cases; proj->allCases(cases); - if ( !cases.empty() ) + if (!cases.empty()) { formationNamesCase = cases[0]; } } - + m_wellLogPlot->trackByIndex(0)->setAndUpdateWellPathFormationNamesData(formationNamesCase, wellPath); } } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RimWellPltPlot::updateWidgetTitleWindowTitle() { @@ -276,18 +282,21 @@ void RimWellPltPlot::updateWidgetTitleWindowTitle() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- -std::set < RiaRftPltCurveDefinition > RimWellPltPlot::selectedCurveDefs() const +std::set RimWellPltPlot::selectedCurveDefs() const { + std::set channelTypesToUse = RifEclipseRftAddress::pltPlotChannelTypes(); + return RimWellPlotTools::curveDefsFromTimesteps(RimWellPlotTools::simWellName(m_wellPathName), m_selectedTimeSteps.v(), false, - selectedSourcesExpanded()); + selectedSourcesExpanded(), + channelTypesToUse); } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- class RigResultPointCalculator { @@ -295,41 +304,44 @@ class RigResultPointCalculator RigResultPointCalculator() {} virtual ~RigResultPointCalculator() {} - const std::vector & pipeBranchCLCoords() { return m_pipeBranchCLCoords; } - const std::vector & pipeBranchWellResultPoints() { return m_pipeBranchWellResultPoints; } - const std::vector & pipeBranchMeasuredDepths() { return m_pipeBranchMeasuredDepths; } + const std::vector& pipeBranchCLCoords() + { + return m_pipeBranchCLCoords; + } + const std::vector& pipeBranchWellResultPoints() + { + return m_pipeBranchWellResultPoints; + } + const std::vector& pipeBranchMeasuredDepths() + { + return m_pipeBranchMeasuredDepths; + } protected: - - RigEclipseWellLogExtractor* findWellLogExtractor(const QString& wellPathName, - RimEclipseResultCase* eclCase) + RigEclipseWellLogExtractor* findWellLogExtractor(const QString& wellPathName, RimEclipseResultCase* eclCase) { - RimProject* proj = RiaApplication::instance()->project(); - RimWellPath* wellPath = proj->wellPathByName(wellPathName); - RimWellLogPlotCollection* wellLogCollection = proj->mainPlotCollection()->wellLogPlotCollection(); - RigEclipseWellLogExtractor* eclExtractor = wellLogCollection->findOrCreateExtractor(wellPath, eclCase); + RimProject* proj = RiaApplication::instance()->project(); + RimWellPath* wellPath = proj->wellPathByName(wellPathName); + RimWellLogPlotCollection* wellLogCollection = proj->mainPlotCollection()->wellLogPlotCollection(); + RigEclipseWellLogExtractor* eclExtractor = wellLogCollection->findOrCreateExtractor(wellPath, eclCase); return eclExtractor; } - - std::vector m_pipeBranchCLCoords; - std::vector m_pipeBranchWellResultPoints; - std::vector m_pipeBranchMeasuredDepths; + std::vector m_pipeBranchCLCoords; + std::vector m_pipeBranchWellResultPoints; + std::vector m_pipeBranchMeasuredDepths; }; //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- class RigRftResultPointCalculator : public RigResultPointCalculator { public: - RigRftResultPointCalculator(const QString& wellPathName, - RimEclipseResultCase* eclCase, - QDateTime m_timeStep) + RigRftResultPointCalculator(const QString& wellPathName, RimEclipseResultCase* eclCase, QDateTime m_timeStep) { - RifEclipseRftAddress gasRateAddress(RimWellPlotTools::simWellName(wellPathName), m_timeStep, RifEclipseRftAddress::GRAT); RifEclipseRftAddress oilRateAddress(RimWellPlotTools::simWellName(wellPathName), m_timeStep, RifEclipseRftAddress::ORAT); RifEclipseRftAddress watRateAddress(RimWellPlotTools::simWellName(wellPathName), m_timeStep, RifEclipseRftAddress::WRAT); @@ -353,8 +365,8 @@ class RigRftResultPointCalculator : public RigResultPointCalculator for (size_t rftCellIdx = 0; rftCellIdx < rftIndices.size(); rftCellIdx++) { - caf::VecIjk ijkIndex = rftIndices[rftCellIdx]; - size_t globalCellIndex = mainGrid->cellIndexFromIJK(ijkIndex.i(), ijkIndex.j(), ijkIndex.k()); + caf::VecIjk ijkIndex = rftIndices[rftCellIdx]; + size_t globalCellIndex = mainGrid->cellIndexFromIJK(ijkIndex.i(), ijkIndex.j(), ijkIndex.k()); globCellIdxToIdxInRftFile[globalCellIndex] = rftCellIdx; } @@ -383,67 +395,68 @@ class RigRftResultPointCalculator : public RigResultPointCalculator m_pipeBranchMeasuredDepths.push_back(intersections[wpExIdx].endMD); RigWellResultPoint resPoint; - resPoint.m_isOpen = true; - resPoint.m_gridIndex = 0; // Always main grid + resPoint.m_isOpen = true; + resPoint.m_gridIndex = 0; // Always main grid resPoint.m_gridCellIndex = globCellIdx; // Shortcut, since we only have main grid results from RFT - resPoint.m_gasRate = RiaEclipseUnitTools::convertSurfaceGasFlowRateToOilEquivalents(eclCase->eclipseCaseData()->unitsType(), - gasRates[it->second]); - resPoint.m_oilRate = oilRates[it->second]; + resPoint.m_gasRate = RiaEclipseUnitTools::convertSurfaceGasFlowRateToOilEquivalents( + eclCase->eclipseCaseData()->unitsType(), gasRates[it->second]); + resPoint.m_oilRate = oilRates[it->second]; resPoint.m_waterRate = watRates[it->second]; m_pipeBranchWellResultPoints.push_back(resPoint); - - if ( wpExIdx < intersections.size() - 1 ) + + if (wpExIdx < intersections.size() - 1) { - m_pipeBranchWellResultPoints.push_back(RigWellResultPoint()); // Invalid res point describing the "line" between the cells + m_pipeBranchWellResultPoints.push_back( + RigWellResultPoint()); // Invalid res point describing the "line" between the cells } } } - - }; //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- -class RigSimWellResultPointCalculator: public RigResultPointCalculator +class RigSimWellResultPointCalculator : public RigResultPointCalculator { public: - RigSimWellResultPointCalculator(const QString& wellPathName, - RimEclipseResultCase* eclCase, - QDateTime m_timeStep) + RigSimWellResultPointCalculator(const QString& wellPathName, RimEclipseResultCase* eclCase, QDateTime m_timeStep) { // Find timestep index from qdatetime const std::vector timeSteps = eclCase->eclipseCaseData()->results(RiaDefines::MATRIX_MODEL)->timeStepDates(); - size_t tsIdx = timeSteps.size(); - for ( tsIdx = 0; tsIdx < timeSteps.size(); ++tsIdx) { if (timeSteps[tsIdx] == m_timeStep) break; } + size_t tsIdx = timeSteps.size(); + for (tsIdx = 0; tsIdx < timeSteps.size(); ++tsIdx) + { + if (timeSteps[tsIdx] == m_timeStep) break; + } if (tsIdx >= timeSteps.size()) return; // Build search map into simulation well data - - std::map > globCellIdxToIdxInSimWellBranch; - const RimWellPath* wellPath = RimWellPlotTools::wellPathByWellPathNameOrSimWellName(wellPathName); - const RigSimWellData* simWell = wellPath != nullptr ? eclCase->eclipseCaseData()->findSimWellData(wellPath->associatedSimulationWellName()) : nullptr; + std::map> globCellIdxToIdxInSimWellBranch; + + const RimWellPath* wellPath = RimWellPlotTools::wellPathByWellPathNameOrSimWellName(wellPathName); + const RigSimWellData* simWell = + wellPath != nullptr ? eclCase->eclipseCaseData()->findSimWellData(wellPath->associatedSimulationWellName()) : nullptr; if (!simWell) return; if (!simWell->hasWellResult(tsIdx)) return; - const RigWellResultFrame & resFrame = simWell->wellResultFrame(tsIdx); + const RigWellResultFrame& resFrame = simWell->wellResultFrame(tsIdx); const RigMainGrid* mainGrid = eclCase->eclipseCaseData()->mainGrid(); for (size_t brIdx = 0; brIdx < resFrame.m_wellResultBranches.size(); ++brIdx) { - const std::vector& branchResPoints = resFrame.m_wellResultBranches[brIdx].m_branchResultPoints; - for ( size_t wrpIdx = 0; wrpIdx < branchResPoints.size(); wrpIdx++ ) + const std::vector& branchResPoints = resFrame.m_wellResultBranches[brIdx].m_branchResultPoints; + for (size_t wrpIdx = 0; wrpIdx < branchResPoints.size(); wrpIdx++) { - const RigGridBase* grid = mainGrid->gridByIndex(branchResPoints[wrpIdx].m_gridIndex); - size_t globalCellIndex = grid->reservoirCellIndex(branchResPoints[wrpIdx].m_gridCellIndex); + const RigGridBase* grid = mainGrid->gridByIndex(branchResPoints[wrpIdx].m_gridIndex); + size_t globalCellIndex = grid->reservoirCellIndex(branchResPoints[wrpIdx].m_gridCellIndex); globCellIdxToIdxInSimWellBranch[globalCellIndex] = std::make_pair(brIdx, wrpIdx); } @@ -452,7 +465,7 @@ class RigSimWellResultPointCalculator: public RigResultPointCalculator RigEclipseWellLogExtractor* eclExtractor = findWellLogExtractor(wellPathName, eclCase); if (!eclExtractor) return; - + std::vector intersections = eclExtractor->cellIntersectionInfosAlongWellPath(); for (size_t wpExIdx = 0; wpExIdx < intersections.size(); wpExIdx++) @@ -475,24 +488,25 @@ class RigSimWellResultPointCalculator: public RigResultPointCalculator m_pipeBranchCLCoords.push_back(intersections[wpExIdx].endPoint); m_pipeBranchMeasuredDepths.push_back(intersections[wpExIdx].endMD); - const RigWellResultPoint& resPoint = resFrame.m_wellResultBranches[it->second.first].m_branchResultPoints[it->second.second]; + const RigWellResultPoint& resPoint = + resFrame.m_wellResultBranches[it->second.first].m_branchResultPoints[it->second.second]; m_pipeBranchWellResultPoints.push_back(resPoint); - if ( wpExIdx < intersections.size() - 1 ) + if (wpExIdx < intersections.size() - 1) { - m_pipeBranchWellResultPoints.push_back(RigWellResultPoint()); // Invalid res point describing the "line" between the cells + m_pipeBranchWellResultPoints.push_back( + RigWellResultPoint()); // Invalid res point describing the "line" between the cells } } } }; - //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RimWellPltPlot::syncCurvesFromUiSelection() { - RimWellLogTrack* plotTrack = m_wellLogPlot->trackByIndex(0); + RimWellLogTrack* plotTrack = m_wellLogPlot->trackByIndex(0); const std::set& curveDefs = selectedCurveDefs(); setPlotXAxisTitles(plotTrack); @@ -506,46 +520,42 @@ void RimWellPltPlot::syncCurvesFromUiSelection() QString dateFormatString; { std::vector allTimeSteps; - for ( const RiaRftPltCurveDefinition& curveDefToAdd : curveDefs ) + for (const RiaRftPltCurveDefinition& curveDefToAdd : curveDefs) { allTimeSteps.push_back(curveDefToAdd.timeStep()); } - dateFormatString = RimTools::createTimeFormatStringFromDates(allTimeSteps); + dateFormatString = RiaQDateTimeTools::createTimeFormatStringFromDates(allTimeSteps); } // Add curves for (const RiaRftPltCurveDefinition& curveDefToAdd : curveDefs) { - std::set selectedPhases = std::set(m_phases().begin(), m_phases().end()) ; + std::set selectedPhases = std::set(m_phases().begin(), m_phases().end()); RifDataSourceForRftPlt sourceDef = curveDefToAdd.address(); - QDateTime timeStep = curveDefToAdd.timeStep(); + QDateTime timeStep = curveDefToAdd.timeStep(); std::unique_ptr resultPointCalc; QString curveName; { - curveName += sourceDef.eclCase() ? sourceDef.eclCase()->caseUserDescription() : ""; + curveName += sourceDef.eclCase() ? sourceDef.eclCase()->caseUserDescription() : ""; curveName += sourceDef.wellLogFile() ? sourceDef.wellLogFile()->name() : ""; - if ( sourceDef.sourceType() == RifDataSourceForRftPlt::RFT ) curveName += ", RFT"; + if (sourceDef.sourceType() == RifDataSourceForRftPlt::RFT) curveName += ", RFT"; curveName += ", " + RiaQDateTimeTools::toStringUsingApplicationLocale(timeStep, dateFormatString); } RimEclipseResultCase* rimEclipseResultCase = dynamic_cast(sourceDef.eclCase()); - if ( sourceDef.sourceType() == RifDataSourceForRftPlt::RFT ) + if (sourceDef.sourceType() == RifDataSourceForRftPlt::RFT) { - resultPointCalc.reset(new RigRftResultPointCalculator(m_wellPathName, - rimEclipseResultCase, - timeStep)); + resultPointCalc.reset(new RigRftResultPointCalculator(m_wellPathName, rimEclipseResultCase, timeStep)); } else if (sourceDef.sourceType() == RifDataSourceForRftPlt::GRID) { - resultPointCalc.reset(new RigSimWellResultPointCalculator(m_wellPathName, - rimEclipseResultCase, - timeStep)); + resultPointCalc.reset(new RigSimWellResultPointCalculator(m_wellPathName, rimEclipseResultCase, timeStep)); } RiaEclipseUnitTools::UnitSystem unitSet = RiaEclipseUnitTools::UNITS_UNKNOWN; @@ -556,97 +566,101 @@ void RimWellPltPlot::syncCurvesFromUiSelection() if (resultPointCalc != nullptr) { - if ( resultPointCalc->pipeBranchCLCoords().size() ) - { - - if ( selectedPhases.count(FLOW_PHASE_TOTAL) - && m_useReservoirConditionCurves() - && sourceDef.sourceType() == RifDataSourceForRftPlt::GRID ) - { - RigAccWellFlowCalculator wfTotalAccumulator(resultPointCalc->pipeBranchCLCoords(), - resultPointCalc->pipeBranchWellResultPoints(), - resultPointCalc->pipeBranchMeasuredDepths(), - true); - - const std::vector& depthValues = wfTotalAccumulator.pseudoLengthFromTop(0); - - QString curveUnitText = RimWellPlotTools::flowUnitText(RimWellLogFile::WELL_FLOW_COND_RESERVOIR, unitSet); - - const std::vector accFlow = wfTotalAccumulator.accumulatedTracerFlowPrPseudoLength(RIG_FLOW_TOTAL_NAME, 0); - addStackedCurve(curveName + ", " + RIG_FLOW_TOTAL_NAME + " " + curveUnitText, - depthValues, - accFlow, - plotTrack, - cvf::Color3f::DARK_GRAY, - curveGroupId, - false); - curveGroupId++; - } - - if ( m_useStandardConditionCurves() ) - { - RigAccWellFlowCalculator wfPhaseAccumulator(resultPointCalc->pipeBranchCLCoords(), - resultPointCalc->pipeBranchWellResultPoints(), - resultPointCalc->pipeBranchMeasuredDepths(), - false); - - - const std::vector& depthValues = wfPhaseAccumulator.pseudoLengthFromTop(0); - std::vector tracerNames = wfPhaseAccumulator.tracerNames(); - for ( const QString& tracerName: tracerNames ) - { - auto color = tracerName == RIG_FLOW_OIL_NAME ? cvf::Color3f::DARK_GREEN : - tracerName == RIG_FLOW_GAS_NAME ? cvf::Color3f::DARK_RED : - tracerName == RIG_FLOW_WATER_NAME ? cvf::Color3f::BLUE : - cvf::Color3f::DARK_GRAY; - - if ( tracerName == RIG_FLOW_OIL_NAME && selectedPhases.count(FLOW_PHASE_OIL) - || tracerName == RIG_FLOW_GAS_NAME && selectedPhases.count(FLOW_PHASE_GAS) - || tracerName == RIG_FLOW_WATER_NAME && selectedPhases.count(FLOW_PHASE_WATER) ) - { - FlowPhase flowPhase = FLOW_PHASE_NONE; - if (tracerName == RIG_FLOW_OIL_NAME) flowPhase = FLOW_PHASE_OIL; - else if (tracerName == RIG_FLOW_GAS_NAME) flowPhase = FLOW_PHASE_GAS; - else if (tracerName == RIG_FLOW_WATER_NAME) flowPhase = FLOW_PHASE_WATER; - QString curveUnitText = RimWellPlotTools::curveUnitText(RimWellLogFile::WELL_FLOW_COND_STANDARD, unitSet, flowPhase); - - const std::vector accFlow = wfPhaseAccumulator.accumulatedTracerFlowPrPseudoLength(tracerName, 0); - addStackedCurve(curveName + ", " + tracerName + " " + curveUnitText, - depthValues, - accFlow, - plotTrack, - color, - curveGroupId, - false); - } - } - } - } + if (!resultPointCalc->pipeBranchCLCoords().empty()) + { + if (selectedPhases.count(FLOW_PHASE_TOTAL) && m_useReservoirConditionCurves() && + sourceDef.sourceType() == RifDataSourceForRftPlt::GRID) + { + RigAccWellFlowCalculator wfTotalAccumulator(resultPointCalc->pipeBranchCLCoords(), + resultPointCalc->pipeBranchWellResultPoints(), + resultPointCalc->pipeBranchMeasuredDepths(), + true); + + const std::vector& depthValues = wfTotalAccumulator.pseudoLengthFromTop(0); + + QString curveUnitText = RimWellPlotTools::flowUnitText(RimWellLogFile::WELL_FLOW_COND_RESERVOIR, unitSet); + + const std::vector accFlow = + wfTotalAccumulator.accumulatedTracerFlowPrPseudoLength(RIG_FLOW_TOTAL_NAME, 0); + addStackedCurve(curveName + ", " + RIG_FLOW_TOTAL_NAME + " " + curveUnitText, + depthValues, + accFlow, + plotTrack, + cvf::Color3f::DARK_GRAY, + curveGroupId, + false); + curveGroupId++; + } + + if (m_useStandardConditionCurves()) + { + RigAccWellFlowCalculator wfPhaseAccumulator(resultPointCalc->pipeBranchCLCoords(), + resultPointCalc->pipeBranchWellResultPoints(), + resultPointCalc->pipeBranchMeasuredDepths(), + false); + + const std::vector& depthValues = wfPhaseAccumulator.pseudoLengthFromTop(0); + std::vector tracerNames = wfPhaseAccumulator.tracerNames(); + for (const QString& tracerName : tracerNames) + { + auto color = tracerName == RIG_FLOW_OIL_NAME + ? cvf::Color3f::DARK_GREEN + : tracerName == RIG_FLOW_GAS_NAME + ? cvf::Color3f::DARK_RED + : tracerName == RIG_FLOW_WATER_NAME ? cvf::Color3f::BLUE : cvf::Color3f::DARK_GRAY; + + if (tracerName == RIG_FLOW_OIL_NAME && selectedPhases.count(FLOW_PHASE_OIL) || + tracerName == RIG_FLOW_GAS_NAME && selectedPhases.count(FLOW_PHASE_GAS) || + tracerName == RIG_FLOW_WATER_NAME && selectedPhases.count(FLOW_PHASE_WATER)) + { + FlowPhase flowPhase = FLOW_PHASE_NONE; + if (tracerName == RIG_FLOW_OIL_NAME) + flowPhase = FLOW_PHASE_OIL; + else if (tracerName == RIG_FLOW_GAS_NAME) + flowPhase = FLOW_PHASE_GAS; + else if (tracerName == RIG_FLOW_WATER_NAME) + flowPhase = FLOW_PHASE_WATER; + QString curveUnitText = + RimWellPlotTools::curveUnitText(RimWellLogFile::WELL_FLOW_COND_STANDARD, unitSet, flowPhase); + + const std::vector& accFlow = + wfPhaseAccumulator.accumulatedTracerFlowPrPseudoLength(tracerName, 0); + addStackedCurve(curveName + ", " + tracerName + " " + curveUnitText, + depthValues, + accFlow, + plotTrack, + color, + curveGroupId, + false); + } + } + } + } } - else if ( sourceDef.sourceType() == RifDataSourceForRftPlt::OBSERVED ) + else if (sourceDef.sourceType() == RifDataSourceForRftPlt::OBSERVED) { - if ( sourceDef.wellLogFile() && sourceDef.wellLogFile()->wellLogFileData() ) + if (sourceDef.wellLogFile() && sourceDef.wellLogFile()->wellLogFileData()) { RimWellLogFile::WellFlowCondition flowCondition = sourceDef.wellLogFile()->wellFlowRateCondition(); - if ( (m_useStandardConditionCurves() && flowCondition == RimWellLogFile::WELL_FLOW_COND_STANDARD) - || (m_useReservoirConditionCurves() && flowCondition == RimWellLogFile::WELL_FLOW_COND_RESERVOIR) ) + if ((m_useStandardConditionCurves() && flowCondition == RimWellLogFile::WELL_FLOW_COND_STANDARD) || + (m_useReservoirConditionCurves() && flowCondition == RimWellLogFile::WELL_FLOW_COND_RESERVOIR)) { - using ChannelValNameIdxTuple = std::tuple ; + using ChannelValNameIdxTuple = std::tuple; RigWellLogFile* wellLogFileData = sourceDef.wellLogFile()->wellLogFileData(); QStringList channelNames = wellLogFileData->wellLogChannelNames(); - std::multiset< ChannelValNameIdxTuple > sortedChannels; - std::vector > channelData; + std::multiset sortedChannels; + std::vector> channelData; channelData.resize(channelNames.size()); - for ( int chIdx = 0; chIdx < channelNames.size(); ++chIdx ) + for (int chIdx = 0; chIdx < channelNames.size(); ++chIdx) { QString channelName = channelNames[chIdx]; - channelData[chIdx] = wellLogFileData->values(channelName); - if ( channelData[chIdx].size() ) + channelData[chIdx] = wellLogFileData->values(channelName); + if (!channelData[chIdx].empty()) { sortedChannels.insert(ChannelValNameIdxTuple(-fabs(channelData[chIdx].front()), channelName, chIdx)); } @@ -661,22 +675,25 @@ void RimWellPltPlot::syncCurvesFromUiSelection() if (depthUnit == RiaDefines::UNIT_METER) unitSystem = RiaEclipseUnitTools::UNITS_METRIC; } - - for ( const ChannelValNameIdxTuple& channelInfo: sortedChannels ) + for (const ChannelValNameIdxTuple& channelInfo : sortedChannels) { const auto& channelName = std::get<1>(channelInfo); - if ( selectedPhases.count(RimWellPlotTools::flowPhaseFromChannelName(channelName)) > 0 ) + if (selectedPhases.count(RimWellPlotTools::flowPhaseFromChannelName(channelName)) > 0) { - auto color = RimWellPlotTools::isOilFlowChannel(channelName) ? cvf::Color3f::DARK_GREEN : - RimWellPlotTools::isGasFlowChannel(channelName) ? cvf::Color3f::DARK_RED : - RimWellPlotTools::isWaterFlowChannel(channelName) ? cvf::Color3f::BLUE : - cvf::Color3f::DARK_GRAY; + auto color = RimWellPlotTools::isOilFlowChannel(channelName) + ? cvf::Color3f::DARK_GREEN + : RimWellPlotTools::isGasFlowChannel(channelName) + ? cvf::Color3f::DARK_RED + : RimWellPlotTools::isWaterFlowChannel(channelName) ? cvf::Color3f::BLUE + : cvf::Color3f::DARK_GRAY; - FlowPhase flowPhase = FLOW_PHASE_NONE; - if (RimWellPlotTools::isOilFlowChannel(channelName)) flowPhase = FLOW_PHASE_OIL; - else if (RimWellPlotTools::isGasFlowChannel(channelName)) flowPhase = FLOW_PHASE_GAS; - else if (RimWellPlotTools::isWaterFlowChannel(channelName)) flowPhase = FLOW_PHASE_WATER; + if (RimWellPlotTools::isOilFlowChannel(channelName)) + flowPhase = FLOW_PHASE_OIL; + else if (RimWellPlotTools::isGasFlowChannel(channelName)) + flowPhase = FLOW_PHASE_GAS; + else if (RimWellPlotTools::isWaterFlowChannel(channelName)) + flowPhase = FLOW_PHASE_WATER; QString curveUnitText = RimWellPlotTools::curveUnitText(flowCondition, unitSystem, flowPhase); addStackedCurve(curveName + ", " + channelName + " " + curveUnitText, @@ -687,9 +704,9 @@ void RimWellPltPlot::syncCurvesFromUiSelection() curveGroupId, true); - // Total flow channel will end up first, so just increment the group + // Total flow channel will end up first, so just increment the group // idx to make the rest of the phases group together - if ( RimWellPlotTools::isTotalFlowChannel(channelName) ) curveGroupId++; + if (RimWellPlotTools::isTotalFlowChannel(channelName)) curveGroupId++; } } } @@ -704,15 +721,15 @@ void RimWellPltPlot::syncCurvesFromUiSelection() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- -void RimWellPltPlot::addStackedCurve(const QString& curveName, +void RimWellPltPlot::addStackedCurve(const QString& curveName, const std::vector& depthValues, const std::vector& accFlow, - RimWellLogTrack* plotTrack, - cvf::Color3f color, - int curveGroupId, - bool doFillCurve) + RimWellLogTrack* plotTrack, + cvf::Color3f color, + int curveGroupId, + bool doFillCurve) { RimWellFlowRateCurve* curve = new RimWellFlowRateCurve; curve->setFlowValuesPrDepthValue(curveName, depthValues, accFlow); @@ -736,7 +753,7 @@ void RimWellPltPlot::addStackedCurve(const QString& curveName, } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- std::vector RimWellPltPlot::selectedSourcesExpanded() const { @@ -757,7 +774,7 @@ std::vector RimWellPltPlot::selectedSourcesExpanded() co } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- QWidget* RimWellPltPlot::viewWidget() { @@ -765,7 +782,7 @@ QWidget* RimWellPltPlot::viewWidget() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RimWellPltPlot::zoomAll() { @@ -773,7 +790,7 @@ void RimWellPltPlot::zoomAll() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- RimWellLogPlot* RimWellPltPlot::wellLogPlot() const { @@ -781,7 +798,7 @@ RimWellLogPlot* RimWellPltPlot::wellLogPlot() const } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RimWellPltPlot::setCurrentWellName(const QString& currWellName) { @@ -789,7 +806,7 @@ void RimWellPltPlot::setCurrentWellName(const QString& currWellName) } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- const char* RimWellPltPlot::plotNameFormatString() { @@ -797,12 +814,13 @@ const char* RimWellPltPlot::plotNameFormatString() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- -QList RimWellPltPlot::calculateValueOptions(const caf::PdmFieldHandle* fieldNeedingOptions, bool * useOptionsOnly) +QList RimWellPltPlot::calculateValueOptions(const caf::PdmFieldHandle* fieldNeedingOptions, + bool* useOptionsOnly) { QList options; - const QString simWellName = RimWellPlotTools::simWellName(m_wellPathName); + const QString simWellName = RimWellPlotTools::simWellName(m_wellPathName); if (fieldNeedingOptions == &m_wellPathName) { @@ -813,24 +831,25 @@ QList RimWellPltPlot::calculateValueOptions(const caf::P std::set optionAddresses; const std::vector rftCases = RimWellPlotTools::rftCasesForWell(simWellName); - std::set availableRftSources; + std::set availableRftSources; for (const auto& rftCase : rftCases) { - std::set rftTimes = rftCase->rftReader()->availableTimeSteps(simWellName, { RifEclipseRftAddress::ORAT, - RifEclipseRftAddress::WRAT, - RifEclipseRftAddress::GRAT }); - if (rftTimes.size()) + std::set channelTypesToUse = RifEclipseRftAddress::pltPlotChannelTypes(); + + std::set rftTimes = rftCase->rftReader()->availableTimeSteps(simWellName, channelTypesToUse); + if (!rftTimes.empty()) { availableRftSources.insert(RifDataSourceForRftPlt(RifDataSourceForRftPlt::RFT, rftCase)); } } - if ( availableRftSources.size() ) + if (!availableRftSources.empty()) { - options.push_back(caf::PdmOptionItemInfo::createHeader(RifDataSourceForRftPlt::sourceTypeUiText(RifDataSourceForRftPlt::RFT), true)); + options.push_back(caf::PdmOptionItemInfo::createHeader( + RifDataSourceForRftPlt::sourceTypeUiText(RifDataSourceForRftPlt::RFT), true)); - for ( const auto& addr : availableRftSources ) + for (const auto& addr : availableRftSources) { auto item = caf::PdmOptionItemInfo(addr.eclCase()->caseUserDescription(), QVariant::fromValue(addr)); item.setLevel(1); @@ -839,9 +858,10 @@ QList RimWellPltPlot::calculateValueOptions(const caf::P } const std::vector gridCases = RimWellPlotTools::gridCasesForWell(simWellName); - if (gridCases.size() > 0) + if (!gridCases.empty()) { - options.push_back(caf::PdmOptionItemInfo::createHeader(RifDataSourceForRftPlt::sourceTypeUiText(RifDataSourceForRftPlt::GRID), true)); + options.push_back(caf::PdmOptionItemInfo::createHeader( + RifDataSourceForRftPlt::sourceTypeUiText(RifDataSourceForRftPlt::GRID), true)); } for (const auto& gridCase : gridCases) @@ -852,9 +872,10 @@ QList RimWellPltPlot::calculateValueOptions(const caf::P options.push_back(item); } - if (RimWellPlotTools::wellLogFilesContainingFlow(m_wellPathName).size() > 0) + if (!RimWellPlotTools::wellLogFilesContainingFlow(m_wellPathName).empty()) { - options.push_back(caf::PdmOptionItemInfo::createHeader(RifDataSourceForRftPlt::sourceTypeUiText(RifDataSourceForRftPlt::OBSERVED), true)); + options.push_back(caf::PdmOptionItemInfo::createHeader( + RifDataSourceForRftPlt::sourceTypeUiText(RifDataSourceForRftPlt::OBSERVED), true)); auto addr = RifDataSourceForRftPlt(RifDataSourceForRftPlt::OBSERVED); auto item = caf::PdmOptionItemInfo("Observed Data", QVariant::fromValue(addr)); @@ -865,12 +886,10 @@ QList RimWellPltPlot::calculateValueOptions(const caf::P } else if (fieldNeedingOptions == &m_selectedTimeSteps) { - RimWellPlotTools::calculateValueOptionsForTimeSteps(RimWellPlotTools::simWellName(m_wellPathName), - selectedSourcesExpanded(), - { RifEclipseRftAddress::ORAT, - RifEclipseRftAddress::WRAT, - RifEclipseRftAddress::GRAT }, - options); + std::set channelTypesToUse = RifEclipseRftAddress::pltPlotChannelTypes(); + + RimWellPlotTools::calculateValueOptionsForTimeSteps( + RimWellPlotTools::simWellName(m_wellPathName), selectedSourcesExpanded(), channelTypesToUse, options); } if (fieldNeedingOptions == &m_phases) @@ -885,7 +904,7 @@ QList RimWellPltPlot::calculateValueOptions(const caf::P } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RimWellPltPlot::fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue) { @@ -906,17 +925,18 @@ void RimWellPltPlot::fieldChangedByUi(const caf::PdmFieldHandle* changedField, c } else if (changedField == &m_selectedSources) { - RimProject* project = RiaApplication::instance()->project(); + RimProject* project = RiaApplication::instance()->project(); RimWellPath* wellPath = project->wellPathByName(m_wellPathName()); if (wellPath && !wellPath->wellPathGeometry()) { - for (RifDataSourceForRftPlt address : m_selectedSources()) + for (const RifDataSourceForRftPlt& address : m_selectedSources()) { if (address.sourceType() == RifDataSourceForRftPlt::RFT || address.sourceType() == RifDataSourceForRftPlt::GRID) { if (!wellPath->wellPathGeometry()) { - QString tmp = QString("Display of Measured Depth (MD) for Grid or RFT curves is not possible without a well log path, and the curve will be hidden in this mode.\n\n"); + QString tmp = QString("Display of Measured Depth (MD) for Grid or RFT curves is not possible without a " + "well log path, and the curve will be hidden in this mode.\n\n"); QMessageBox::warning(nullptr, "Grid/RFT curve without MD", tmp); @@ -928,8 +948,7 @@ void RimWellPltPlot::fieldChangedByUi(const caf::PdmFieldHandle* changedField, c } } - if (changedField == &m_selectedSources || - changedField == &m_selectedTimeSteps) + if (changedField == &m_selectedSources || changedField == &m_selectedTimeSteps) { updateFormationsOnPlot(); syncSourcesIoFieldFromGuiField(); @@ -940,21 +959,19 @@ void RimWellPltPlot::fieldChangedByUi(const caf::PdmFieldHandle* changedField, c plotTrack->calculateXZoomRangeAndUpdateQwt(); } - if ( changedField == &m_useStandardConditionCurves - || changedField == &m_useReservoirConditionCurves - || changedField == &m_phases) + if (changedField == &m_useStandardConditionCurves || changedField == &m_useReservoirConditionCurves || + changedField == &m_phases) { syncCurvesFromUiSelection(); m_wellLogPlot->updateDepthZoom(); RimWellLogTrack* const plotTrack = m_wellLogPlot->trackByIndex(0); plotTrack->calculateXZoomRangeAndUpdateQwt(); - } } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RimWellPltPlot::defineUiTreeOrdering(caf::PdmUiTreeOrdering& uiTreeOrdering, QString uiConfigName) { @@ -962,7 +979,7 @@ void RimWellPltPlot::defineUiTreeOrdering(caf::PdmUiTreeOrdering& uiTreeOrdering } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- QImage RimWellPltPlot::snapshotWindowContent() { @@ -971,14 +988,14 @@ QImage RimWellPltPlot::snapshotWindowContent() if (m_wellLogPlotWidget) { QPixmap pix = QPixmap::grabWidget(m_wellLogPlotWidget); - image = pix.toImage(); + image = pix.toImage(); } return image; } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RimWellPltPlot::defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering) { @@ -986,7 +1003,7 @@ void RimWellPltPlot::defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering.add(&m_userName); uiOrdering.add(&m_wellPathName); - + caf::PdmUiGroup* sourcesGroup = uiOrdering.addNewGroupWithKeyword("Sources", "Sources"); sourcesGroup->add(&m_selectedSources); @@ -1019,20 +1036,22 @@ void RimWellPltPlot::defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- -void RimWellPltPlot::defineEditorAttribute(const caf::PdmFieldHandle* field, QString uiConfigName, caf::PdmUiEditorAttribute* attribute) +void RimWellPltPlot::defineEditorAttribute(const caf::PdmFieldHandle* field, + QString uiConfigName, + caf::PdmUiEditorAttribute* attribute) { if (field == &m_phases) { - caf::PdmUiTreeSelectionEditorAttribute* attrib = dynamic_cast (attribute); - attrib->showTextFilter = false; - attrib->showToggleAllCheckbox = false; + caf::PdmUiTreeSelectionEditorAttribute* attrib = dynamic_cast(attribute); + attrib->showTextFilter = false; + attrib->showToggleAllCheckbox = false; } } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RimWellPltPlot::initAfterRead() { @@ -1043,7 +1062,7 @@ void RimWellPltPlot::initAfterRead() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RimWellPltPlot::setupBeforeSave() { @@ -1051,7 +1070,7 @@ void RimWellPltPlot::setupBeforeSave() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RimWellPltPlot::initAfterLoad() { @@ -1064,7 +1083,7 @@ void RimWellPltPlot::initAfterLoad() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RimWellPltPlot::syncSourcesIoFieldFromGuiField() { @@ -1074,15 +1093,14 @@ void RimWellPltPlot::syncSourcesIoFieldFromGuiField() { m_selectedSourcesForIo.push_back(new RimDataSourceForRftPlt(addr)); } - } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RimWellPltPlot::calculateValueOptionsForWells(QList& options) { - RimProject * proj = RiaApplication::instance()->project(); + RimProject* proj = RiaApplication::instance()->project(); if (proj != nullptr) { @@ -1091,7 +1109,7 @@ void RimWellPltPlot::calculateValueOptionsForWells(QList { const QString wellName = wellPath->name(); - if(wellPath->wellPathGeometry() || RimWellPlotTools::hasFlowData(wellPath)) + if (wellPath->wellPathGeometry() || RimWellPlotTools::hasFlowData(wellPath)) options.push_back(caf::PdmOptionItemInfo(wellName, wellName)); } } @@ -1100,7 +1118,7 @@ void RimWellPltPlot::calculateValueOptionsForWells(QList } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RimWellPltPlot::setDescription(const QString& description) { @@ -1110,7 +1128,7 @@ void RimWellPltPlot::setDescription(const QString& description) } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- QString RimWellPltPlot::description() const { @@ -1118,7 +1136,7 @@ QString RimWellPltPlot::description() const } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RimWellPltPlot::onLoadDataAndUpdate() { @@ -1144,7 +1162,7 @@ void RimWellPltPlot::onLoadDataAndUpdate() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- QWidget* RimWellPltPlot::createViewWidget(QWidget* mainWindowParent) { diff --git a/ApplicationCode/ProjectDataModel/Flow/RimWellPltPlot.h b/ApplicationCode/ProjectDataModel/Flow/RimWellPltPlot.h index 2186674528..307adb7113 100644 --- a/ApplicationCode/ProjectDataModel/Flow/RimWellPltPlot.h +++ b/ApplicationCode/ProjectDataModel/Flow/RimWellPltPlot.h @@ -17,12 +17,8 @@ ///////////////////////////////////////////////////////////////////////////////// #pragma once -#include "RimViewWindow.h" -#include "RigFlowDiagResultAddress.h" - -#include "RimDataSourceForRftPlt.h" #include "RifDataSourceForRftPltQMetaType.h" -#include "RimPlotCurve.h" + #include "RimWellPlotTools.h" #include "cafPdmField.h" @@ -34,9 +30,9 @@ #include #include #include + #include #include -#include "RifEclipseRftAddress.h" class RimEclipseCase; class RimEclipseResultCase; @@ -46,6 +42,8 @@ class RimWellLogPlot; class RimWellPath; class RiuWellPltPlot; class RimWellLogTrack; +class RiaRftPltCurveDefinition; +class RimDataSourceForRftPlt; namespace cvf { @@ -70,63 +68,62 @@ class RimWellPltPlot : public RimViewWindow RimWellPltPlot(); ~RimWellPltPlot() override; - void setDescription(const QString& description); - QString description() const; + void setDescription(const QString& description); + QString description() const; - QWidget* viewWidget() override; - void zoomAll() override; + QWidget* viewWidget() override; + void zoomAll() override; - RimWellLogPlot* wellLogPlot() const; + RimWellLogPlot* wellLogPlot() const; - void setCurrentWellName(const QString& currWellName); + void setCurrentWellName(const QString& currWellName); - static const char* plotNameFormatString(); + static const char* plotNameFormatString(); protected: // Overridden PDM methods - caf::PdmFieldHandle* userDescriptionField() override { return &m_userName; } - void fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue) override; - void defineUiTreeOrdering(caf::PdmUiTreeOrdering& uiTreeOrdering, QString uiConfigName) override; + caf::PdmFieldHandle* userDescriptionField() override { return &m_userName; } + void fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue) override; + void defineUiTreeOrdering(caf::PdmUiTreeOrdering& uiTreeOrdering, QString uiConfigName) override; - QList calculateValueOptions(const caf::PdmFieldHandle* fieldNeedingOptions, bool * useOptionsOnly) override; - void calculateValueOptionsForWells(QList& options); + QList calculateValueOptions(const caf::PdmFieldHandle* fieldNeedingOptions, bool * useOptionsOnly) override; + void calculateValueOptionsForWells(QList& options); - QImage snapshotWindowContent() override; + QImage snapshotWindowContent() override; - void defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering) override; - void defineEditorAttribute(const caf::PdmFieldHandle* field, QString uiConfigName, caf::PdmUiEditorAttribute* attribute) override; - void onLoadDataAndUpdate() override; + void defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering) override; + void defineEditorAttribute(const caf::PdmFieldHandle* field, QString uiConfigName, caf::PdmUiEditorAttribute* attribute) override; + void onLoadDataAndUpdate() override; - void initAfterRead() override; - void setupBeforeSave() override; - void initAfterLoad(); + void initAfterRead() override; + void setupBeforeSave() override; + void initAfterLoad(); private: + void syncSourcesIoFieldFromGuiField(); + void syncCurvesFromUiSelection(); - void syncSourcesIoFieldFromGuiField(); - void syncCurvesFromUiSelection(); - - std::set selectedCurveDefs() const; - void addStackedCurve(const QString& tracerName, - const std::vector& depthValues, - const std::vector& accFlow, - RimWellLogTrack* plotTrack, - cvf::Color3f color, - int curveGroupId, - bool doFillCurve); + std::set selectedCurveDefs() const; + void addStackedCurve(const QString& tracerName, + const std::vector& depthValues, + const std::vector& accFlow, + RimWellLogTrack* plotTrack, + cvf::Color3f color, + int curveGroupId, + bool doFillCurve); - std::vector selectedSourcesExpanded() const; + std::vector selectedSourcesExpanded() const; // RimViewWindow overrides - void updateWidgetTitleWindowTitle(); - QWidget* createViewWidget(QWidget* mainWindowParent) override; - void deleteViewWidget() override; + void updateWidgetTitleWindowTitle(); + QWidget* createViewWidget(QWidget* mainWindowParent) override; + void deleteViewWidget() override; - void setPlotXAxisTitles(RimWellLogTrack* plotTrack); + void setPlotXAxisTitles(RimWellLogTrack* plotTrack); - void updateFormationsOnPlot() const; + void updateFormationsOnPlot() const; private: caf::PdmField m_showPlotTitle; @@ -134,8 +131,8 @@ class RimWellPltPlot : public RimViewWindow caf::PdmField m_wellPathName; - caf::PdmField> m_selectedSources; - caf::PdmChildArrayField m_selectedSourcesForIo; + caf::PdmField> m_selectedSources; + caf::PdmChildArrayField m_selectedSourcesForIo; caf::PdmField> m_selectedTimeSteps; diff --git a/ApplicationCode/ProjectDataModel/Flow/RimWellRftPlot.cpp b/ApplicationCode/ProjectDataModel/Flow/RimWellRftPlot.cpp index 82383f0986..0dc7439a8b 100644 --- a/ApplicationCode/ProjectDataModel/Flow/RimWellRftPlot.cpp +++ b/ApplicationCode/ProjectDataModel/Flow/RimWellRftPlot.cpp @@ -105,8 +105,7 @@ RimWellRftPlot::RimWellRftPlot() m_selectedTimeSteps.uiCapability()->setAutoAddingOptionFromValue(false); this->setAsPlotMdiWindow(); - m_selectedSourcesOrTimeStepsFieldsChanged = false; - m_isOnLoad = true; + m_isOnLoad = true; } //-------------------------------------------------------------------------------------------------- @@ -152,11 +151,11 @@ void RimWellRftPlot::applyCurveAppearance(RimWellLogCurve* newCurve) static size_t defaultColorTableIndex = 0; static size_t defaultSymbolTableIndex = 0; - cvf::Color3f currentColor; - RiuQwtSymbol::PointSymbolEnum currentSymbol = symbolTable.front(); - RiuQwtPlotCurve::LineStyleEnum currentLineStyle = RiuQwtPlotCurve::STYLE_SOLID; - bool isCurrentColorSet = false; - bool isCurrentSymbolSet = false; + cvf::Color3f currentColor; + RiuQwtSymbol::PointSymbolEnum currentSymbol = symbolTable.front(); + RiuQwtPlotCurve::LineStyleEnum currentLineStyle = RiuQwtPlotCurve::STYLE_SOLID; + bool isCurrentColorSet = false; + bool isCurrentSymbolSet = false; std::set assignedColors; std::set assignedSymbols; @@ -302,8 +301,10 @@ void RimWellRftPlot::applyInitialSelections() m_selectedSources = sourcesToSelect; { - auto relevantTimeSteps = RimWellPlotTools::calculateRelevantTimeStepsFromCases( - associatedSimWellName(), m_selectedSources, {RifEclipseRftAddress::PRESSURE}); + std::set channelTypesToUse = RifEclipseRftAddress::rftPlotChannelTypes(); + + auto relevantTimeSteps = + RimWellPlotTools::calculateRelevantTimeStepsFromCases(associatedSimWellName(), m_selectedSources, channelTypesToUse); std::vector timeStepVector; for (const auto& item : relevantTimeSteps) @@ -412,8 +413,10 @@ void RimWellRftPlot::syncCurvesFromUiSelection() //-------------------------------------------------------------------------------------------------- std::set RimWellRftPlot::selectedCurveDefs() const { + std::set channelTypesToUse = RifEclipseRftAddress::rftPlotChannelTypes(); + return RimWellPlotTools::curveDefsFromTimesteps( - associatedSimWellName(), m_selectedTimeSteps.v(), true, selectedSourcesExpanded()); + associatedSimWellName(), m_selectedTimeSteps.v(), true, selectedSourcesExpanded(), channelTypesToUse); } //-------------------------------------------------------------------------------------------------- @@ -519,6 +522,11 @@ void RimWellRftPlot::updateCurvesInPlot(const std::set } } + if (m_wellLogPlot->depthType() == RimWellLogPlot::MEASURED_DEPTH) + { + assignWellPathToExtractionCurves(); + } + m_wellLogPlot->loadDataAndUpdate(); if (plotTrack->curveCount()) { @@ -659,8 +667,10 @@ QList RimWellRftPlot::calculateValueOptions(const caf::P } else if (fieldNeedingOptions == &m_selectedTimeSteps) { + std::set channelTypesToUse = RifEclipseRftAddress::rftPlotChannelTypes(); + RimWellPlotTools::calculateValueOptionsForTimeSteps( - associatedSimWellName(), selectedSourcesExpanded(), {RifEclipseRftAddress::PRESSURE}, options); + associatedSimWellName(), selectedSourcesExpanded(), channelTypesToUse, options); } else if (fieldNeedingOptions == &m_branchIndex) { @@ -682,17 +692,14 @@ void RimWellRftPlot::fieldChangedByUi(const caf::PdmFieldHandle* changedField, c if (changedField == &m_wellPathNameOrSimWellName) { setDescription(QString(plotNameFormatString()).arg(m_wellPathNameOrSimWellName)); - } - if (changedField == &m_wellPathNameOrSimWellName) - { - if (changedField == &m_wellPathNameOrSimWellName) - { - m_branchIndex = 0; - } + m_branchIndex = 0; RimWellLogTrack* const plotTrack = m_wellLogPlot->trackByIndex(0); - plotTrack->deleteAllCurves(); + if (plotTrack) + { + plotTrack->deleteAllCurves(); + } updateEditorsFromCurves(); updateFormationsOnPlot(); @@ -709,7 +716,6 @@ void RimWellRftPlot::fieldChangedByUi(const caf::PdmFieldHandle* changedField, c { updateFormationsOnPlot(); syncCurvesFromUiSelection(); - m_selectedSourcesOrTimeStepsFieldsChanged = true; } else if (changedField == &m_showPlotTitle) { @@ -746,12 +752,6 @@ QImage RimWellRftPlot::snapshotWindowContent() //-------------------------------------------------------------------------------------------------- void RimWellRftPlot::defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering) { - if (!m_selectedSourcesOrTimeStepsFieldsChanged) - { - updateEditorsFromCurves(); - } - m_selectedSourcesOrTimeStepsFieldsChanged = false; - uiOrdering.add(&m_userName); uiOrdering.add(&m_wellPathNameOrSimWellName); @@ -861,12 +861,39 @@ void RimWellRftPlot::onLoadDataAndUpdate() updateMdiWindowVisibility(); updateFormationsOnPlot(); + if (m_wellLogPlot->depthType() == RimWellLogPlot::MEASURED_DEPTH) + { + assignWellPathToExtractionCurves(); + } + m_wellLogPlot->loadDataAndUpdate(); updateEditorsFromCurves(); updateWidgetTitleWindowTitle(); } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimWellRftPlot::assignWellPathToExtractionCurves() +{ + RimProject* proj = RiaApplication::instance()->project(); + RimWellPath* wellPath = proj->wellPathByName(m_wellPathNameOrSimWellName); + + if (wellPath) + { + for (RimWellLogCurve* curve : m_wellLogPlot->trackByIndex(0)->curvesVector()) + { + auto extractionCurve = dynamic_cast(curve); + if (extractionCurve) + { + extractionCurve->setTrajectoryType(RimWellLogExtractionCurve::WELL_PATH); + extractionCurve->setWellPath(wellPath); + } + } + } +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/ProjectDataModel/Flow/RimWellRftPlot.h b/ApplicationCode/ProjectDataModel/Flow/RimWellRftPlot.h index 3e2dbc571e..367b7b2830 100644 --- a/ApplicationCode/ProjectDataModel/Flow/RimWellRftPlot.h +++ b/ApplicationCode/ProjectDataModel/Flow/RimWellRftPlot.h @@ -21,11 +21,6 @@ #include "RimViewWindow.h" -#include "RiaRftPltCurveDefinition.h" - -#include "RimCase.h" -#include "RimPlotCurve.h" - #include "RifDataSourceForRftPltQMetaType.h" #include "cafPdmField.h" @@ -36,6 +31,7 @@ #include #include #include + #include #include #include @@ -48,6 +44,8 @@ class RimWellLogPlot; class RimWellPath; class RiuWellRftPlot; class RigEclipseCaseData; +class RiaRftPltCurveDefinition; +class RifDataSourceForRftPlt; namespace cvf { class Color3f; @@ -73,60 +71,61 @@ class RimWellRftPlot : public RimViewWindow RimWellRftPlot(); ~RimWellRftPlot() override; - void setDescription(const QString& description); - QString description() const; + void setDescription(const QString& description); + QString description() const; - QWidget* viewWidget() override; - void zoomAll() override; + QWidget* viewWidget() override; + void zoomAll() override; - RimWellLogPlot* wellLogPlot() const; + RimWellLogPlot* wellLogPlot() const; - void setSimWellOrWellPathName(const QString& currWellName); - int branchIndex() const; + void setSimWellOrWellPathName(const QString& currWellName); - static const char* plotNameFormatString(); + int branchIndex() const; - void applyInitialSelections(); + void applyInitialSelections(); + + static const char* plotNameFormatString(); protected: // Overridden PDM methods - caf::PdmFieldHandle* userDescriptionField() override { return &m_userName; } - void fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue) override; - void defineUiTreeOrdering(caf::PdmUiTreeOrdering& uiTreeOrdering, QString uiConfigName) override; + caf::PdmFieldHandle* userDescriptionField() override { return &m_userName; } + void fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue) override; + void defineUiTreeOrdering(caf::PdmUiTreeOrdering& uiTreeOrdering, QString uiConfigName) override; - QList calculateValueOptions(const caf::PdmFieldHandle* fieldNeedingOptions, bool * useOptionsOnly) override; + QList calculateValueOptions(const caf::PdmFieldHandle* fieldNeedingOptions, bool * useOptionsOnly) override; - QImage snapshotWindowContent() override; + QImage snapshotWindowContent() override; - void defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering) override; - void onLoadDataAndUpdate() override; + void defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering) override; + void onLoadDataAndUpdate() override; private: - void calculateValueOptionsForWells(QList& options); - - void updateEditorsFromCurves(); - void updateWidgetTitleWindowTitle(); + void calculateValueOptionsForWells(QList& options); + void updateEditorsFromCurves(); + void updateWidgetTitleWindowTitle(); + void syncCurvesFromUiSelection(); + void assignWellPathToExtractionCurves(); - void syncCurvesFromUiSelection(); + std::set selectedCurveDefs() const; + std::set curveDefsFromCurves() const; - std::set selectedCurveDefs() const; - std::set curveDefsFromCurves() const; + void updateCurvesInPlot(const std::set& allCurveDefs, + const std::set& curveDefsToAdd, + const std::set& curvesToDelete); - void updateCurvesInPlot(const std::set& allCurveDefs, - const std::set& curveDefsToAdd, - const std::set& curvesToDelete); - std::vector selectedSourcesExpanded() const; + std::vector selectedSourcesExpanded() const; // RimViewWindow overrides - QWidget* createViewWidget(QWidget* mainWindowParent) override; - void deleteViewWidget() override; + QWidget* createViewWidget(QWidget* mainWindowParent) override; + void deleteViewWidget() override; - void applyCurveAppearance(RimWellLogCurve* newCurve); + void applyCurveAppearance(RimWellLogCurve* newCurve); - void updateFormationsOnPlot() const; - QString associatedSimWellName() const; + void updateFormationsOnPlot() const; + QString associatedSimWellName() const; private: caf::PdmField m_showPlotTitle; @@ -144,6 +143,5 @@ class RimWellRftPlot : public RimViewWindow QPointer m_wellLogPlotWidget; - bool m_selectedSourcesOrTimeStepsFieldsChanged; bool m_isOnLoad; }; diff --git a/ApplicationCode/ProjectDataModel/GridCrossPlots/CMakeLists_files.cmake b/ApplicationCode/ProjectDataModel/GridCrossPlots/CMakeLists_files.cmake new file mode 100644 index 0000000000..08df9907c6 --- /dev/null +++ b/ApplicationCode/ProjectDataModel/GridCrossPlots/CMakeLists_files.cmake @@ -0,0 +1,28 @@ + +set (SOURCE_GROUP_HEADER_FILES +${CMAKE_CURRENT_LIST_DIR}/RimGridCrossPlot.h +${CMAKE_CURRENT_LIST_DIR}/RimGridCrossPlotCollection.h +${CMAKE_CURRENT_LIST_DIR}/RimGridCrossPlotCurve.h +${CMAKE_CURRENT_LIST_DIR}/RimGridCrossPlotDataSet.h +${CMAKE_CURRENT_LIST_DIR}/RimSaturationPressurePlot.h +${CMAKE_CURRENT_LIST_DIR}/RimSaturationPressurePlotCollection.h +) + +set (SOURCE_GROUP_SOURCE_FILES +${CMAKE_CURRENT_LIST_DIR}/RimGridCrossPlot.cpp +${CMAKE_CURRENT_LIST_DIR}/RimGridCrossPlotCollection.cpp +${CMAKE_CURRENT_LIST_DIR}/RimGridCrossPlotCurve.cpp +${CMAKE_CURRENT_LIST_DIR}/RimGridCrossPlotDataSet.cpp +${CMAKE_CURRENT_LIST_DIR}/RimSaturationPressurePlot.cpp +${CMAKE_CURRENT_LIST_DIR}/RimSaturationPressurePlotCollection.cpp +) + +list(APPEND CODE_HEADER_FILES +${SOURCE_GROUP_HEADER_FILES} +) + +list(APPEND CODE_SOURCE_FILES +${SOURCE_GROUP_SOURCE_FILES} +) + +source_group( "ProjectDataModel\\GridCrossPlots" FILES ${SOURCE_GROUP_HEADER_FILES} ${SOURCE_GROUP_SOURCE_FILES} ${CMAKE_CURRENT_LIST_DIR}/CMakeLists_files.cmake ) diff --git a/ApplicationCode/ProjectDataModel/GridCrossPlots/CellFilters/CMakeLists_files.cmake b/ApplicationCode/ProjectDataModel/GridCrossPlots/CellFilters/CMakeLists_files.cmake new file mode 100644 index 0000000000..46fc736a04 --- /dev/null +++ b/ApplicationCode/ProjectDataModel/GridCrossPlots/CellFilters/CMakeLists_files.cmake @@ -0,0 +1,22 @@ + +set (SOURCE_GROUP_HEADER_FILES +${CMAKE_CURRENT_LIST_DIR}/RimPlotCellFilter.h +${CMAKE_CURRENT_LIST_DIR}/RimPlotCellFilterCollection.h +${CMAKE_CURRENT_LIST_DIR}/RimPlotCellPropertyFilter.h +) + +set (SOURCE_GROUP_SOURCE_FILES +${CMAKE_CURRENT_LIST_DIR}/RimPlotCellFilter.cpp +${CMAKE_CURRENT_LIST_DIR}/RimPlotCellFilterCollection.cpp +${CMAKE_CURRENT_LIST_DIR}/RimPlotCellPropertyFilter.cpp +) + +list(APPEND CODE_HEADER_FILES +${SOURCE_GROUP_HEADER_FILES} +) + +list(APPEND CODE_SOURCE_FILES +${SOURCE_GROUP_SOURCE_FILES} +) + +source_group( "ProjectDataModel\\GridCrossPlots\\CellFilters" FILES ${SOURCE_GROUP_HEADER_FILES} ${SOURCE_GROUP_SOURCE_FILES} ${CMAKE_CURRENT_LIST_DIR}/CMakeLists_files.cmake ) diff --git a/ApplicationCode/ProjectDataModel/GridCrossPlots/CellFilters/RimPlotCellFilter.cpp b/ApplicationCode/ProjectDataModel/GridCrossPlots/CellFilters/RimPlotCellFilter.cpp new file mode 100644 index 0000000000..6f08e60927 --- /dev/null +++ b/ApplicationCode/ProjectDataModel/GridCrossPlots/CellFilters/RimPlotCellFilter.cpp @@ -0,0 +1,59 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2019- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "RimPlotCellFilter.h" + +namespace caf +{ +template<> +void caf::AppEnum::setUp() +{ + addItem(RimPlotCellFilter::INCLUDE, "INCLUDE", "Include"); + addItem(RimPlotCellFilter::EXCLUDE, "EXCLUDE", "Exclude"); + setDefault(RimPlotCellFilter::INCLUDE); +} +} // namespace caf + +CAF_PDM_ABSTRACT_SOURCE_INIT(RimPlotCellFilter, "RimPlotCellFilter"); + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimPlotCellFilter::RimPlotCellFilter() +{ + CAF_PDM_InitFieldNoDefault(&m_filterMode, "FilterMode", "Filter Mode", "", "", ""); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimPlotCellFilter::updateCellVisibility(size_t timeStepIndex, cvf::UByteArray* cellVisibility) +{ + if (isChecked()) + { + updateCellVisibilityFromFilter(timeStepIndex, cellVisibility); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimPlotCellFilter::FilterModeType RimPlotCellFilter::filterMode() const +{ + return m_filterMode(); +} diff --git a/ApplicationCode/ProjectDataModel/GridCrossPlots/CellFilters/RimPlotCellFilter.h b/ApplicationCode/ProjectDataModel/GridCrossPlots/CellFilters/RimPlotCellFilter.h new file mode 100644 index 0000000000..e0eb10d594 --- /dev/null +++ b/ApplicationCode/ProjectDataModel/GridCrossPlots/CellFilters/RimPlotCellFilter.h @@ -0,0 +1,51 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2019- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "RimCheckableNamedObject.h" + +#include "cvfArray.h" +#include "cvfBase.h" + +//================================================================================================== +/// +//================================================================================================== +class RimPlotCellFilter : public RimCheckableNamedObject +{ + CAF_PDM_HEADER_INIT; + +public: + enum FilterModeType + { + INCLUDE, + EXCLUDE + }; + +public: + RimPlotCellFilter(); + + void updateCellVisibility(size_t timeStepIndex, cvf::UByteArray* cellVisibility); + FilterModeType filterMode() const; + +protected: + virtual void updateCellVisibilityFromFilter(size_t timeStepIndex, cvf::UByteArray* cellVisibility) = 0; + +private: + caf::PdmField> m_filterMode; +}; diff --git a/ApplicationCode/ProjectDataModel/GridCrossPlots/CellFilters/RimPlotCellFilterCollection.cpp b/ApplicationCode/ProjectDataModel/GridCrossPlots/CellFilters/RimPlotCellFilterCollection.cpp new file mode 100644 index 0000000000..76e0940d98 --- /dev/null +++ b/ApplicationCode/ProjectDataModel/GridCrossPlots/CellFilters/RimPlotCellFilterCollection.cpp @@ -0,0 +1,96 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2019- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "RimPlotCellFilterCollection.h" + +#include "RimEclipseResultCase.h" +#include "RimEclipseResultDefinition.h" + +CAF_PDM_SOURCE_INIT(RimPlotCellFilterCollection, "RimPlotCellFilterCollection"); + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimPlotCellFilterCollection::RimPlotCellFilterCollection() +{ + CAF_PDM_InitObject("Plot Cell Filters", "", "", ""); + + CAF_PDM_InitFieldNoDefault(&m_cellFilters, "CellFilters", "Cell Filters", "", "", ""); + m_cellFilters.uiCapability()->setUiHidden(true); + + setName("Filter Collection"); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimPlotCellFilterCollection::addCellFilter(RimPlotCellFilter* cellFilter) +{ + m_cellFilters.push_back(cellFilter); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +size_t RimPlotCellFilterCollection::cellFilterCount() const +{ + return m_cellFilters.size(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimPlotCellFilterCollection::computeCellVisibilityFromFilter(size_t timeStepIndex, cvf::UByteArray* cellVisibility) +{ + if (isChecked()) + { + updateCellVisibilityFromFilter(timeStepIndex, cellVisibility); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimPlotCellFilterCollection::setCase(RimCase* gridCase) +{ + RimEclipseResultCase* eclipseResultCase = dynamic_cast(gridCase); + if (eclipseResultCase) + { + std::vector resultDefinitions; + + this->descendantsIncludingThisOfType(resultDefinitions); + for (auto r : resultDefinitions) + { + r->setEclipseCase(eclipseResultCase); + } + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimPlotCellFilterCollection::updateCellVisibilityFromFilter(size_t timeStepIndex, cvf::UByteArray* cellVisibility) +{ + for (RimPlotCellFilter* f : m_cellFilters()) + { + if (f->isChecked()) + { + f->updateCellVisibility(timeStepIndex, cellVisibility); + } + } +} diff --git a/ApplicationCode/ProjectDataModel/GridCrossPlots/CellFilters/RimPlotCellFilterCollection.h b/ApplicationCode/ProjectDataModel/GridCrossPlots/CellFilters/RimPlotCellFilterCollection.h new file mode 100644 index 0000000000..eddec02982 --- /dev/null +++ b/ApplicationCode/ProjectDataModel/GridCrossPlots/CellFilters/RimPlotCellFilterCollection.h @@ -0,0 +1,49 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2019- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "RimPlotCellFilter.h" + +#include "cafPdmChildArrayField.h" + +class RimCase; + +//================================================================================================== +/// +//================================================================================================== +class RimPlotCellFilterCollection : public RimPlotCellFilter +{ + CAF_PDM_HEADER_INIT; + +public: + RimPlotCellFilterCollection(); + + void addCellFilter(RimPlotCellFilter* cellFilter); + size_t cellFilterCount() const; + + void computeCellVisibilityFromFilter(size_t timeStepIndex, cvf::UByteArray* cellVisibility); + + void setCase(RimCase* gridCase); + +protected: + void updateCellVisibilityFromFilter(size_t timeStepIndex, cvf::UByteArray* cellVisibility) override; + +private: + caf::PdmChildArrayField m_cellFilters; +}; diff --git a/ApplicationCode/ProjectDataModel/GridCrossPlots/CellFilters/RimPlotCellPropertyFilter.cpp b/ApplicationCode/ProjectDataModel/GridCrossPlots/CellFilters/RimPlotCellPropertyFilter.cpp new file mode 100644 index 0000000000..a1e0aa1deb --- /dev/null +++ b/ApplicationCode/ProjectDataModel/GridCrossPlots/CellFilters/RimPlotCellPropertyFilter.cpp @@ -0,0 +1,230 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2019- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "RimPlotCellPropertyFilter.h" + +#include "RiaLogging.h" + +#include "RigActiveCellInfo.h" +#include "RigResultAccessor.h" +#include "RigResultAccessorFactory.h" + +#include "RimEclipseCase.h" +#include "RimEclipseResultDefinition.h" +#include "RimGeoMechResultDefinition.h" + +#include "cafPdmUiDoubleSliderEditor.h" + +CAF_PDM_SOURCE_INIT(RimPlotCellPropertyFilter, "RimPlotCellPropertyFilter"); + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimPlotCellPropertyFilter::RimPlotCellPropertyFilter() +{ + CAF_PDM_InitObject("Plot Cell Property Filter", "", "", ""); + + CAF_PDM_InitFieldNoDefault(&m_resultDefinition, "ResultDefinition", "Result Definition", "", "", ""); + + // Set to hidden to avoid this item to been displayed as a child item + // Fields in this object are displayed using defineUiOrdering() + m_resultDefinition.uiCapability()->setUiHidden(true); + m_resultDefinition.uiCapability()->setUiTreeChildrenHidden(true); + + CAF_PDM_InitField(&m_lowerBound, "LowerBound", 0.0, "Min", "", "", ""); + m_lowerBound.uiCapability()->setUiEditorTypeName(caf::PdmUiDoubleSliderEditor::uiEditorTypeName()); + + CAF_PDM_InitField(&m_upperBound, "UpperBound", 0.0, "Max", "", "", ""); + m_upperBound.uiCapability()->setUiEditorTypeName(caf::PdmUiDoubleSliderEditor::uiEditorTypeName()); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimPlotCellPropertyFilter::setResultDefinition(caf::PdmObject* resultDefinition) +{ + m_resultDefinition = resultDefinition; + + updateName(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimPlotCellPropertyFilter::setValueRange(double lowerBound, double upperBound) +{ + m_lowerBound = lowerBound; + m_upperBound = upperBound; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimEclipseResultDefinition* RimPlotCellPropertyFilter::eclipseResultDefinition() +{ + caf::PdmObject* pdmObj = m_resultDefinition; + + return dynamic_cast(pdmObj); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimPlotCellPropertyFilter::findOrComputeMinMaxResultValues(double& minimumValue, double& maximumValue) +{ + RimEclipseResultDefinition* resDef = eclipseResultDefinition(); + if (resDef) + { + RimEclipseCase* eclCase = resDef->eclipseCase(); + if (!eclCase) return; + + RigEclipseCaseData* eclipseCaseData = eclCase->eclipseCaseData(); + if (!eclipseCaseData) return; + + resDef->loadResult(); + + RigCaseCellResultsData* cellResultsData = resDef->currentGridCellResults(); + if (!cellResultsData) return; + + cellResultsData->minMaxCellScalarValues(resDef->eclipseResultAddress(), minimumValue, maximumValue); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimPlotCellPropertyFilter::updateName() +{ + QString name = "Property filter - "; + + RimEclipseResultDefinition* resDef = eclipseResultDefinition(); + if (resDef) + { + name += resDef->resultVariableUiName(); + } + + setName(name); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimPlotCellPropertyFilter::updateCellVisibilityFromFilter(size_t timeStepIndex, cvf::UByteArray* visibleCells) +{ + CVF_ASSERT(visibleCells); + + RimEclipseResultDefinition* resDef = eclipseResultDefinition(); + if (resDef) + { + RimEclipseCase* eclCase = resDef->eclipseCase(); + if (!eclCase) return; + + RigEclipseCaseData* eclipseCaseData = eclCase->eclipseCaseData(); + if (!eclipseCaseData) return; + + resDef->loadResult(); + + RigCaseCellResultsData* cellResultsData = resDef->currentGridCellResults(); + if (!cellResultsData) return; + + if (!resDef->currentGridCellResults()->hasResultEntry(resDef->eclipseResultAddress())) return; + + const std::vector& cellResultValues = + cellResultsData->cellScalarResults(resDef->eclipseResultAddress(), timeStepIndex); + if (cellResultValues.empty()) return; + + const RigActiveCellInfo* actCellInfo = cellResultsData->activeCellInfo(); + size_t totalReservoirCellCount = actCellInfo->reservoirCellCount(); + + if (visibleCells->size() < totalReservoirCellCount) + { + QString message = QString("Size of visible Cells (%1) is less than total cell count (%2)") + .arg(visibleCells->size()) + .arg(totalReservoirCellCount); + + RiaLogging::error(message); + + return; + } + + bool isUsingGlobalActiveIndex = cellResultsData->isUsingGlobalActiveIndex(resDef->eclipseResultAddress()); + double lowerBound = m_lowerBound; + double upperBound = m_upperBound; + size_t cellResultIndex = 0; + double scalarValue = 0.0; + FilterModeType currentFilterMode = filterMode(); + + for (size_t reservoirCellIndex = 0; reservoirCellIndex < totalReservoirCellCount; ++reservoirCellIndex) + { + if (!actCellInfo->isActive(reservoirCellIndex)) continue; + + cellResultIndex = reservoirCellIndex; + if (isUsingGlobalActiveIndex) + { + cellResultIndex = actCellInfo->cellResultIndex(reservoirCellIndex); + } + + if (cellResultIndex != cvf::UNDEFINED_SIZE_T && cellResultIndex < cellResultValues.size()) + { + if ((*visibleCells)[reservoirCellIndex]) + { + scalarValue = cellResultValues[cellResultIndex]; + if (lowerBound <= scalarValue && scalarValue <= upperBound) + { + if (currentFilterMode == RimPlotCellFilter::EXCLUDE) + { + (*visibleCells)[reservoirCellIndex] = false; + } + } + else + { + if (currentFilterMode == RimPlotCellFilter::INCLUDE) + { + (*visibleCells)[reservoirCellIndex] = false; + } + } + } + } + } + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimPlotCellPropertyFilter::defineEditorAttribute(const caf::PdmFieldHandle* field, + QString uiConfigName, + caf::PdmUiEditorAttribute* attribute) +{ + if (field == &m_lowerBound || field == &m_upperBound) + { + caf::PdmUiDoubleSliderEditorAttribute* myAttr = dynamic_cast(attribute); + if (!myAttr) + { + return; + } + + double minimumValue = 0.0; + double maximumValue = 0.0; + + findOrComputeMinMaxResultValues(minimumValue, maximumValue); + + myAttr->m_minimum = minimumValue; + myAttr->m_maximum = maximumValue; + } +} diff --git a/ApplicationCode/ProjectDataModel/GridCrossPlots/CellFilters/RimPlotCellPropertyFilter.h b/ApplicationCode/ProjectDataModel/GridCrossPlots/CellFilters/RimPlotCellPropertyFilter.h new file mode 100644 index 0000000000..237f5a91d0 --- /dev/null +++ b/ApplicationCode/ProjectDataModel/GridCrossPlots/CellFilters/RimPlotCellPropertyFilter.h @@ -0,0 +1,62 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2019- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "RimPlotCellFilter.h" + +#include "cafPdmChildField.h" +#include "cafPdmField.h" + +#include "cvfArray.h" +#include "cvfBase.h" + +class RimEclipseResultDefinition; + +//================================================================================================== +/// +//================================================================================================== +class RimPlotCellPropertyFilter : public RimPlotCellFilter +{ + CAF_PDM_HEADER_INIT; + +public: + RimPlotCellPropertyFilter(); + + // Currently supported result definition is RimEclipseResultDefinition, but the interface is designed to also support + // RimGeoMechResultDefinition + void setResultDefinition(caf::PdmObject* resultDefinition); + + void setValueRange(double lowerBound, double upperBound); + +protected: + void updateCellVisibilityFromFilter(size_t timeStepIndex, cvf::UByteArray* visibleCells) override; + void defineEditorAttribute(const caf::PdmFieldHandle* field, + QString uiConfigName, + caf::PdmUiEditorAttribute* attribute) override; + +private: + RimEclipseResultDefinition* eclipseResultDefinition(); + void findOrComputeMinMaxResultValues(double& minimumValue, double& maximumValue); + void updateName(); + +private: + caf::PdmChildField m_resultDefinition; + caf::PdmField m_lowerBound; + caf::PdmField m_upperBound; +}; diff --git a/ApplicationCode/ProjectDataModel/GridCrossPlots/RimGridCrossPlot.cpp b/ApplicationCode/ProjectDataModel/GridCrossPlots/RimGridCrossPlot.cpp new file mode 100644 index 0000000000..75fd58a8ff --- /dev/null +++ b/ApplicationCode/ProjectDataModel/GridCrossPlots/RimGridCrossPlot.cpp @@ -0,0 +1,979 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2019- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// +#include "RimGridCrossPlot.h" + +#include "RiaApplication.h" +#include "RiaFontCache.h" +#include "RiaPreferences.h" + +#include "RifEclipseDataTableFormatter.h" +#include "RiuGridCrossQwtPlot.h" +#include "RiuPlotMainWindowTools.h" +#include "RiuQwtPlotTools.h" + +#include "RimGridCrossPlotCurve.h" +#include "RimGridCrossPlotDataSet.h" +#include "RimPlotAxisProperties.h" + +#include "cafPdmUiCheckBoxEditor.h" +#include "cafPdmUiTreeOrdering.h" + +#include "cafProgressInfo.h" +#include "cvfAssert.h" + +#include "qwt_legend.h" +#include "qwt_plot.h" +#include "qwt_plot_curve.h" +#include "qwt_scale_engine.h" + +#include + +CAF_PDM_SOURCE_INIT(RimGridCrossPlot, "RimGridCrossPlot"); + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimGridCrossPlot::RimGridCrossPlot() +{ + CAF_PDM_InitObject("Grid Cross Plot", ":/SummaryXPlotLight16x16.png", "", ""); + + CAF_PDM_InitField(&m_showInfoBox, "ShowInfoBox", true, "Show Info Box", "", "", ""); + CAF_PDM_InitField(&m_showLegend, "ShowLegend", true, "Show Legend", "", "", ""); + CAF_PDM_InitField(&m_legendFontSize, "LegendFontSize", 10, "Legend and Info Font Size", "", "", ""); + m_legendFontSize = RiaFontCache::pointSizeFromFontSizeEnum(RiaApplication::instance()->preferences()->defaultPlotFontSize()); + + CAF_PDM_InitFieldNoDefault(&m_nameConfig, "NameConfig", "Name Config", "", "", ""); + m_nameConfig.uiCapability()->setUiTreeHidden(true); + m_nameConfig.uiCapability()->setUiTreeChildrenHidden(true); + + CAF_PDM_InitFieldNoDefault(&m_xAxisProperties, "xAxisProperties", "X Axis", "", "", ""); + m_xAxisProperties.uiCapability()->setUiTreeHidden(true); + m_xAxisProperties = new RimPlotAxisProperties; + m_xAxisProperties->setNameAndAxis("X-Axis", QwtPlot::xBottom); + m_xAxisProperties->setEnableTitleTextSettings(false); + + CAF_PDM_InitFieldNoDefault(&m_yAxisProperties, "yAxisProperties", "Y Axis", "", "", ""); + m_yAxisProperties.uiCapability()->setUiTreeHidden(true); + m_yAxisProperties = new RimPlotAxisProperties; + m_yAxisProperties->setNameAndAxis("Y-Axis", QwtPlot::yLeft); + m_yAxisProperties->setEnableTitleTextSettings(false); + + CAF_PDM_InitFieldNoDefault(&m_crossPlotDataSets, "CrossPlotCurve", "Cross Plot Data Set", "", "", ""); + m_crossPlotDataSets.uiCapability()->setUiHidden(true); + + m_nameConfig = new RimGridCrossPlotNameConfig(this); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimGridCrossPlot::~RimGridCrossPlot() +{ + removeMdiWindowFromMdiArea(); + deleteViewWidget(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimGridCrossPlotDataSet* RimGridCrossPlot::createDataSet() +{ + RimGridCrossPlotDataSet* dataSet = new RimGridCrossPlotDataSet(); + m_crossPlotDataSets.push_back(dataSet); + return dataSet; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +int RimGridCrossPlot::indexOfDataSet(const RimGridCrossPlotDataSet* dataSetToCheck) const +{ + int index = 0; + for (auto dataSet : m_crossPlotDataSets()) + { + if (dataSet == dataSetToCheck) + { + return index; + } + if (dataSet->isChecked() && dataSet->visibleCurveCount() > 0u) + { + index++; + } + } + return -1; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimGridCrossPlot::addDataSet(RimGridCrossPlotDataSet* dataSet) +{ + m_crossPlotDataSets.push_back(dataSet); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector RimGridCrossPlot::dataSets() const +{ + return m_crossPlotDataSets.childObjects(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QWidget* RimGridCrossPlot::viewWidget() +{ + return m_qwtPlot; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QImage RimGridCrossPlot::snapshotWindowContent() +{ + QImage image; + + if (m_qwtPlot) + { + QPixmap pix = QPixmap::grabWidget(m_qwtPlot); + image = pix.toImage(); + } + + return image; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimGridCrossPlot::zoomAll() +{ + if (!m_qwtPlot) return; + + setAutoZoomForAllAxes(true); + updateAxisInQwt(RiaDefines::PLOT_AXIS_LEFT); + updateAxisInQwt(RiaDefines::PLOT_AXIS_BOTTOM); + + m_qwtPlot->replot(); + + updateAxisFromQwt(RiaDefines::PLOT_AXIS_LEFT); + updateAxisFromQwt(RiaDefines::PLOT_AXIS_BOTTOM); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimGridCrossPlot::calculateZoomRangeAndUpdateQwt() +{ + if (m_qwtPlot) + { + m_qwtPlot->replot(); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimGridCrossPlot::reattachCurvesToQwtAndReplot() +{ + if (m_qwtPlot) + { + for (auto dataSet : m_crossPlotDataSets) + { + dataSet->detachAllCurves(); + if (dataSet->isChecked()) + { + dataSet->setParentQwtPlotNoReplot(m_qwtPlot); + } + } + updateAxisDisplay(); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RimGridCrossPlot::createAutoName() const +{ + QStringList autoName; + if (!m_nameConfig->customName().isEmpty()) + { + autoName += m_nameConfig->customName(); + } + + if (m_nameConfig->addDataSetNames()) + { + QStringList dataSetStrings; + std::map> allNameComponents; + for (auto dataSet : m_crossPlotDataSets) + { + if (dataSet->isChecked()) + { + QStringList componentList; + auto dataSetNameComponents = dataSet->nameComponents(); + + for (auto dataSetNameComponent : dataSetNameComponents) + { + if (!dataSetNameComponent.second.isEmpty()) + { + if (allNameComponents[dataSetNameComponent.first].count(dataSetNameComponent.second) == 0u) + { + componentList += dataSetNameComponent.second; + allNameComponents[dataSetNameComponent.first].insert(dataSetNameComponent.second); + } + } + } + if (!componentList.isEmpty()) + { + dataSetStrings += componentList.join(", "); + } + } + } + + dataSetStrings.removeDuplicates(); + if (dataSetStrings.size() > 2) + { + autoName += QString("(%1 Data Sets)").arg(dataSetStrings.size()); + } + if (!dataSetStrings.isEmpty()) + { + autoName += QString("(%1)").arg(dataSetStrings.join("; ")); + } + } + + return autoName.join(" "); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RimGridCrossPlot::showInfoBox() const +{ + return m_showInfoBox(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +caf::PdmFieldHandle* RimGridCrossPlot::userDescriptionField() +{ + return m_nameConfig->nameField(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimGridCrossPlot::detachAllCurves() +{ + for (auto dataSet : m_crossPlotDataSets()) + { + dataSet->detachAllCurves(); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimGridCrossPlot::updateAxisScaling() +{ + loadDataAndUpdate(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimGridCrossPlot::updateAxisDisplay() +{ + if (!m_qwtPlot) return; + + updateAxisInQwt(RiaDefines::PLOT_AXIS_BOTTOM); + updateAxisInQwt(RiaDefines::PLOT_AXIS_LEFT); + + m_qwtPlot->updateAnnotationObjects(m_xAxisProperties); + m_qwtPlot->updateAnnotationObjects(m_yAxisProperties); + + m_qwtPlot->replot(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimGridCrossPlot::updateZoomWindowFromQwt() +{ + if (!m_qwtPlot) return; + + updateAxisFromQwt(RiaDefines::PLOT_AXIS_LEFT); + updateAxisFromQwt(RiaDefines::PLOT_AXIS_BOTTOM); + setAutoZoomForAllAxes(false); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimGridCrossPlot::selectAxisInPropertyEditor(int axis) +{ + RiuPlotMainWindowTools::showPlotMainWindow(); + if (axis == QwtPlot::yLeft) + { + RiuPlotMainWindowTools::selectAsCurrentItem(m_yAxisProperties); + } + else if (axis == QwtPlot::xBottom) + { + RiuPlotMainWindowTools::selectAsCurrentItem(m_xAxisProperties); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimGridCrossPlot::setAutoZoomForAllAxes(bool enableAutoZoom) +{ + m_xAxisProperties->setAutoZoom(enableAutoZoom); + m_yAxisProperties->setAutoZoom(enableAutoZoom); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +caf::PdmObject* RimGridCrossPlot::findRimPlotObjectFromQwtCurve(const QwtPlotCurve* qwtCurve) const +{ + for (auto dataSet : m_crossPlotDataSets) + { + for (auto curve : dataSet->curves()) + { + if (curve->qwtPlotCurve() == qwtCurve) + { + return curve; + } + } + } + return nullptr; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QWidget* RimGridCrossPlot::createViewWidget(QWidget* mainWindowParent) +{ + if (!m_qwtPlot) + { + m_qwtPlot = new RiuGridCrossQwtPlot(this, mainWindowParent); + + for (auto dataSet : m_crossPlotDataSets) + { + dataSet->setParentQwtPlotNoReplot(m_qwtPlot); + } + m_qwtPlot->replot(); + } + + return m_qwtPlot; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimGridCrossPlot::deleteViewWidget() +{ + detachAllCurves(); + if (m_qwtPlot) + { + m_qwtPlot->deleteLater(); + m_qwtPlot = nullptr; + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimGridCrossPlot::onLoadDataAndUpdate() +{ + updateMdiWindowVisibility(); + + for (auto dataSet : m_crossPlotDataSets) + { + dataSet->loadDataAndUpdate(false); + dataSet->updateConnectedEditors(); + } + + updateCurveNamesAndPlotTitle(); + updatePlot(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimGridCrossPlot::defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering) +{ + uiOrdering.add(&m_showInfoBox); + uiOrdering.add(&m_showLegend); + + if (m_showLegend()) + { + uiOrdering.add(&m_legendFontSize); + } + + caf::PdmUiGroup* nameGroup = uiOrdering.addNewGroup("Name Configuration"); + m_nameConfig->uiOrdering(uiConfigName, *nameGroup); + + uiOrdering.skipRemainingFields(true); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimGridCrossPlot::defineUiTreeOrdering(caf::PdmUiTreeOrdering& uiTreeOrdering, QString uiConfigName /*= ""*/) +{ + caf::PdmUiTreeOrdering* axisFolder = uiTreeOrdering.add("Axes", ":/Axes16x16.png"); + + axisFolder->add(&m_xAxisProperties); + axisFolder->add(&m_yAxisProperties); + + uiTreeOrdering.add(&m_crossPlotDataSets); + + uiTreeOrdering.skipRemainingChildren(true); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimGridCrossPlot::fieldChangedByUi(const caf::PdmFieldHandle* changedField, + const QVariant& oldValue, + const QVariant& newValue) +{ + if (changedField == &m_legendFontSize) + { + for (auto dataSet : m_crossPlotDataSets) + { + dataSet->updateLegendIcons(); + } + } + onLoadDataAndUpdate(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QList RimGridCrossPlot::calculateValueOptions(const caf::PdmFieldHandle* fieldNeedingOptions, + bool* useOptionsOnly) +{ + QList options; + + if (fieldNeedingOptions == &m_legendFontSize) + { + std::vector fontSizes; + fontSizes.push_back(8); + fontSizes.push_back(10); + fontSizes.push_back(12); + fontSizes.push_back(14); + fontSizes.push_back(16); + + for (int value : fontSizes) + { + QString text = QString("%1").arg(value); + options.push_back(caf::PdmOptionItemInfo(text, value)); + } + } + return options; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimGridCrossPlot::performAutoNameUpdate() +{ + updateCurveNamesAndPlotTitle(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimGridCrossPlot::updatePlot() +{ + if (m_qwtPlot) + { + RiuQwtPlotTools::setCommonPlotBehaviour(m_qwtPlot); + RiuQwtPlotTools::setDefaultAxes(m_qwtPlot); + + updateAxisDisplay(); + + for (auto dataSet : m_crossPlotDataSets) + { + dataSet->setParentQwtPlotNoReplot(m_qwtPlot); + } + + if (m_showLegend()) + { + // Will be released in plot destructor or when a new legend is set + QwtLegend* legend = new QwtLegend(m_qwtPlot); + + auto font = legend->font(); + font.setPointSize(m_legendFontSize()); + legend->setFont(font); + m_qwtPlot->insertLegend(legend, QwtPlot::BottomLegend); + } + else + { + m_qwtPlot->insertLegend(nullptr); + } + m_qwtPlot->updateLegendSizesToMatchPlot(); + m_qwtPlot->replot(); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimGridCrossPlot::updateCurveNamesAndPlotTitle() +{ + for (size_t i = 0; i < m_crossPlotDataSets.size(); ++i) + { + m_crossPlotDataSets[i]->updateCurveNames(i, m_crossPlotDataSets.size()); + } + + if (m_qwtPlot) + { + m_qwtPlot->setTitle(this->createAutoName()); + } + updateMdiWindowTitle(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimGridCrossPlot::swapAxes() +{ + RimPlotAxisProperties* xAxisProperties = m_xAxisProperties(); + RimPlotAxisProperties* yAxisProperties = m_yAxisProperties(); + + QString tmpName = xAxisProperties->name(); + QwtPlot::Axis tmpAxis = xAxisProperties->qwtPlotAxisType(); + xAxisProperties->setNameAndAxis(yAxisProperties->name(), yAxisProperties->qwtPlotAxisType()); + yAxisProperties->setNameAndAxis(tmpName, tmpAxis); + + m_xAxisProperties.removeChildObject(xAxisProperties); + m_yAxisProperties.removeChildObject(yAxisProperties); + m_yAxisProperties = xAxisProperties; + m_xAxisProperties = yAxisProperties; + + for (auto dataSet : m_crossPlotDataSets) + { + dataSet->swapAxisProperties(false); + } + + loadDataAndUpdate(); + + updateAxisDisplay(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RimGridCrossPlot::asciiTitleForPlotExport(int dataSetIndex) const +{ + if ((size_t)dataSetIndex < m_crossPlotDataSets.size()) + { + return m_crossPlotDataSets[dataSetIndex]->createAutoName(); + } + return "Data invalid"; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RimGridCrossPlot::asciiDataForPlotExport(int dataSetIndex) const +{ + if ((size_t)dataSetIndex < m_crossPlotDataSets.size()) + { + QString asciiData; + QTextStream stringStream(&asciiData); + + RifEclipseDataTableFormatter formatter(stringStream); + formatter.setCommentPrefix(""); + formatter.setTableRowPrependText(""); + formatter.setTableRowLineAppendText(""); + formatter.setColumnSpacing(3); + + m_crossPlotDataSets[dataSetIndex]->exportFormattedData(formatter); + formatter.tableCompleted(); + return asciiData; + } + else + { + return "Data invalid and may have been deleted."; + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RiuGridCrossQwtPlot* RimGridCrossPlot::qwtPlot() const +{ + return m_qwtPlot; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RimGridCrossPlot::isXAxisLogarithmic() const +{ + return m_xAxisProperties->isLogarithmicScaleEnabled(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RimGridCrossPlot::isYAxisLogarithmic() const +{ + return m_yAxisProperties->isLogarithmicScaleEnabled(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimGridCrossPlot::setYAxisInverted(bool inverted) +{ + m_yAxisProperties->setAxisInverted(inverted); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +int RimGridCrossPlot::legendFontSize() const +{ + return m_legendFontSize; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RimGridCrossPlot::hasCustomFontSizes(RiaDefines::FontSettingType fontSettingType, int defaultFontSize) const +{ + if (fontSettingType != RiaDefines::PLOT_FONT) return false; + + for (auto plotAxis : allPlotAxes()) + { + if (plotAxis->titleFontSize() != defaultFontSize || plotAxis->valuesFontSize() != defaultFontSize) + { + return true; + } + } + + if (legendFontSize() != defaultFontSize) + { + return true; + } + return false; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RimGridCrossPlot::applyFontSize(RiaDefines::FontSettingType fontSettingType, int oldFontSize, int fontSize, bool forceChange /*= false*/) +{ + if (fontSettingType != RiaDefines::PLOT_FONT) return false; + + bool anyChange = false; + for (auto plotAxis : allPlotAxes()) + { + if (forceChange || plotAxis->titleFontSize() == oldFontSize) + { + plotAxis->setTitleFontSize(fontSize); + anyChange = true; + } + if (forceChange || plotAxis->valuesFontSize() == oldFontSize) + { + plotAxis->setValuesFontSize(fontSize); + anyChange = true; + } + } + + if (forceChange || legendFontSize() == oldFontSize) + { + m_legendFontSize = fontSize; + anyChange = true; + } + + if (anyChange) loadDataAndUpdate(); + + return anyChange; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RimGridCrossPlot::xAxisParameterString() const +{ + QStringList xAxisParams; + for (auto dataSet : m_crossPlotDataSets) + { + if (dataSet->isChecked() && dataSet->sampleCount() > 0u) + { + xAxisParams.push_back(dataSet->xAxisName()); + } + } + + xAxisParams.removeDuplicates(); + + if (xAxisParams.size() > 4) + { + return QString("%1 parameters").arg(xAxisParams.size()); + } + + return xAxisParams.join(", "); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RimGridCrossPlot::yAxisParameterString() const +{ + QStringList yAxisParams; + for (auto dataSet : m_crossPlotDataSets) + { + if (dataSet->isChecked() && dataSet->sampleCount() > 0u) + { + yAxisParams.push_back(dataSet->yAxisName()); + } + } + + yAxisParams.removeDuplicates(); + + if (yAxisParams.size() > 4) + { + return QString("%1 parameters").arg(yAxisParams.size()); + } + + return yAxisParams.join(", "); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimGridCrossPlot::updateAxisInQwt(RiaDefines::PlotAxis axisType) +{ + if (!m_qwtPlot) return; + + RimPlotAxisProperties* axisProperties = m_xAxisProperties(); + QString axisParameterString = xAxisParameterString(); + + if (axisType == RiaDefines::PLOT_AXIS_LEFT) + { + axisProperties = m_yAxisProperties(); + axisParameterString = yAxisParameterString(); + } + + QwtPlot::Axis qwtAxisId = axisProperties->qwtPlotAxisType(); + + if (axisProperties->isActive()) + { + m_qwtPlot->enableAxis(qwtAxisId, true); + + QwtText axisTitle(axisParameterString); + QFont titleFont = m_qwtPlot->axisTitle(qwtAxisId).font(); + titleFont.setBold(true); + titleFont.setPointSize(axisProperties->titleFontSize()); + axisTitle.setFont(titleFont); + + QFont valuesFont = m_qwtPlot->axisFont(qwtAxisId); + valuesFont.setPointSize(axisProperties->valuesFontSize()); + m_qwtPlot->setAxisFont(qwtAxisId, valuesFont); + + switch (axisProperties->titlePosition()) + { + case RimPlotAxisProperties::AXIS_TITLE_CENTER: + axisTitle.setRenderFlags(Qt::AlignCenter); + break; + case RimPlotAxisProperties::AXIS_TITLE_END: + axisTitle.setRenderFlags(Qt::AlignRight); + break; + } + + m_qwtPlot->setAxisTitle(qwtAxisId, axisTitle); + + if (axisProperties->isLogarithmicScaleEnabled) + { + QwtLogScaleEngine* currentScaleEngine = + dynamic_cast(m_qwtPlot->axisScaleEngine(axisProperties->qwtPlotAxisType())); + if (!currentScaleEngine) + { + m_qwtPlot->setAxisScaleEngine(axisProperties->qwtPlotAxisType(), new QwtLogScaleEngine); + m_qwtPlot->setAxisMaxMinor(axisProperties->qwtPlotAxisType(), 5); + } + + if (axisProperties->isAutoZoom()) + { + std::vector plotCurves = visibleQwtCurves(); + + double min, max; + RimPlotAxisLogRangeCalculator logRangeCalculator(qwtAxisId, plotCurves); + logRangeCalculator.computeAxisRange(&min, &max); + if (axisProperties->isAxisInverted()) + { + std::swap(min, max); + } + + m_qwtPlot->setAxisScale(qwtAxisId, min, max); + } + else + { + m_qwtPlot->setAxisScale(qwtAxisId, axisProperties->visibleRangeMin, axisProperties->visibleRangeMax); + } + } + else + { + QwtLinearScaleEngine* currentScaleEngine = + dynamic_cast(m_qwtPlot->axisScaleEngine(axisProperties->qwtPlotAxisType())); + if (!currentScaleEngine) + { + m_qwtPlot->setAxisScaleEngine(axisProperties->qwtPlotAxisType(), new QwtLinearScaleEngine); + m_qwtPlot->setAxisMaxMinor(axisProperties->qwtPlotAxisType(), 3); + } + + if (axisProperties->isAutoZoom()) + { + m_qwtPlot->setAxisAutoScale(qwtAxisId); + } + else + { + m_qwtPlot->setAxisScale(qwtAxisId, axisProperties->visibleRangeMin, axisProperties->visibleRangeMax); + } + } + m_qwtPlot->axisScaleEngine(axisProperties->qwtPlotAxisType()) + ->setAttribute(QwtScaleEngine::Inverted, axisProperties->isAxisInverted()); + } + else + { + m_qwtPlot->enableAxis(qwtAxisId, false); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimGridCrossPlot::updateAxisFromQwt(RiaDefines::PlotAxis axisType) +{ + CVF_ASSERT(m_qwtPlot); + + QwtInterval xAxisRange = m_qwtPlot->currentAxisRange(QwtPlot::xBottom); + QwtInterval yAxisRange = m_qwtPlot->currentAxisRange(QwtPlot::yLeft); + + RimPlotAxisProperties* axisProperties = m_xAxisProperties(); + QwtInterval axisRange = xAxisRange; + + if (axisType == RiaDefines::PLOT_AXIS_LEFT) + { + axisProperties = m_yAxisProperties(); + axisRange = yAxisRange; + } + + axisProperties->visibleRangeMin = axisRange.minValue(); + axisProperties->visibleRangeMax = axisRange.maxValue(); + + axisProperties->updateConnectedEditors(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector RimGridCrossPlot::visibleQwtCurves() const +{ + std::vector plotCurves; + for (auto dataSet : m_crossPlotDataSets) + { + if (dataSet->isChecked()) + { + for (auto curve : dataSet->curves()) + { + if (curve->isCurveVisible()) + { + plotCurves.push_back(curve->qwtPlotCurve()); + } + } + } + } + return plotCurves; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimPlotAxisProperties* RimGridCrossPlot::xAxisProperties() +{ + return m_xAxisProperties(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimPlotAxisProperties* RimGridCrossPlot::yAxisProperties() +{ + return m_yAxisProperties(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimGridCrossPlotNameConfig* RimGridCrossPlot::nameConfig() +{ + return m_nameConfig(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimGridCrossPlot::setShowInfoBox(bool enable) +{ + m_showInfoBox = enable; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::set RimGridCrossPlot::allPlotAxes() const +{ + return { m_xAxisProperties, m_yAxisProperties }; +} + +//-------------------------------------------------------------------------------------------------- +/// Name Configuration +/// +//-------------------------------------------------------------------------------------------------- + +CAF_PDM_SOURCE_INIT(RimGridCrossPlotNameConfig, "RimGridCrossPlotNameConfig"); + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimGridCrossPlotNameConfig::RimGridCrossPlotNameConfig(RimNameConfigHolderInterface* holder /*= nullptr*/) + : RimNameConfig(holder) +{ + CAF_PDM_InitObject("Cross Plot Name Generator", "", "", ""); + + CAF_PDM_InitField(&addDataSetNames, "AddDataSetNames", true, "Add Data Set Names", "", "", ""); + + setCustomName("Cross Plot"); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimGridCrossPlotNameConfig::defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering) +{ + RimNameConfig::defineUiOrdering(uiConfigName, uiOrdering); + uiOrdering.add(&addDataSetNames); +} diff --git a/ApplicationCode/ProjectDataModel/GridCrossPlots/RimGridCrossPlot.h b/ApplicationCode/ProjectDataModel/GridCrossPlots/RimGridCrossPlot.h new file mode 100644 index 0000000000..ea4b199e05 --- /dev/null +++ b/ApplicationCode/ProjectDataModel/GridCrossPlots/RimGridCrossPlot.h @@ -0,0 +1,141 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2019- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// +#pragma once + +#include "cafPdmChildArrayField.h" +#include "cafPdmChildField.h" +#include "cafPdmObject.h" + +#include "RiaDefines.h" +#include "RimRiuQwtPlotOwnerInterface.h" +#include "RimNameConfig.h" +#include "RimViewWindow.h" + +#include + +#include + +class RimPlotAxisPropertiesInterface; +class RimPlotAxisProperties; +class RimGridCrossPlotDataSet; +class RiuGridCrossQwtPlot; + +class RimGridCrossPlotNameConfig : public RimNameConfig +{ + CAF_PDM_HEADER_INIT; +public: + RimGridCrossPlotNameConfig(RimNameConfigHolderInterface* holder = nullptr); +public: + caf::PdmField addDataSetNames; + +protected: + virtual void defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering) override; + +}; + +class RimGridCrossPlot : public RimViewWindow, public RimRiuQwtPlotOwnerInterface, public RimNameConfigHolderInterface +{ + CAF_PDM_HEADER_INIT; + +public: + RimGridCrossPlot(); + ~RimGridCrossPlot(); + + RimGridCrossPlotDataSet* createDataSet(); + int indexOfDataSet(const RimGridCrossPlotDataSet* dataSet) const; + void addDataSet(RimGridCrossPlotDataSet* dataSet); + + std::vector dataSets() const; + + QWidget* viewWidget() override; + QImage snapshotWindowContent() override; + void zoomAll() override; + void calculateZoomRangeAndUpdateQwt(); + void reattachCurvesToQwtAndReplot(); + QString createAutoName() const override; + + bool showInfoBox() const; + caf::PdmFieldHandle* userDescriptionField() override; + void detachAllCurves(); + void performAutoNameUpdate() override; + void updateCurveNamesAndPlotTitle(); + void swapAxes(); + QString asciiTitleForPlotExport(int dataSetIndex) const; + QString asciiDataForPlotExport(int dataSetIndex) const; + RiuGridCrossQwtPlot* qwtPlot() const; + bool isXAxisLogarithmic() const; + bool isYAxisLogarithmic() const; + void setYAxisInverted(bool inverted); + int legendFontSize() const; + + bool hasCustomFontSizes(RiaDefines::FontSettingType fontSettingType, int defaultFontSize) const override; + bool applyFontSize(RiaDefines::FontSettingType fontSettingType, int oldFontSize, int fontSize, bool forceChange = false) override; + +public: + // Rim2dPlotInterface overrides + void updateAxisScaling() override; + void updateAxisDisplay() override; + void updateZoomWindowFromQwt() override; + void selectAxisInPropertyEditor(int axis) override; + void setAutoZoomForAllAxes(bool enableAutoZoom) override; + caf::PdmObject* findRimPlotObjectFromQwtCurve(const QwtPlotCurve* curve) const override; + +protected: + QWidget* createViewWidget(QWidget* mainWindowParent) override; + void deleteViewWidget() override; + void onLoadDataAndUpdate() override; + void defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering) override; + void defineUiTreeOrdering(caf::PdmUiTreeOrdering& uiTreeOrdering, QString uiConfigName = "") override; + + void fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue) override; + QList calculateValueOptions(const caf::PdmFieldHandle* fieldNeedingOptions, + bool* useOptionsOnly) override; + + void updatePlot(); + + virtual QString xAxisParameterString() const; + QString yAxisParameterString() const; + + void updateAxisInQwt(RiaDefines::PlotAxis axisType); + void updateAxisFromQwt(RiaDefines::PlotAxis axisType); + std::vector visibleQwtCurves() const; + + RimPlotAxisProperties* xAxisProperties(); + RimPlotAxisProperties* yAxisProperties(); + + RimGridCrossPlotNameConfig* nameConfig(); + void setShowInfoBox(bool enable); + + std::set allPlotAxes() const; +private: + caf::PdmField m_showInfoBox; + caf::PdmField m_showLegend; + caf::PdmField m_legendFontSize; + caf::PdmChildField m_nameConfig; + + caf::PdmChildField m_yAxisProperties; + caf::PdmChildField m_xAxisProperties; + + caf::PdmChildArrayField m_crossPlotDataSets; + + QPointer m_qwtPlot; + +}; + + + diff --git a/ApplicationCode/ProjectDataModel/GridCrossPlots/RimGridCrossPlotCollection.cpp b/ApplicationCode/ProjectDataModel/GridCrossPlots/RimGridCrossPlotCollection.cpp new file mode 100644 index 0000000000..bf6d29fdea --- /dev/null +++ b/ApplicationCode/ProjectDataModel/GridCrossPlots/RimGridCrossPlotCollection.cpp @@ -0,0 +1,75 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2019- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// +#include "RimGridCrossPlotCollection.h" + +#include "RimGridCrossPlot.h" + +CAF_PDM_SOURCE_INIT(RimGridCrossPlotCollection, "RimGridCrossPlotCollection"); + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimGridCrossPlotCollection::RimGridCrossPlotCollection() +{ + CAF_PDM_InitObject("Grid Cross Plots", ":/SummaryXPlotsLight16x16.png", "", ""); + + CAF_PDM_InitFieldNoDefault(&m_gridCrossPlots, "GridCrossPlots", "Grid Cross Plots", "", "", ""); + m_gridCrossPlots.uiCapability()->setUiHidden(true); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimGridCrossPlotCollection::~RimGridCrossPlotCollection() {} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimGridCrossPlotCollection::deleteAllChildObjects() +{ + m_gridCrossPlots.deleteAllChildObjects(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector RimGridCrossPlotCollection::gridCrossPlots() const +{ + return m_gridCrossPlots.childObjects(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimGridCrossPlot* RimGridCrossPlotCollection::createGridCrossPlot() +{ + RimGridCrossPlot* plot = new RimGridCrossPlot(); + plot->setAsPlotMdiWindow(); + + //plot->setDescription(QString("Summary Cross Plot %1").arg(m_gridCrossPlots.size())); + addGridCrossPlot(plot); + return plot; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimGridCrossPlotCollection::addGridCrossPlot(RimGridCrossPlot* plot) +{ + m_gridCrossPlots().push_back(plot); +} diff --git a/ApplicationCode/ProjectDataModel/GridCrossPlots/RimGridCrossPlotCollection.h b/ApplicationCode/ProjectDataModel/GridCrossPlots/RimGridCrossPlotCollection.h new file mode 100644 index 0000000000..8407e98367 --- /dev/null +++ b/ApplicationCode/ProjectDataModel/GridCrossPlots/RimGridCrossPlotCollection.h @@ -0,0 +1,45 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2019- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// +#pragma once + +#include "cafPdmChildArrayField.h" +#include "cafPdmObject.h" + +class RimGridCrossPlot; + +//================================================================================================== +/// +/// +//================================================================================================== +class RimGridCrossPlotCollection : public caf::PdmObject +{ + CAF_PDM_HEADER_INIT; + +public: + RimGridCrossPlotCollection(); + ~RimGridCrossPlotCollection() override; + + void deleteAllChildObjects(); + + std::vector gridCrossPlots() const; + RimGridCrossPlot* createGridCrossPlot(); + void addGridCrossPlot(RimGridCrossPlot* plot); + +private: + caf::PdmChildArrayField m_gridCrossPlots; +}; diff --git a/ApplicationCode/ProjectDataModel/GridCrossPlots/RimGridCrossPlotCurve.cpp b/ApplicationCode/ProjectDataModel/GridCrossPlots/RimGridCrossPlotCurve.cpp new file mode 100644 index 0000000000..b53ffe70bc --- /dev/null +++ b/ApplicationCode/ProjectDataModel/GridCrossPlots/RimGridCrossPlotCurve.cpp @@ -0,0 +1,185 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2019- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// +#include "RimGridCrossPlotCurve.h" + +#include "RiaColorTables.h" + +#include "RigCaseCellResultCalculator.h" +#include "RiuQwtSymbol.h" + +#include "RimCase.h" +#include "RimEclipseCase.h" +#include "RimEclipseResultDefinition.h" +#include "RimGridCrossPlot.h" +#include "RimTools.h" + +#include "cafPdmUiComboBoxEditor.h" + +#include +#include +#include + +#include "qwt_plot.h" +#include "qwt_plot_curve.h" +#include "qwt_graphic.h" + +#include + +CAF_PDM_SOURCE_INIT(RimGridCrossPlotCurve, "GridCrossPlotCurve"); + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimGridCrossPlotCurve::RimGridCrossPlotCurve() + : m_dataSetIndex(0) + , m_groupIndex(0) +{ + CAF_PDM_InitObject("Cross Plot Points", ":/WellLogCurve16x16.png", "", ""); + + setLineStyle(RiuQwtPlotCurve::STYLE_NONE); + setSymbol(RiuQwtSymbol::SYMBOL_NONE); + setSymbolSize(4); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimGridCrossPlotCurve::setGroupingInformation(int dataSetIndex, int groupIndex) +{ + m_dataSetIndex = dataSetIndex; + m_groupIndex = groupIndex; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimGridCrossPlotCurve::setSamples(const std::vector& xValues, const std::vector& yValues) +{ + CVF_ASSERT(xValues.size() == yValues.size()); + + m_qwtPlotCurve->setSamples(&xValues[0], &yValues[0], static_cast(xValues.size())); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimGridCrossPlotCurve::setCurveAutoAppearance() +{ + determineSymbol(); + updateCurveAppearance(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +int RimGridCrossPlotCurve::groupIndex() const +{ + return m_groupIndex; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +size_t RimGridCrossPlotCurve::sampleCount() const +{ + return m_qwtPlotCurve ? m_qwtPlotCurve->dataSize() : 0; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimGridCrossPlotCurve::determineLegendIcon() +{ + RimGridCrossPlot* plot = nullptr; + firstAncestorOrThisOfTypeAsserted(plot); + int fontSize = plot->legendFontSize(); + m_qwtPlotCurve->setLegendIconSize(QSize(fontSize, fontSize)); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimGridCrossPlotCurve::setBlackAndWhiteLegendIcons(bool blackAndWhite) +{ + m_qwtPlotCurve->setBlackAndWhiteLegendIcon(blackAndWhite); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimGridCrossPlotCurve::determineSymbol() +{ + RiuQwtSymbol::PointSymbolEnum symbol = RiuQwtSymbol::cycledSymbolStyle(m_dataSetIndex); + setSymbol(symbol); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimGridCrossPlotCurve::updateZoomInParentPlot() +{ + RimGridCrossPlot* plot; + this->firstAncestorOrThisOfTypeAsserted(plot); + plot->calculateZoomRangeAndUpdateQwt(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimGridCrossPlotCurve::updateLegendsInPlot() +{ + RimGridCrossPlot* plot = nullptr; + this->firstAncestorOrThisOfType(plot); + if (plot) + { + plot->reattachCurvesToQwtAndReplot(); + } + RimPlotCurve::updateLegendsInPlot(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RimGridCrossPlotCurve::createCurveAutoName() +{ + return m_customCurveName; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimGridCrossPlotCurve::onLoadDataAndUpdate(bool updateParentPlot) +{ + if (updateParentPlot) + { + m_parentQwtPlot->replot(); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimGridCrossPlotCurve::defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering) +{ + caf::PdmUiGroup* appearanceGroup = uiOrdering.addNewGroup("Appearance"); + RimPlotCurve::appearanceUiOrdering(*appearanceGroup); + caf::PdmUiGroup* nameGroup = uiOrdering.addNewGroup("Curve Name"); + nameGroup->add(&m_curveName); + nameGroup->add(&m_showLegend); + uiOrdering.skipRemainingFields(true); +} diff --git a/ApplicationCode/ProjectDataModel/GridCrossPlots/RimGridCrossPlotCurve.h b/ApplicationCode/ProjectDataModel/GridCrossPlots/RimGridCrossPlotCurve.h new file mode 100644 index 0000000000..cd94d6a2a5 --- /dev/null +++ b/ApplicationCode/ProjectDataModel/GridCrossPlots/RimGridCrossPlotCurve.h @@ -0,0 +1,64 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2019- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// +#pragma once + +#include "RimPlotCurve.h" + +#include "cafPdmChildField.h" +#include "cafPdmPtrField.h" + +#include +#include + +class RimCase; +class RimEclipseResultDefinition; +class QwtPlotCurve; + +//================================================================================================== +/// +/// +//================================================================================================== +class RimGridCrossPlotCurve : public RimPlotCurve +{ + CAF_PDM_HEADER_INIT; + +public: + RimGridCrossPlotCurve(); + ~RimGridCrossPlotCurve() override = default; + void setGroupingInformation(int dataSetIndex, int groupIndex); + void setSamples(const std::vector& xValues, const std::vector& yValues); + + void setCurveAutoAppearance(); + int groupIndex() const; + size_t sampleCount() const; + void determineLegendIcon(); + void setBlackAndWhiteLegendIcons(bool blackAndWhite); +protected: + + void determineSymbol(); + void updateZoomInParentPlot() override; + void updateLegendsInPlot() override; + QString createCurveAutoName() override; + void onLoadDataAndUpdate(bool updateParentPlot) override; + void defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering) override; + +private: + int m_dataSetIndex; + int m_groupIndex; +}; + diff --git a/ApplicationCode/ProjectDataModel/GridCrossPlots/RimGridCrossPlotDataSet.cpp b/ApplicationCode/ProjectDataModel/GridCrossPlots/RimGridCrossPlotDataSet.cpp new file mode 100644 index 0000000000..b491074dae --- /dev/null +++ b/ApplicationCode/ProjectDataModel/GridCrossPlots/RimGridCrossPlotDataSet.cpp @@ -0,0 +1,1390 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2019- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "RimGridCrossPlotDataSet.h" + +#include "RiaApplication.h" +#include "RiaColorTables.h" +#include "RiaLogging.h" + +#include "RifEclipseDataTableFormatter.h" + +#include "RigActiveCellInfo.h" +#include "RigActiveCellsResultAccessor.h" +#include "RigCaseCellResultCalculator.h" +#include "RigEclipseCaseData.h" +#include "RigEclipseCrossPlotDataExtractor.h" + +#include "RigFormationNames.h" +#include "RigMainGrid.h" + +#include "RiuGridCrossQwtPlot.h" + +#include "RimCase.h" +#include "RimEclipseCase.h" +#include "RimEclipseCellColors.h" +#include "RimEclipseResultCase.h" +#include "RimEclipseResultDefinition.h" +#include "RimEclipseView.h" +#include "RimGridCrossPlot.h" +#include "RimGridCrossPlotCurve.h" +#include "RimGridView.h" +#include "RimFormationNames.h" +#include "RimProject.h" +#include "RimRegularLegendConfig.h" +#include "RimTools.h" + +#include "CellFilters/RimPlotCellFilterCollection.h" + +#include "cafCategoryMapper.h" +#include "cafColorTable.h" +#include "cafPdmUiComboBoxEditor.h" +#include "cafPdmUiSliderEditor.h" +#include "cafPdmUiTreeOrdering.h" +#include "cafProgressInfo.h" +#include "cvfScalarMapper.h" +#include "cvfqtUtils.h" + +#include + +CAF_PDM_SOURCE_INIT(RimGridCrossPlotDataSet, "GridCrossPlotCurveSet"); + +namespace caf +{ +template<> +void RimGridCrossPlotDataSet::CurveGroupingEnum::setUp() +{ + addItem(RigGridCrossPlotCurveGrouping::NO_GROUPING, "NONE", "Nothing"); + addItem(RigGridCrossPlotCurveGrouping::GROUP_BY_TIME, "TIME", "Time Step"); + addItem(RigGridCrossPlotCurveGrouping::GROUP_BY_FORMATION, "FORMATION", "Formations"); + addItem(RigGridCrossPlotCurveGrouping::GROUP_BY_RESULT, "RESULT", "Result Property"); + setDefault(RigGridCrossPlotCurveGrouping::NO_GROUPING); +} +} // namespace caf + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimGridCrossPlotDataSet::RimGridCrossPlotDataSet() +{ + CAF_PDM_InitObject("Cross Plot Data Set", ":/WellLogCurve16x16.png", "", ""); + + CAF_PDM_InitFieldNoDefault(&m_case, "Case", "Case", "", "", ""); + m_case.uiCapability()->setUiTreeChildrenHidden(true); + CAF_PDM_InitField(&m_timeStep, "TimeStep", -1, "Time Step", "", "", ""); + m_timeStep.uiCapability()->setUiEditorTypeName(caf::PdmUiComboBoxEditor::uiEditorTypeName()); + + CAF_PDM_InitFieldNoDefault(&m_cellFilterView, "VisibleCellView", "Filter by 3d View Visibility", "", "", ""); + + CAF_PDM_InitFieldNoDefault(&m_grouping, "Grouping", "Group Data by", "", "", ""); + + CAF_PDM_InitFieldNoDefault(&m_xAxisProperty, "XAxisProperty", "X-Axis Property", "", "", ""); + m_xAxisProperty = new RimEclipseResultDefinition(caf::PdmUiItemInfo::TOP); + m_xAxisProperty.uiCapability()->setUiHidden(true); + m_xAxisProperty.uiCapability()->setUiTreeChildrenHidden(true); + m_xAxisProperty->setTernaryEnabled(false); + + CAF_PDM_InitFieldNoDefault(&m_yAxisProperty, "YAxisProperty", "Y-Axis Property", "", "", ""); + m_yAxisProperty = new RimEclipseResultDefinition(caf::PdmUiItemInfo::TOP); + m_yAxisProperty.uiCapability()->setUiHidden(true); + m_yAxisProperty.uiCapability()->setUiTreeChildrenHidden(true); + + m_yAxisProperty->setTernaryEnabled(false); + + CAF_PDM_InitFieldNoDefault(&m_groupingProperty, "GroupingProperty", "Data Grouping Property", "", "", ""); + m_groupingProperty = new RimEclipseCellColors; + m_groupingProperty.uiCapability()->setUiHidden(true); + CVF_ASSERT(m_groupingProperty->legendConfig()); + m_groupingProperty->legendConfig()->setMappingMode(RimRegularLegendConfig::CATEGORY_INTEGER); + m_groupingProperty->setTernaryEnabled(false); + + CAF_PDM_InitFieldNoDefault(&m_nameConfig, "NameConfig", "Name", "", "", ""); + m_nameConfig = new RimGridCrossPlotDataSetNameConfig(this); + m_nameConfig.uiCapability()->setUiTreeHidden(true); + m_nameConfig.uiCapability()->setUiTreeChildrenHidden(true); + + CAF_PDM_InitFieldNoDefault(&m_crossPlotCurves, "CrossPlotCurves", "Curves", "", "", ""); + m_crossPlotCurves.uiCapability()->setUiTreeHidden(true); + + CAF_PDM_InitField(&m_useCustomColor, "UseCustomColor", false, "Use Custom Color", "", "", ""); + CAF_PDM_InitField(&m_customColor, "CustomColor", cvf::Color3f(cvf::Color3f::BLACK), "Custom Color", "", "", ""); + + CAF_PDM_InitFieldNoDefault(&m_plotCellFilterCollection, "PlotCellFilterCollection", "Cell Filters", "", "", ""); + m_plotCellFilterCollection.uiCapability()->setUiHidden(true); + m_plotCellFilterCollection.uiCapability()->setUiTreeHidden(true); + m_plotCellFilterCollection.uiCapability()->setUiTreeChildrenHidden(true); + m_plotCellFilterCollection = new RimPlotCellFilterCollection; + + setDefaults(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimGridCrossPlotDataSet::setCellFilterView(RimGridView* cellFilterView) +{ + m_cellFilterView = cellFilterView; + auto eclipseView = dynamic_cast(m_cellFilterView()); + + if (eclipseView) + { + m_groupingProperty->setReservoirView(eclipseView); + RigEclipseResultAddress resAddr = eclipseView->cellResult()->eclipseResultAddress(); + if (resAddr.isValid()) + { + m_xAxisProperty->setResultType(resAddr.m_resultCatType); + m_xAxisProperty->setResultVariable(resAddr.m_resultName); + m_yAxisProperty->setResultType(RiaDefines::STATIC_NATIVE); + m_yAxisProperty->setResultVariable("DEPTH"); + m_timeStep = eclipseView->currentTimeStep(); + m_grouping = NO_GROUPING; + if (eclipseView->eclipseCase() && eclipseView->eclipseCase()->activeFormationNames()) + { + m_grouping = GROUP_BY_FORMATION; + m_groupingProperty->legendConfig()->setColorRange(RimRegularLegendConfig::CATEGORY); + } + + RimGridCrossPlot* parentPlot = nullptr; + firstAncestorOrThisOfType(parentPlot); + if (parentPlot) + { + parentPlot->setYAxisInverted(true); + } + } + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimGridCrossPlotDataSet::loadDataAndUpdate(bool updateParentPlot) +{ + onLoadDataAndUpdate(updateParentPlot); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimGridCrossPlotDataSet::setParentQwtPlotNoReplot(QwtPlot* parent) +{ + for (auto& curve : m_crossPlotCurves()) + { + curve->setParentQwtPlotNoReplot(m_isChecked() ? parent : nullptr); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RimGridCrossPlotDataSet::xAxisName() const +{ + return m_xAxisProperty->resultVariableUiShortName(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RimGridCrossPlotDataSet::yAxisName() const +{ + return m_yAxisProperty->resultVariableUiShortName(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RimGridCrossPlotDataSet::infoText() const +{ + if (!m_case()) return ""; + + if (visibleCurveCount() == 0u) return ""; + + QStringList textLines; + textLines += QString("Case: %1").arg(m_case()->caseUserDescription()); + textLines += QString("Parameters:: %1 x %2") + .arg(m_xAxisProperty->resultVariableUiShortName()) + .arg(m_yAxisProperty->resultVariableUiShortName()); + if (m_timeStep != -1) + { + textLines += QString("Time step: %1").arg(timeStepString()); + } + if (m_grouping != NO_GROUPING) + { + textLines += QString("Grouped By: %1").arg(groupParameter()); + } + if (m_cellFilterView()) + { + textLines += QString("Filter view: %1").arg(m_cellFilterView->name()); + } + textLines += QString("Sample Count: %1").arg(sampleCount()); + return textLines.join("
\n"); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +int RimGridCrossPlotDataSet::indexInPlot() const +{ + RimGridCrossPlot* parent; + this->firstAncestorOrThisOfTypeAsserted(parent); + return parent->indexOfDataSet(this); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RimGridCrossPlotDataSet::createAutoName() const +{ + if (m_case() == nullptr) + { + return "Undefined"; + } + + QStringList nameTags; + if (!m_nameConfig->customName().isEmpty()) + { + nameTags += m_nameConfig->customName(); + } + + if (m_nameConfig->addCaseName()) + { + nameTags += caseNameString(); + } + + if (m_nameConfig->addAxisVariables()) + { + nameTags += axisVariableString(); + } + + if (m_nameConfig->addTimestep() && !timeStepString().isEmpty()) + { + nameTags += timeStepString(); + } + + if (m_nameConfig->addGrouping() && groupParameter() != "None") + { + QString catTitle = groupTitle(); + if (!catTitle.isEmpty()) nameTags += catTitle; + } + + return nameTags.join(", "); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RimGridCrossPlotDataSet::groupTitle() const +{ + if (m_grouping != NO_GROUPING) + { + return QString("Grouped by %1").arg(groupParameter()); + } + return ""; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RimGridCrossPlotDataSet::groupParameter() const +{ + if (m_grouping() == GROUP_BY_TIME) + { + return QString("Time Steps"); + } + else if (m_grouping() == GROUP_BY_FORMATION) + { + return QString("Formations"); + } + else if (m_grouping() == GROUP_BY_RESULT && m_groupingProperty->hasResult()) + { + return QString("%1").arg(m_groupingProperty->resultVariableUiShortName()); + } + return "None"; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimGridCrossPlotDataSet::detachAllCurves() +{ + for (auto curve : m_crossPlotCurves()) + { + curve->detachQwtCurve(); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimGridCrossPlotDataSet::cellFilterViewUpdated() +{ + if (m_cellFilterView()) + { + loadDataAndUpdate(true); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimRegularLegendConfig* RimGridCrossPlotDataSet::legendConfig() const +{ + return m_groupingProperty->legendConfig(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector RimGridCrossPlotDataSet::curves() const +{ + return m_crossPlotCurves.childObjects(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RimGridCrossPlotDataSet::caseNameString() const +{ + if (m_case()) + { + return m_case->caseUserDescription(); + } + return ""; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RimGridCrossPlotDataSet::axisVariableString() const +{ + return QString("%1 x %2").arg(xAxisName(), yAxisName()); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RimGridCrossPlotDataSet::timeStepString() const +{ + // If using time categorization, the time step will be included as a category, so skip it here. + if (m_grouping() != RigGridCrossPlotCurveGrouping::GROUP_BY_TIME) + { + if (m_case() && (m_xAxisProperty->hasDynamicResult() || m_yAxisProperty->hasDynamicResult())) + { + if (m_timeStep == -1) + { + return "All Time Steps"; + } + return m_case->timeStepStrings()[m_timeStep]; + } + } + return ""; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::map RimGridCrossPlotDataSet::nameComponents() const +{ + std::map componentNames; + if (m_nameConfig->addCaseName()) componentNames[GCP_CASE_NAME] = caseNameString(); + if (m_nameConfig->addAxisVariables()) componentNames[GCP_AXIS_VARIABLES] = axisVariableString(); + if (m_nameConfig->addTimestep()) componentNames[GCP_TIME_STEP] = timeStepString(); + if (m_nameConfig->addGrouping()) componentNames[GCP_GROUP_NAME] = groupTitle(); + + return componentNames; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimGridCrossPlotDataSet::initAfterRead() +{ + RimEclipseCase* eclipseCase = dynamic_cast(m_case()); + if (eclipseCase) + { + m_xAxisProperty->setEclipseCase(eclipseCase); + m_yAxisProperty->setEclipseCase(eclipseCase); + m_groupingProperty->setEclipseCase(eclipseCase); + m_plotCellFilterCollection->setCase(eclipseCase); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimGridCrossPlotDataSet::onLoadDataAndUpdate(bool updateParentPlot) +{ + updateDataSetName(); + + if (m_case() == nullptr) + { + return; + } + + RimEclipseCase* eclipseCase = dynamic_cast(m_case.value()); + + if (eclipseCase == nullptr) + { + return; + } + + if (!eclipseCase->ensureReservoirCaseIsOpen()) + { + RiaLogging::warning(QString("Failed to open eclipse grid file %1").arg(eclipseCase->gridFileName())); + + return; + } + + RigEclipseResultAddress xAddress(m_xAxisProperty->resultType(), m_xAxisProperty->resultVariable()); + RigEclipseResultAddress yAddress(m_yAxisProperty->resultType(), m_yAxisProperty->resultVariable()); + RigEclipseResultAddress groupAddress(m_groupingProperty->resultType(), m_groupingProperty->resultVariable()); + + std::map timeStepCellVisibilityMap = calculateCellVisibility(eclipseCase); + + updateLegendRange(); + + RigEclipseCrossPlotResult result = RigEclipseCrossPlotDataExtractor::extract( + eclipseCase->eclipseCaseData(), m_timeStep(), xAddress, yAddress, m_grouping(), groupAddress, timeStepCellVisibilityMap); + + if (isXAxisLogarithmic() || isYAxisLogarithmic()) + { + filterInvalidCurveValues(&result); + } + + assignCurveDataGroups(result); + + if (m_crossPlotCurves.size() != m_groupedResults.size()) + { + destroyCurves(); + } + + if (m_crossPlotCurves.empty()) + { + createCurves(result); + } + else + { + fillCurveDataInExistingCurves(result); + } + + updateLegendIcons(); + + if (updateParentPlot) + { + triggerPlotNameUpdateAndReplot(); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimGridCrossPlotDataSet::assignCurveDataGroups(const RigEclipseCrossPlotResult& result) +{ + m_groupedResults.clear(); + + if (groupingEnabled() && + (result.groupValuesContinuous.empty() && result.groupValuesDiscrete.empty())) + { + // Basis for group determination (i.e. formation list) may have been deleted since the grouping was assigned. + m_grouping = NO_GROUPING; + } + + if (!groupingEnabled()) + { + m_groupedResults[0] = result; + } + else + { + std::vector tickValues; + + if (groupingByCategoryResult()) + { + for (size_t i = 0; i < result.xValues.size(); ++i) + { + int categoryNum = m_grouping == GROUP_BY_RESULT ? static_cast(result.groupValuesContinuous[i]) + : result.groupValuesDiscrete[i]; + + m_groupedResults[categoryNum].xValues.push_back(result.xValues[i]); + m_groupedResults[categoryNum].yValues.push_back(result.yValues[i]); + if (!result.groupValuesContinuous.empty()) + m_groupedResults[categoryNum].groupValuesContinuous.push_back(result.groupValuesContinuous[i]); + if (!result.groupValuesDiscrete.empty()) + m_groupedResults[categoryNum].groupValuesDiscrete.push_back(result.groupValuesDiscrete[i]); + } + } + else + { + legendConfig()->scalarMapper()->majorTickValues(&tickValues); + + for (size_t i = 0; i < result.xValues.size(); ++i) + { + auto upperBoundIt = std::lower_bound(tickValues.begin(), tickValues.end(), result.groupValuesContinuous[i]); + int upperBoundIndex = static_cast(upperBoundIt - tickValues.begin()); + int categoryNum = std::min((int)tickValues.size() - 2, std::max(0, upperBoundIndex - 1)); + m_groupedResults[categoryNum].xValues.push_back(result.xValues[i]); + m_groupedResults[categoryNum].yValues.push_back(result.yValues[i]); + if (!result.groupValuesContinuous.empty()) + m_groupedResults[categoryNum].groupValuesContinuous.push_back(result.groupValuesContinuous[i]); + if (!result.groupValuesDiscrete.empty()) + m_groupedResults[categoryNum].groupValuesDiscrete.push_back(result.groupValuesDiscrete[i]); + } + } + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimGridCrossPlotDataSet::createCurves(const RigEclipseCrossPlotResult& result) +{ + if (!groupingEnabled()) + { + RimGridCrossPlotCurve* curve = new RimGridCrossPlotCurve(); + if (m_useCustomColor) + { + curve->setColor(m_customColor()); + } + else + { + const caf::ColorTable& colors = RiaColorTables::contrastCategoryPaletteColors(); + int colorIndex = indexInPlot(); + curve->setColor(colors.cycledColor3f(colorIndex)); + } + curve->setSymbolEdgeColor(curve->color()); + curve->setGroupingInformation(indexInPlot(), 0); + curve->setSamples(result.xValues, result.yValues); + curve->setCurveAutoAppearance(); + curve->updateUiIconFromPlotSymbol(); + m_crossPlotCurves.push_back(curve); + } + else + { + std::vector tickValues; + + if (!groupingByCategoryResult()) + { + legendConfig()->scalarMapper()->majorTickValues(&tickValues); + } + + for (auto it = m_groupedResults.rbegin(); it != m_groupedResults.rend(); ++it) + { + RimGridCrossPlotCurve* curve = new RimGridCrossPlotCurve(); + curve->setGroupingInformation(indexInPlot(), it->first); + if (groupingByCategoryResult()) + { + curve->setColor(cvf::Color3f(legendConfig()->scalarMapper()->mapToColor(it->first))); + } + else + { + curve->setColor(cvf::Color3f(legendConfig()->scalarMapper()->mapToColor(tickValues[it->first]))); + } + curve->setSymbolEdgeColor(curve->color()); + curve->setSamples(it->second.xValues, it->second.yValues); + curve->showLegend(m_crossPlotCurves.empty()); + curve->setLegendEntryText(createAutoName()); + curve->setCurveAutoAppearance(); + curve->updateUiIconFromPlotSymbol(); + m_crossPlotCurves.push_back(curve); + } + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimGridCrossPlotDataSet::fillCurveDataInExistingCurves(const RigEclipseCrossPlotResult& result) +{ + if (!groupingEnabled()) + { + CVF_ASSERT(m_crossPlotCurves.size() == 1u); + RimGridCrossPlotCurve* curve = m_crossPlotCurves[0]; + curve->setSamples(result.xValues, result.yValues); + curve->setGroupingInformation(indexInPlot(), 0); + curve->updateCurveAppearance(); + curve->updateUiIconFromPlotSymbol(); + } + else + { + auto curveIt = m_crossPlotCurves.begin(); + auto groupIt = m_groupedResults.begin(); + for (; curveIt != m_crossPlotCurves.end() && groupIt != m_groupedResults.end(); ++curveIt, ++groupIt) + { + RimGridCrossPlotCurve* curve = *curveIt; + curve->setSamples(groupIt->second.xValues, groupIt->second.yValues); + curve->setGroupingInformation(indexInPlot(), groupIt->first); + curve->updateCurveAppearance(); + curve->updateUiIconFromPlotSymbol(); + } + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimGridCrossPlotDataSet::destroyCurves() +{ + detachAllCurves(); + m_crossPlotCurves.deleteAllChildObjects(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +size_t RimGridCrossPlotDataSet::visibleCurveCount() const +{ + size_t visibleCurves = 0; + for (auto curve : m_crossPlotCurves) + { + if (curve && curve->isCurveVisible()) visibleCurves++; + } + return visibleCurves; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +size_t RimGridCrossPlotDataSet::sampleCount() const +{ + size_t sampleCount = 0; + for (auto curve : m_crossPlotCurves) + { + if (curve && curve->isCurveVisible()) sampleCount += curve->sampleCount(); + } + return sampleCount; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RimGridCrossPlotDataSet::createGroupName(size_t groupIndex) const +{ + if (groupingByCategoryResult()) + { + return legendConfig()->categoryNameFromCategoryValue(groupIndex); + } + else + { + std::vector tickValues; + legendConfig()->scalarMapper()->majorTickValues(&tickValues); + double lowerLimit = tickValues[groupIndex]; + double upperLimit = + groupIndex + 1u < tickValues.size() ? tickValues[groupIndex + 1u] : std::numeric_limits::infinity(); + return QString("%1 [%2, %3]").arg(groupParameter()).arg(lowerLimit).arg(upperLimit); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::map RimGridCrossPlotDataSet::calculateCellVisibility(RimEclipseCase* eclipseCase) const +{ + std::map timeStepCellVisibilityMap; + if (m_cellFilterView) + { + RimEclipseView* eclipseView = dynamic_cast(m_cellFilterView()); + if (eclipseView) + { + std::set timeSteps; + if (m_timeStep() == -1) + { + for (int i = 0; i < (int)eclipseCase->timeStepDates().size(); ++i) + { + timeSteps.insert(i); + } + } + else + { + timeSteps.insert(m_timeStep()); + } + for (int i : timeSteps) + { + eclipseView->calculateCurrentTotalCellVisibility(&timeStepCellVisibilityMap[i], i); + } + } + } + else if (m_plotCellFilterCollection->cellFilterCount() > 0) + { + std::set timeSteps; + if (m_timeStep() == -1) + { + for (int i = 0; i < (int)eclipseCase->timeStepDates().size(); ++i) + { + timeSteps.insert(i); + } + } + else + { + timeSteps.insert(m_timeStep()); + } + + RigEclipseCaseData* eclipseCaseData = eclipseCase->eclipseCaseData(); + if (eclipseCaseData) + { + RiaDefines::PorosityModelType porosityModel = RiaDefines::MATRIX_MODEL; + + RigCaseCellResultsData* cellResultsData = eclipseCaseData->results(porosityModel); + if (cellResultsData) + { + const RigActiveCellInfo* actCellInfo = cellResultsData->activeCellInfo(); + size_t cellCount = actCellInfo->reservoirCellCount(); + + for (int i : timeSteps) + { + cvf::UByteArray* cellVisibility = &timeStepCellVisibilityMap[i]; + cellVisibility->resize(cellCount); + cellVisibility->setAll(true); + + m_plotCellFilterCollection->computeCellVisibilityFromFilter(i, cellVisibility); + } + } + } + } + + return timeStepCellVisibilityMap; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimGridCrossPlotDataSet::defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering) +{ + uiOrdering.add(&m_case); + if (m_case) + { + uiOrdering.add(&m_timeStep); + uiOrdering.add(&m_cellFilterView); + uiOrdering.add(&m_grouping); + + CVF_ASSERT(m_xAxisProperty && m_yAxisProperty && m_groupingProperty && "All property objects should always be created"); + + if (m_grouping() == GROUP_BY_TIME && !(m_xAxisProperty->hasDynamicResult() || m_yAxisProperty->hasDynamicResult())) + { + m_grouping = NO_GROUPING; + } + + if (m_grouping() == GROUP_BY_RESULT) + { + caf::PdmUiGroup* dataGroupingGroup = uiOrdering.addNewGroup("Data Grouping Property"); + m_groupingProperty->uiOrdering("AddLegendLevels", *dataGroupingGroup); + } + + caf::PdmUiGroup* invisibleFullWidthGroup = uiOrdering.addNewGroup("Property Group"); + invisibleFullWidthGroup->setEnableFrame(false); + + caf::PdmUiGroup* xAxisGroup = invisibleFullWidthGroup->addNewGroup("X-Axis Property"); + m_xAxisProperty->uiOrdering(uiConfigName, *xAxisGroup); + + caf::PdmUiGroup* yAxisGroup = invisibleFullWidthGroup->addNewGroup("Y-Axis Property", false); + m_yAxisProperty->uiOrdering(uiConfigName, *yAxisGroup); + } + + caf::PdmUiGroup* nameGroup = uiOrdering.addNewGroup("Name Configuration"); + m_nameConfig->uiOrdering(uiConfigName, *nameGroup); + + uiOrdering.skipRemainingFields(true); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimGridCrossPlotDataSet::fieldChangedByUi(const caf::PdmFieldHandle* changedField, + const QVariant& oldValue, + const QVariant& newValue) +{ + if (changedField == &m_case) + { + RimEclipseCase* eclipseCase = dynamic_cast(m_case.value()); + if (eclipseCase) + { + m_xAxisProperty->setEclipseCase(eclipseCase); + m_yAxisProperty->setEclipseCase(eclipseCase); + m_groupingProperty->setEclipseCase(eclipseCase); + // TODO: Do we need all these?? + m_xAxisProperty->updateConnectedEditors(); + m_yAxisProperty->updateConnectedEditors(); + m_groupingProperty->updateConnectedEditors(); + + if (m_grouping == GROUP_BY_FORMATION && !eclipseCase->activeFormationNames()) + { + m_grouping = NO_GROUPING; + } + + destroyCurves(); + loadDataAndUpdate(true); + } + } + else if (changedField == &m_timeStep) + { + if (m_timeStep != -1 && m_grouping == GROUP_BY_TIME) + { + m_grouping = NO_GROUPING; + } + + destroyCurves(); + loadDataAndUpdate(true); + } + else if (changedField == &m_grouping) + { + if (m_grouping == GROUP_BY_TIME) + { + legendConfig()->setColorRange(RimRegularLegendConfig::NORMAL); + legendConfig()->setMappingMode(RimRegularLegendConfig::CATEGORY_INTEGER); + } + else if (groupingByCategoryResult()) + { + legendConfig()->setColorRange(RimRegularLegendConfig::CATEGORY); + legendConfig()->setMappingMode(RimRegularLegendConfig::CATEGORY_INTEGER); + } + else + { + legendConfig()->setColorRange(RimRegularLegendConfig::NORMAL); + legendConfig()->setMappingMode(RimRegularLegendConfig::LINEAR_DISCRETE); + } + + destroyCurves(); + loadDataAndUpdate(true); + } + else if (changedField == &m_cellFilterView) + { + m_groupingProperty->setReservoirView(dynamic_cast(m_cellFilterView())); + + loadDataAndUpdate(true); + } + else if (changedField == &m_isChecked) + { + updateLegendRange(); + triggerPlotNameUpdateAndReplot(); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimGridCrossPlotDataSet::childFieldChangedByUi(const caf::PdmFieldHandle* changedChildField) +{ + if (changedChildField == &m_yAxisProperty) + { + if (m_yAxisProperty->resultVariable() == "DEPTH") + { + RimGridCrossPlot* plot; + this->firstAncestorOrThisOfTypeAsserted(plot); + plot->setYAxisInverted(true); + triggerPlotNameUpdateAndReplot(); + } + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QList RimGridCrossPlotDataSet::calculateValueOptions(const caf::PdmFieldHandle* fieldNeedingOptions, + bool* useOptionsOnly) +{ + QList options; + + if (fieldNeedingOptions == &m_case) + { + RimTools::eclipseCaseOptionItems(&options); + if (options.empty()) + { + options.push_front(caf::PdmOptionItemInfo("None", nullptr)); + } + } + else if (fieldNeedingOptions == &m_timeStep) + { + QStringList timeStepNames; + + if (m_case) + { + timeStepNames = m_case->timeStepStrings(); + } + options.push_back(caf::PdmOptionItemInfo("All Time Steps", -1)); + for (int i = 0; i < timeStepNames.size(); i++) + { + options.push_back(caf::PdmOptionItemInfo(timeStepNames[i], i)); + } + } + else if (fieldNeedingOptions == &m_cellFilterView) + { + RimEclipseCase* eclipseCase = dynamic_cast(m_case()); + if (eclipseCase) + { + options.push_back(caf::PdmOptionItemInfo("Disabled", nullptr)); + for (RimEclipseView* view : eclipseCase->reservoirViews.childObjects()) + { + CVF_ASSERT(view && "Really always should have a valid view pointer in ReservoirViews"); + options.push_back(caf::PdmOptionItemInfo(view->name(), view, false, view->uiIcon())); + } + } + } + else if (fieldNeedingOptions == &m_grouping) + { + std::set validOptions = {NO_GROUPING, GROUP_BY_TIME, GROUP_BY_FORMATION, GROUP_BY_RESULT}; + if (!hasMultipleTimeSteps()) + { + validOptions.erase(GROUP_BY_TIME); + } + { + RimEclipseCase* eclipseCase = dynamic_cast(m_case()); + if (!(eclipseCase && eclipseCase->activeFormationNames())) + { + validOptions.erase(GROUP_BY_FORMATION); + } + } + for (auto optionItem : validOptions) + { + options.push_back(caf::PdmOptionItemInfo(CurveGroupingEnum::uiText(optionItem), optionItem)); + } + } + + return options; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimGridCrossPlotDataSet::updateLegendRange() +{ + legendConfig()->setTitle(groupParameter()); + legendConfig()->disableAllTimeStepsRange(!hasMultipleTimeSteps()); + + RimGridCrossPlot* parent; + this->firstAncestorOrThisOfTypeAsserted(parent); + if (parent->qwtPlot()) + { + if (groupingEnabled() && m_case() && isChecked() && legendConfig()->showLegend()) + { + if (m_grouping() == GROUP_BY_FORMATION) + { + RimEclipseCase* eclipseCase = dynamic_cast(m_case()); + if (eclipseCase) + { + RigFormationNames* formationNames = eclipseCase->eclipseCaseData()->activeFormationNames(); + if (formationNames) + { + const std::vector& categoryNames = formationNames->formationNames(); + if (!categoryNames.empty()) + { + legendConfig()->setNamedCategories(categoryNames); + legendConfig()->setAutomaticRanges(0, categoryNames.size() - 1, 0, categoryNames.size() - 1); + } + } + } + } + else if (m_grouping() == GROUP_BY_TIME) + { + QStringList timeStepNames = m_case->timeStepStrings(); + std::vector categoryNames; + for (auto name : timeStepNames) + { + categoryNames.push_back(name); + } + if (!categoryNames.empty()) + { + legendConfig()->setNamedCategories(categoryNames); + legendConfig()->setAutomaticRanges(0, categoryNames.size() - 1, 0, categoryNames.size() - 1); + } + } + else if (m_groupingProperty->eclipseResultAddress().isValid()) + { + RimEclipseCase* eclipseCase = dynamic_cast(m_case()); + if (eclipseCase) + { + m_groupingProperty->updateLegendData(eclipseCase, m_timeStep()); + } + } + parent->qwtPlot()->addOrUpdateDataSetLegend(this); + } + else + { + parent->qwtPlot()->removeDataSetLegend(this); + } + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimGridCrossPlotDataSet::updateLegendIcons() +{ + for (auto curve : m_crossPlotCurves) + { + curve->determineLegendIcon(); + curve->setBlackAndWhiteLegendIcons(groupingEnabled()); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RimGridCrossPlotDataSet::groupingByCategoryResult() const +{ + if (m_grouping == GROUP_BY_FORMATION || m_grouping == GROUP_BY_TIME) + { + return true; + } + else if (m_grouping == GROUP_BY_RESULT) + { + return m_groupingProperty->hasCategoryResult(); + } + return false; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RimGridCrossPlotDataSet::groupingEnabled() const +{ + if (m_grouping != NO_GROUPING) + { + if (m_grouping == GROUP_BY_RESULT && !m_groupingProperty->eclipseResultAddress().isValid()) + { + return false; + } + return true; + } + return false; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimGridCrossPlotDataSet::swapAxisProperties(bool updatePlot) +{ + RimEclipseResultDefinition* xAxisProperties = m_xAxisProperty(); + RimEclipseResultDefinition* yAxisProperties = m_yAxisProperty(); + + m_xAxisProperty.removeChildObject(xAxisProperties); + m_yAxisProperty.removeChildObject(yAxisProperties); + m_yAxisProperty = xAxisProperties; + m_xAxisProperty = yAxisProperties; + + updateConnectedEditors(); + loadDataAndUpdate(updatePlot); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimGridCrossPlotDataSet::exportFormattedData(RifEclipseDataTableFormatter& formatter) const +{ + if (m_groupedResults.empty()) return; + + QString xTitle = QString("%1").arg(m_xAxisProperty->resultVariableUiShortName()); + QString yTitle = QString("%1").arg(m_yAxisProperty->resultVariableUiShortName()); + + if (m_grouping != NO_GROUPING) + { + std::vector header = {RifEclipseOutputTableColumn(xTitle), + RifEclipseOutputTableColumn(yTitle), + RifEclipseOutputTableColumn("Group Index"), + RifEclipseOutputTableColumn("Group Description")}; + + formatter.header(header); + } + else + { + std::vector header = {RifEclipseOutputTableColumn(xTitle), RifEclipseOutputTableColumn(yTitle)}; + formatter.header(header); + } + + caf::ProgressInfo progress(m_groupedResults.size(), "Gathering Data Points"); + for (auto it = m_groupedResults.begin(); it != m_groupedResults.end(); ++it) + { + auto task = progress.task(QString("Exporting Group %1").arg(it->first)); + + RigEclipseCrossPlotResult res = it->second; + + for (size_t i = 0; i < it->second.xValues.size(); ++i) + { + if (m_grouping() == NO_GROUPING) + { + formatter.add(res.xValues[i]); + formatter.add(res.yValues[i]); + } + else + { + int groupIndex = it->first; + QString groupName = createGroupName(groupIndex); + formatter.add(res.xValues[i]); + formatter.add(res.yValues[i]); + formatter.add(groupIndex); + formatter.add(groupName); + } + formatter.rowCompleted(); + } + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RimGridCrossPlotDataSet::isXAxisLogarithmic() const +{ + RimGridCrossPlot* parent = nullptr; + firstAncestorOrThisOfTypeAsserted(parent); + return parent->isXAxisLogarithmic(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RimGridCrossPlotDataSet::isYAxisLogarithmic() const +{ + RimGridCrossPlot* parent = nullptr; + firstAncestorOrThisOfTypeAsserted(parent); + return parent->isYAxisLogarithmic(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimGridCrossPlotDataSet::configureForPressureSaturationCurves(RimEclipseResultCase* eclipseCase, + const QString& dynamicResultName) +{ + m_case = eclipseCase; + + m_xAxisProperty->setEclipseCase(eclipseCase); + m_xAxisProperty->setResultType(RiaDefines::DYNAMIC_NATIVE); + m_xAxisProperty->setResultVariable(dynamicResultName); + + m_yAxisProperty->setEclipseCase(eclipseCase); + m_yAxisProperty->setResultType(RiaDefines::STATIC_NATIVE); + m_yAxisProperty->setResultVariable("DEPTH"); + + m_grouping = NO_GROUPING; + + m_nameConfig->setCustomName(dynamicResultName); + + m_nameConfig->addCaseName = false; + m_nameConfig->addAxisVariables = false; + m_nameConfig->addTimestep = false; + m_nameConfig->addGrouping = false; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimGridCrossPlotDataSet::addCellFilter(RimPlotCellFilter* cellFilter) +{ + m_plotCellFilterCollection->addCellFilter(cellFilter); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimGridCrossPlotDataSet::setCustomColor(const cvf::Color3f color) +{ + m_useCustomColor = true; + m_customColor = color; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimGridCrossPlotDataSet::triggerPlotNameUpdateAndReplot() +{ + RimGridCrossPlot* parent; + this->firstAncestorOrThisOfType(parent); + if (parent) + { + parent->updateCurveNamesAndPlotTitle(); + parent->reattachCurvesToQwtAndReplot(); + parent->updateConnectedEditors(); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimGridCrossPlotDataSet::updateCurveNames(size_t dataSetIndex, size_t dataSetCount) +{ + for (size_t i = 0; i < m_crossPlotCurves.size(); ++i) + { + QString dataSetName = createAutoName(); + if (dataSetName.isEmpty()) + { + if (dataSetCount > 1u) + dataSetName = QString("DataSet #%1").arg(dataSetIndex + 1); + else + dataSetName = "Data Set"; + } + + auto curve = m_crossPlotCurves[i]; + if (groupingEnabled()) + { + QString curveGroupName = createGroupName(curve->groupIndex()); + curve->setCustomName(curveGroupName); + curve->setLegendEntryText(dataSetName); + } + else + { + curve->setCustomName(dataSetName); + } + curve->updateCurveNameAndUpdatePlotLegendAndTitle(); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimGridCrossPlotDataSet::updateDataSetName() +{ + this->setName(createAutoName()); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimGridCrossPlotDataSet::performAutoNameUpdate() +{ + updateDataSetName(); + triggerPlotNameUpdateAndReplot(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimGridCrossPlotDataSet::setDefaults() +{ + RimProject* project = RiaApplication::instance()->project(); + if (project) + { + if (!project->eclipseCases().empty()) + { + RimEclipseCase* eclipseCase = project->eclipseCases().front(); + m_case = eclipseCase; + m_xAxisProperty->setEclipseCase(eclipseCase); + m_yAxisProperty->setEclipseCase(eclipseCase); + m_groupingProperty->setEclipseCase(eclipseCase); + + m_xAxisProperty->setResultType(RiaDefines::STATIC_NATIVE); + m_xAxisProperty->setResultVariable("PORO"); + + m_yAxisProperty->setResultType(RiaDefines::STATIC_NATIVE); + m_yAxisProperty->setResultVariable("PERMX"); + + m_grouping = NO_GROUPING; + if (eclipseCase->activeFormationNames()) + { + m_grouping = GROUP_BY_FORMATION; + m_groupingProperty->legendConfig()->setColorRange(RimRegularLegendConfig::CATEGORY); + } + } + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimGridCrossPlotDataSet::defineEditorAttribute(const caf::PdmFieldHandle* field, + QString uiConfigName, + caf::PdmUiEditorAttribute* attribute) +{ +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimGridCrossPlotDataSet::defineUiTreeOrdering(caf::PdmUiTreeOrdering& uiTreeOrdering, QString uiConfigName /*= ""*/) +{ + if (groupingEnabled()) + { + m_groupingProperty->uiTreeOrdering(uiTreeOrdering, uiConfigName); + } + + for (auto curve : m_crossPlotCurves()) + { + uiTreeOrdering.add(curve); + } + + uiTreeOrdering.add(&m_plotCellFilterCollection); + + uiTreeOrdering.skipRemainingChildren(true); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RimGridCrossPlotDataSet::hasMultipleTimeSteps() const +{ + return m_timeStep() == -1 && (m_xAxisProperty->hasDynamicResult() || m_yAxisProperty->hasDynamicResult()); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimGridCrossPlotDataSet::filterInvalidCurveValues(RigEclipseCrossPlotResult* result) +{ + bool xLog = isXAxisLogarithmic(); + bool yLog = isYAxisLogarithmic(); + + if (xLog || yLog) + { + RigEclipseCrossPlotResult validResult; + for (size_t i = 0; i < result->xValues.size(); ++i) + { + double xValue = result->xValues[i]; + double yValue = result->yValues[i]; + bool invalid = (xLog && xValue <= 0.0) || (yLog && yValue <= 0.0); + if (!invalid) + { + validResult.xValues.push_back(xValue); + validResult.yValues.push_back(yValue); + if (i < result->groupValuesContinuous.size()) + { + validResult.groupValuesContinuous.push_back(result->groupValuesContinuous[i]); + } + if (i < result->groupValuesDiscrete.size()) + { + validResult.groupValuesDiscrete.push_back(result->groupValuesDiscrete[i]); + } + } + } + + *result = validResult; + } +} + +CAF_PDM_SOURCE_INIT(RimGridCrossPlotDataSetNameConfig, "RimGridCrossPlotCurveSetNameConfig"); + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimGridCrossPlotDataSetNameConfig::RimGridCrossPlotDataSetNameConfig(RimNameConfigHolderInterface* parent) + : RimNameConfig(parent) +{ + CAF_PDM_InitObject("Cross Plot Data Set NameGenerator", "", "", ""); + + CAF_PDM_InitField(&addCaseName, "AddCaseName", true, "Add Case Name", "", "", ""); + CAF_PDM_InitField(&addAxisVariables, "AddAxisVariables", true, "Add Axis Variables", "", "", ""); + CAF_PDM_InitField(&addTimestep, "AddTimeStep", true, "Add Time Step", "", "", ""); + CAF_PDM_InitField(&addGrouping, "AddGrouping", true, "Add Data Group", "", "", ""); + + setCustomName(""); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimGridCrossPlotDataSetNameConfig::defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering) +{ + uiOrdering.add(&addCaseName); + uiOrdering.add(&addAxisVariables); + uiOrdering.add(&addTimestep); + uiOrdering.add(&addGrouping); +} diff --git a/ApplicationCode/ProjectDataModel/GridCrossPlots/RimGridCrossPlotDataSet.h b/ApplicationCode/ProjectDataModel/GridCrossPlots/RimGridCrossPlotDataSet.h new file mode 100644 index 0000000000..1f3ed999e2 --- /dev/null +++ b/ApplicationCode/ProjectDataModel/GridCrossPlots/RimGridCrossPlotDataSet.h @@ -0,0 +1,186 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2019- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// +#pragma once + +#include "RigGridCrossPlotCurveGrouping.h" +#include "RigEclipseCrossPlotDataExtractor.h" + +#include "RimCheckableNamedObject.h" +#include "RimNameConfig.h" + +#include "cafAppEnum.h" +#include "cafPdmChildArrayField.h" +#include "cafPdmChildField.h" +#include "cafPdmField.h" +#include "cafPdmObject.h" +#include "cafPdmPtrField.h" + +// Include to make Pdm work for cvf::Color +#include "cafPdmFieldCvfColor.h" + +#include + +#include +#include + +class RifEclipseDataTableFormatter; +class RimCase; +class RimGridCrossPlotCurve; +class RimGridView; +class RimEclipseCase; +class RimEclipseResultCase; +class RimEclipseCellColors; +class RimEclipseResultDefinition; +class RimRegularLegendConfig; +class QwtPlot; +class QwtPlotCurve; +class QString; +class RimPlotCellFilterCollection; +class RimPlotCellFilter; + +class RimGridCrossPlotDataSetNameConfig : public RimNameConfig +{ + CAF_PDM_HEADER_INIT; + +public: + RimGridCrossPlotDataSetNameConfig(RimNameConfigHolderInterface* parent = nullptr); + + caf::PdmField addCaseName; + caf::PdmField addAxisVariables; + caf::PdmField addTimestep; + caf::PdmField addGrouping; + +protected: + void defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering) override; +}; + +//================================================================================================== +/// +/// +//================================================================================================== +class RimGridCrossPlotDataSet : public RimCheckableNamedObject, public RimNameConfigHolderInterface +{ + CAF_PDM_HEADER_INIT; + +public: + typedef caf::AppEnum CurveGroupingEnum; + + enum NameComponents + { + GCP_CASE_NAME, + GCP_AXIS_VARIABLES, + GCP_TIME_STEP, + GCP_GROUP_NAME + }; + +public: + RimGridCrossPlotDataSet(); + ~RimGridCrossPlotDataSet() = default; + + void setCellFilterView(RimGridView* cellFilterView); + void loadDataAndUpdate(bool updateParentPlot); + void setParentQwtPlotNoReplot(QwtPlot* parent); + QString xAxisName() const; + QString yAxisName() const; + QString infoText() const; + + int indexInPlot() const; + QString createAutoName() const override; + QString groupTitle() const; + QString groupParameter() const; + void detachAllCurves(); + void cellFilterViewUpdated(); + + RimRegularLegendConfig* legendConfig() const; + + std::vector< RimGridCrossPlotCurve*> curves() const; + + QString caseNameString() const; + QString axisVariableString() const; + QString timeStepString() const; + + std::map nameComponents() const; + + void updateCurveNames(size_t dataSetIndex, size_t dataSetCount); + void updateLegendRange(); + void updateLegendIcons(); + bool groupingByCategoryResult() const; + bool groupingEnabled() const; + void swapAxisProperties(bool updatePlot); + void exportFormattedData(RifEclipseDataTableFormatter& formatter) const; + + bool isXAxisLogarithmic() const; + bool isYAxisLogarithmic() const; + + void configureForPressureSaturationCurves(RimEclipseResultCase* eclipseResultCase, const QString& dynamicResultName); + void addCellFilter(RimPlotCellFilter* cellFilter); + void setCustomColor(const cvf::Color3f color); + void destroyCurves(); + + size_t visibleCurveCount() const; + size_t sampleCount() const; + +protected: + void initAfterRead() override; + void onLoadDataAndUpdate(bool updateParentPlot); + + void assignCurveDataGroups(const RigEclipseCrossPlotResult& result); + void createCurves(const RigEclipseCrossPlotResult& result); + void fillCurveDataInExistingCurves(const RigEclipseCrossPlotResult& result); + QString createGroupName(size_t curveIndex) const; + + std::map calculateCellVisibility(RimEclipseCase* eclipseCase) const; + + void defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering) override; + void fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue) override; + void childFieldChangedByUi(const caf::PdmFieldHandle* changedChildField) override; + + QList calculateValueOptions(const caf::PdmFieldHandle* fieldNeedingOptions, + bool* useOptionsOnly) override; + void triggerPlotNameUpdateAndReplot(); + void updateDataSetName(); + void performAutoNameUpdate() override; + void setDefaults(); + void defineEditorAttribute(const caf::PdmFieldHandle* field, QString uiConfigName, caf::PdmUiEditorAttribute* attribute) override; + + void defineUiTreeOrdering(caf::PdmUiTreeOrdering& uiTreeOrdering, QString uiConfigName = "") override; + + bool hasMultipleTimeSteps() const; + void filterInvalidCurveValues(RigEclipseCrossPlotResult* result); + +private: + + caf::PdmPtrField m_case; + caf::PdmField m_timeStep; + caf::PdmPtrField m_cellFilterView; + caf::PdmField m_grouping; + caf::PdmChildField m_xAxisProperty; + caf::PdmChildField m_yAxisProperty; + caf::PdmChildField m_groupingProperty; + + caf::PdmChildField m_nameConfig; + + caf::PdmChildArrayField m_crossPlotCurves; + + std::map m_groupedResults; + + caf::PdmField m_useCustomColor; + caf::PdmField m_customColor; + caf::PdmChildField m_plotCellFilterCollection;; + +}; diff --git a/ApplicationCode/ProjectDataModel/GridCrossPlots/RimSaturationPressurePlot.cpp b/ApplicationCode/ProjectDataModel/GridCrossPlots/RimSaturationPressurePlot.cpp new file mode 100644 index 0000000000..89da8b8050 --- /dev/null +++ b/ApplicationCode/ProjectDataModel/GridCrossPlots/RimSaturationPressurePlot.cpp @@ -0,0 +1,246 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2019- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "RimSaturationPressurePlot.h" + +#include "RiaColorTables.h" +#include "RiaLogging.h" + +#include "RigCaseCellResultsData.h" +#include "RigEclipseCaseData.h" +#include "RigEquil.h" + +#include "RimEclipseResultCase.h" +#include "RimEclipseResultDefinition.h" +#include "RimGridCrossPlotDataSet.h" +#include "RimPlotAxisAnnotation.h" +#include "RimPlotAxisProperties.h" + +#include "CellFilters/RimPlotCellPropertyFilter.h" + +CAF_PDM_SOURCE_INIT(RimSaturationPressurePlot, "RimSaturationPressurePlot"); + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimSaturationPressurePlot::RimSaturationPressurePlot() +{ + CAF_PDM_InitObject("Saturation Pressure Plot", ":/SummaryXPlotLight16x16.png", "", ""); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimSaturationPressurePlot::assignCaseAndEquilibriumRegion(RiaDefines::PorosityModelType porosityModel, + RimEclipseResultCase* eclipseResultCase, + int zeroBasedEquilRegionIndex) +{ + CVF_ASSERT(eclipseResultCase && eclipseResultCase->eclipseCaseData()); + + auto equilData = eclipseResultCase->eclipseCaseData()->equilData(); + if (zeroBasedEquilRegionIndex >= (int) equilData.size()) + { + RiaLogging::error("Invalid equilibrium region index"); + return; + } + + setShowInfoBox(false); + nameConfig()->addDataSetNames = false; + + QString caseName = eclipseResultCase->caseUserDescription(); + QString plotTitle = QString("%1 - EQLNUM %2").arg(caseName).arg(zeroBasedEquilRegionIndex + 1); + + nameConfig()->setCustomName(plotTitle); + + auto eq = equilData[zeroBasedEquilRegionIndex]; + + double gasOilContactDepth = eq.gasOilContactDepth(); + double waterOilContactDepth = eq.waterOilContactDepth(); + + { + // Blue PRESSURE curve with data for specified EQLNUM value + + RimGridCrossPlotDataSet* curveSet = createDataSet(); + curveSet->configureForPressureSaturationCurves(eclipseResultCase, "PRESSURE"); + + cvf::Color3f curveColor = RiaColorTables::summaryCurveBluePaletteColors().cycledColor3f(0); + curveSet->setCustomColor(curveColor); + + RimPlotCellPropertyFilter* cellFilter = + createEquilibriumRegionPropertyFilter(eclipseResultCase, zeroBasedEquilRegionIndex); + + curveSet->addCellFilter(cellFilter); + } + + { + // Red dew pressure (PDEW) curve with data for specified EQLNUM value, filtered on depth by gasOilContact + + RimGridCrossPlotDataSet* curveSet = createDataSet(); + curveSet->configureForPressureSaturationCurves(eclipseResultCase, "PDEW"); + + cvf::Color3f curveColor = RiaColorTables::summaryCurveRedPaletteColors().cycledColor3f(0); + curveSet->setCustomColor(curveColor); + + RimPlotCellPropertyFilter* cellFilter = + createEquilibriumRegionPropertyFilter(eclipseResultCase, zeroBasedEquilRegionIndex); + curveSet->addCellFilter(cellFilter); + + { + RigCaseCellResultsData* caseCellResultsData = eclipseResultCase->eclipseCaseData()->results(porosityModel); + if (caseCellResultsData) + { + RigEclipseResultAddress depthResultAddress(RiaDefines::STATIC_NATIVE, "DEPTH"); + + double minDepth = 0.0; + double maxDepth = 0.0; + caseCellResultsData->minMaxCellScalarValues(depthResultAddress, minDepth, maxDepth); + + maxDepth = gasOilContactDepth; + + RimPlotCellPropertyFilter* depthCellFilter = createDepthPropertyFilter(eclipseResultCase, minDepth, maxDepth); + + curveSet->addCellFilter(depthCellFilter); + } + } + } + + { + // Green bubble point pressure (PBUB) curve with data for specified EQLNUM value, filtered on depth between gasOilContact + // and waterOilContactDepth + + RimGridCrossPlotDataSet* curveSet = createDataSet(); + curveSet->configureForPressureSaturationCurves(eclipseResultCase, "PBUB"); + + cvf::Color3f curveColor = RiaColorTables::summaryCurveGreenPaletteColors().cycledColor3f(0); + curveSet->setCustomColor(curveColor); + + { + RimPlotCellPropertyFilter* cellFilter = new RimPlotCellPropertyFilter(); + { + RimEclipseResultDefinition* resultDefinition = new RimEclipseResultDefinition(); + resultDefinition->setEclipseCase(eclipseResultCase); + resultDefinition->setResultType(RiaDefines::STATIC_NATIVE); + resultDefinition->setResultVariable(RiaDefines::eqlnumResultName()); + + cellFilter->setResultDefinition(resultDefinition); + } + + cellFilter->setValueRange(zeroBasedEquilRegionIndex + 1, zeroBasedEquilRegionIndex + 1); + + curveSet->addCellFilter(cellFilter); + } + + { + RigCaseCellResultsData* caseCellResultsData = eclipseResultCase->eclipseCaseData()->results(porosityModel); + if (caseCellResultsData) + { + RigEclipseResultAddress depthResultAddress(RiaDefines::STATIC_NATIVE, "DEPTH"); + + double minDepth = 0.0; + double maxDepth = 0.0; + caseCellResultsData->minMaxCellScalarValues(depthResultAddress, minDepth, maxDepth); + + minDepth = gasOilContactDepth; + maxDepth = waterOilContactDepth; + + RimPlotCellPropertyFilter* depthCellFilter = createDepthPropertyFilter(eclipseResultCase, minDepth, maxDepth); + + curveSet->addCellFilter(depthCellFilter); + } + } + } + + RimPlotAxisProperties* yAxisProps = yAxisProperties(); + + yAxisProps->setInvertedAxis(true); + + { + RimPlotAxisAnnotation* annotation = new RimPlotAxisAnnotation; + annotation->setEquilibriumData( + eclipseResultCase, zeroBasedEquilRegionIndex, RimPlotAxisAnnotation::PL_EQUIL_GAS_OIL_CONTACT); + + yAxisProps->appendAnnotation(annotation); + } + { + RimPlotAxisAnnotation* annotation = new RimPlotAxisAnnotation; + annotation->setEquilibriumData( + eclipseResultCase, zeroBasedEquilRegionIndex, RimPlotAxisAnnotation::PL_EQUIL_WATER_OIL_CONTACT); + + yAxisProps->appendAnnotation(annotation); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimSaturationPressurePlot::initAfterRead() +{ + yAxisProperties()->showAnnotationObjectsInProjectTree(); + + RimGridCrossPlot::initAfterRead(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RimSaturationPressurePlot::xAxisParameterString() const +{ + return ""; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimPlotCellPropertyFilter* + RimSaturationPressurePlot::createEquilibriumRegionPropertyFilter(RimEclipseResultCase* eclipseResultCase, + int zeroBasedEquilRegionIndex) +{ + RimPlotCellPropertyFilter* cellFilter = new RimPlotCellPropertyFilter(); + + RimEclipseResultDefinition* resultDefinition = new RimEclipseResultDefinition(); + resultDefinition->setEclipseCase(eclipseResultCase); + resultDefinition->setResultType(RiaDefines::STATIC_NATIVE); + resultDefinition->setResultVariable(RiaDefines::eqlnumResultName()); + + cellFilter->setResultDefinition(resultDefinition); + + cellFilter->setValueRange(zeroBasedEquilRegionIndex + 1, zeroBasedEquilRegionIndex + 1); + + return cellFilter; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimPlotCellPropertyFilter* RimSaturationPressurePlot::createDepthPropertyFilter(RimEclipseResultCase* eclipseResultCase, + double minDepth, + double maxDepth) +{ + RimPlotCellPropertyFilter* depthCellFilter = new RimPlotCellPropertyFilter(); + + RimEclipseResultDefinition* resultDefinition = new RimEclipseResultDefinition(); + resultDefinition->setEclipseCase(eclipseResultCase); + resultDefinition->setResultType(RiaDefines::STATIC_NATIVE); + resultDefinition->setResultVariable("DEPTH"); + + depthCellFilter->setResultDefinition(resultDefinition); + + depthCellFilter->setValueRange(minDepth, maxDepth); + + return depthCellFilter; +} diff --git a/ApplicationCode/ProjectDataModel/GridCrossPlots/RimSaturationPressurePlot.h b/ApplicationCode/ProjectDataModel/GridCrossPlots/RimSaturationPressurePlot.h new file mode 100644 index 0000000000..c598d3d046 --- /dev/null +++ b/ApplicationCode/ProjectDataModel/GridCrossPlots/RimSaturationPressurePlot.h @@ -0,0 +1,52 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2019- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "RiaPorosityModel.h" + +#include "RimGridCrossPlot.h" + +class RimEclipseResultCase; +class RimPlotCellPropertyFilter; + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +class RimSaturationPressurePlot : public RimGridCrossPlot +{ + CAF_PDM_HEADER_INIT; + +public: + RimSaturationPressurePlot(); + + void assignCaseAndEquilibriumRegion(RiaDefines::PorosityModelType porosityModel, + RimEclipseResultCase* eclipseResultCase, + int zeroBasedEquilRegionIndex); + +protected: + void initAfterRead() override; + QString xAxisParameterString() const override; + +private: + RimPlotCellPropertyFilter* createEquilibriumRegionPropertyFilter(RimEclipseResultCase* eclipseResultCase, + int zeroBasedEquilRegionIndex); + + RimPlotCellPropertyFilter* + createDepthPropertyFilter(RimEclipseResultCase* eclipseResultCase, double minDepth, double maxDepth); +}; diff --git a/ApplicationCode/ProjectDataModel/GridCrossPlots/RimSaturationPressurePlotCollection.cpp b/ApplicationCode/ProjectDataModel/GridCrossPlots/RimSaturationPressurePlotCollection.cpp new file mode 100644 index 0000000000..d7bd12655f --- /dev/null +++ b/ApplicationCode/ProjectDataModel/GridCrossPlots/RimSaturationPressurePlotCollection.cpp @@ -0,0 +1,115 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2019- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "RimSaturationPressurePlotCollection.h" + +#include "RigCaseCellResultsData.h" +#include "RigEclipseCaseData.h" +#include "RigEclipseResultAddress.h" +#include "RigEquil.h" + +#include "RimEclipseResultCase.h" +#include "RimSaturationPressurePlot.h" + +CAF_PDM_SOURCE_INIT(RimSaturationPressurePlotCollection, "RimSaturationPressurePlotCollection"); + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimSaturationPressurePlotCollection::RimSaturationPressurePlotCollection() +{ + CAF_PDM_InitObject("Saturation Pressure Plots", ":/SummaryXPlotsLight16x16.png", "", ""); + + CAF_PDM_InitFieldNoDefault(&m_saturationPressurePlots, "SaturationPressurePlots", "Saturation Pressure Plots", "", "", ""); + m_saturationPressurePlots.uiCapability()->setUiHidden(true); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimSaturationPressurePlotCollection::~RimSaturationPressurePlotCollection() {} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector + RimSaturationPressurePlotCollection::createSaturationPressurePlots(RimEclipseResultCase* eclipseResultCase) +{ + std::vector generatedPlots; + + if (!eclipseResultCase) return generatedPlots; + + RigEclipseCaseData* eclipseCaseData = eclipseResultCase->eclipseCaseData(); + if (!eclipseCaseData) return generatedPlots; + + auto results = eclipseCaseData->results(RiaDefines::MATRIX_MODEL); + + std::set eqlnumRegionIdsFound; + { + RigEclipseResultAddress resAdr(RiaDefines::STATIC_NATIVE, RiaDefines::eqlnumResultName()); + if (results->hasResultEntry(resAdr)) + { + results->ensureKnownResultLoaded(resAdr); + + auto vals = results->uniqueCellScalarValues(resAdr); + for (auto v : vals) + { + eqlnumRegionIdsFound.insert(v); + } + } + } + + eclipseResultCase->ensureDeckIsParsedForEquilData(); + std::vector equilData = eclipseCaseData->equilData(); + for (size_t i = 0; i < equilData.size(); i++) + { + int zeroBasedEquilibriumRegion = static_cast(i); + + if (eqlnumRegionIdsFound.find(zeroBasedEquilibriumRegion + 1) != eqlnumRegionIdsFound.end()) + { + RimSaturationPressurePlot* plot = new RimSaturationPressurePlot(); + plot->setAsPlotMdiWindow(); + + // As discussed with Liv Merete, it is not any use for creation of different plots for matrix/fracture. For now, use + // hardcoded value for MATRIX + plot->assignCaseAndEquilibriumRegion(RiaDefines::MATRIX_MODEL, eclipseResultCase, zeroBasedEquilibriumRegion); + + m_saturationPressurePlots.push_back(plot); + + generatedPlots.push_back(plot); + } + } + + return generatedPlots; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector RimSaturationPressurePlotCollection::plots() +{ + return m_saturationPressurePlots.childObjects(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimSaturationPressurePlotCollection::deleteAllChildObjects() +{ + m_saturationPressurePlots.deleteAllChildObjects(); +} diff --git a/ApplicationCode/ProjectDataModel/GridCrossPlots/RimSaturationPressurePlotCollection.h b/ApplicationCode/ProjectDataModel/GridCrossPlots/RimSaturationPressurePlotCollection.h new file mode 100644 index 0000000000..cbbbba3609 --- /dev/null +++ b/ApplicationCode/ProjectDataModel/GridCrossPlots/RimSaturationPressurePlotCollection.h @@ -0,0 +1,45 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2019- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// +#pragma once + +#include "cafPdmChildArrayField.h" +#include "cafPdmObject.h" + +class RimSaturationPressurePlot; +class RimEclipseResultCase; + +//================================================================================================== +/// +/// +//================================================================================================== +class RimSaturationPressurePlotCollection : public caf::PdmObject +{ + CAF_PDM_HEADER_INIT; + +public: + RimSaturationPressurePlotCollection(); + ~RimSaturationPressurePlotCollection() override; + + std::vector createSaturationPressurePlots(RimEclipseResultCase* eclipseResultCase); + + std::vector plots(); + void deleteAllChildObjects(); + +private: + caf::PdmChildArrayField m_saturationPressurePlots; +}; diff --git a/ApplicationCode/ProjectDataModel/Measurement/CMakeLists_files.cmake b/ApplicationCode/ProjectDataModel/Measurement/CMakeLists_files.cmake new file mode 100644 index 0000000000..5f9c9c78dc --- /dev/null +++ b/ApplicationCode/ProjectDataModel/Measurement/CMakeLists_files.cmake @@ -0,0 +1,26 @@ + +set (SOURCE_GROUP_HEADER_FILES +${CMAKE_CURRENT_LIST_DIR}/RimMeasurement.h +${CMAKE_CURRENT_LIST_DIR}/RiuMeasurementEventFilter.h +) + +set (SOURCE_GROUP_SOURCE_FILES +${CMAKE_CURRENT_LIST_DIR}/RimMeasurement.cpp +${CMAKE_CURRENT_LIST_DIR}/RiuMeasurementEventFilter.cpp +) + +list(APPEND CODE_HEADER_FILES +${SOURCE_GROUP_HEADER_FILES} +) + +list(APPEND CODE_SOURCE_FILES +${SOURCE_GROUP_SOURCE_FILES} +) + +set (QT_MOC_HEADERS +${CMAKE_CURRENT_LIST_DIR}/RiuMeasurementEventFilter.h +${QT_MOC_HEADERS} +) + + +source_group( "ProjectDataModel\\Measurement" FILES ${SOURCE_GROUP_HEADER_FILES} ${SOURCE_GROUP_SOURCE_FILES} ${CMAKE_CURRENT_LIST_DIR}/CMakeLists_files.cmake ) diff --git a/ApplicationCode/ProjectDataModel/Measurement/RimMeasurement.cpp b/ApplicationCode/ProjectDataModel/Measurement/RimMeasurement.cpp new file mode 100644 index 0000000000..c0f0d9949e --- /dev/null +++ b/ApplicationCode/ProjectDataModel/Measurement/RimMeasurement.cpp @@ -0,0 +1,201 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2018- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "RimMeasurement.h" + +#include "RiaApplication.h" + +#include "Rim3dView.h" + +#include "MeasurementCommands/RicMeasurementPickEventHandler.h" + +#include "RiuMeasurementEventFilter.h" +#include "RiuViewerCommands.h" + +#include "cvfGeometryTools.h" +#include "RiuMainWindow.h" + +CAF_PDM_SOURCE_INIT(RimMeasurement, "RimMeasurement"); + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimMeasurement::RimMeasurement() + : m_measurementMode(MEASURE_DISABLED) +{ + CAF_PDM_InitObject("Measurement", ":/TextAnnotation16x16.png", "", ""); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimMeasurement::~RimMeasurement() {} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimMeasurement::setMeasurementMode(MeasurementMode measurementMode) +{ + m_measurementMode = measurementMode; + + if (m_measurementMode != MEASURE_DISABLED) + { + RicMeasurementPickEventHandler::instance()->registerAsPickEventHandler(); + RicMeasurementPickEventHandler::instance()->enablePolyLineMode(m_measurementMode == MEASURE_POLYLINE); + m_eventFilter = new RiuMeasurementEventFilter(this); + m_eventFilter->registerFilter(); + } + else + { + RicMeasurementPickEventHandler::instance()->unregisterAsPickEventHandler(); + removeAllPoints(); + + if (m_eventFilter) + { + m_eventFilter->unregisterFilter(); + m_eventFilter->deleteLater(); + m_eventFilter = nullptr; + } + } + + RiuMainWindow::instance()->refreshViewActions(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimMeasurement::MeasurementMode RimMeasurement::measurementMode() const +{ + return m_measurementMode; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimMeasurement::addPointInDomainCoords(const Vec3d& domainCoord) +{ + auto activeView = RiaApplication::instance()->activeReservoirView(); + + if (m_sourceView.p() != activeView) + { + removeAllPoints(); + } + + m_pointsInDomainCoords.push_back(domainCoord); + m_sourceView = activeView; + + updateView(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector RimMeasurement::pointsInDomainCoords() const +{ + return m_pointsInDomainCoords; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimMeasurement::removeAllPoints() +{ + m_pointsInDomainCoords.clear(); + updateView(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RimMeasurement::label() const +{ + auto lengths = calculateLenghts(); + + QString text; + + if (m_pointsInDomainCoords.size() > 2) + { + text = QString("Segment Length: %1\nSegment Horizontal Length: %2\n") + .arg(lengths.lastSegmentLength) + .arg(lengths.lastSegmentHorisontalLength); + + text += QString("Total Length: %1\nTotal Horizontal Length: %2\n") + .arg(lengths.totalLength) + .arg(lengths.totalHorizontalLength); + + text += QString("\nHorizontal Area : %1").arg(lengths.area); + } + else + { + text = QString("Length: %1\nHorizontal Length: %2\n") + .arg(lengths.lastSegmentLength) + .arg(lengths.lastSegmentHorisontalLength); + } + + return text; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimMeasurement::Lengths RimMeasurement::calculateLenghts() const +{ + Lengths lengths; + + for (size_t p = 1; p < m_pointsInDomainCoords.size(); p++) + { + const auto& p0 = m_pointsInDomainCoords[p - 1]; + const auto& p1 = m_pointsInDomainCoords[p]; + + lengths.lastSegmentLength = (p1 - p0).length(); + + const auto& p1_horiz = cvf::Vec3d(p1.x(), p1.y(), p0.z()); + + lengths.lastSegmentHorisontalLength = (p1_horiz - p0).length(); + + lengths.totalLength += lengths.lastSegmentLength; + lengths.totalHorizontalLength += lengths.lastSegmentHorisontalLength; + } + + { + std::vector pointsProjectedInZPlane; + for (const auto& p : m_pointsInDomainCoords) + { + auto pointInZ = p; + pointInZ.z() = 0.0; + pointsProjectedInZPlane.push_back(pointInZ); + } + + Vec3d area = cvf::GeometryTools::polygonAreaNormal3D(pointsProjectedInZPlane); + + lengths.area = cvf::Math::abs(area.z()); + } + + return lengths; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimMeasurement::updateView() const +{ + if (m_sourceView) + { + m_sourceView->updateMeasurement(); + } +} diff --git a/ApplicationCode/ProjectDataModel/Measurement/RimMeasurement.h b/ApplicationCode/ProjectDataModel/Measurement/RimMeasurement.h new file mode 100644 index 0000000000..3b12ca0de0 --- /dev/null +++ b/ApplicationCode/ProjectDataModel/Measurement/RimMeasurement.h @@ -0,0 +1,91 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2018- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "cafPdmObject.h" +#include "cvfBase.h" +#include "cvfVector3.h" + +#include + +class Rim3dView; +class RiuMeasurementEventFilter; + +//================================================================================================== +/// +/// +//================================================================================================== +class RimMeasurement : public caf::PdmObject +{ + CAF_PDM_HEADER_INIT; + + using Vec3d = cvf::Vec3d; + +public: + enum MeasurementMode + { + MEASURE_DISABLED = 0, + MEASURE_REGULAR, + MEASURE_POLYLINE + }; + + class Lengths + { + public: + Lengths() + : totalLength(0) + , lastSegmentLength(0) + , totalHorizontalLength(0) + , lastSegmentHorisontalLength(0) + , area(0) + { + } + + double totalLength; + double lastSegmentLength; + double totalHorizontalLength; + double lastSegmentHorisontalLength; + double area; + }; + + RimMeasurement(); + ~RimMeasurement() override; + + void setMeasurementMode(MeasurementMode measureMode); + MeasurementMode measurementMode() const; + + void addPointInDomainCoords(const Vec3d& pointInDomainCoord); + std::vector pointsInDomainCoords() const; + + void removeAllPoints(); + + QString label() const; + +private: + Lengths calculateLenghts() const; + + void updateView() const; + +private: + MeasurementMode m_measurementMode; + std::vector m_pointsInDomainCoords; + caf::PdmPointer m_sourceView; + + QPointer m_eventFilter; +}; diff --git a/ApplicationCode/ProjectDataModel/Measurement/RiuMeasurementEventFilter.cpp b/ApplicationCode/ProjectDataModel/Measurement/RiuMeasurementEventFilter.cpp new file mode 100644 index 0000000000..18badfd7be --- /dev/null +++ b/ApplicationCode/ProjectDataModel/Measurement/RiuMeasurementEventFilter.cpp @@ -0,0 +1,78 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2019- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "RiuMeasurementEventFilter.h" + +#include "RiaApplication.h" + +#include "RimMeasurement.h" + +#include "RiuMainWindow.h" +#include + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RiuMeasurementEventFilter::RiuMeasurementEventFilter(RimMeasurement* parent) + : QObject(nullptr) + , m_parent(parent) +{ +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuMeasurementEventFilter::registerFilter() +{ + RiaApplication::instance()->installEventFilter(this); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuMeasurementEventFilter::unregisterFilter() +{ + RiaApplication::instance()->removeEventFilter(this); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RiuMeasurementEventFilter::eventFilter(QObject* obj, QEvent* event) +{ + if (event->type() == QEvent::KeyPress) + { + QKeyEvent* keyEvent = static_cast(event); + + if (keyEvent->key() == Qt::Key_Escape) + { + keyEvent->setAccepted(true); + + unregisterFilter(); + + if (m_parent) + { + m_parent->setMeasurementMode(RimMeasurement::MEASURE_DISABLED); + } + + return true; + } + } + + return QObject::eventFilter(obj, event); +} diff --git a/ApplicationCode/ProjectDataModel/Measurement/RiuMeasurementEventFilter.h b/ApplicationCode/ProjectDataModel/Measurement/RiuMeasurementEventFilter.h new file mode 100644 index 0000000000..65d09baab2 --- /dev/null +++ b/ApplicationCode/ProjectDataModel/Measurement/RiuMeasurementEventFilter.h @@ -0,0 +1,46 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2019- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + + +#include "cafPdmPointer.h" + +#include + +class QEvent; +class RimMeasurement; + +//-------------------------------------------------------------------------------------------------- +// +//-------------------------------------------------------------------------------------------------- +class RiuMeasurementEventFilter : public QObject +{ + Q_OBJECT +public: + explicit RiuMeasurementEventFilter(RimMeasurement* parent); + + void registerFilter(); + void unregisterFilter(); + +protected: + bool eventFilter(QObject *obj, QEvent *event) override; + +private: + caf::PdmPointer m_parent; +}; diff --git a/ApplicationCode/ProjectDataModel/Rim2dIntersectionView.cpp b/ApplicationCode/ProjectDataModel/Rim2dIntersectionView.cpp index dee625562f..9c1531e0f9 100644 --- a/ApplicationCode/ProjectDataModel/Rim2dIntersectionView.cpp +++ b/ApplicationCode/ProjectDataModel/Rim2dIntersectionView.cpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018- Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -30,6 +30,7 @@ #include "RimSimWellInView.h" #include "RimTernaryLegendConfig.h" #include "RimWellPath.h" +#include "RimViewNameConfig.h" #include "RiuMainWindow.h" #include "RiuViewer.h" @@ -41,6 +42,7 @@ #include "RivWellPathPartMgr.h" #include "cafDisplayCoordTransform.h" +#include "cafPdmUiTreeOrdering.h" #include "cvfModelBasicList.h" #include "cvfTransform.h" @@ -51,10 +53,12 @@ CAF_PDM_SOURCE_INIT(Rim2dIntersectionView, "Intersection2dView"); -const cvf::Mat4d defaultViewMatrix(1, 0, 0, 0, - 0, 0, 1, 0, - 0, -1, 0, 1000, - 0, 0, 0, 1); + +const cvf::Mat4d Rim2dIntersectionView::sm_defaultViewMatrix = cvf::Mat4d(1, 0, 0, 0, + 0, 0, 1, 0, + 0, -1, 0, 1000, + 0, 0, 0, 1); + //-------------------------------------------------------------------------------------------------- /// @@ -66,13 +70,13 @@ Rim2dIntersectionView::Rim2dIntersectionView(void) CAF_PDM_InitFieldNoDefault(&m_intersection, "Intersection", "Intersection", ":/CrossSection16x16.png", "", ""); m_intersection.uiCapability()->setUiHidden(true); - CAF_PDM_InitFieldNoDefault(&m_legendConfig, "LegendDefinition", "Legend Definition", "", "", ""); + CAF_PDM_InitFieldNoDefault(&m_legendConfig, "LegendDefinition", "Color Legend", "", "", ""); m_legendConfig.uiCapability()->setUiHidden(true); m_legendConfig.uiCapability()->setUiTreeChildrenHidden(true); m_legendConfig.xmlCapability()->disableIO(); m_legendConfig = new RimRegularLegendConfig(); - CAF_PDM_InitFieldNoDefault(&m_ternaryLegendConfig, "TernaryLegendDefinition", "Ternary Legend Definition", "", "", ""); + CAF_PDM_InitFieldNoDefault(&m_ternaryLegendConfig, "TernaryLegendDefinition", "Ternary Color Legend", "", "", ""); m_ternaryLegendConfig.uiCapability()->setUiTreeHidden(true); m_ternaryLegendConfig.uiCapability()->setUiTreeChildrenHidden(true); m_ternaryLegendConfig.xmlCapability()->disableIO(); @@ -81,16 +85,26 @@ Rim2dIntersectionView::Rim2dIntersectionView(void) CAF_PDM_InitField(&m_showDefiningPoints, "ShowDefiningPoints", true, "Show Points", "", "", ""); CAF_PDM_InitField(&m_showAxisLines, "ShowAxisLines", false, "Show Axis Lines", "", "", ""); + CAF_PDM_InitFieldNoDefault(&m_nameProxy, "NameProxy", "Name", "", "", ""); + m_nameProxy.xmlCapability()->disableIO(); + m_nameProxy.registerGetMethod(this, &Rim2dIntersectionView::getName); + m_nameProxy.registerSetMethod(this, &Rim2dIntersectionView::setName); + m_showWindow = false; m_scaleTransform = new cvf::Transform(); m_intersectionVizModel = new cvf::ModelBasicList; hasUserRequestedAnimation = true; - ((RiuViewerToViewInterface*)this)->setCameraPosition(defaultViewMatrix ); + ((RiuViewerToViewInterface*)this)->setCameraPosition(sm_defaultViewMatrix ); disableGridBoxField(); disablePerspectiveProjectionField(); + + nameConfig()->hideCaseNameField(true); + nameConfig()->hideAggregationTypeField(true); + nameConfig()->hidePropertyField(true); + nameConfig()->hideSampleSpacingField(true); } //-------------------------------------------------------------------------------------------------- @@ -189,6 +203,7 @@ void Rim2dIntersectionView::update3dInfo() m_viewer->showInfoText(false); m_viewer->showHistogram(false); m_viewer->showAnimationProgress(false); + m_viewer->showVersionInfo(false); m_viewer->update(); return; @@ -426,6 +441,30 @@ int Rim2dIntersectionView::timeStepCount() return 0; } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString Rim2dIntersectionView::createAutoName() const +{ + return nameConfig()->customName(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString Rim2dIntersectionView::getName() const +{ + return nameConfig()->customName(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void Rim2dIntersectionView::setName(const QString& name) +{ + nameConfig()->setCustomName(name); +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -514,7 +553,7 @@ void Rim2dIntersectionView::createDisplayModel() updateCurrentTimeStep(); } - if ( this->viewer()->mainCamera()->viewMatrix() == defaultViewMatrix ) + if ( this->viewer()->mainCamera()->viewMatrix() == sm_defaultViewMatrix ) { this->zoomAll(); } @@ -621,7 +660,7 @@ void Rim2dIntersectionView::updateLegends() { m_legendConfig()->setUiValuesFromLegendConfig(eclView->cellResult()->legendConfig()); m_ternaryLegendConfig()->setUiValuesFromLegendConfig(eclView->cellResult()->ternaryLegendConfig()); - eclView->cellResult()->updateLegendData(m_currentTimeStep(), m_legendConfig(), m_ternaryLegendConfig()); + eclView->cellResult()->updateLegendData(eclView->eclipseCase(), m_currentTimeStep(), m_legendConfig(), m_ternaryLegendConfig()); if ( eclView->cellResult()->isTernarySaturationSelected() ) { @@ -664,6 +703,7 @@ void Rim2dIntersectionView::resetLegendsInViewer() m_viewer->showAnimationProgress(true); m_viewer->showHistogram(false); m_viewer->showInfoText(false); + m_viewer->showVersionInfo(false); m_viewer->showEdgeTickMarksXZ(true, m_showAxisLines()); m_viewer->setMainScene(new cvf::Scene()); @@ -758,6 +798,8 @@ void Rim2dIntersectionView::fieldChangedByUi(const caf::PdmFieldHandle* changedF //-------------------------------------------------------------------------------------------------- void Rim2dIntersectionView::defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering) { + uiOrdering.add(&m_nameProxy); + Rim3dView::defineUiOrdering(uiConfigName, uiOrdering); caf::PdmUiGroup* viewGroup = uiOrdering.findGroup("ViewGroup"); if (viewGroup) @@ -773,3 +815,11 @@ void Rim2dIntersectionView::defineUiOrdering(QString uiConfigName, caf::PdmUiOrd plGroup->add(&m_showDefiningPoints); } } + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void Rim2dIntersectionView::defineUiTreeOrdering(caf::PdmUiTreeOrdering& uiTreeOrdering, QString uiConfigName /*= ""*/) +{ + uiTreeOrdering.skipRemainingChildren(true); +} diff --git a/ApplicationCode/ProjectDataModel/Rim2dIntersectionView.h b/ApplicationCode/ProjectDataModel/Rim2dIntersectionView.h index 517fdc4ac2..da697a13dc 100644 --- a/ApplicationCode/ProjectDataModel/Rim2dIntersectionView.h +++ b/ApplicationCode/ProjectDataModel/Rim2dIntersectionView.h @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018- Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -20,6 +20,7 @@ #include "Rim3dView.h" #include "cafPdmPtrField.h" +#include "cafPdmProxyValueField.h" class RimIntersection; class RimRegularLegendConfig; @@ -92,11 +93,16 @@ class Rim2dIntersectionView : public Rim3dView void fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue) override; void defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering ) override; + void defineUiTreeOrdering(caf::PdmUiTreeOrdering& uiTreeOrdering, QString uiConfigName = "") override; QList calculateValueOptions(const caf::PdmFieldHandle* fieldNeedingOptions, bool* useOptionsOnly) override; bool hasResults(); int timeStepCount(); +private: + QString createAutoName() const override; + QString getName() const; + void setName(const QString& name); caf::PdmChildField m_legendConfig; caf::PdmChildField m_ternaryLegendConfig; @@ -110,8 +116,11 @@ class Rim2dIntersectionView : public Rim3dView cvf::ref m_intersectionVizModel; cvf::ref m_scaleTransform; + caf::PdmProxyValueField m_nameProxy; caf::PdmField m_showDefiningPoints; caf::PdmField m_showAxisLines; caf::PdmPointer m_legendObjectToSelect; + + const static cvf::Mat4d sm_defaultViewMatrix; }; diff --git a/ApplicationCode/ProjectDataModel/Rim2dIntersectionViewCollection.cpp b/ApplicationCode/ProjectDataModel/Rim2dIntersectionViewCollection.cpp index 3b85df0ccc..f8c7360e2c 100644 --- a/ApplicationCode/ProjectDataModel/Rim2dIntersectionViewCollection.cpp +++ b/ApplicationCode/ProjectDataModel/Rim2dIntersectionViewCollection.cpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018- Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -63,7 +63,6 @@ void Rim2dIntersectionViewCollection::syncFromExistingIntersections( bool doUpda parentCase->descendantsIncludingThisOfType(allOrderedIntersectionsInCase); std::set currentIntersections(allOrderedIntersectionsInCase.begin(), allOrderedIntersectionsInCase.end()); - std::set intersectionsNeedingViews = currentIntersections; // Delete views without a valid intersection @@ -98,6 +97,14 @@ void Rim2dIntersectionViewCollection::syncFromExistingIntersections( bool doUpda if (it == intersectionToViewMap.end()) { Rim2dIntersectionView* newView = new Rim2dIntersectionView(); + + Rim3dView* view = nullptr; + intersection->firstAncestorOrThisOfType(view); + if (view) + { + newView->setCurrentTimeStep(view->currentTimeStep()); + } + newView->setIntersection(intersection); m_intersectionViews.push_back(newView); } diff --git a/ApplicationCode/ProjectDataModel/Rim2dIntersectionViewCollection.h b/ApplicationCode/ProjectDataModel/Rim2dIntersectionViewCollection.h index 60dcddfd30..6bfebc496d 100644 --- a/ApplicationCode/ProjectDataModel/Rim2dIntersectionViewCollection.h +++ b/ApplicationCode/ProjectDataModel/Rim2dIntersectionViewCollection.h @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018- Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by diff --git a/ApplicationCode/ProjectDataModel/Rim3dOverlayInfoConfig.cpp b/ApplicationCode/ProjectDataModel/Rim3dOverlayInfoConfig.cpp index 9d68b66ac2..b9d8221bf8 100644 --- a/ApplicationCode/ProjectDataModel/Rim3dOverlayInfoConfig.cpp +++ b/ApplicationCode/ProjectDataModel/Rim3dOverlayInfoConfig.cpp @@ -3,17 +3,17 @@ // Copyright (C) 2011- Statoil ASA // Copyright (C) 2013- Ceetron Solutions AS // Copyright (C) 2011-2012 Ceetron AS -// +// // ResInsight 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 3 of the License, or // (at your option) any later version. -// +// // ResInsight 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 at +// +// See the GNU General Public License at // for more details. // ///////////////////////////////////////////////////////////////////////////////// @@ -37,8 +37,6 @@ #include "RigMainGrid.h" #include "RigStatisticsDataCache.h" -#include "RimContourMapView.h" -#include "RimContourMapProjection.h" #include "Rim2dIntersectionView.h" #include "Rim2dIntersectionViewCollection.h" #include "Rim3dView.h" @@ -46,54 +44,57 @@ #include "RimCellEdgeColors.h" #include "RimEclipseCase.h" #include "RimEclipseCellColors.h" +#include "RimEclipseContourMapProjection.h" +#include "RimEclipseContourMapView.h" #include "RimEclipseFaultColors.h" #include "RimEclipsePropertyFilterCollection.h" #include "RimEclipseView.h" #include "RimFaultInViewCollection.h" #include "RimGeoMechCase.h" +#include "RimGeoMechContourMapProjection.h" +#include "RimGeoMechContourMapView.h" #include "RimGeoMechResultDefinition.h" #include "RimGeoMechView.h" #include "RimReservoirCellResultsStorage.h" #include "RimSimWellInViewCollection.h" -#include "RimTools.h" #include "RiuViewer.h" -#include #include +#include CAF_PDM_SOURCE_INIT(Rim3dOverlayInfoConfig, "View3dOverlayInfoConfig"); //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- namespace caf { - template<> - void caf::AppEnum::setUp() - { - addItem(Rim3dOverlayInfoConfig::ALL_TIMESTEPS, "ALL_TIMESTEPS", "All Time Steps"); - addItem(Rim3dOverlayInfoConfig::CURRENT_TIMESTEP, "CURRENT_TIMESTEP", "Current Time Step"); - setDefault(Rim3dOverlayInfoConfig::ALL_TIMESTEPS); - } +template<> +void caf::AppEnum::setUp() +{ + addItem(Rim3dOverlayInfoConfig::ALL_TIMESTEPS, "ALL_TIMESTEPS", "All Time Steps"); + addItem(Rim3dOverlayInfoConfig::CURRENT_TIMESTEP, "CURRENT_TIMESTEP", "Current Time Step"); + setDefault(Rim3dOverlayInfoConfig::ALL_TIMESTEPS); } +} // namespace caf //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- namespace caf { - template<> - void caf::AppEnum::setUp() - { - addItem(Rim3dOverlayInfoConfig::ALL_CELLS, "ALL_CELLS", "All Active Cells"); - addItem(Rim3dOverlayInfoConfig::VISIBLE_CELLS, "VISIBLE_CELLS", "Visible Cells"); - setDefault(Rim3dOverlayInfoConfig::ALL_CELLS); - } +template<> +void caf::AppEnum::setUp() +{ + addItem(Rim3dOverlayInfoConfig::ALL_CELLS, "ALL_CELLS", "All Active Cells"); + addItem(Rim3dOverlayInfoConfig::VISIBLE_CELLS, "VISIBLE_CELLS", "Visible Cells"); + setDefault(Rim3dOverlayInfoConfig::ALL_CELLS); } +} // namespace caf //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- Rim3dOverlayInfoConfig::Rim3dOverlayInfoConfig() { @@ -102,15 +103,16 @@ Rim3dOverlayInfoConfig::Rim3dOverlayInfoConfig() CAF_PDM_InitField(&m_active, "Active", true, "Active", "", "", ""); m_active.uiCapability()->setUiHidden(true); - CAF_PDM_InitField(&m_showAnimProgress, "ShowAnimProgress", true, "Animation progress", "", "", ""); - CAF_PDM_InitField(&m_showCaseInfo, "ShowInfoText", true, "Case Info", "", "", ""); - CAF_PDM_InitField(&m_showResultInfo, "ShowResultInfo", true, "Result Info", "", "", ""); - CAF_PDM_InitField(&m_showHistogram, "ShowHistogram", true, "Histogram", "", "", ""); + CAF_PDM_InitField(&m_showAnimProgress, "ShowAnimProgress", true, "Animation progress", "", "", ""); + CAF_PDM_InitField(&m_showCaseInfo, "ShowInfoText", true, "Case Info", "", "", ""); + CAF_PDM_InitField(&m_showResultInfo, "ShowResultInfo", true, "Result Info", "", "", ""); + CAF_PDM_InitField(&m_showHistogram, "ShowHistogram", true, "Histogram", "", "", ""); CAF_PDM_InitField(&m_showVolumeWeightedMean, "ShowVolumeWeightedMean", true, "Mobile Volume Weighted Mean", "", "", ""); + CAF_PDM_InitField(&m_showVersionInfo, "ShowVersionInfo", true, "Version Info", "", "", ""); CAF_PDM_InitFieldNoDefault(&m_statisticsTimeRange, "StatisticsTimeRange", "Statistics Time Range", "", "", ""); CAF_PDM_InitFieldNoDefault(&m_statisticsCellRange, "StatisticsCellRange", "Statistics Cell Range", "", "", ""); - //m_statisticsCellRange.uiCapability()->setUiHidden(true); + // m_statisticsCellRange.uiCapability()->setUiHidden(true); m_isVisCellStatUpToDate = false; @@ -118,24 +120,22 @@ Rim3dOverlayInfoConfig::Rim3dOverlayInfoConfig() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- -Rim3dOverlayInfoConfig::~Rim3dOverlayInfoConfig() -{ - -} +Rim3dOverlayInfoConfig::~Rim3dOverlayInfoConfig() {} //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- -void Rim3dOverlayInfoConfig::fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue) +void Rim3dOverlayInfoConfig::fieldChangedByUi(const caf::PdmFieldHandle* changedField, + const QVariant& oldValue, + const QVariant& newValue) { - - if ( hasInvalidStatisticsCombination() ) + if (hasInvalidStatisticsCombination()) { displayPropertyFilteredStatisticsMessage(false); - if ( changedField == &m_statisticsTimeRange ) m_statisticsTimeRange = CURRENT_TIMESTEP; - if ( changedField == &m_statisticsCellRange ) m_statisticsCellRange = ALL_CELLS; + if (changedField == &m_statisticsTimeRange) m_statisticsTimeRange = CURRENT_TIMESTEP; + if (changedField == &m_statisticsCellRange) m_statisticsCellRange = ALL_CELLS; } if (changedField == &m_showResultInfo) @@ -158,11 +158,10 @@ void Rim3dOverlayInfoConfig::fieldChangedByUi(const caf::PdmFieldHandle* changed { m_viewDef->viewer()->update(); } - } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void Rim3dOverlayInfoConfig::setPosition(cvf::Vec2ui position) { @@ -170,27 +169,33 @@ void Rim3dOverlayInfoConfig::setPosition(cvf::Vec2ui position) } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- Rim3dOverlayInfoConfig::HistogramData Rim3dOverlayInfoConfig::histogramData() { - auto eclipseView = dynamic_cast(m_viewDef.p()); - auto geoMechView = dynamic_cast(m_viewDef.p()); - auto contourMap = dynamic_cast(eclipseView); - - if (contourMap) return histogramData(contourMap); - else if (eclipseView) return histogramData(eclipseView); - else if (geoMechView) return histogramData(geoMechView); + auto eclipseView = dynamic_cast(m_viewDef.p()); + auto geoMechView = dynamic_cast(m_viewDef.p()); + auto eclipseContourMap = dynamic_cast(eclipseView); + auto geoMechContourMap = dynamic_cast(geoMechView); + + if (eclipseContourMap) + return histogramData(eclipseContourMap); + else if (geoMechContourMap) + return histogramData(geoMechContourMap); + else if (eclipseView) + return histogramData(eclipseView); + else if (geoMechView) + return histogramData(geoMechView); return HistogramData(); } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- QString Rim3dOverlayInfoConfig::timeStepText() { - RimEclipseView * eclipseView = dynamic_cast(m_viewDef.p()); - RimGeoMechView * geoMechView = dynamic_cast(m_viewDef.p()); + RimEclipseView* eclipseView = dynamic_cast(m_viewDef.p()); + RimGeoMechView* geoMechView = dynamic_cast(m_viewDef.p()); if (eclipseView) return timeStepText(eclipseView); if (geoMechView) return timeStepText(geoMechView); @@ -198,7 +203,7 @@ QString Rim3dOverlayInfoConfig::timeStepText() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- QString Rim3dOverlayInfoConfig::caseInfoText() { @@ -211,7 +216,7 @@ QString Rim3dOverlayInfoConfig::caseInfoText() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- QString Rim3dOverlayInfoConfig::resultInfoText(const HistogramData& histData) { @@ -224,7 +229,7 @@ QString Rim3dOverlayInfoConfig::resultInfoText(const HistogramData& histData) } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- QImage Rim3dOverlayInfoConfig::statisticsDialogScreenShotImage() { @@ -236,7 +241,7 @@ QImage Rim3dOverlayInfoConfig::statisticsDialogScreenShotImage() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- bool Rim3dOverlayInfoConfig::showAnimProgress() const { @@ -244,7 +249,7 @@ bool Rim3dOverlayInfoConfig::showAnimProgress() const } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- bool Rim3dOverlayInfoConfig::showCaseInfo() const { @@ -252,7 +257,7 @@ bool Rim3dOverlayInfoConfig::showCaseInfo() const } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- bool Rim3dOverlayInfoConfig::showResultInfo() const { @@ -260,7 +265,7 @@ bool Rim3dOverlayInfoConfig::showResultInfo() const } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- bool Rim3dOverlayInfoConfig::isActive() const { @@ -270,15 +275,15 @@ bool Rim3dOverlayInfoConfig::isActive() const //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void Rim3dOverlayInfoConfig::setIsActive(bool active) +bool Rim3dOverlayInfoConfig::showVersionInfo() const { - m_active = active; + return m_showVersionInfo(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -Rim3dOverlayInfoConfig::HistogramData Rim3dOverlayInfoConfig::histogramData(RimContourMapView* contourMap) +Rim3dOverlayInfoConfig::HistogramData Rim3dOverlayInfoConfig::histogramData(RimEclipseContourMapView* contourMap) { HistogramData histData; @@ -288,20 +293,41 @@ Rim3dOverlayInfoConfig::HistogramData Rim3dOverlayInfoConfig::histogramData(RimC if (isResultsInfoRelevant) { - histData.min = contourMap->contourMapProjection()->minValue(); - histData.max = contourMap->contourMapProjection()->maxValue(); + histData.min = contourMap->contourMapProjection()->minValue(); + histData.max = contourMap->contourMapProjection()->maxValue(); histData.mean = contourMap->contourMapProjection()->meanValue(); - histData.sum = contourMap->contourMapProjection()->sumAllValues(); + histData.sum = contourMap->contourMapProjection()->sumAllValues(); } } return histData; } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +Rim3dOverlayInfoConfig::HistogramData Rim3dOverlayInfoConfig::histogramData(RimGeoMechContourMapView* contourMap) +{ + HistogramData histData; + + if (contourMap) + { + bool isResultsInfoRelevant = contourMap->contourMapProjection()->numberOfValidCells() > 0u; + + if (isResultsInfoRelevant) + { + histData.min = contourMap->contourMapProjection()->minValue(); + histData.max = contourMap->contourMapProjection()->maxValue(); + histData.mean = contourMap->contourMapProjection()->meanValue(); + histData.sum = contourMap->contourMapProjection()->sumAllValues(); + } + } + return histData; +} //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- -Rim3dOverlayInfoConfig::HistogramData Rim3dOverlayInfoConfig::histogramData(RimEclipseView* eclipseView) +Rim3dOverlayInfoConfig::HistogramData Rim3dOverlayInfoConfig::histogramData(RimEclipseView* eclipseView) { HistogramData histData; @@ -311,20 +337,20 @@ Rim3dOverlayInfoConfig::HistogramData Rim3dOverlayInfoConfig::histogramData(RimE if (isResultsInfoRelevant) { - size_t scalarIndex = eclipseView->cellResult()->scalarResultIndex(); + RigEclipseResultAddress eclResAddr = eclipseView->cellResult()->eclipseResultAddress(); - if (scalarIndex != cvf::UNDEFINED_SIZE_T) + if (eclResAddr.isValid()) { if (m_statisticsCellRange == ALL_CELLS) { if (m_statisticsTimeRange == ALL_TIMESTEPS) { - eclipseView->currentGridCellResults()->minMaxCellScalarValues(scalarIndex, histData.min, histData.max); - eclipseView->currentGridCellResults()->p10p90CellScalarValues(scalarIndex, histData.p10, histData.p90); - eclipseView->currentGridCellResults()->meanCellScalarValues(scalarIndex, histData.mean); - eclipseView->currentGridCellResults()->sumCellScalarValues(scalarIndex, histData.sum); - eclipseView->currentGridCellResults()->mobileVolumeWeightedMean(scalarIndex, histData.weightedMean); - histData.histogram = &(eclipseView->currentGridCellResults()->cellScalarValuesHistogram(scalarIndex)); + eclipseView->currentGridCellResults()->minMaxCellScalarValues(eclResAddr, histData.min, histData.max); + eclipseView->currentGridCellResults()->p10p90CellScalarValues(eclResAddr, histData.p10, histData.p90); + eclipseView->currentGridCellResults()->meanCellScalarValues(eclResAddr, histData.mean); + eclipseView->currentGridCellResults()->sumCellScalarValues(eclResAddr, histData.sum); + eclipseView->currentGridCellResults()->mobileVolumeWeightedMean(eclResAddr, histData.weightedMean); + histData.histogram = &(eclipseView->currentGridCellResults()->cellScalarValuesHistogram(eclResAddr)); } else if (m_statisticsTimeRange == CURRENT_TIMESTEP) { @@ -334,13 +360,17 @@ Rim3dOverlayInfoConfig::HistogramData Rim3dOverlayInfoConfig::histogramData(RimE currentTimeStep = 0; } - eclipseView->currentGridCellResults()->minMaxCellScalarValues(scalarIndex, currentTimeStep, histData.min, histData.max); - eclipseView->currentGridCellResults()->p10p90CellScalarValues(scalarIndex, currentTimeStep, histData.p10, histData.p90); - eclipseView->currentGridCellResults()->meanCellScalarValues(scalarIndex, currentTimeStep, histData.mean); - eclipseView->currentGridCellResults()->sumCellScalarValues(scalarIndex, currentTimeStep, histData.sum); - eclipseView->currentGridCellResults()->mobileVolumeWeightedMean(scalarIndex, currentTimeStep, histData.weightedMean); - - histData.histogram = &(eclipseView->currentGridCellResults()->cellScalarValuesHistogram(scalarIndex, currentTimeStep)); + eclipseView->currentGridCellResults()->minMaxCellScalarValues( + eclResAddr, currentTimeStep, histData.min, histData.max); + eclipseView->currentGridCellResults()->p10p90CellScalarValues( + eclResAddr, currentTimeStep, histData.p10, histData.p90); + eclipseView->currentGridCellResults()->meanCellScalarValues(eclResAddr, currentTimeStep, histData.mean); + eclipseView->currentGridCellResults()->sumCellScalarValues(eclResAddr, currentTimeStep, histData.sum); + eclipseView->currentGridCellResults()->mobileVolumeWeightedMean( + eclResAddr, currentTimeStep, histData.weightedMean); + + histData.histogram = + &(eclipseView->currentGridCellResults()->cellScalarValuesHistogram(eclResAddr, currentTimeStep)); } else { @@ -381,14 +411,15 @@ Rim3dOverlayInfoConfig::HistogramData Rim3dOverlayInfoConfig::histogramData(RimE } else if (eclipseView->cellResult()->isFlowDiagOrInjectionFlooding()) { - if (m_statisticsTimeRange == CURRENT_TIMESTEP || m_statisticsTimeRange == ALL_TIMESTEPS) // All timesteps is ignored + if (m_statisticsTimeRange == CURRENT_TIMESTEP || + m_statisticsTimeRange == ALL_TIMESTEPS) // All timesteps is ignored { int currentTimeStep = eclipseView->currentTimeStep(); if (m_statisticsCellRange == ALL_CELLS) { - RigFlowDiagResults* fldResults = eclipseView->cellResult()->flowDiagSolution()->flowDiagResults(); - RigFlowDiagResultAddress resAddr = eclipseView->cellResult()->flowDiagResAddress(); + RigFlowDiagResults* fldResults = eclipseView->cellResult()->flowDiagSolution()->flowDiagResults(); + RigFlowDiagResultAddress resAddr = eclipseView->cellResult()->flowDiagResAddress(); fldResults->minMaxScalarValues(resAddr, currentTimeStep, &histData.min, &histData.max); fldResults->p10p90ScalarValues(resAddr, currentTimeStep, &histData.p10, &histData.p90); @@ -418,7 +449,7 @@ Rim3dOverlayInfoConfig::HistogramData Rim3dOverlayInfoConfig::histogramData(RimE } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- Rim3dOverlayInfoConfig::HistogramData Rim3dOverlayInfoConfig::histogramData(RimGeoMechView* geoMechView) { @@ -426,9 +457,10 @@ Rim3dOverlayInfoConfig::HistogramData Rim3dOverlayInfoConfig::histogramData(RimG if (geoMechView) { - RimGeoMechCase* geoMechCase = geoMechView->geoMechCase(); - RigGeoMechCaseData* caseData = geoMechCase ? geoMechCase->geoMechData() : nullptr; - bool isResultsInfoRelevant = caseData && geoMechView->hasUserRequestedAnimation() && geoMechView->cellResultResultDefinition()->hasResult(); + RimGeoMechCase* geoMechCase = geoMechView->geoMechCase(); + RigGeoMechCaseData* caseData = geoMechCase ? geoMechCase->geoMechData() : nullptr; + bool isResultsInfoRelevant = + caseData && geoMechView->hasUserRequestedAnimation() && geoMechView->cellResultResultDefinition()->hasResult(); if (isResultsInfoRelevant) { @@ -486,66 +518,71 @@ Rim3dOverlayInfoConfig::HistogramData Rim3dOverlayInfoConfig::histogramData(RimG } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- QString Rim3dOverlayInfoConfig::caseInfoText(RimEclipseView* eclipseView) { QString infoText; - if (eclipseView) + if (eclipseView && eclipseView->eclipseCase()) { QString caseName = eclipseView->eclipseCase()->caseUserDescription(); - RimContourMapView* contourMap = dynamic_cast(eclipseView); + RimEclipseContourMapView* contourMap = dynamic_cast(eclipseView); if (contourMap && contourMap->contourMapProjection()) { - QString totCellCount = QString::number(contourMap->contourMapProjection()->numberOfCells()); - cvf::uint validCellCount = contourMap->contourMapProjection()->numberOfValidCells(); - QString activeCellCountText = QString::number(validCellCount); - QString iSize = QString::number(contourMap->contourMapProjection()->numberOfElementsIJ().x()); - QString jSize = QString::number(contourMap->contourMapProjection()->numberOfElementsIJ().y()); - QString aggregationType = contourMap->contourMapProjection()->resultAggregationText(); - QString weightingParameterString; + QString totCellCount = QString::number(contourMap->contourMapProjection()->numberOfCells()); + cvf::uint validCellCount = contourMap->contourMapProjection()->numberOfValidCells(); + QString activeCellCountText = QString::number(validCellCount); + QString iSize = QString::number(contourMap->contourMapProjection()->numberOfElementsIJ().x()); + QString jSize = QString::number(contourMap->contourMapProjection()->numberOfElementsIJ().y()); + QString aggregationType = contourMap->contourMapProjection()->resultAggregationText(); + QString weightingParameterString; if (contourMap->contourMapProjection()->weightingParameter() != "None") { - weightingParameterString += QString(" (Weight: %1)").arg(contourMap->contourMapProjection()->weightingParameter()); + weightingParameterString += + QString(" (Weight: %1)").arg(contourMap->contourMapProjection()->weightingParameter()); } - infoText += QString( - "

-- Contour Map: %1 --

" - "Sample Count. Total: %2 Valid Results: %3
" - "Projection Type: %4%5
").arg(caseName, totCellCount, activeCellCountText, aggregationType, weightingParameterString); + infoText += QString("

-- Contour Map: %1 --

" + "Sample Count. Total: %2 Valid Results: %3
" + "Projection Type: %4%5
") + .arg(caseName, totCellCount, activeCellCountText, aggregationType, weightingParameterString); } else if (eclipseView->mainGrid()) { - QString totCellCount = QString::number(eclipseView->mainGrid()->globalCellArray().size()); - size_t mxActCellCount = eclipseView->eclipseCase()->eclipseCaseData()->activeCellInfo(RiaDefines::MATRIX_MODEL)->reservoirActiveCellCount(); - size_t frActCellCount = eclipseView->eclipseCase()->eclipseCaseData()->activeCellInfo(RiaDefines::FRACTURE_MODEL)->reservoirActiveCellCount(); - + QString totCellCount = QString::number(eclipseView->mainGrid()->globalCellArray().size()); + size_t mxActCellCount = eclipseView->eclipseCase() + ->eclipseCaseData() + ->activeCellInfo(RiaDefines::MATRIX_MODEL) + ->reservoirActiveCellCount(); + size_t frActCellCount = eclipseView->eclipseCase() + ->eclipseCaseData() + ->activeCellInfo(RiaDefines::FRACTURE_MODEL) + ->reservoirActiveCellCount(); + QString activeCellCountText; - if (frActCellCount > 0) activeCellCountText += "Matrix : "; + if (frActCellCount > 0) activeCellCountText += "Matrix : "; activeCellCountText += QString::number(mxActCellCount); - if (frActCellCount > 0) activeCellCountText += " Fracture : " + QString::number(frActCellCount); + if (frActCellCount > 0) activeCellCountText += " Fracture : " + QString::number(frActCellCount); QString iSize = QString::number(eclipseView->mainGrid()->cellCountI()); QString jSize = QString::number(eclipseView->mainGrid()->cellCountJ()); QString kSize = QString::number(eclipseView->mainGrid()->cellCountK()); QString zScale = QString::number(eclipseView->scaleZ()); - infoText += QString( - "

-- %1 --

" - "Cell count. Total: %2 Active: %3
" - "Main Grid I,J,K: %4, %5, %6 Z-Scale: %7
").arg(caseName, totCellCount, activeCellCountText, iSize, jSize, kSize, zScale); - + infoText += QString("

-- %1 --

" + "Cell count. Total: %2 Active: %3
" + "Main Grid I,J,K: %4, %5, %6 Z-Scale: %7
") + .arg(caseName, totCellCount, activeCellCountText, iSize, jSize, kSize, zScale); } - } return infoText; } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- QString Rim3dOverlayInfoConfig::caseInfoText(RimGeoMechView* geoMechView) { @@ -553,48 +590,77 @@ QString Rim3dOverlayInfoConfig::caseInfoText(RimGeoMechView* geoMechView) if (geoMechView) { - RimGeoMechCase* geoMechCase = geoMechView->geoMechCase(); - RigGeoMechCaseData* caseData = geoMechCase ? geoMechCase->geoMechData() : nullptr; - RigFemPartCollection* femParts = caseData ? caseData->femParts() : nullptr; + RimGeoMechCase* geoMechCase = geoMechView->geoMechCase(); + RigGeoMechCaseData* caseData = geoMechCase ? geoMechCase->geoMechData() : nullptr; + RigFemPartCollection* femParts = caseData ? caseData->femParts() : nullptr; if (femParts) { - QString caseName = geoMechCase->caseUserDescription(); - QString cellCount = QString("%1").arg(femParts->totalElementCount()); - QString zScale = QString::number(geoMechView->scaleZ()); + QString caseName = geoMechCase->caseUserDescription(); + RimGeoMechContourMapView* contourMap = dynamic_cast(geoMechView); + + if (contourMap && contourMap->contourMapProjection()) + { + QString totCellCount = QString::number(contourMap->contourMapProjection()->numberOfCells()); + cvf::uint validCellCount = contourMap->contourMapProjection()->numberOfValidCells(); + QString activeCellCountText = QString::number(validCellCount); + QString iSize = QString::number(contourMap->contourMapProjection()->numberOfElementsIJ().x()); + QString jSize = QString::number(contourMap->contourMapProjection()->numberOfElementsIJ().y()); + QString aggregationType = contourMap->contourMapProjection()->resultAggregationText(); + + infoText += QString("

-- Contour Map: %1 --

" + "Sample Count. Total: %2 Valid Results: %3
" + "Projection Type: %4
") + .arg(caseName, totCellCount, activeCellCountText, aggregationType); + } + else + { + QString cellCount = QString("%1").arg(femParts->totalElementCount()); + QString zScale = QString::number(geoMechView->scaleZ()); - infoText = QString( - "

-- %1 --

" - "Cell count: %2 Z-Scale: %3
").arg(caseName, cellCount, zScale); + infoText = QString("

-- %1 --

" + "Cell count: %2 Z-Scale: %3
") + .arg(caseName, cellCount, zScale); + } } } return infoText; } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- -QString Rim3dOverlayInfoConfig::resultInfoText(const HistogramData& histData, RimEclipseView* eclipseView, bool showVolumeWeightedMean) +QString Rim3dOverlayInfoConfig::resultInfoText(const HistogramData& histData, + RimEclipseView* eclipseView, + bool showVolumeWeightedMean) { QString infoText; - RimContourMapView* contourMap = dynamic_cast(eclipseView); + RimEclipseContourMapView* contourMap = dynamic_cast(eclipseView); if (contourMap) { bool isResultsInfoRelevant = contourMap->contourMapProjection()->numberOfValidCells() > 0u; if (isResultsInfoRelevant) { - QString propName = eclipseView->cellResult()->resultVariableUiShortName(); + QString propName = eclipseView->cellResult()->resultVariableUiShortName(); + QString diffResString = eclipseView->cellResult()->diffResultUiName(); if (!contourMap->contourMapProjection()->isColumnResult()) { - infoText += QString("Cell Property: %1 ").arg(propName); + infoText += QString("Cell Property: %1
").arg(propName); + } + if (!diffResString.isEmpty()) + { + infoText += QString("%1
").arg(diffResString); } infoText += QString("
Statistics: Current Time Step and Visible Cells"); infoText += QString("" - "" - "" - "
Min Mean Max Sum
%1 %2 %3 %4
").arg(histData.min).arg(histData.mean).arg(histData.max).arg(histData.sum); + " Min Mean Max " + " %1 %2 %3 " + "") + .arg(histData.min) + .arg(histData.mean) + .arg(histData.max); } } else if (eclipseView) @@ -609,24 +675,44 @@ QString Rim3dOverlayInfoConfig::resultInfoText(const HistogramData& histData, Ri if (isResultsInfoRelevant) { - QString propName = eclipseView->cellResult()->resultVariableUiShortName(); + QString propName = eclipseView->cellResult()->resultVariableUiShortName(); + QString diffResString = eclipseView->cellResult()->diffResultUiName(); QString timeRangeText = m_statisticsTimeRange().uiText(); if (eclipseView->cellResult()->isFlowDiagOrInjectionFlooding()) { timeRangeText = caf::AppEnum::uiText(CURRENT_TIMESTEP); } - infoText += QString("Cell Property: %1 ").arg(propName); + infoText += QString("Cell Property: %1
").arg(propName); + if (!diffResString.isEmpty()) + { + infoText += QString("%1
").arg(diffResString); + } + + if (eclipseView->cellResult()->hasDualPorFractureResult()) + { + QString porosityModelText = + caf::AppEnum::uiText(eclipseView->cellResult()->porosityModel()); + + infoText += QString("Dual Porosity Type: %1
").arg(porosityModelText); + } + infoText += QString("
Statistics: ") + timeRangeText + " and " + m_statisticsCellRange().uiText(); infoText += QString("" "" "" - "
Min P90 Mean P10 Max Sum
%1 %2 %3 %4 %5 %6
").arg(histData.min).arg(histData.p10).arg(histData.mean).arg(histData.p90).arg(histData.max).arg(histData.sum); + "") + .arg(histData.min) + .arg(histData.p10) + .arg(histData.mean) + .arg(histData.p90) + .arg(histData.max) + .arg(histData.sum); if (eclipseView->faultResultSettings()->hasValidCustomResult()) { QString faultMapping; - bool isShowingGrid = eclipseView->faultCollection()->isGridVisualizationMode(); + bool isShowingGrid = eclipseView->faultCollection()->isGridVisualizationMode(); if (!isShowingGrid) { if (eclipseView->faultCollection()->faultResult() == RimFaultInViewCollection::FAULT_BACK_FACE_CULLING) @@ -648,20 +734,23 @@ QString Rim3dOverlayInfoConfig::resultInfoText(const HistogramData& histData, Ri } infoText += QString("Fault results: %1
").arg(faultMapping); - infoText += QString("Fault Property: %1
").arg(eclipseView->faultResultSettings()->customFaultResult()->resultVariableUiShortName()); + infoText += QString("Fault Property: %1
") + .arg(eclipseView->faultResultSettings()->customFaultResult()->resultVariableUiShortName()); } } if (eclipseView->hasUserRequestedAnimation() && eclipseView->cellEdgeResult()->hasResult()) { - double min, max; + double min, max; QString cellEdgeName = eclipseView->cellEdgeResult()->resultVariableUiShortName(); eclipseView->cellEdgeResult()->minMaxCellEdgeValues(min, max); infoText += QString("Cell Edge Property: %1 ").arg(cellEdgeName); infoText += QString("" "" "" - "
Min Max
%1 %2
").arg(min).arg(max); + "") + .arg(min) + .arg(max); } if (showVolumeWeightedMean && histData.weightedMean != HUGE_VAL) @@ -673,7 +762,7 @@ QString Rim3dOverlayInfoConfig::resultInfoText(const HistogramData& histData, Ri } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- QString Rim3dOverlayInfoConfig::resultInfoText(const HistogramData& histData, RimGeoMechView* geoMechView) { @@ -681,57 +770,93 @@ QString Rim3dOverlayInfoConfig::resultInfoText(const HistogramData& histData, Ri if (geoMechView) { - RimGeoMechCase* geoMechCase = geoMechView->geoMechCase(); - RigGeoMechCaseData* caseData = geoMechCase ? geoMechCase->geoMechData() : nullptr; - bool isResultsInfoRelevant = caseData && geoMechView->hasUserRequestedAnimation() && geoMechView->cellResultResultDefinition()->hasResult(); + RimGeoMechCase* geoMechCase = geoMechView->geoMechCase(); + RigGeoMechCaseData* caseData = geoMechCase ? geoMechCase->geoMechData() : nullptr; + bool isResultsInfoRelevant = + caseData && geoMechView->hasUserRequestedAnimation() && geoMechView->cellResultResultDefinition()->hasResult(); if (isResultsInfoRelevant) { QString resultPos; - QString fieldName = geoMechView->cellResultResultDefinition()->resultFieldUiName(); - QString compName = geoMechView->cellResultResultDefinition()->resultComponentUiName(); - + QString fieldName = geoMechView->cellResultResultDefinition()->resultFieldUiName(); + QString compName = geoMechView->cellResultResultDefinition()->resultComponentUiName(); + QString diffResString = geoMechView->cellResultResultDefinition()->diffResultUiName(); switch (geoMechView->cellResultResultDefinition()->resultPositionType()) { - case RIG_NODAL: - resultPos = "Nodal"; - break; - - case RIG_ELEMENT_NODAL: - resultPos = "Element nodal"; - break; - - case RIG_INTEGRATION_POINT: - resultPos = "Integration point"; - break; - - case RIG_ELEMENT: - resultPos = "Element"; - break; - default: - break; + case RIG_NODAL: + resultPos = "Nodal"; + break; + + case RIG_ELEMENT_NODAL: + resultPos = "Element nodal"; + break; + + case RIG_INTEGRATION_POINT: + resultPos = "Integration point"; + break; + + case RIG_ELEMENT: + resultPos = "Element"; + break; + default: + break; } if (compName == "") { - infoText += QString("Cell result: %1, %2").arg(resultPos).arg(fieldName); + infoText += QString("Cell result: %1, %2
").arg(resultPos).arg(fieldName); } else { - infoText += QString("Cell result: %1, %2, %3").arg(resultPos).arg(fieldName).arg(compName); + infoText += QString("Cell result: %1, %2, %3
").arg(resultPos).arg(fieldName).arg(compName); } - infoText += QString("
Statistics: ") + m_statisticsTimeRange().uiText() + " and " + m_statisticsCellRange().uiText(); - infoText += QString("" - "" - "" - "
Min P90 Mean P10 Max Sum
%1 %2 %3 %4 %5 %6
").arg(histData.min).arg(histData.p10).arg(histData.mean).arg(histData.p90).arg(histData.max).arg(histData.sum); + const RimGeoMechContourMapView* contourMapView = dynamic_cast(geoMechView); + if (contourMapView) + { + if (!diffResString.isEmpty()) + { + infoText += QString("%1
").arg(diffResString); + } + infoText += QString("
Statistics: ") + m_statisticsTimeRange().uiText() + " and " + + m_statisticsCellRange().uiText(); + infoText += QString("" + "" + "" + "
Min Mean Max
%1 %2 %3
") + .arg(histData.min) + .arg(histData.mean) + .arg(histData.max); + } + else + { + if (!diffResString.isEmpty()) + { + infoText += QString("%1
").arg(diffResString); + } + infoText += QString("
Statistics: ") + m_statisticsTimeRange().uiText() + " and " + + m_statisticsCellRange().uiText(); + infoText += QString("" + "" + "" + "
Min P90 Mean P10 Max Sum
%1 %2 %3 %4 %5 %6
") + .arg(histData.min) + .arg(histData.p10) + .arg(histData.mean) + .arg(histData.p90) + .arg(histData.max) + .arg(histData.sum); + } + } + else + { + infoText += QString("No valid result selected"); } } return infoText; } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void Rim3dOverlayInfoConfig::showStatisticsInfoDialog(bool raise) { @@ -752,7 +877,7 @@ void Rim3dOverlayInfoConfig::showStatisticsInfoDialog(bool raise) } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void Rim3dOverlayInfoConfig::update3DInfo() { @@ -766,6 +891,7 @@ void Rim3dOverlayInfoConfig::update3DInfo() m_viewDef->viewer()->showInfoText(false); m_viewDef->viewer()->showHistogram(false); m_viewDef->viewer()->showAnimationProgress(false); + m_viewDef->viewer()->showVersionInfo(false); update3DInfoIn2dViews(); return; @@ -774,6 +900,7 @@ void Rim3dOverlayInfoConfig::update3DInfo() m_viewDef->viewer()->showInfoText(m_showCaseInfo() || m_showResultInfo()); m_viewDef->viewer()->showHistogram(false); m_viewDef->viewer()->showAnimationProgress(m_showAnimProgress()); + m_viewDef->viewer()->showVersionInfo(m_showVersionInfo()); m_isVisCellStatUpToDate = false; @@ -783,7 +910,7 @@ void Rim3dOverlayInfoConfig::update3DInfo() m_statisticsTimeRange = CURRENT_TIMESTEP; } - RimEclipseView * reservoirView = dynamic_cast(m_viewDef.p()); + RimEclipseView* reservoirView = dynamic_cast(m_viewDef.p()); if (reservoirView) { updateEclipse3DInfo(reservoirView); @@ -792,7 +919,7 @@ void Rim3dOverlayInfoConfig::update3DInfo() m_gridStatisticsDialog->updateFromRimView(reservoirView); } - RimGeoMechView * geoMechView = dynamic_cast(m_viewDef.p()); + RimGeoMechView* geoMechView = dynamic_cast(m_viewDef.p()); if (geoMechView) { m_showVolumeWeightedMean = false; @@ -807,24 +934,23 @@ void Rim3dOverlayInfoConfig::update3DInfo() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- caf::PdmFieldHandle* Rim3dOverlayInfoConfig::objectToggleField() { return &m_active; } - //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void Rim3dOverlayInfoConfig::defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering) { caf::PdmUiGroup* visGroup = uiOrdering.addNewGroup("Visibility"); - RimEclipseView * eclipseView = dynamic_cast(m_viewDef.p()); - RimContourMapView* contourMap = dynamic_cast(eclipseView); - RimGeoMechView * geoMechView = dynamic_cast(m_viewDef.p()); + RimEclipseView* eclipseView = dynamic_cast(m_viewDef.p()); + RimEclipseContourMapView* contourMap = dynamic_cast(eclipseView); + RimGeoMechView* geoMechView = dynamic_cast(m_viewDef.p()); visGroup->add(&m_showAnimProgress); visGroup->add(&m_showCaseInfo); @@ -839,6 +965,8 @@ void Rim3dOverlayInfoConfig::defineUiOrdering(QString uiConfigName, caf::PdmUiOr visGroup->add(&m_showHistogram); } + visGroup->add(&m_showVersionInfo); + if (contourMap) { m_statisticsTimeRange = Rim3dOverlayInfoConfig::CURRENT_TIMESTEP; @@ -858,7 +986,7 @@ void Rim3dOverlayInfoConfig::defineUiOrdering(QString uiConfigName, caf::PdmUiOr } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void Rim3dOverlayInfoConfig::setReservoirView(RimGridView* ownerReservoirView) { @@ -866,9 +994,9 @@ void Rim3dOverlayInfoConfig::setReservoirView(RimGridView* ownerReservoirView) } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- -void Rim3dOverlayInfoConfig::updateEclipse3DInfo(RimEclipseView * eclipseView) +void Rim3dOverlayInfoConfig::updateEclipse3DInfo(RimEclipseView* eclipseView) { HistogramData histData; @@ -897,7 +1025,7 @@ void Rim3dOverlayInfoConfig::updateEclipse3DInfo(RimEclipseView * eclipseView) if (m_showHistogram()) { bool isResultsInfoRelevant = eclipseView->hasUserRequestedAnimation() && eclipseView->cellResult()->hasResult(); - + if (isResultsInfoRelevant && histData.histogram) { eclipseView->viewer()->showHistogram(true); @@ -908,9 +1036,9 @@ void Rim3dOverlayInfoConfig::updateEclipse3DInfo(RimEclipseView * eclipseView) } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- -void Rim3dOverlayInfoConfig::updateGeoMech3DInfo(RimGeoMechView * geoMechView) +void Rim3dOverlayInfoConfig::updateGeoMech3DInfo(RimGeoMechView* geoMechView) { HistogramData histData; @@ -942,9 +1070,10 @@ void Rim3dOverlayInfoConfig::updateGeoMech3DInfo(RimGeoMechView * geoMechView) if (m_showHistogram()) { - RimGeoMechCase* geoMechCase = geoMechView->geoMechCase(); - RigGeoMechCaseData* caseData = geoMechCase ? geoMechCase->geoMechData() : nullptr; - bool isResultsInfoRelevant = caseData && geoMechView->hasUserRequestedAnimation() && geoMechView->cellResultResultDefinition()->hasResult(); + RimGeoMechCase* geoMechCase = geoMechView->geoMechCase(); + RigGeoMechCaseData* caseData = geoMechCase ? geoMechCase->geoMechData() : nullptr; + bool isResultsInfoRelevant = + caseData && geoMechView->hasUserRequestedAnimation() && geoMechView->cellResultResultDefinition()->hasResult(); if (isResultsInfoRelevant) { @@ -956,7 +1085,7 @@ void Rim3dOverlayInfoConfig::updateGeoMech3DInfo(RimGeoMechView * geoMechView) } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void Rim3dOverlayInfoConfig::update3DInfoIn2dViews() const { @@ -972,31 +1101,34 @@ void Rim3dOverlayInfoConfig::update3DInfoIn2dViews() const } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- QString Rim3dOverlayInfoConfig::timeStepText(RimEclipseView* eclipseView) { - int currTimeStepIndex = eclipseView->currentTimeStep(); - std::vector timeSteps = eclipseView->currentGridCellResults()->allTimeStepDatesFromEclipseReader(); - QString dateTimeString; - if (currTimeStepIndex >= 0 && currTimeStepIndex < (int)timeSteps.size()) + + if (eclipseView && eclipseView->currentGridCellResults()) { - QString dateFormat = RimTools::createTimeFormatStringFromDates(timeSteps); + int currTimeStepIndex = eclipseView->currentTimeStep(); + std::vector timeSteps = eclipseView->currentGridCellResults()->allTimeStepDatesFromEclipseReader(); + + if (currTimeStepIndex >= 0 && currTimeStepIndex < (int)timeSteps.size()) + { + QString dateFormat = RiaQDateTimeTools::createTimeFormatStringFromDates(timeSteps); - QString dateString = RiaQDateTimeTools::toStringUsingApplicationLocale(timeSteps[currTimeStepIndex], dateFormat); + QString dateString = RiaQDateTimeTools::toStringUsingApplicationLocale(timeSteps[currTimeStepIndex], dateFormat); - dateTimeString = QString("Time Step: %1/%2 %3").arg(QString::number(currTimeStepIndex), - QString::number(timeSteps.size() - 1), - dateString); + dateTimeString = QString("Time Step: %1/%2 %3") + .arg(QString::number(currTimeStepIndex), QString::number(timeSteps.size() - 1), dateString); + } } return QString("

-- %1 --
").arg(dateTimeString) + - QString("
------------------------------------------------
"); + QString("
------------------------------------------------
"); } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- QString Rim3dOverlayInfoConfig::timeStepText(RimGeoMechView* geoMechView) { @@ -1008,22 +1140,22 @@ QString Rim3dOverlayInfoConfig::timeStepText(RimGeoMechView* geoMechView) QString dateTimeString; if (currTimeStepIndex >= 0 && currTimeStepIndex < timeSteps.size()) { - dateTimeString = QString("Time Step: %1/%2 %3").arg(QString::number(currTimeStepIndex), - QString::number(timeSteps.size() - 1), - timeSteps[currTimeStepIndex]); + dateTimeString = + QString("Time Step: %1/%2 %3") + .arg(QString::number(currTimeStepIndex), QString::number(timeSteps.size() - 1), timeSteps[currTimeStepIndex]); } return QString("

-- %1 --
").arg(dateTimeString) + - QString("
------------------------------------------------
"); + QString("
------------------------------------------------
"); } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void Rim3dOverlayInfoConfig::updateVisCellStatsIfNeeded() { - RimEclipseView * eclipseView = dynamic_cast(m_viewDef.p()); - RimGeoMechView * geoMechView = dynamic_cast(m_viewDef.p()); + RimEclipseView* eclipseView = dynamic_cast(m_viewDef.p()); + RimGeoMechView* geoMechView = dynamic_cast(m_viewDef.p()); if (!m_isVisCellStatUpToDate) { @@ -1031,28 +1163,22 @@ void Rim3dOverlayInfoConfig::updateVisCellStatsIfNeeded() if (geoMechView) { RigFemResultAddress resAddress = geoMechView->cellResultResultDefinition()->resultAddress(); - calc = new RigFemNativeVisibleCellsStatCalc(geoMechView->geoMechCase()->geoMechData(), - resAddress, - geoMechView->currentTotalCellVisibility().p()); - + calc = new RigFemNativeVisibleCellsStatCalc( + geoMechView->geoMechCase()->geoMechData(), resAddress, geoMechView->currentTotalCellVisibility().p()); } else if (eclipseView) { if (eclipseView->cellResult()->isFlowDiagOrInjectionFlooding()) { - RigFlowDiagResultAddress resAddr = eclipseView->cellResult()->flowDiagResAddress(); - RigFlowDiagResults* fldResults = eclipseView->cellResult()->flowDiagSolution()->flowDiagResults(); - calc = new RigFlowDiagVisibleCellsStatCalc(fldResults, - resAddr, - eclipseView->currentTotalCellVisibility().p()); - + RigFlowDiagResultAddress resAddr = eclipseView->cellResult()->flowDiagResAddress(); + RigFlowDiagResults* fldResults = eclipseView->cellResult()->flowDiagSolution()->flowDiagResults(); + calc = new RigFlowDiagVisibleCellsStatCalc(fldResults, resAddr, eclipseView->currentTotalCellVisibility().p()); } else { - size_t scalarIndex = eclipseView->cellResult()->scalarResultIndex(); - calc = new RigEclipseNativeVisibleCellsStatCalc(eclipseView->currentGridCellResults(), - scalarIndex, - eclipseView->currentTotalCellVisibility().p()); + RigEclipseResultAddress scalarIndex = eclipseView->cellResult()->eclipseResultAddress(); + calc = new RigEclipseNativeVisibleCellsStatCalc( + eclipseView->currentGridCellResults(), scalarIndex, eclipseView->currentTotalCellVisibility().p()); } } @@ -1062,7 +1188,7 @@ void Rim3dOverlayInfoConfig::updateVisCellStatsIfNeeded() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void Rim3dOverlayInfoConfig::displayPropertyFilteredStatisticsMessage(bool showSwitchToCurrentTimestep) { @@ -1072,35 +1198,36 @@ void Rim3dOverlayInfoConfig::displayPropertyFilteredStatisticsMessage(bool showS if (showSwitchToCurrentTimestep) { switchString = QString("
" - "Switching to statistics for Current Time Step"); + "Switching to statistics for Current Time Step"); } if (!isShowing) { isShowing = true; - QMessageBox::information(m_viewDef->viewer()->layoutWidget(), + QMessageBox::information( + m_viewDef->viewer()->layoutWidget(), QString("ResInsight"), QString("Statistics not available
" - "
" - "Statistics calculations of Visible Cells for All Time Steps is not supported
" - "when you have an active Property filter on a time varying result.
") - + switchString); + "
" + "Statistics calculations of Visible Cells for All Time Steps is not supported
" + "when you have an active Property filter on a time varying result.
") + + switchString); isShowing = false; } } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- bool Rim3dOverlayInfoConfig::hasInvalidStatisticsCombination() { - if (m_viewDef->propertyFilterCollection() - && m_viewDef->propertyFilterCollection()->hasActiveDynamicFilters() - && m_statisticsCellRange() == VISIBLE_CELLS - && m_statisticsTimeRange() == ALL_TIMESTEPS ) + if (m_viewDef->propertyFilterCollection() && m_viewDef->propertyFilterCollection()->hasActiveDynamicFilters() && + m_statisticsCellRange() == VISIBLE_CELLS && m_statisticsTimeRange() == ALL_TIMESTEPS) { - RimEclipseView * eclipseView = dynamic_cast(m_viewDef.p()); - if (!(eclipseView && eclipseView->cellResult()->isFlowDiagOrInjectionFlooding())) // If isFlowDiagOrInjFlooding then skip this check as ALL_TIMESTEPS is overridden to CURRENT behind the scenes + RimEclipseView* eclipseView = dynamic_cast(m_viewDef.p()); + if (!(eclipseView && eclipseView->cellResult() + ->isFlowDiagOrInjectionFlooding())) // If isFlowDiagOrInjFlooding then skip this check as + // ALL_TIMESTEPS is overridden to CURRENT behind the scenes { return true; } diff --git a/ApplicationCode/ProjectDataModel/Rim3dOverlayInfoConfig.h b/ApplicationCode/ProjectDataModel/Rim3dOverlayInfoConfig.h index d87ce75c87..5097e378b9 100644 --- a/ApplicationCode/ProjectDataModel/Rim3dOverlayInfoConfig.h +++ b/ApplicationCode/ProjectDataModel/Rim3dOverlayInfoConfig.h @@ -27,10 +27,12 @@ #include "cvfObject.h" #include "cvfVector2.h" + #include #include -class RimContourMapView; +class RimGeoMechContourMapView; +class RimEclipseContourMapView; class RimEclipseView; class RimGeoMechView; class RimGridView; @@ -85,7 +87,8 @@ class Rim3dOverlayInfoConfig : public caf::PdmObject bool showCaseInfo() const; bool showResultInfo() const; bool isActive() const; - void setIsActive(bool active); + + bool showVersionInfo() const; enum StatisticsTimeRangeType { @@ -99,47 +102,44 @@ class Rim3dOverlayInfoConfig : public caf::PdmObject VISIBLE_CELLS }; -protected: - void fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue) override; - caf::PdmFieldHandle* objectToggleField() override; +private: + void fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue) override; + caf::PdmFieldHandle* objectToggleField() override; + void defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering) override; + void updateEclipse3DInfo(RimEclipseView* reservoirView); + void updateGeoMech3DInfo(RimGeoMechView* geoMechView); + void update3DInfoIn2dViews() const; + QString timeStepText(RimEclipseView* eclipseView); + QString timeStepText(RimGeoMechView* geoMechView); + HistogramData histogramData(RimEclipseContourMapView* contourMap); + HistogramData histogramData(RimGeoMechContourMapView* contourMap); + HistogramData histogramData(RimEclipseView* eclipseView); + HistogramData histogramData(RimGeoMechView* geoMechView); + QString caseInfoText(RimEclipseView* eclipseView); + QString caseInfoText(RimGeoMechView* geoMechView); + QString resultInfoText(const HistogramData& histData, RimEclipseView* eclipseView, bool showVolumeWeightedMean); + QString resultInfoText(const HistogramData& histData, RimGeoMechView* geoMechView); - void defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering) override; + void updateVisCellStatsIfNeeded(); + void displayPropertyFilteredStatisticsMessage(bool showSwitchToCurrentTimestep); + bool hasInvalidStatisticsCombination(); private: - void updateEclipse3DInfo(RimEclipseView * reservoirView); - void updateGeoMech3DInfo(RimGeoMechView * geoMechView); - - void update3DInfoIn2dViews() const; - - QString timeStepText(RimEclipseView* eclipseView); - QString timeStepText(RimGeoMechView* geoMechView); - HistogramData histogramData(RimContourMapView* contourMap); - HistogramData histogramData(RimEclipseView* eclipseView); - HistogramData histogramData(RimGeoMechView* geoMechView); - QString caseInfoText(RimEclipseView* eclipseView); - QString caseInfoText(RimGeoMechView* geoMechView); - QString resultInfoText(const HistogramData& histData, RimEclipseView* eclipseView, bool showVolumeWeightedMean); - QString resultInfoText(const HistogramData& histData, RimGeoMechView* geoMechView); - - caf::PdmField m_active; - caf::PdmField m_showAnimProgress; - caf::PdmField m_showCaseInfo; - caf::PdmField m_showResultInfo; - caf::PdmField m_showVolumeWeightedMean; - caf::PdmField m_showHistogram; + caf::PdmField m_active; + caf::PdmField m_showAnimProgress; + caf::PdmField m_showCaseInfo; + caf::PdmField m_showResultInfo; + caf::PdmField m_showVolumeWeightedMean; + caf::PdmField m_showHistogram; + caf::PdmField m_showVersionInfo; caf::PdmField > m_statisticsTimeRange; caf::PdmField > m_statisticsCellRange; - caf::PdmPointer m_viewDef; - - cvf::Vec2ui m_position; - - void updateVisCellStatsIfNeeded(); - void displayPropertyFilteredStatisticsMessage(bool showSwitchToCurrentTimestep); - bool hasInvalidStatisticsCombination(); - bool m_isVisCellStatUpToDate; - cvf::ref m_visibleCellStatistics; + caf::PdmPointer m_viewDef; + cvf::Vec2ui m_position; + bool m_isVisCellStatUpToDate; + cvf::ref m_visibleCellStatistics; std::unique_ptr m_gridStatisticsDialog; }; diff --git a/ApplicationCode/ProjectDataModel/Rim3dView.cpp b/ApplicationCode/ProjectDataModel/Rim3dView.cpp index e88a0d9013..1d957e811f 100644 --- a/ApplicationCode/ProjectDataModel/Rim3dView.cpp +++ b/ApplicationCode/ProjectDataModel/Rim3dView.cpp @@ -25,6 +25,7 @@ #include "RiaViewRedrawScheduler.h" #include "Rim3dWellLogCurve.h" +#include "RimAnnotationInViewCollection.h" #include "RimCase.h" #include "RimGridView.h" #include "RimMainPlotCollection.h" @@ -33,8 +34,12 @@ #include "RimViewController.h" #include "RimViewLinker.h" #include "RimWellPathCollection.h" +#include "RimViewNameConfig.h" +#include "RimMeasurement.h" +#include "RivAnnotationsPartMgr.h" #include "RivWellPathsPartMgr.h" +#include "RivMeasurementPartMgr.h" #include "RiuMainWindow.h" #include "RiuViewer.h" @@ -55,15 +60,6 @@ namespace caf { -template<> -void caf::AppEnum< Rim3dView::MeshModeType >::setUp() -{ - addItem(Rim3dView::FULL_MESH, "FULL_MESH", "All"); - addItem(Rim3dView::FAULTS_MESH, "FAULTS_MESH", "Faults only"); - addItem(Rim3dView::NO_MESH, "NO_MESH", "None"); - setDefault(Rim3dView::FULL_MESH); -} - template<> void caf::AppEnum< Rim3dView::SurfaceModeType >::setUp() { @@ -87,8 +83,11 @@ Rim3dView::Rim3dView(void) RiaPreferences* preferences = app->preferences(); CVF_ASSERT(preferences); + CAF_PDM_InitFieldNoDefault(&m_nameConfig, "NameConfig", "", "", "", ""); + m_nameConfig = new RimViewNameConfig(this); - CAF_PDM_InitField(&m_name, "UserDescription", QString(""), "Name", "", "", ""); + CAF_PDM_InitField(&m_name_OBSOLETE, "UserDescription", QString(""), "Name", "", "", ""); + m_name_OBSOLETE.xmlCapability()->setIOWritable(false); CAF_PDM_InitField(&m_cameraPosition, "CameraPosition", cvf::Mat4d::IDENTITY, "", "", "", ""); m_cameraPosition.uiCapability()->setUiHidden(true); @@ -112,8 +111,7 @@ Rim3dView::Rim3dView(void) CAF_PDM_InitField(&m_currentTimeStep, "CurrentTimeStep", 0, "Current Time Step", "", "", ""); m_currentTimeStep.uiCapability()->setUiHidden(true); - caf::AppEnum defaultMeshType = NO_MESH; - if (preferences->defaultGridLines) defaultMeshType = FULL_MESH; + caf::AppEnum defaultMeshType = preferences->defaultMeshModeType(); CAF_PDM_InitField(&meshMode, "MeshMode", defaultMeshType, "Grid Lines", "", "", ""); CAF_PDM_InitFieldNoDefault(&surfaceMode, "SurfaceMode", "Grid Surface", "", "", ""); @@ -121,6 +119,8 @@ Rim3dView::Rim3dView(void) CAF_PDM_InitField(&m_disableLighting, "DisableLighting", false, "Disable Results Lighting", "", "Disable light model for scalar result colors", ""); + CAF_PDM_InitField(&m_showZScaleLabel, "ShowZScale", true, "Show Z Scale Label", "", "", ""); + m_crossSectionVizModel = new cvf::ModelBasicList; m_crossSectionVizModel->setName("CrossSectionModel"); @@ -131,7 +131,9 @@ Rim3dView::Rim3dView(void) m_wellPathPipeVizModel->setName("WellPathPipeModel"); m_wellPathsPartManager = new RivWellPathsPartMgr(this); + m_annotationsPartManager = new RivAnnotationsPartMgr(this); + m_measurementPartManager = new RivMeasurementPartMgr(this); this->setAs3DViewMdiWindow(); } @@ -140,6 +142,10 @@ Rim3dView::Rim3dView(void) //-------------------------------------------------------------------------------------------------- Rim3dView::~Rim3dView(void) { + if (m_viewer) + { + m_viewer->clearRimView(); + } removeMdiWindowFromMdiArea(); deleteViewWidget(); @@ -158,7 +164,7 @@ RiuViewer* Rim3dView::viewer() const //-------------------------------------------------------------------------------------------------- void Rim3dView::setName(const QString& name) { - m_name = name; + m_nameConfig->setCustomName(name); } //-------------------------------------------------------------------------------------------------- @@ -166,7 +172,7 @@ void Rim3dView::setName(const QString& name) //-------------------------------------------------------------------------------------------------- QString Rim3dView::name() const { - return m_name; + return m_nameConfig->customName(); } //-------------------------------------------------------------------------------------------------- @@ -177,7 +183,7 @@ QWidget* Rim3dView::createViewWidget(QWidget* mainWindowParent) QGLFormat glFormat; glFormat.setDirectRendering(RiaApplication::instance()->useShaders()); - m_viewer = new RiuViewer(glFormat, nullptr); + m_viewer = new RiuViewer(glFormat, mainWindowParent); m_viewer->setOwnerReservoirView(this); cvf::String xLabel; @@ -187,6 +193,7 @@ QWidget* Rim3dView::createViewWidget(QWidget* mainWindowParent) this->axisLabels(&xLabel, &yLabel, &zLabel); m_viewer->setAxisLabels(xLabel, yLabel, zLabel); + updateZScaleLabel(); return m_viewer->layoutWidget(); } @@ -215,6 +222,23 @@ void Rim3dView::updateViewWidgetAfterCreation() m_viewer->update(); } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void Rim3dView::initAfterRead() +{ + RimViewWindow::initAfterRead(); + + if (!m_name_OBSOLETE().isEmpty()) + { + nameConfig()->setCustomName(m_name_OBSOLETE()); + nameConfig()->setAddCaseName(false); + nameConfig()->setAddAggregationType(false); + nameConfig()->setAddProperty(false); + nameConfig()->setAddSampleSpacing(false); + } +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -225,11 +249,11 @@ void Rim3dView::updateMdiWindowTitle() QString windowTitle; if (ownerCase()) { - windowTitle = QString("%1 - %2").arg(ownerCase()->caseUserDescription()).arg(m_name); + windowTitle = QString("%1 - %2").arg(ownerCase()->caseUserDescription()).arg(name()); } else { - windowTitle = m_name; + windowTitle = name(); } m_viewer->layoutWidget()->setWindowTitle(windowTitle); @@ -241,11 +265,12 @@ void Rim3dView::updateMdiWindowTitle() //-------------------------------------------------------------------------------------------------- void Rim3dView::deleteViewWidget() { - if (m_viewer) - { - m_viewer->deleteLater(); - m_viewer = nullptr; - } + // Earlier implementations has used m_viewer->deleteLater(). This caused issues triggered by 3D editors and interaction with + // the event processing. deleteLater() will not be handeled by processEvents() if we are in the state of processing UI events, + // ie in the process of handling a QAction + + delete m_viewer; + m_viewer = nullptr; } //-------------------------------------------------------------------------------------------------- @@ -255,8 +280,9 @@ void Rim3dView::defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrd { caf::PdmUiGroup* viewGroup = uiOrdering.addNewGroupWithKeyword("Viewer", "ViewGroup"); - viewGroup->add(&m_name); + //viewGroup->add(m_nameConfig->nameField()); viewGroup->add(&m_backgroundColor); + viewGroup->add(&m_showZScaleLabel); viewGroup->add(&m_showGridBox); viewGroup->add(&isPerspectiveView); viewGroup->add(&m_disableLighting); @@ -265,6 +291,8 @@ void Rim3dView::defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrd gridGroup->add(&scaleZ); gridGroup->add(&meshMode); gridGroup->add(&surfaceMode); + + uiOrdering.skipRemainingFields(true); } //-------------------------------------------------------------------------------------------------- @@ -313,6 +341,9 @@ void Rim3dView::setCurrentTimeStepAndUpdate(int frameIndex) RimProject* project; firstAncestorOrThisOfTypeAsserted(project); project->mainPlotCollection()->updateCurrentTimeStepInPlots(); + + appendAnnotationsToModel(); + appendMeasurementToModel(); } //-------------------------------------------------------------------------------------------------- @@ -434,15 +465,19 @@ RimWellPathCollection* Rim3dView::wellPathCollection() const //-------------------------------------------------------------------------------------------------- bool Rim3dView::hasVisibleTimeStepDependent3dWellLogCurves() const { - std::vector wellLogCurves; - wellPathCollection()->descendantsIncludingThisOfType(wellLogCurves); - for (const Rim3dWellLogCurve* curve : wellLogCurves) + if (wellPathCollection()) { - if (curve->showInView(this) && curve->isShowingTimeDependentResult()) + std::vector wellLogCurves; + wellPathCollection()->descendantsIncludingThisOfType(wellLogCurves); + for (const Rim3dWellLogCurve* curve : wellLogCurves) { - return true; + if (curve->showInView(this) && curve->isShowingTimeDependentResult()) + { + return true; + } } } + return false; } @@ -464,7 +499,7 @@ void Rim3dView::setupBeforeSave() //-------------------------------------------------------------------------------------------------- void Rim3dView::setMeshOnlyDrawstyle() { - meshMode.setValueWithFieldChanged(FULL_MESH); + meshMode.setValueWithFieldChanged(RiaDefines::FULL_MESH); surfaceMode.setValueWithFieldChanged(NO_SURFACE); } @@ -474,7 +509,7 @@ void Rim3dView::setMeshOnlyDrawstyle() void Rim3dView::setMeshSurfDrawstyle() { surfaceMode.setValueWithFieldChanged(SURFACE); - meshMode.setValueWithFieldChanged(FULL_MESH); + meshMode.setValueWithFieldChanged(RiaDefines::FULL_MESH); } //-------------------------------------------------------------------------------------------------- @@ -483,7 +518,7 @@ void Rim3dView::setMeshSurfDrawstyle() void Rim3dView::setFaultMeshSurfDrawstyle() { surfaceMode.setValueWithFieldChanged(SURFACE); - meshMode.setValueWithFieldChanged(FAULTS_MESH); + meshMode.setValueWithFieldChanged(RiaDefines::FAULTS_MESH); } //-------------------------------------------------------------------------------------------------- @@ -492,7 +527,7 @@ void Rim3dView::setFaultMeshSurfDrawstyle() void Rim3dView::setSurfOnlyDrawstyle() { surfaceMode.setValueWithFieldChanged(SURFACE); - meshMode.setValueWithFieldChanged(NO_MESH); + meshMode.setValueWithFieldChanged(RiaDefines::NO_MESH); } //-------------------------------------------------------------------------------------------------- @@ -521,6 +556,14 @@ bool Rim3dView::isLightingDisabled() const return m_disableLighting(); } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +caf::PdmFieldHandle* Rim3dView::userDescriptionField() +{ + return m_nameConfig->nameField(); +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -541,31 +584,7 @@ void Rim3dView::fieldChangedByUi(const caf::PdmFieldHandle* changedField, const } else if (changedField == &scaleZ) { - if (scaleZ < 1) scaleZ = 1; - - this->updateGridBoxData(); - - if (m_viewer) - { - cvf::Vec3d poi = m_viewer->pointOfInterest(); - cvf::Vec3d eye, dir, up; - eye = m_viewer->mainCamera()->position(); - dir = m_viewer->mainCamera()->direction(); - up = m_viewer->mainCamera()->up(); - - eye[2] = poi[2]*scaleZ()/this->scaleTransform()->worldTransform()(2, 2) + (eye[2] - poi[2]); - poi[2] = poi[2]*scaleZ()/this->scaleTransform()->worldTransform()(2, 2); - - m_viewer->mainCamera()->setFromLookAt(eye, eye + dir, up); - m_viewer->setPointOfInterest(poi); - - updateScaleTransform(); - createDisplayModelAndRedraw(); - - m_viewer->update(); - - - } + updateScaling(); RiuMainWindow::instance()->updateScaleValue(); } @@ -586,7 +605,7 @@ void Rim3dView::fieldChangedByUi(const caf::PdmFieldHandle* changedField, const RiuMainWindow::instance()->refreshDrawStyleActions(); RiuMainWindow::instance()->refreshAnimationActions(); } - else if (changedField == &m_name) + else if (changedField == m_nameConfig->nameField()) { updateMdiWindowTitle(); @@ -615,7 +634,7 @@ void Rim3dView::fieldChangedByUi(const caf::PdmFieldHandle* changedField, const } else if (changedField == &m_backgroundColor) { - this->applyBackgroundColor(); + this->applyBackgroundColorAndFontChanges(); } else if (changedField == &maximumFrameRate) { @@ -626,6 +645,11 @@ void Rim3dView::fieldChangedByUi(const caf::PdmFieldHandle* changedField, const m_viewer->animationControl()->setTimeout(maximumFrameRate != 0 ? 1000/maximumFrameRate : std::numeric_limits::max()); } } + else if (changedField == &m_showZScaleLabel) + { + m_viewer->showZScaleLabel(m_showZScaleLabel()); + m_viewer->update(); + } } //-------------------------------------------------------------------------------------------------- @@ -665,6 +689,52 @@ void Rim3dView::addDynamicWellPathsToModel(cvf::ModelBasicList* wellPathModelBas wellPathModelBasicList->updateBoundingBoxesRecursive(); } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void Rim3dView::addAnnotationsToModel(cvf::ModelBasicList* wellPathModelBasicList) +{ + if (!this->ownerCase()) return; + + std::vector annotationCollections; + descendantsIncludingThisOfType(annotationCollections); + + if (annotationCollections.empty() || !annotationCollections.front()->isActive()) + { + m_annotationsPartManager->clearGeometryCache(); + } + else + { + cvf::ref transForm = displayCoordTransform(); + m_annotationsPartManager->appendGeometryPartsToModel(wellPathModelBasicList, transForm.p(), ownerCase()->allCellsBoundingBox()); + } + + wellPathModelBasicList->updateBoundingBoxesRecursive(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void Rim3dView::addMeasurementToModel(cvf::ModelBasicList* wellPathModelBasicList) +{ + if (!this->ownerCase()) return; + + RimMeasurement* measurement = RiaApplication::instance()->project()->measurement(); + + if (!measurement || measurement->pointsInDomainCoords().empty()) + { + m_measurementPartManager->clearGeometryCache(); + } + else + { + cvf::ref transForm = displayCoordTransform(); + m_measurementPartManager->appendGeometryPartsToModel(m_viewer->mainCamera(), + wellPathModelBasicList, transForm.p(), ownerCase()->allCellsBoundingBox()); + } + + wellPathModelBasicList->updateBoundingBoxesRecursive(); +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -719,6 +789,60 @@ void Rim3dView::updateAnnotationItems() } } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void Rim3dView::updateScaling() +{ + if (scaleZ < 1) scaleZ = 1; + + this->updateGridBoxData(); + + if (m_viewer) + { + cvf::Vec3d poi = m_viewer->pointOfInterest(); + cvf::Vec3d eye, dir, up; + eye = m_viewer->mainCamera()->position(); + dir = m_viewer->mainCamera()->direction(); + up = m_viewer->mainCamera()->up(); + + eye[2] = poi[2] * scaleZ() / this->scaleTransform()->worldTransform()(2, 2) + (eye[2] - poi[2]); + poi[2] = poi[2] * scaleZ() / this->scaleTransform()->worldTransform()(2, 2); + + m_viewer->mainCamera()->setFromLookAt(eye, eye + dir, up); + m_viewer->setPointOfInterest(poi); + + updateScaleTransform(); + createDisplayModelAndRedraw(); + + m_viewer->update(); + + updateZScaleLabel(); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void Rim3dView::updateZScaleLabel() +{ + // Update Z scale label + int scale = static_cast(scaleZ()); + m_viewer->setZScale(scale); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void Rim3dView::updateMeasurement() +{ + if (m_viewer) + { + appendMeasurementToModel(); + m_viewer->update(); + } +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -776,17 +900,26 @@ void Rim3dView::setShowGridBox(bool showGridBox) //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void Rim3dView::applyBackgroundColor() +void Rim3dView::applyBackgroundColorAndFontChanges() { if (m_viewer != nullptr) { m_viewer->mainCamera()->viewport()->setClearColor(cvf::Color4f(backgroundColor())); + m_viewer->updateFonts(); } updateGridBoxData(); updateAnnotationItems(); updateLegends(); } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void Rim3dView::performAutoNameUpdate() +{ + updateMdiWindowTitle(); +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -827,14 +960,14 @@ void Rim3dView::updateDisplayModelVisibility() mask |= intersectionCellFaceBit; } - if (meshMode == FULL_MESH) + if (meshMode == RiaDefines::FULL_MESH) { mask |= uintMeshSurfaceBit; mask |= uintMeshFaultBit; mask |= intersectionCellMeshBit; mask |= intersectionFaultMeshBit; } - else if (meshMode == FAULTS_MESH) + else if (meshMode == RiaDefines::FAULTS_MESH) { mask |= uintMeshFaultBit; mask |= intersectionFaultMeshBit; @@ -882,6 +1015,27 @@ cvf::ref Rim3dView::displayCoordTransform() const return coordTrans; } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool Rim3dView::hasCustomFontSizes(RiaDefines::FontSettingType fontSettingType, int defaultFontSize) const +{ + return false; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool Rim3dView::applyFontSize(RiaDefines::FontSettingType fontSettingType, int oldFontSize, int fontSize, bool forceChange /*= false*/) +{ + if (fontSettingType == RiaDefines::SCENE_FONT) + { + applyBackgroundColorAndFontChanges(); + return true; + } + return false; +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -898,6 +1052,14 @@ cvf::Vec3d Rim3dView::cameraPointOfInterest() const return m_cameraPointOfInterest(); } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimViewNameConfig* Rim3dView::nameConfig() const +{ + return m_nameConfig(); +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -935,15 +1097,6 @@ void Rim3dView::disablePerspectiveProjectionField() RiaFieldhandleTools::disableWriteAndSetFieldHidden(&isPerspectiveView); } -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void Rim3dView::enablePerspectiveProjectionField() -{ - isPerspectiveView.uiCapability()->setUiHidden(false); - isPerspectiveView.xmlCapability()->setIOWritable(true); -} - //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -961,11 +1114,45 @@ void Rim3dView::setMdiWindowGeometry(const RimMdiWindowGeometry& windowGeometry) } //-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -//-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- +void Rim3dView::appendAnnotationsToModel() +{ + if (!m_viewer) return; + + cvf::Scene* frameScene = m_viewer->frame(m_currentTimeStep); + if (frameScene) + { + cvf::String name = "Annotations"; + this->removeModelByName(frameScene, name); + + cvf::ref model = new cvf::ModelBasicList; + model->setName(name); + + addAnnotationsToModel(model.p()); + + frameScene->addModel(model.p()); + } +} + //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- +void Rim3dView::appendMeasurementToModel() +{ + if (!m_viewer) return; + + cvf::Scene* frameScene = m_viewer->frame(m_currentTimeStep); + if (frameScene) + { + cvf::String name = "Measurement"; + this->removeModelByName(frameScene, name); + + cvf::ref model = new cvf::ModelBasicList; + model->setName(name); + + addMeasurementToModel(model.p()); + + frameScene->addModel(model.p()); + } +} diff --git a/ApplicationCode/ProjectDataModel/Rim3dView.h b/ApplicationCode/ProjectDataModel/Rim3dView.h index 2352d41e60..584ce63f75 100644 --- a/ApplicationCode/ProjectDataModel/Rim3dView.h +++ b/ApplicationCode/ProjectDataModel/Rim3dView.h @@ -18,7 +18,9 @@ ///////////////////////////////////////////////////////////////////////////////// #pragma once +#include "RiaDefines.h" #include "RiuViewerToViewInterface.h" +#include "RimNameConfig.h" #include "RimViewWindow.h" #include "RivCellSetEnum.h" @@ -41,7 +43,10 @@ class RimCase; class RimLegendConfig; class RimWellPathCollection; class RiuViewer; +class RivAnnotationsPartMgr; +class RivMeasurementPartMgr; class RivWellPathsPartMgr; +class RimViewNameConfig; namespace cvf { @@ -75,7 +80,7 @@ enum PartRenderMaskEnum /// /// //================================================================================================== -class Rim3dView : public RimViewWindow, public RiuViewerToViewInterface +class Rim3dView : public RimViewWindow, public RiuViewerToViewInterface, public RimNameConfigHolderInterface { CAF_PDM_HEADER_INIT; public: @@ -91,11 +96,10 @@ class Rim3dView : public RimViewWindow, public RiuViewerToViewInterface // Draw style - enum MeshModeType { FULL_MESH, FAULTS_MESH, NO_MESH }; enum SurfaceModeType { SURFACE, FAULTS, NO_SURFACE }; - caf::PdmField< caf::AppEnum< MeshModeType > > meshMode; - caf::PdmField< caf::AppEnum< SurfaceModeType > > surfaceMode; + caf::PdmField< caf::AppEnum< RiaDefines::MeshModeType > > meshMode; + caf::PdmField< caf::AppEnum< SurfaceModeType > > surfaceMode; RiuViewer* viewer() const; @@ -112,6 +116,8 @@ class Rim3dView : public RimViewWindow, public RiuViewerToViewInterface void setBackgroundColor(const cvf::Color3f& newBackgroundColor); void setShowGridBox(bool showGridBox); + void applyBackgroundColorAndFontChanges(); + void disableLighting(bool disable); bool isLightingDisabled() const; @@ -121,8 +127,8 @@ class Rim3dView : public RimViewWindow, public RiuViewerToViewInterface virtual bool showActiveCellsOnly(); virtual bool isUsingFormationNames() const = 0; - QImage snapshotWindowContent() override; - void zoomAll() override; + QImage snapshotWindowContent() override; + void zoomAll() override; void forceShowWindowOn(); // Animation @@ -139,6 +145,9 @@ class Rim3dView : public RimViewWindow, public RiuViewerToViewInterface void createHighlightAndGridBoxDisplayModelWithRedraw(); void updateGridBoxData(); void updateAnnotationItems(); + void updateScaling(); + void updateZScaleLabel(); + void updateMeasurement(); bool isMasterView() const; @@ -147,16 +156,19 @@ class Rim3dView : public RimViewWindow, public RiuViewerToViewInterface virtual RimCase* ownerCase() const = 0; virtual std::vector legendConfigs() const = 0; + + bool hasCustomFontSizes(RiaDefines::FontSettingType fontSettingType, int defaultFontSize) const override; + bool applyFontSize(RiaDefines::FontSettingType fontSettingType, int oldFontSize, int fontSize, bool forceChange = false) override; + protected: static void removeModelByName(cvf::Scene* scene, const cvf::String& modelName); virtual void setDefaultView(); void disableGridBoxField(); void disablePerspectiveProjectionField(); - void enablePerspectiveProjectionField(); cvf::Mat4d cameraPosition() const; cvf::Vec3d cameraPointOfInterest() const; - + RimViewNameConfig* nameConfig() const; RimWellPathCollection* wellPathCollection() const; bool hasVisibleTimeStepDependent3dWellLogCurves() const; @@ -166,10 +178,13 @@ class Rim3dView : public RimViewWindow, public RiuViewerToViewInterface void addDynamicWellPathsToModel(cvf::ModelBasicList* wellPathModelBasicList, const cvf::BoundingBox& wellPathClipBoundingBox); + void addAnnotationsToModel(cvf::ModelBasicList* wellPathModelBasicList); + void addMeasurementToModel(cvf::ModelBasicList* wellPathModelBasicList); + void createHighlightAndGridBoxDisplayModel(); - // Implementation of RiuViewerToViewInterface - void applyBackgroundColor(); + // Implementation of RimNameConfigHolderInterface + void performAutoNameUpdate() override; // Abstract methods to implement in subclasses @@ -201,23 +216,26 @@ class Rim3dView : public RimViewWindow, public RiuViewerToViewInterface cvf::ref m_highlightVizModel; cvf::ref m_wellPathsPartManager; + cvf::ref m_annotationsPartManager; + cvf::ref m_measurementPartManager; private: // Overridden PdmObject methods: void setupBeforeSave() override; protected: - caf::PdmFieldHandle* userDescriptionField() override { return &m_name; } + caf::PdmFieldHandle* userDescriptionField() override; caf::PdmFieldHandle* backgroundColorField() { return &m_backgroundColor; } void fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue) override; void defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering) override; - virtual void updateViewWidgetAfterCreation() override; - + void updateViewWidgetAfterCreation() override; + QWidget* createViewWidget(QWidget* mainWindowParent) override; + void initAfterRead() override; + private: // Overridden ViewWindow methods: - QWidget* createViewWidget(QWidget* mainWindowParent) override; void updateMdiWindowTitle() override; void deleteViewWidget() override; QWidget* viewWidget() override; @@ -230,13 +248,16 @@ class Rim3dView : public RimViewWindow, public RiuViewerToViewInterface caf::PdmObjectHandle* implementingPdmObject() override { return this; } void handleMdiWindowClosed() override; void setMdiWindowGeometry(const RimMdiWindowGeometry& windowGeometry) override; + void appendAnnotationsToModel(); + void appendMeasurementToModel(); private: - caf::PdmField m_name; + caf::PdmField m_name_OBSOLETE; + caf::PdmChildField m_nameConfig; caf::PdmField m_disableLighting; caf::PdmField m_cameraPosition; caf::PdmField m_cameraPointOfInterest; caf::PdmField< cvf::Color3f > m_backgroundColor; caf::PdmField m_showGridBox; - + caf::PdmField m_showZScaleLabel; }; diff --git a/ApplicationCode/ProjectDataModel/Rim3dWellLogCurve.cpp b/ApplicationCode/ProjectDataModel/Rim3dWellLogCurve.cpp index b55f0bf61b..89c6017eaf 100644 --- a/ApplicationCode/ProjectDataModel/Rim3dWellLogCurve.cpp +++ b/ApplicationCode/ProjectDataModel/Rim3dWellLogCurve.cpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018- Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by diff --git a/ApplicationCode/ProjectDataModel/Rim3dWellLogCurve.h b/ApplicationCode/ProjectDataModel/Rim3dWellLogCurve.h index b5dbd81959..df9145bf94 100644 --- a/ApplicationCode/ProjectDataModel/Rim3dWellLogCurve.h +++ b/ApplicationCode/ProjectDataModel/Rim3dWellLogCurve.h @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018- Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by diff --git a/ApplicationCode/ProjectDataModel/Rim3dWellLogExtractionCurve.cpp b/ApplicationCode/ProjectDataModel/Rim3dWellLogExtractionCurve.cpp index d36f5aa619..f40afa0626 100644 --- a/ApplicationCode/ProjectDataModel/Rim3dWellLogExtractionCurve.cpp +++ b/ApplicationCode/ProjectDataModel/Rim3dWellLogExtractionCurve.cpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018- Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by diff --git a/ApplicationCode/ProjectDataModel/Rim3dWellLogExtractionCurve.h b/ApplicationCode/ProjectDataModel/Rim3dWellLogExtractionCurve.h index 3e9ec79406..3517dbd1ae 100644 --- a/ApplicationCode/ProjectDataModel/Rim3dWellLogExtractionCurve.h +++ b/ApplicationCode/ProjectDataModel/Rim3dWellLogExtractionCurve.h @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018- Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by diff --git a/ApplicationCode/ProjectDataModel/Rim3dWellLogFileCurve.cpp b/ApplicationCode/ProjectDataModel/Rim3dWellLogFileCurve.cpp index 91827b4d0a..47121f150c 100644 --- a/ApplicationCode/ProjectDataModel/Rim3dWellLogFileCurve.cpp +++ b/ApplicationCode/ProjectDataModel/Rim3dWellLogFileCurve.cpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018- Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by diff --git a/ApplicationCode/ProjectDataModel/Rim3dWellLogFileCurve.h b/ApplicationCode/ProjectDataModel/Rim3dWellLogFileCurve.h index 6b859a9eab..bc2ecd37b6 100644 --- a/ApplicationCode/ProjectDataModel/Rim3dWellLogFileCurve.h +++ b/ApplicationCode/ProjectDataModel/Rim3dWellLogFileCurve.h @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018- Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by diff --git a/ApplicationCode/ProjectDataModel/Rim3dWellLogRftCurve.cpp b/ApplicationCode/ProjectDataModel/Rim3dWellLogRftCurve.cpp index 921d9433f0..7665f3b1ff 100644 --- a/ApplicationCode/ProjectDataModel/Rim3dWellLogRftCurve.cpp +++ b/ApplicationCode/ProjectDataModel/Rim3dWellLogRftCurve.cpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018- Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -124,7 +124,7 @@ QString Rim3dWellLogRftCurve::createAutoName() const } if (!m_timeStep().isNull()) { - name.push_back(m_timeStep().toString(RimTools::dateFormatString())); + name.push_back(m_timeStep().toString(RiaQDateTimeTools::dateFormatString())); } return name.join(", "); diff --git a/ApplicationCode/ProjectDataModel/Rim3dWellLogRftCurve.h b/ApplicationCode/ProjectDataModel/Rim3dWellLogRftCurve.h index b002a06460..420d76fb24 100644 --- a/ApplicationCode/ProjectDataModel/Rim3dWellLogRftCurve.h +++ b/ApplicationCode/ProjectDataModel/Rim3dWellLogRftCurve.h @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018- Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by diff --git a/ApplicationCode/ProjectDataModel/RimAdvancedSnapshotExportDefinition.cpp b/ApplicationCode/ProjectDataModel/RimAdvancedSnapshotExportDefinition.cpp new file mode 100644 index 0000000000..1029a8ca7b --- /dev/null +++ b/ApplicationCode/ProjectDataModel/RimAdvancedSnapshotExportDefinition.cpp @@ -0,0 +1,304 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2016- Statoil ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "RimAdvancedSnapshotExportDefinition.h" + +#include "RiaApplication.h" +#include "RiaOptionItemFactory.h" + +#include "RigActiveCellInfo.h" +#include "RigCaseCellResultsData.h" +#include "RigReservoirGridTools.h" + +#include "Rim3dView.h" +#include "RimCase.h" +#include "RimEclipseView.h" +#include "RimProject.h" +#include "RimReservoirCellResultsStorage.h" +#include "RimTools.h" + +#include "cafPdmPointer.h" + +// clang-format off + +namespace caf +{ + template<> + void caf::AppEnum< RimAdvancedSnapshotExportDefinition::SnapShotDirectionEnum >::setUp() + { + addItem(RimAdvancedSnapshotExportDefinition::NO_RANGEFILTER, "None", "None"); + addItem(RimAdvancedSnapshotExportDefinition::RANGEFILTER_I, "I", "I"); + addItem(RimAdvancedSnapshotExportDefinition::RANGEFILTER_J, "J", "J"); + addItem(RimAdvancedSnapshotExportDefinition::RANGEFILTER_K, "K", "K"); + + setDefault(RimAdvancedSnapshotExportDefinition::RANGEFILTER_K); + } +} + +CAF_PDM_SOURCE_INIT(RimAdvancedSnapshotExportDefinition, "MultiSnapshotDefinition"); + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimAdvancedSnapshotExportDefinition::RimAdvancedSnapshotExportDefinition() +{ + //CAF_PDM_InitObject("MultiSnapshotDefinition", ":/Well.png", "", ""); + CAF_PDM_InitObject("MultiSnapshotDefinition", "", "", ""); + + CAF_PDM_InitField(&isActive, "IsActive", true, "Active", "", "", ""); + + CAF_PDM_InitFieldNoDefault(&view, "View", "View", "", "", ""); + + CAF_PDM_InitFieldNoDefault(&eclipseResultType, "EclipseResultType", "Result Type", "", "", ""); + CAF_PDM_InitFieldNoDefault(&selectedEclipseResults, "SelectedEclipseResults", "Properties", "", "", ""); + + CAF_PDM_InitField(&timeStepStart, "TimeStepStart", 0, "Start Time", "", "", ""); + CAF_PDM_InitField(&timeStepEnd, "TimeStepEnd", 0, "End Time", "", "", ""); + + CAF_PDM_InitField(&sliceDirection, "SnapShotDirection", caf::AppEnum(NO_RANGEFILTER), "Range Filter Slice", "", "", ""); + CAF_PDM_InitField(&startSliceIndex, "RangeFilterStart", 1, "Range Start", "", "", ""); + CAF_PDM_InitField(&endSliceIndex, "RangeFilterEnd", 1, "Range End", "", "", ""); + + CAF_PDM_InitFieldNoDefault(&additionalCases, "AdditionalCases", "Cases", "", "", ""); +} + +// clang-format on + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimAdvancedSnapshotExportDefinition::~RimAdvancedSnapshotExportDefinition() {} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QList RimAdvancedSnapshotExportDefinition::calculateValueOptions(const caf::PdmFieldHandle* fieldNeedingOptions, + bool* useOptionsOnly) +{ + QList options; + + if (fieldNeedingOptions == &view) + { + options.push_back(caf::PdmOptionItemInfo("None", nullptr)); + + std::vector views; + + RimProject* proj = RiaApplication::instance()->project(); + std::vector cases; + proj->allCases(cases); + + for (RimCase* rimCase : cases) + { + for (Rim3dView* rimView : rimCase->views()) + { + views.push_back(rimView); + } + } + + for (Rim3dView* rim3dView : views) + { + RiaOptionItemFactory::appendOptionItemFromViewNameAndCaseName(rim3dView, &options); + } + } + else if (fieldNeedingOptions == &eclipseResultType) + { + options.push_back(caf::PdmOptionItemInfo(caf::AppEnum(RiaDefines::DYNAMIC_NATIVE).uiText(), + RiaDefines::DYNAMIC_NATIVE)); + options.push_back(caf::PdmOptionItemInfo(caf::AppEnum(RiaDefines::STATIC_NATIVE).uiText(), + RiaDefines::STATIC_NATIVE)); + } + else if (fieldNeedingOptions == &selectedEclipseResults) + { + RimEclipseView* rimEclipseView = dynamic_cast(view()); + if (rimEclipseView) + { + QStringList varList; + varList = rimEclipseView->currentGridCellResults()->resultNames(eclipseResultType()); + + options = toOptionList(varList); + } + } + else if (fieldNeedingOptions == &timeStepEnd) + { + getTimeStepStrings(options); + } + else if (fieldNeedingOptions == &timeStepStart) + { + getTimeStepStrings(options); + } + else if (fieldNeedingOptions == &additionalCases) + { + RimTools::caseOptionItems(&options); + } + + if (useOptionsOnly) *useOptionsOnly = true; + + return options; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimAdvancedSnapshotExportDefinition::getTimeStepStrings(QList& options) +{ + if (!view()) return; + + QStringList timeSteps; + + timeSteps = view->ownerCase()->timeStepStrings(); + + for (int i = 0; i < timeSteps.size(); i++) + { + options.push_back(caf::PdmOptionItemInfo(timeSteps[i], i)); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimAdvancedSnapshotExportDefinition::fieldChangedByUi(const caf::PdmFieldHandle* changedField, + const QVariant& oldValue, + const QVariant& newValue) +{ + if (changedField == &eclipseResultType) + { + selectedEclipseResults.v().clear(); + } + else if (changedField == &sliceDirection) + { + const cvf::StructGridInterface* mainGrid = nullptr; + const RigActiveCellInfo* actCellInfo = nullptr; + + if (view()) + { + actCellInfo = RigReservoirGridTools::activeCellInfo(view()); + + RimCase* rimCase = nullptr; + view()->firstAncestorOrThisOfTypeAsserted(rimCase); + + mainGrid = RigReservoirGridTools::mainGrid(rimCase); + } + + if (mainGrid && actCellInfo) + { + cvf::Vec3st min, max; + actCellInfo->IJKBoundingBox(min, max); + + // Adjust to Eclipse indexing + min.x() = min.x() + 1; + min.y() = min.y() + 1; + min.z() = min.z() + 1; + + max.x() = max.x() + 1; + max.y() = max.y() + 1; + max.z() = max.z() + 1; + + int maxInt = 0; + int minInt = 0; + + if (newValue == RimAdvancedSnapshotExportDefinition::RANGEFILTER_I) + { + maxInt = static_cast(max.x()); + minInt = static_cast(min.x()); + } + else if (newValue == RimAdvancedSnapshotExportDefinition::RANGEFILTER_J) + { + maxInt = static_cast(max.y()); + minInt = static_cast(min.y()); + } + else if (newValue == RimAdvancedSnapshotExportDefinition::RANGEFILTER_K) + { + maxInt = static_cast(max.z()); + minInt = static_cast(min.z()); + } + + startSliceIndex = minInt; + endSliceIndex = maxInt; + } + + startSliceIndex.uiCapability()->updateConnectedEditors(); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QList RimAdvancedSnapshotExportDefinition::toOptionList(const QStringList& varList) +{ + QList optionList; + int i; + for (i = 0; i < varList.size(); ++i) + { + optionList.push_back(caf::PdmOptionItemInfo(varList[i], varList[i])); + } + return optionList; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimAdvancedSnapshotExportDefinition::defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering) +{ + if (!isActive()) + { + view.uiCapability()->setUiReadOnly(true); + eclipseResultType.uiCapability()->setUiReadOnly(true); + selectedEclipseResults.uiCapability()->setUiReadOnly(true); + timeStepStart.uiCapability()->setUiReadOnly(true); + timeStepEnd.uiCapability()->setUiReadOnly(true); + sliceDirection.uiCapability()->setUiReadOnly(true); + startSliceIndex.uiCapability()->setUiReadOnly(true); + endSliceIndex.uiCapability()->setUiReadOnly(true); + additionalCases.uiCapability()->setUiReadOnly(true); + } + else + { + view.uiCapability()->setUiReadOnly(false); + + if (!view()) + { + eclipseResultType.uiCapability()->setUiReadOnly(true); + selectedEclipseResults.uiCapability()->setUiReadOnly(true); + timeStepStart.uiCapability()->setUiReadOnly(true); + timeStepEnd.uiCapability()->setUiReadOnly(true); + sliceDirection.uiCapability()->setUiReadOnly(true); + startSliceIndex.uiCapability()->setUiReadOnly(true); + endSliceIndex.uiCapability()->setUiReadOnly(true); + additionalCases.uiCapability()->setUiReadOnly(true); + } + else + { + eclipseResultType.uiCapability()->setUiReadOnly(false); + selectedEclipseResults.uiCapability()->setUiReadOnly(false); + timeStepStart.uiCapability()->setUiReadOnly(false); + timeStepEnd.uiCapability()->setUiReadOnly(false); + sliceDirection.uiCapability()->setUiReadOnly(false); + + additionalCases.uiCapability()->setUiReadOnly(false); + + bool rangeReadOnly = false; + if (sliceDirection() == NO_RANGEFILTER) + { + rangeReadOnly = true; + } + + startSliceIndex.uiCapability()->setUiReadOnly(rangeReadOnly); + endSliceIndex.uiCapability()->setUiReadOnly(rangeReadOnly); + } + } +} diff --git a/ApplicationCode/ProjectDataModel/RimAdvancedSnapshotExportDefinition.h b/ApplicationCode/ProjectDataModel/RimAdvancedSnapshotExportDefinition.h new file mode 100644 index 0000000000..a106df2dfb --- /dev/null +++ b/ApplicationCode/ProjectDataModel/RimAdvancedSnapshotExportDefinition.h @@ -0,0 +1,78 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2016- Statoil ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "RiaDefines.h" + +#include "cafAppEnum.h" +#include "cafPdmField.h" +#include "cafPdmObject.h" +#include "cafPdmPtrField.h" +#include "cafPdmPtrArrayField.h" + +class RimCase; +class Rim3dView; + +//================================================================================================== +/// +/// +//================================================================================================== +class RimAdvancedSnapshotExportDefinition : public caf::PdmObject +{ + CAF_PDM_HEADER_INIT; +public: + RimAdvancedSnapshotExportDefinition(); + ~RimAdvancedSnapshotExportDefinition() override; + + caf::PdmField isActive; + + caf::PdmPtrField view; + + caf::PdmField< caf::AppEnum< RiaDefines::ResultCatType > > eclipseResultType; + caf::PdmField< std::vector > selectedEclipseResults; + + caf::PdmField timeStepStart; + caf::PdmField timeStepEnd; + + enum SnapShotDirectionEnum + { + RANGEFILTER_I, + RANGEFILTER_J, + RANGEFILTER_K, + NO_RANGEFILTER + }; + + caf::PdmField< caf::AppEnum< SnapShotDirectionEnum > > sliceDirection; + caf::PdmField startSliceIndex; + caf::PdmField endSliceIndex; + + caf::PdmPtrArrayField additionalCases; + +protected: + void defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering) override; + +private: + QList calculateValueOptions(const caf::PdmFieldHandle* fieldNeedingOptions, bool * useOptionsOnly) override; + + void getTimeStepStrings(QList &options); + + void fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue) override; + + QList toOptionList(const QStringList& varList); +}; diff --git a/ApplicationCode/ProjectDataModel/RimCalcScript.cpp b/ApplicationCode/ProjectDataModel/RimCalcScript.cpp index 3ff0998456..ffaccf9832 100644 --- a/ApplicationCode/ProjectDataModel/RimCalcScript.cpp +++ b/ApplicationCode/ProjectDataModel/RimCalcScript.cpp @@ -18,11 +18,15 @@ #include "RimCalcScript.h" +#include "RiaApplication.h" #include "RiaFieldHandleTools.h" +#include "RiaLogging.h" #include "cafPdmField.h" #include "cafPdmUiFilePathEditor.h" +#include + CAF_PDM_SOURCE_INIT(RimCalcScript, "CalcScript"); //-------------------------------------------------------------------------------------------------- @@ -32,14 +36,48 @@ RimCalcScript::RimCalcScript() { CAF_PDM_InitObject("CalcScript", ":/OctaveScriptFile16x16.png", "Calc Script", ""); - CAF_PDM_InitField(&absolutePath, "AbsolutePath", QString(), "Location", "", "", ""); + CAF_PDM_InitField(&absoluteFileName, "AbsolutePath", QString(), "Location", "", "", ""); CAF_PDM_InitField(&content, "Content", QString(), "Directory", "", "", ""); RiaFieldhandleTools::disableWriteAndSetFieldHidden(&content); - absolutePath.uiCapability()->setUiEditorTypeName(caf::PdmUiFilePathEditor::uiEditorTypeName()); + absoluteFileName.uiCapability()->setUiEditorTypeName(caf::PdmUiFilePathEditor::uiEditorTypeName()); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- RimCalcScript::~RimCalcScript() {} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QStringList RimCalcScript::createCommandLineArguments(const QString& absoluteFileNameScript) +{ + QStringList arguments; + + { + auto app = RiaApplication::instance(); + + arguments = app->octaveArguments(); + arguments.append("--path"); + } + + { + QFileInfo fi(absoluteFileNameScript); + QString octaveFunctionSearchPath = fi.absolutePath(); + QString absFilePath = fi.absoluteFilePath(); + + arguments << octaveFunctionSearchPath; + arguments << absFilePath; + } + + bool debugPrintArgumentText = false; + if (debugPrintArgumentText) + { + QString argumentString = arguments.join(" "); + + RiaLogging::info("Octave arguments : " + argumentString); + } + + return arguments; +} diff --git a/ApplicationCode/ProjectDataModel/RimCalcScript.h b/ApplicationCode/ProjectDataModel/RimCalcScript.h index d3852fdf7b..442bc97cf0 100644 --- a/ApplicationCode/ProjectDataModel/RimCalcScript.h +++ b/ApplicationCode/ProjectDataModel/RimCalcScript.h @@ -33,6 +33,8 @@ class RimCalcScript : public caf::PdmObject RimCalcScript(); ~RimCalcScript() override; - caf::PdmField absolutePath; + static QStringList createCommandLineArguments(const QString& absoluteFileNameScript); + + caf::PdmField absoluteFileName; caf::PdmField content; // TODO: Obsolete field, can be deleted on next project file revision. }; diff --git a/ApplicationCode/ProjectDataModel/RimCellEdgeColors.cpp b/ApplicationCode/ProjectDataModel/RimCellEdgeColors.cpp index 5a5de5301e..b948fcac4e 100644 --- a/ApplicationCode/ProjectDataModel/RimCellEdgeColors.cpp +++ b/ApplicationCode/ProjectDataModel/RimCellEdgeColors.cpp @@ -64,7 +64,7 @@ RimCellEdgeColors::RimCellEdgeColors() CAF_PDM_InitField(&useYVariable, "UseYVariable", true, "Use Y Values", "", "", ""); CAF_PDM_InitField(&useZVariable, "UseZVariable", true, "Use Z Values", "", "", ""); - CAF_PDM_InitFieldNoDefault(&m_legendConfig, "LegendDefinition", "Legend Definition", ":/Legend.png", "", ""); + CAF_PDM_InitFieldNoDefault(&m_legendConfig, "LegendDefinition", "Color Legend", ":/Legend.png", "", ""); CAF_PDM_InitFieldNoDefault(&m_singleVarEdgeResultColors, "SingleVarEdgeResult", "Result Property", ":/CellResult.png", "", ""); m_singleVarEdgeResultColors = new RimEclipseCellColors(); @@ -74,7 +74,7 @@ RimCellEdgeColors::RimCellEdgeColors() m_legendConfig = new RimRegularLegendConfig(); m_ignoredResultScalar = cvf::UNDEFINED_DOUBLE; - resetResultIndices(); + resetResultAddresses(); } //-------------------------------------------------------------------------------------------------- @@ -105,22 +105,22 @@ void RimCellEdgeColors::loadResult() { m_singleVarEdgeResultColors->loadResult();; - size_t resultindex = m_singleVarEdgeResultColors->scalarResultIndex(); + RigEclipseResultAddress resultAddr = m_singleVarEdgeResultColors->eclipseResultAddress(); for (int cubeFaceIdx = 0; cubeFaceIdx < 6; ++cubeFaceIdx) { - m_resultNameToIndexPairs[cubeFaceIdx] = std::make_pair(m_singleVarEdgeResultColors->resultVariable(), resultindex); + m_resultNameToAddressPairs[cubeFaceIdx] = std::make_pair(m_singleVarEdgeResultColors->resultVariable(), resultAddr); } } else { - resetResultIndices(); + resetResultAddresses(); QStringList vars = findResultVariableNames(); updateIgnoredScalarValue(); int i; for (i = 0; i < vars.size(); ++i) { - size_t resultindex = m_reservoirView->currentGridCellResults()->findOrLoadScalarResult(RiaDefines::STATIC_NATIVE, vars[i]); + m_reservoirView->currentGridCellResults()->ensureKnownResultLoaded(RigEclipseResultAddress(RiaDefines::STATIC_NATIVE, vars[i])); int cubeFaceIdx; for (cubeFaceIdx = 0; cubeFaceIdx < 6; ++cubeFaceIdx) { @@ -132,7 +132,7 @@ void RimCellEdgeColors::loadResult() if (vars[i].endsWith(varEnd)) { - m_resultNameToIndexPairs[cubeFaceIdx] = std::make_pair(vars[i], resultindex); + m_resultNameToAddressPairs[cubeFaceIdx] = std::make_pair(vars[i], RigEclipseResultAddress(RiaDefines::STATIC_NATIVE, vars[i])); } } } @@ -317,12 +317,12 @@ QStringList RimCellEdgeColors::findResultVariableNames() //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RimCellEdgeColors::gridScalarIndices(size_t resultIndices[6]) +void RimCellEdgeColors::gridScalarIndices(RigEclipseResultAddress resultIndices[6]) { int cubeFaceIndex; for (cubeFaceIndex = 0; cubeFaceIndex < 6; ++cubeFaceIndex) { - resultIndices[cubeFaceIndex] = m_resultNameToIndexPairs[cubeFaceIndex].second; + resultIndices[cubeFaceIndex] = RigEclipseResultAddress(m_resultNameToAddressPairs[cubeFaceIndex].second); } } @@ -336,7 +336,7 @@ void RimCellEdgeColors::gridScalarResultNames(std::vector* resultNames) int cubeFaceIndex; for (cubeFaceIndex = 0; cubeFaceIndex < 6; ++cubeFaceIndex) { - resultNames->push_back(m_resultNameToIndexPairs[cubeFaceIndex].first); + resultNames->push_back(m_resultNameToAddressPairs[cubeFaceIndex].first); } } @@ -356,7 +356,7 @@ void RimCellEdgeColors::cellEdgeMetaData(std::vector* metaD { CVF_ASSERT(metaDataVector); - size_t resultIndices[6]; + RigEclipseResultAddress resultIndices[6]; this->gridScalarIndices(resultIndices); std::vector resultNames; @@ -371,7 +371,7 @@ void RimCellEdgeColors::cellEdgeMetaData(std::vector* metaD for (size_t i = 0; i < 6; i++) { RimCellEdgeMetaData metaData; - metaData.m_resultIndex = resultIndices[i]; + metaData.m_eclipseResultAddress = resultIndices[i]; metaData.m_resultVariable = resultNames[i]; metaData.m_isStatic = isStatic; @@ -382,12 +382,12 @@ void RimCellEdgeColors::cellEdgeMetaData(std::vector* metaD //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RimCellEdgeColors::resetResultIndices() +void RimCellEdgeColors::resetResultAddresses() { int cubeFaceIndex; for (cubeFaceIndex = 0; cubeFaceIndex < 6; ++cubeFaceIndex) { - m_resultNameToIndexPairs[cubeFaceIndex].second = cvf::UNDEFINED_SIZE_T; + m_resultNameToAddressPairs[cubeFaceIndex].second = RigEclipseResultAddress(); } } @@ -407,7 +407,7 @@ bool RimCellEdgeColors::hasResult() const int cubeFaceIndex; for (cubeFaceIndex = 0; cubeFaceIndex < 6; ++cubeFaceIndex) { - hasResult |= ((m_resultNameToIndexPairs[cubeFaceIndex].second) != cvf::UNDEFINED_SIZE_T); + hasResult |= m_resultNameToAddressPairs[cubeFaceIndex].second.isValid(); } return hasResult; @@ -450,17 +450,17 @@ void RimCellEdgeColors::minMaxCellEdgeValues(double& min, double& max) } else { - size_t resultIndices[6]; - this->gridScalarIndices(resultIndices); + RigEclipseResultAddress resultAddresses[6]; + this->gridScalarIndices(resultAddresses); - size_t idx; - for (idx = 0; idx < 6; idx++) + size_t faceIdx; + for (faceIdx = 0; faceIdx < 6; faceIdx++) { - if (resultIndices[idx] == cvf::UNDEFINED_SIZE_T) continue; + if (!resultAddresses[faceIdx].isValid()) continue; { double cMin, cMax; - m_reservoirView->currentGridCellResults()->minMaxCellScalarValues(resultIndices[idx], cMin, cMax); + m_reservoirView->currentGridCellResults()->minMaxCellScalarValues(resultAddresses[faceIdx], cMin, cMax); globalMin = CVF_MIN(globalMin, cMin); globalMax = CVF_MAX(globalMax, cMax); @@ -481,17 +481,17 @@ void RimCellEdgeColors::posNegClosestToZero(double& pos, double& neg) pos = HUGE_VAL; neg = -HUGE_VAL; - size_t resultIndices[6]; - this->gridScalarIndices(resultIndices); + RigEclipseResultAddress resultAddresses[6]; + this->gridScalarIndices(resultAddresses); - size_t idx; - for (idx = 0; idx < 6; idx++) + size_t faceIdx; + for (faceIdx = 0; faceIdx < 6; faceIdx++) { - if (resultIndices[idx] == cvf::UNDEFINED_SIZE_T) continue; + if (!resultAddresses[faceIdx].isValid()) continue; { double localPos, localNeg; - m_reservoirView->currentGridCellResults()->posNegClosestToZero(resultIndices[idx], localPos, localNeg); + m_reservoirView->currentGridCellResults()->posNegClosestToZero(resultAddresses[faceIdx], localPos, localNeg); if (localPos > 0 && localPos < pos) pos = localPos; if (localNeg < 0 && localNeg > neg) neg = localNeg; diff --git a/ApplicationCode/ProjectDataModel/RimCellEdgeColors.h b/ApplicationCode/ProjectDataModel/RimCellEdgeColors.h index 49a63fc9f7..8528d27462 100644 --- a/ApplicationCode/ProjectDataModel/RimCellEdgeColors.h +++ b/ApplicationCode/ProjectDataModel/RimCellEdgeColors.h @@ -27,6 +27,8 @@ #include +#include "RigCaseCellResultsData.h" + class RigCaseCellResultsData; class RimEclipseCase; class RimEclipseCellColors; @@ -36,7 +38,7 @@ class RimRegularLegendConfig; class RimCellEdgeMetaData { public: - size_t m_resultIndex; + RigEclipseResultAddress m_eclipseResultAddress; QString m_resultVariable; bool m_isStatic; }; @@ -78,7 +80,7 @@ class RimCellEdgeColors : public caf::PdmObject void setActive(bool active); double ignoredScalarValue() { return m_ignoredResultScalar; } - void gridScalarIndices(size_t resultIndices[6]); + void gridScalarIndices(RigEclipseResultAddress resultIndices[6]); void cellEdgeMetaData(std::vector* metaData); void loadResult(); @@ -105,7 +107,7 @@ class RimCellEdgeColors : public caf::PdmObject QStringList findResultVariableNames(); private: - void resetResultIndices(); + void resetResultAddresses(); void updateIgnoredScalarValue(); void gridScalarResultNames(std::vector* resultNames); @@ -118,7 +120,7 @@ class RimCellEdgeColors : public caf::PdmObject caf::PdmField useYVariable; caf::PdmField useZVariable; - std::array, 6> m_resultNameToIndexPairs; + std::array, 6> m_resultNameToAddressPairs; caf::PdmPointer m_reservoirView; double m_ignoredResultScalar; diff --git a/ApplicationCode/ProjectDataModel/RimCommandObject.cpp b/ApplicationCode/ProjectDataModel/RimCommandObject.cpp index 4fdbc6a4f0..b260a82817 100644 --- a/ApplicationCode/ProjectDataModel/RimCommandObject.cpp +++ b/ApplicationCode/ProjectDataModel/RimCommandObject.cpp @@ -165,7 +165,7 @@ void RimCommandFactory::createCommandObjects(const caf::PdmObjectGroup& selected { RimCalcScript* calcScript = dynamic_cast(pdmObject); - QFile file(calcScript->absolutePath); + QFile file(calcScript->absoluteFileName); if (file.open(QIODevice::ReadOnly | QIODevice::Text)) { QTextStream in(&file); diff --git a/ApplicationCode/ProjectDataModel/RimContextCommandBuilder.cpp b/ApplicationCode/ProjectDataModel/RimContextCommandBuilder.cpp index 3eb2af41a9..7b6addfef3 100644 --- a/ApplicationCode/ProjectDataModel/RimContextCommandBuilder.cpp +++ b/ApplicationCode/ProjectDataModel/RimContextCommandBuilder.cpp @@ -26,11 +26,14 @@ #include "Rim3dWellLogExtractionCurve.h" #include "Rim3dWellLogFileCurve.h" #include "Rim3dWellLogRftCurve.h" +#include "RimAnnotationCollection.h" +#include "RimAnnotationInViewCollection.h" +#include "RimAnnotationGroupCollection.h" #include "RimCalcScript.h" #include "RimCaseCollection.h" #include "RimCellRangeFilter.h" #include "RimCellRangeFilterCollection.h" -#include "RimContourMapViewCollection.h" +#include "RimEclipseContourMapViewCollection.h" #include "RimEclipseCase.h" #include "RimEclipseCaseCollection.h" #include "RimEclipseCellColors.h" @@ -44,21 +47,30 @@ #include "RimEnsembleCurveSetCollection.h" #include "RimEnsembleCurveSet.h" #include "RimFaultInView.h" +#include "RimFishbonesCollection.h" +#include "RimFishbonesMultipleSubs.h" +#include "RimFishboneWellPathCollection.h" #include "RimFlowCharacteristicsPlot.h" #include "RimFlowDiagSolution.h" #include "RimFlowPlotCollection.h" #include "RimFormationNames.h" #include "RimFormationNamesCollection.h" #include "RimGeoMechCase.h" +#include "RimGeoMechContourMapViewCollection.h" #include "RimGeoMechPropertyFilter.h" #include "RimGeoMechPropertyFilterCollection.h" #include "RimGeoMechView.h" #include "RimGridCollection.h" +#include "RimGridCrossPlot.h" +#include "RimGridCrossPlotCollection.h" +#include "RimGridCrossPlotDataSet.h" #include "RimIdenticalGridCaseGroup.h" #include "RimIntersection.h" #include "RimIntersectionBox.h" #include "RimIntersectionCollection.h" #include "RimObservedData.h" +#include "RimPerforationCollection.h" +#include "RimPerforationInterval.h" #include "RimPltPlotCollection.h" #include "RimProject.h" #include "RimRftPlotCollection.h" @@ -76,6 +88,7 @@ #include "RimSummaryPlotCollection.h" #include "RimViewController.h" #include "RimViewLinker.h" +#include "RimViewLinkerCollection.h" #include "RimWellAllocationPlot.h" #include "RimWellLogCurve.h" #include "RimWellLogFile.h" @@ -86,8 +99,11 @@ #include "RimWellPath.h" #include "RimWellPathAttributeCollection.h" #include "RimWellPathCollection.h" +#include "RimWellPathCompletions.h" +#include "RimWellPathFractureCollection.h" #include "RimWellPltPlot.h" #include "RimWellRftPlot.h" +#include "RimSaturationPressurePlotCollection.h" #include "RimEllipseFractureTemplate.h" #include "RimStimPlanFractureTemplate.h" @@ -97,10 +113,13 @@ #include "RimWellPathFracture.h" #include "RimWellPathFractureCollection.h" #include "RimModeledWellPath.h" +#include "RimValveTemplate.h" +#include "RimValveTemplateCollection.h" #include "RiuMainWindow.h" #include "ToggleCommands/RicToggleItemsFeatureImpl.h" +#include "OctaveScriptCommands/RicExecuteScriptForCasesFeature.h" #include "cafCmdFeature.h" #include "cafCmdFeatureManager.h" @@ -110,10 +129,13 @@ #include "cafSelectionManagerTools.h" #include "cvfAssert.h" -#include +#include #include +#include +#include #include -#include "OctaveScriptCommands/RicExecuteScriptForCasesFeature.h" + +#include //-------------------------------------------------------------------------------------------------- /// @@ -148,6 +170,8 @@ caf::CmdFeatureMenuBuilder RimContextCommandBuilder::commandsFromSelection() menuBuilder << "Separator"; menuBuilder << "RicNewViewFeature"; + menuBuilder << "RicNewContourMapViewFeature"; + menuBuilder << "Separator"; menuBuilder << "RicCopyReferencesToClipboardFeature"; } @@ -157,11 +181,17 @@ caf::CmdFeatureMenuBuilder RimContextCommandBuilder::commandsFromSelection() menuBuilder << "Separator"; menuBuilder << "RicNewViewFeature"; menuBuilder << "RicNewContourMapViewFeature"; + menuBuilder << "RicCreateGridCrossPlotFeature"; menuBuilder << "Separator"; menuBuilder << "RicCopyReferencesToClipboardFeature"; + menuBuilder << "RicExportEclipseInputGridFeature"; menuBuilder << "RicSaveEclipseInputVisibleCellsFeature"; } - else if (dynamic_cast(uiItem)) + else if (dynamic_cast(uiItem)) + { + menuBuilder << "RicNewContourMapViewFeature"; + } + else if (dynamic_cast(uiItem)) { menuBuilder << "RicNewContourMapViewFeature"; } @@ -201,6 +231,7 @@ caf::CmdFeatureMenuBuilder RimContextCommandBuilder::commandsFromSelection() menuBuilder << "RicPasteGeoMechViewsFeature"; menuBuilder << "Separator"; menuBuilder << "RicNewViewFeature"; + menuBuilder << "RicNewContourMapViewFeature"; menuBuilder << "Separator"; menuBuilder << "RicImportElementPropertyFeature"; menuBuilder << "Separator"; @@ -214,7 +245,9 @@ caf::CmdFeatureMenuBuilder RimContextCommandBuilder::commandsFromSelection() else if (dynamic_cast(uiItem)) { menuBuilder << "RicSaveEclipseResultAsInputPropertyFeature"; + menuBuilder << "RicExportEclipseInputGridFeature"; menuBuilder << "RicSaveEclipseInputVisibleCellsFeature"; + menuBuilder << "RicCreateGridCrossPlotFeature"; } else if (dynamic_cast(uiItem)) { @@ -258,28 +291,36 @@ caf::CmdFeatureMenuBuilder RimContextCommandBuilder::commandsFromSelection() } else if (dynamic_cast(uiItem)) { + menuBuilder << "RicNewEditableWellPathFeature"; + menuBuilder.addSeparator(); menuBuilder.subMenuStart("Import"); menuBuilder << "RicWellPathsImportFileFeature"; menuBuilder << "RicWellPathsImportSsihubFeature"; menuBuilder << "RicWellPathFormationsImportFileFeature"; menuBuilder << "RicWellLogsImportFileFeature"; menuBuilder << "RicReloadWellPathFormationNamesFeature"; + menuBuilder.addSeparator(); menuBuilder << "RicWellPathImportPerforationIntervalsFeature"; + menuBuilder << "RicWellPathImportCompletionsFileFeature"; menuBuilder.subMenuEnd(); - menuBuilder.addSeparator(); - - menuBuilder << "RicNewEditableWellPathFeature"; + menuBuilder.subMenuStart("Export Well Paths", QIcon(":/Save.png")); + menuBuilder << "RicExportSelectedWellPathsFeature"; + menuBuilder << "RicExportVisibleWellPathsFeature"; + menuBuilder.subMenuEnd(); + appendExportCompletions(menuBuilder); } else if (dynamic_cast(uiItem)) { - menuBuilder.subMenuStart("Import"); - menuBuilder << "RicWellPathsImportFileFeature"; - menuBuilder << "RicWellPathFormationsImportFileFeature"; - menuBuilder << "RicWellLogsImportFileFeature"; - menuBuilder << "RicReloadWellPathFormationNamesFeature"; - menuBuilder.subMenuEnd(); - + menuBuilder << "RicNewEditableWellPathFeature"; + menuBuilder << "RicNewWellPathIntersectionFeature"; + appendCreateCompletions(menuBuilder); + menuBuilder.addSeparator(); + appendImportMenu(menuBuilder); + menuBuilder.addSeparator(); + appendExportCompletions(menuBuilder); + menuBuilder.addSeparator(); + appendExportWellPaths(menuBuilder); menuBuilder.addSeparator(); menuBuilder.subMenuStart("Well Plots", QIcon(":/WellLogTrack16x16.png")); @@ -291,40 +332,54 @@ caf::CmdFeatureMenuBuilder RimContextCommandBuilder::commandsFromSelection() menuBuilder << "RicNewWellLogCurveExtractionFeature"; menuBuilder.subMenuEnd(); - menuBuilder.addSeparator(); - menuBuilder.subMenuStart("3D Well Log Curves", QIcon(":/WellLogCurve16x16.png")); menuBuilder << "RicAdd3dWellLogCurveFeature"; menuBuilder << "RicAdd3dWellLogFileCurveFeature"; menuBuilder << "RicAdd3dWellLogRftCurveFeature"; menuBuilder.subMenuEnd(); - - menuBuilder << "RicNewEditableWellPathFeature"; - menuBuilder << "RicNewWellPathIntersectionFeature"; - menuBuilder.addSeparator(); - menuBuilder.subMenuStart("Completions", QIcon(":/CompletionsSymbol16x16.png")); - menuBuilder << "RicNewWellPathFractureFeature"; - menuBuilder << "RicNewFishbonesSubsFeature"; - menuBuilder << "RicNewPerforationIntervalFeature"; - menuBuilder << "RicNewValveFeature"; - menuBuilder << "RicEditPerforationCollectionFeature"; - menuBuilder.subMenuEnd(); - menuBuilder.subMenuStart("Export Completions", QIcon(":/ExportCompletionsSymbol16x16.png")); - menuBuilder << "RicExportCompletionsForVisibleWellPathsFeature"; - menuBuilder << "RicWellPathExportCompletionDataFeature"; - menuBuilder.subMenuEnd(); + menuBuilder.addSeparator(); if ( dynamic_cast(uiItem) ) { menuBuilder << "RicShowWellPlanFeature"; } - menuBuilder << "RicCreateMultipleFracturesFeature"; - menuBuilder << "RicNewWellPathAttributeFeature"; - - menuBuilder << "Separator"; - + } + else if (dynamic_cast(uiItem)) + { + menuBuilder.subMenuStart("Create Completions", QIcon(":/CompletionsSymbol16x16.png")); + menuBuilder << "RicNewPerforationIntervalFeature"; + menuBuilder << "RicNewFishbonesSubsFeature"; + menuBuilder << "RicNewWellPathFractureFeature"; + menuBuilder.subMenuEnd(); + menuBuilder << "RicCreateTemporaryLgrFeature"; + menuBuilder.addSeparator(); + appendExportCompletions(menuBuilder); + } + else if (dynamic_cast(uiItem) || + dynamic_cast(uiItem)) + { + menuBuilder << "RicNewPerforationIntervalFeature"; + if (dynamic_cast(uiItem)) + menuBuilder << "RicNewValveFeature"; + menuBuilder.addSeparator(); + menuBuilder << "RicEditPerforationCollectionFeature"; + menuBuilder.addSeparator(); + appendExportCompletions(menuBuilder); + } + else if (dynamic_cast(uiItem) || + dynamic_cast(uiItem) || + dynamic_cast(uiItem)) + { + menuBuilder << "RicNewFishbonesSubsFeature"; + appendExportCompletions(menuBuilder); + } + else if (dynamic_cast(uiItem) || + dynamic_cast(uiItem)) + { + menuBuilder << "RicNewWellPathFractureFeature"; + appendExportCompletions(menuBuilder); } else if (dynamic_cast(uiItem)) { @@ -389,7 +444,7 @@ caf::CmdFeatureMenuBuilder RimContextCommandBuilder::commandsFromSelection() { menuBuilder << "RicShowAllLinkedViewsFeature"; } - else if (dynamic_cast(uiItem)) + else if (dynamic_cast(uiItem) || dynamic_cast(uiItem)) { menuBuilder << "RicShowAllLinkedViewsFeature"; menuBuilder << "Separator"; @@ -448,6 +503,27 @@ caf::CmdFeatureMenuBuilder RimContextCommandBuilder::commandsFromSelection() { menuBuilder << "RicPasteWellLogCurveFeature"; } + else if (dynamic_cast(uiItem)) + { + menuBuilder << "RicCreateGridCrossPlotFeature"; + } + else if (dynamic_cast(uiItem)) + { + menuBuilder << "RicCreateSaturationPressurePlotsFeature"; + } + else if (dynamic_cast(uiItem)) + { + menuBuilder << "RicPasteGridCrossPlotDataSetFeature"; + menuBuilder << "Separator"; + menuBuilder << "RicCreateGridCrossPlotDataSetFeature"; + menuBuilder << "RicSwapGridCrossPlotDataSetAxesFeature"; + } + else if (dynamic_cast(uiItem)) + { + menuBuilder << "RicPasteGridCrossPlotDataSetFeature"; + menuBuilder << "Separator"; + menuBuilder << "RicSwapGridCrossPlotDataSetAxesFeature"; + } else if (dynamic_cast(uiItem)) // This is also the definition for RimSummaryCrossPlot { RimSummaryCrossPlot* summaryCrossPlot = dynamic_cast(uiItem); @@ -655,6 +731,14 @@ caf::CmdFeatureMenuBuilder RimContextCommandBuilder::commandsFromSelection() { menuBuilder << "RicNewSimWellFractureFeature"; } + else if (dynamic_cast(uiItem)) + { + menuBuilder << "RicNewValveTemplateFeature"; + } + else if (dynamic_cast(uiItem)) + { + menuBuilder << "RicDeleteValveTemplateFeature"; + } else if (dynamic_cast(uiItem)) { menuBuilder << "RicPasteEllipseFractureFeature"; @@ -686,7 +770,18 @@ caf::CmdFeatureMenuBuilder RimContextCommandBuilder::commandsFromSelection() menuBuilder << "Separator"; menuBuilder << "RicConvertFractureTemplateUnitFeature"; } - + else if (dynamic_cast(uiItem) + || dynamic_cast(uiItem)) + { + menuBuilder << "RicCreateTextAnnotationFeature"; + menuBuilder << "RicCreateReachCircleAnnotationFeature"; + menuBuilder << "RicCreateUserDefinedPolylinesAnnotationFeature"; + menuBuilder << "RicImportPolylinesAnnotationFeature"; + } + else if (dynamic_cast(uiItem)) + { + menuBuilder << "RicCreateTextAnnotationFeature"; + } if (dynamic_cast(uiItem)) { menuBuilder << "Separator"; @@ -725,76 +820,6 @@ caf::CmdFeatureMenuBuilder RimContextCommandBuilder::commandsFromSelection() menuBuilder << "RicConvertGroupToEnsembleFeature"; menuBuilder.addSeparator(); - if (!menuBuilder.isCmdFeatureAdded("RicNewFishbonesSubsFeature")) - { - menuBuilder << "RicNewFishbonesSubsFeature"; - } - if (!menuBuilder.isCmdFeatureAdded("RicNewPerforationIntervalFeature")) - { - menuBuilder << "RicNewPerforationIntervalFeature"; - } - if (!menuBuilder.isCmdFeatureAdded("RicNewValveFeature")) - { - menuBuilder << "RicNewValveFeature"; - } - - menuBuilder << "RicEditPerforationCollectionFeature"; - menuBuilder << "RicExportFishbonesLateralsFeature"; - menuBuilder << "RicExportFishbonesWellSegmentsFeature"; - menuBuilder << "RicExportFracturesWellSegmentsFeature"; - { - QStringList candidates; - - if (!menuBuilder.isCmdFeatureAdded("RicExportCompletionsForVisibleWellPathsFeature")) - { - candidates << "RicExportCompletionsForVisibleWellPathsFeature"; - } - if (!menuBuilder.isCmdFeatureAdded("RicWellPathExportCompletionDataFeature")) - { - candidates << "RicWellPathExportCompletionDataFeature"; - } - - if (!candidates.isEmpty()) - { - menuBuilder.subMenuStart("Export Completions", QIcon(":/ExportCompletionsSymbol16x16.png")); - - for (const auto& text : candidates) - { - menuBuilder << text; - } - - menuBuilder.subMenuEnd(); - } - } - - { - QStringList candidates; - - if (!menuBuilder.isCmdFeatureAdded("RicExportSelectedWellPathsFeature")) - { - candidates << "RicExportSelectedWellPathsFeature"; - - } - if (!menuBuilder.isCmdFeatureAdded("RicExportVisibleWellPathsFeature")) - { - candidates << "RicExportVisibleWellPathsFeature"; - } - - if (!candidates.isEmpty()) - { - menuBuilder.subMenuStart("Export Well Paths", QIcon(":/Save.png")); - - for (const auto& text : candidates) - { - menuBuilder << text; - } - - menuBuilder.subMenuEnd(); - } - } - - menuBuilder << "RicCreateMultipleFracturesFeature"; - menuBuilder << "RicWellPathImportCompletionsFileFeature"; menuBuilder << "RicFlyToObjectFeature"; menuBuilder << "RicImportObservedDataFeature"; @@ -808,9 +833,15 @@ caf::CmdFeatureMenuBuilder RimContextCommandBuilder::commandsFromSelection() menuBuilder << "RicDeleteSummaryCaseCollectionFeature"; menuBuilder << "RicCloseObservedDataFeature"; - menuBuilder << "RicCreateTemporaryLgrFeature"; - // Work in progress -- End + appendCreateCompletions(menuBuilder, menuBuilder.itemCount() > 0u); + bool addedExportWellPaths = appendExportWellPaths(menuBuilder, menuBuilder.itemCount() > 0u) > 0; + appendExportCompletions(menuBuilder, menuBuilder.itemCount() > 0u && !addedExportWellPaths); + + if (menuBuilder.itemCount() > 0u) + { + menuBuilder.addSeparator(); + } caf::PdmUiItem* uiItem = uiItems[0]; if (dynamic_cast(uiItem)) @@ -997,10 +1028,10 @@ void RimContextCommandBuilder::appendScriptItems(caf::CmdFeatureMenuBuilder& men for (size_t i = 0; i < scriptCollection->calcScripts.size(); i++) { RimCalcScript* calcScript = scriptCollection->calcScripts[i]; - QFileInfo fi(calcScript->absolutePath()); + QFileInfo fi(calcScript->absoluteFileName()); QString menuText = fi.baseName(); - menuBuilder.addCmdFeatureWithUserData("RicExecuteScriptForCasesFeature", menuText, QVariant(calcScript->absolutePath())); + menuBuilder.addCmdFeatureWithUserData("RicExecuteScriptForCasesFeature", menuText, QVariant(calcScript->absoluteFileName())); } for (size_t i = 0; i < scriptCollection->subDirectories.size(); i++) @@ -1012,3 +1043,116 @@ void RimContextCommandBuilder::appendScriptItems(caf::CmdFeatureMenuBuilder& men menuBuilder.subMenuEnd(); } + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +int RimContextCommandBuilder::appendImportMenu(caf::CmdFeatureMenuBuilder& menuBuilder, bool addSeparatorBeforeMenu) +{ + QStringList candidates; + candidates << "RicWellPathsImportFileFeature"; + candidates << "RicWellPathFormationsImportFileFeature"; + candidates << "RicWellLogsImportFileFeature"; + candidates << "RicReloadWellPathFormationNamesFeature"; + candidates << "Separator"; + candidates << "RicWellPathImportCompletionsFileFeature"; + + return appendSubMenuWithCommands(menuBuilder, candidates, "Import", QIcon(), addSeparatorBeforeMenu); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +int RimContextCommandBuilder::appendCreateCompletions(caf::CmdFeatureMenuBuilder& menuBuilder, bool addSeparatorBeforeMenu) +{ + QStringList candidates; + candidates << "RicNewPerforationIntervalFeature"; + candidates << "RicEditPerforationCollectionFeature"; + candidates << "RicNewValveFeature"; + candidates << "RicNewFishbonesSubsFeature"; + candidates << "RicNewWellPathFractureFeature"; + candidates << "Separator"; + candidates << "RicCreateMultipleFracturesFeature"; + candidates << "RicNewWellPathAttributeFeature"; + candidates << "Separator"; + candidates << "RicCreateTemporaryLgrFeature"; + + return appendSubMenuWithCommands(menuBuilder, candidates, "Create Completions", QIcon(":/CompletionsSymbol16x16.png"), addSeparatorBeforeMenu); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +int RimContextCommandBuilder::appendExportCompletions(caf::CmdFeatureMenuBuilder& menuBuilder, bool addSeparatorBeforeMenu) +{ + QStringList candidates; + candidates << "RicExportCompletionsForVisibleWellPathsFeature"; + candidates << "RicWellPathExportCompletionDataFeature"; + candidates << "RicExportFishbonesLateralsFeature"; + candidates << "RicExportCompletionsWellSegmentsFeature"; + + return appendSubMenuWithCommands(menuBuilder, candidates, "Export Completions", QIcon(":/ExportCompletionsSymbol16x16.png"), addSeparatorBeforeMenu); +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +int RimContextCommandBuilder::appendExportWellPaths(caf::CmdFeatureMenuBuilder& menuBuilder, bool addSeparatorBeforeMenu) +{ + QStringList candidates; + candidates << "RicExportSelectedWellPathsFeature"; + candidates << "RicExportVisibleWellPathsFeature"; + + return appendSubMenuWithCommands(menuBuilder, candidates, "Export Well Paths", QIcon(":/Save.png"), addSeparatorBeforeMenu); +} + +//------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +int RimContextCommandBuilder::appendSubMenuWithCommands(caf::CmdFeatureMenuBuilder& menuBuilder, + const QStringList& commandCandidates, + const QString& menuLabel, + const QIcon& menuIcon /*= QIcon()*/, + bool addSeparatorBeforeMenu /*=false*/) +{ + int actualCommandsAdded = 0; + QStringList validCommands; + for (QString candidate : commandCandidates) + { + if (candidate == "Separator") + { + validCommands << candidate; + } + else + { + if (caf::CmdFeatureManager::instance()->getCommandFeature(candidate.toStdString())->canFeatureBeExecuted() && + !menuBuilder.isCmdFeatureAdded(candidate)) + { + validCommands << candidate; + actualCommandsAdded++; + } + } + } + + if (actualCommandsAdded > 0) + { + if (addSeparatorBeforeMenu) + { + menuBuilder << "Separator"; + } + menuBuilder.subMenuStart(menuLabel, menuIcon); + + for (int i = 0; i < validCommands.size(); ++i) + { + bool firstOrLast = i == 0 || i == validCommands.size() - 1; + if (!firstOrLast || validCommands[i] != "Separator") + { + menuBuilder << validCommands[i]; + } + } + + menuBuilder.subMenuEnd(); + } + return actualCommandsAdded; +} \ No newline at end of file diff --git a/ApplicationCode/ProjectDataModel/RimContextCommandBuilder.h b/ApplicationCode/ProjectDataModel/RimContextCommandBuilder.h index 3cee744d61..09158ba19e 100644 --- a/ApplicationCode/ProjectDataModel/RimContextCommandBuilder.h +++ b/ApplicationCode/ProjectDataModel/RimContextCommandBuilder.h @@ -19,11 +19,15 @@ #pragma once +#include #include namespace caf { class CmdFeatureMenuBuilder; } + +class QString; +class QStringList; class QMenu; class RimWellPath; class RimScriptCollection; @@ -41,4 +45,14 @@ class RimContextCommandBuilder static std::vector allWellPaths(); static void createExecuteScriptForCasesFeatureMenu(caf::CmdFeatureMenuBuilder& menuBuilder); static void appendScriptItems(caf::CmdFeatureMenuBuilder& menuBuilder, RimScriptCollection* scriptCollection); + + static int appendImportMenu(caf::CmdFeatureMenuBuilder& menuBuilder, bool addSeparatorBeforeMenu = false); + static int appendCreateCompletions(caf::CmdFeatureMenuBuilder& menuBuilder, bool addSeparatorBeforeMenu = false); + static int appendExportCompletions(caf::CmdFeatureMenuBuilder& menuBuilder, bool addSeparatorBeforeMenu = false); + static int appendExportWellPaths(caf::CmdFeatureMenuBuilder& menuBuilder, bool addSeparatorBeforeMenu = false); + static int appendSubMenuWithCommands(caf::CmdFeatureMenuBuilder& menuBuilder, + const QStringList& commandCandidates, + const QString& menuLabel, + const QIcon& menuIcon = QIcon(), + bool addSeparatorBeforeMenu = false); }; diff --git a/ApplicationCode/ProjectDataModel/RimContourMapNameConfig.cpp b/ApplicationCode/ProjectDataModel/RimContourMapNameConfig.cpp deleted file mode 100644 index d4b8478be0..0000000000 --- a/ApplicationCode/ProjectDataModel/RimContourMapNameConfig.cpp +++ /dev/null @@ -1,97 +0,0 @@ -///////////////////////////////////////////////////////////////////////////////// -// -// Copyright (C) 2018- Equinor ASA -// -// ResInsight 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 3 of the License, or -// (at your option) any later version. -// -// ResInsight 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 at -// for more details. -// -///////////////////////////////////////////////////////////////////////////////// - -#include "RimContourMapNameConfig.h" - -//================================================================================================== -/// -/// -//================================================================================================== - -CAF_PDM_SOURCE_INIT(RimContourMapNameConfig, "RimContourMapNameConfig"); - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -RimContourMapNameConfig::RimContourMapNameConfig(const RimNameConfigHolderInterface* configHolder) - : RimNameConfig(configHolder) -{ - CAF_PDM_InitObject("Contour Map Name Generator", "", "", ""); - - CAF_PDM_InitField(&m_addCaseName, "AddCaseName", true, "Add Case Name", "", "", ""); - CAF_PDM_InitField(&m_addAggregationType, "AddAggregationType", true, "Add Aggregation Type", "", "", ""); - CAF_PDM_InitField(&m_addProperty, "AddProperty", true, "Add Property Type", "", "", ""); - CAF_PDM_InitField(&m_addSampleSpacing, "AddSampleSpacing", false, "Add Sample Spacing", "", "", ""); - - m_customName = "Contour Map"; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -bool RimContourMapNameConfig::addCaseName() const -{ - return m_addCaseName(); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -bool RimContourMapNameConfig::addAggregationType() const -{ - return m_addAggregationType(); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -bool RimContourMapNameConfig::addProperty() const -{ - return m_addProperty(); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -bool RimContourMapNameConfig::addSampleSpacing() const -{ - return m_addSampleSpacing(); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RimContourMapNameConfig::enableAllAutoNameTags(bool enable) -{ - m_addCaseName = enable; - m_addAggregationType = enable; - m_addProperty = enable; - m_addSampleSpacing = enable; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RimContourMapNameConfig::defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering) -{ - RimNameConfig::defineUiOrdering(uiConfigName, uiOrdering); - uiOrdering.add(&m_addCaseName); - uiOrdering.add(&m_addAggregationType); - uiOrdering.add(&m_addProperty); - uiOrdering.add(&m_addSampleSpacing); -} diff --git a/ApplicationCode/ProjectDataModel/RimContourMapNameConfig.h b/ApplicationCode/ProjectDataModel/RimContourMapNameConfig.h deleted file mode 100644 index 9fc9c61a7d..0000000000 --- a/ApplicationCode/ProjectDataModel/RimContourMapNameConfig.h +++ /dev/null @@ -1,51 +0,0 @@ -///////////////////////////////////////////////////////////////////////////////// -// -// Copyright (C) 2018- Equinor ASA -// -// ResInsight 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 3 of the License, or -// (at your option) any later version. -// -// ResInsight 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 at -// for more details. -// -///////////////////////////////////////////////////////////////////////////////// - -#pragma once - -#include "RimNameConfig.h" - -//================================================================================================== -/// -/// -//================================================================================================== -class RimContourMapNameConfig : public RimNameConfig -{ - CAF_PDM_HEADER_INIT; - -public: - RimContourMapNameConfig(const RimNameConfigHolderInterface* configHolder = nullptr); - - bool addCaseName() const; - bool addAggregationType() const; - bool addProperty() const; - bool addSampleSpacing() const; - - void enableAllAutoNameTags(bool enable) override; - -protected: - void defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering) override; - -private: - caf::PdmField m_addCaseName; - caf::PdmField m_addAggregationType; - caf::PdmField m_addProperty; - caf::PdmField m_addSampleSpacing; -}; - - diff --git a/ApplicationCode/ProjectDataModel/RimContourMapProjection.cpp b/ApplicationCode/ProjectDataModel/RimContourMapProjection.cpp index d7fa52466b..e60aab03c1 100644 --- a/ApplicationCode/ProjectDataModel/RimContourMapProjection.cpp +++ b/ApplicationCode/ProjectDataModel/RimContourMapProjection.cpp @@ -1,93 +1,99 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2018- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + #include "RimContourMapProjection.h" #include "RiaWeightedGeometricMeanCalculator.h" #include "RiaWeightedHarmonicMeanCalculator.h" #include "RiaWeightedMeanCalculator.h" -#include "RigActiveCellInfo.h" -#include "RigCaseCellResultsData.h" -#include "RigCell.h" #include "RigCellGeometryTools.h" -#include "RigEclipseCaseData.h" #include "RigHexIntersectionTools.h" -#include "RigMainGrid.h" -#include "RigResultAccessor.h" -#include "RigResultAccessorFactory.h" - -#include "RivReservoirViewPartMgr.h" - -#include "RimCellRangeFilterCollection.h" -#include "RimContourMapView.h" -#include "RimEclipseCellColors.h" -#include "RimEclipseView.h" -#include "RimEclipseResultCase.h" -#include "RimEclipseResultDefinition.h" + +#include "RimCase.h" +#include "RimGridView.h" #include "RimProject.h" #include "RimRegularLegendConfig.h" +#include "RimTextAnnotation.h" #include "cafContourLines.h" #include "cafPdmUiDoubleSliderEditor.h" #include "cafPdmUiTreeOrdering.h" +#include "cafProgressInfo.h" #include "cvfArray.h" #include "cvfCellRange.h" #include "cvfGeometryTools.h" +#include "cvfGeometryUtils.h" #include "cvfScalarMapper.h" #include "cvfStructGridGeometryGenerator.h" #include +#include namespace caf { - template<> - void RimContourMapProjection::ResultAggregation::setUp() - { - addItem(RimContourMapProjection::RESULTS_OIL_COLUMN, "OIL_COLUMN", "Oil Column"); - addItem(RimContourMapProjection::RESULTS_GAS_COLUMN, "GAS_COLUMN", "Gas Column"); - addItem(RimContourMapProjection::RESULTS_HC_COLUMN, "HC_COLUMN", "Hydrocarbon Column"); +template<> +void RimContourMapProjection::ResultAggregation::setUp() +{ + addItem(RimContourMapProjection::RESULTS_OIL_COLUMN, "OIL_COLUMN", "Oil Column"); + addItem(RimContourMapProjection::RESULTS_GAS_COLUMN, "GAS_COLUMN", "Gas Column"); + addItem(RimContourMapProjection::RESULTS_HC_COLUMN, "HC_COLUMN", "Hydrocarbon Column"); - addItem(RimContourMapProjection::RESULTS_MEAN_VALUE, "MEAN_VALUE", "Arithmetic Mean"); - addItem(RimContourMapProjection::RESULTS_HARM_VALUE, "HARM_VALUE", "Harmonic Mean"); - addItem(RimContourMapProjection::RESULTS_GEOM_VALUE, "GEOM_VALUE", "Geometric Mean"); - addItem(RimContourMapProjection::RESULTS_VOLUME_SUM, "VOLUME_SUM", "Volume Weighted Sum"); - addItem(RimContourMapProjection::RESULTS_SUM, "SUM", "Sum"); + addItem(RimContourMapProjection::RESULTS_MEAN_VALUE, "MEAN_VALUE", "Arithmetic Mean"); + addItem(RimContourMapProjection::RESULTS_HARM_VALUE, "HARM_VALUE", "Harmonic Mean"); + addItem(RimContourMapProjection::RESULTS_GEOM_VALUE, "GEOM_VALUE", "Geometric Mean"); + addItem(RimContourMapProjection::RESULTS_VOLUME_SUM, "VOLUME_SUM", "Volume Weighted Sum"); + addItem(RimContourMapProjection::RESULTS_SUM, "SUM", "Sum"); - addItem(RimContourMapProjection::RESULTS_TOP_VALUE, "TOP_VALUE", "Top Value"); - addItem(RimContourMapProjection::RESULTS_MIN_VALUE, "MIN_VALUE", "Min Value"); - addItem(RimContourMapProjection::RESULTS_MAX_VALUE, "MAX_VALUE", "Max Value"); + addItem(RimContourMapProjection::RESULTS_TOP_VALUE, "TOP_VALUE", "Top Value"); + addItem(RimContourMapProjection::RESULTS_MIN_VALUE, "MIN_VALUE", "Min Value"); + addItem(RimContourMapProjection::RESULTS_MAX_VALUE, "MAX_VALUE", "Max Value"); - setDefault(RimContourMapProjection::RESULTS_MEAN_VALUE); - } + setDefault(RimContourMapProjection::RESULTS_MEAN_VALUE); } -CAF_PDM_SOURCE_INIT(RimContourMapProjection, "RimContourMapProjection"); +} // namespace caf +CAF_PDM_ABSTRACT_SOURCE_INIT(RimContourMapProjection, "RimContourMapProjection"); //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- RimContourMapProjection::RimContourMapProjection() - : m_pickPoint(cvf::Vec2d::UNDEFINED), - m_mapSize(cvf::Vec2ui(0u, 0u)), - m_sampleSpacing(-1.0) + : m_pickPoint(cvf::Vec2d::UNDEFINED) + , m_mapSize(cvf::Vec2ui(0u, 0u)) + , m_sampleSpacing(-1.0) + , m_currentResultTimestep(-1) + , m_minResultAllTimeSteps(std::numeric_limits::infinity()) + , m_maxResultAllTimeSteps(-std::numeric_limits::infinity()) { - CAF_PDM_InitObject("RimContourMapProjection", ":/draw_style_meshlines_24x24.png", "", ""); + CAF_PDM_InitObject("RimContourMapProjection", ":/2DMapProjection16x16.png", "", ""); - CAF_PDM_InitField(&m_relativeSampleSpacing, "SampleSpacing", 0.75, "Sample Spacing Factor", "", "", ""); + CAF_PDM_InitField(&m_relativeSampleSpacing, "SampleSpacing", 0.8, "Sample Spacing Factor", "", "", ""); m_relativeSampleSpacing.uiCapability()->setUiEditorTypeName(caf::PdmUiDoubleSliderEditor::uiEditorTypeName()); CAF_PDM_InitFieldNoDefault(&m_resultAggregation, "ResultAggregation", "Result Aggregation", "", "", ""); CAF_PDM_InitField(&m_showContourLines, "ContourLines", true, "Show Contour Lines", "", "", ""); + CAF_PDM_InitField(&m_showContourLabels, "ContourLabels", true, "Show Contour Labels", "", "", ""); + CAF_PDM_InitField(&m_smoothContourLines, "SmoothContourLines", true, "Smooth Contour Lines", "", "", ""); - CAF_PDM_InitField(&m_weightByParameter, "WeightByParameter", false, "Weight by Result Parameter", "", "", ""); - CAF_PDM_InitFieldNoDefault(&m_weightingResult, "WeightingResult", "", "", "", ""); - m_weightingResult.uiCapability()->setUiHidden(true); - m_weightingResult.uiCapability()->setUiTreeChildrenHidden(true); - m_weightingResult = new RimEclipseResultDefinition; - m_weightingResult->findField("MResultType")->uiCapability()->setUiName("Result Type"); setName("Map Projection"); nameField()->uiCapability()->setUiReadOnly(true); - - m_resultAccessor = new RigHugeValResultAccessor; } //-------------------------------------------------------------------------------------------------- @@ -95,202 +101,120 @@ RimContourMapProjection::RimContourMapProjection() //-------------------------------------------------------------------------------------------------- RimContourMapProjection::~RimContourMapProjection() { - } - //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RimContourMapProjection::generateVertices(cvf::Vec3fArray* vertices, const caf::DisplayCoordTransform* displayCoordTransform) +void RimContourMapProjection::generateResultsIfNecessary(int timeStep) { - CVF_ASSERT(vertices); - size_t nVertices = numberOfVertices(); - vertices->resize(nVertices); + caf::ProgressInfo progress(100, "Generate Results", true); -#pragma omp parallel for - for (int index = 0; index < static_cast(nVertices); ++index) - { - cvf::Vec2ui ij = ijFromVertexIndex(index); - cvf::Vec2d globalPos = globalCellCenterPosition(ij.x(), ij.y()); - // Shift away from sample point to vertex - globalPos.x() -= m_sampleSpacing * 0.5; - globalPos.y() -= m_sampleSpacing * 0.5; + updateGridInformation(); + progress.setProgress(10); - cvf::Vec3d globalVertexPos(globalPos, m_fullBoundingBox.min().z() - 1.0); - cvf::Vec3f displayVertexPos(displayCoordTransform->transformToDisplayCoord(globalVertexPos)); - (*vertices)[index] = displayVertexPos; + if (gridMappingNeedsUpdating() || mapCellVisibilityNeedsUpdating()) + { + clearResults(); + m_projected3dGridIndices = generateGridMapping(); + progress.setProgress(20); + m_mapCellVisibility = getMapCellVisibility(); + progress.setProgress(30); + } + else + { + progress.setProgress(30); } -} + if (resultVariableChanged()) + { + clearResults(); + clearTimeStepRange(); + } + if (resultsNeedsUpdating(timeStep)) + { + clearGeometry(); + m_aggregatedResults = generateResults(timeStep); + progress.setProgress(80); + generateVertexResults(); + } + progress.setProgress(100); + m_currentResultTimestep = timeStep; +} //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -RimContourMapProjection::ContourPolygons RimContourMapProjection::generateContourPolygons(const caf::DisplayCoordTransform* displayCoordTransform) -{ - std::vector> contourPolygons; - if (minValue() != std::numeric_limits::infinity() && - maxValue() != -std::numeric_limits::infinity() && - std::fabs(maxValue() - minValue()) > 1.0e-8) - { - std::vector contourLevels; - if (legendConfig()->mappingMode() != RimRegularLegendConfig::CATEGORY_INTEGER) - { - legendConfig()->scalarMapper()->majorTickValues(&contourLevels); - int nContourLevels = static_cast(contourLevels.size()); - if (nContourLevels > 2) - { - if (legendConfig()->mappingMode() == RimRegularLegendConfig::LINEAR_CONTINUOUS || legendConfig()->mappingMode() == RimRegularLegendConfig::LINEAR_DISCRETE) - { - // Slight fudge to avoid very jagged contour lines at the very edge - // Shift the contour levels inwards. - contourLevels[0] += (contourLevels[1] - contourLevels[0]) * 0.1; - contourLevels[nContourLevels - 1] -= (contourLevels[nContourLevels - 1] - contourLevels[nContourLevels - 2]) * 0.1; - } - std::vector> contourLines; - caf::ContourLines::create(m_aggregatedVertexResults, xVertexPositions(), yVertexPositions(), contourLevels, &contourLines); +void RimContourMapProjection::generateGeometryIfNecessary() +{ + caf::ProgressInfo progress(100, "Generate Geometry", true); - contourPolygons.reserve(contourLines.size()); - for (size_t i = 0; i < contourLines.size(); ++i) - { - if (!contourLines[i].empty()) - { - cvf::ref contourPolygon = new cvf::Vec3fArray(contourLines[i].size()); - for (size_t j = 0; j < contourLines[i].size(); ++j) - { - cvf::Vec3d contourPoint3d = cvf::Vec3d(contourLines[i][j], m_fullBoundingBox.min().z()); - cvf::Vec3d displayPoint3d = displayCoordTransform->transformToDisplayCoord(contourPoint3d); - (*contourPolygon)[j] = cvf::Vec3f(displayPoint3d); - } - contourPolygons.push_back(contourPolygon); - } - } - } - } + if (geometryNeedsUpdating()) + { + generateContourPolygons(); + progress.setProgress(25); + generateTrianglesWithVertexValues(); } - return contourPolygons; + progress.setProgress(100); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -cvf::ref -RimContourMapProjection::generatePickPointPolygon(const caf::DisplayCoordTransform* displayCoordTransform) +std::vector RimContourMapProjection::generatePickPointPolygon() { - cvf::ref pickPolygon; + std::vector points; + if (!m_pickPoint.isUndefined()) { - double zPos = m_fullBoundingBox.min().z(); - - std::vector points; { - cvf::Vec2d gridorigin(m_fullBoundingBox.min().x(), m_fullBoundingBox.min().y()); - - cvf::Vec2d localPickPoint = m_pickPoint - gridorigin; - - cvf::Vec2d cellDiagonal(m_sampleSpacing*0.5, m_sampleSpacing*0.5); - cvf::Vec2ui pickedCell = ijFromLocalPos(localPickPoint); - cvf::Vec2d cellCenter = globalCellCenterPosition(pickedCell.x(), pickedCell.y()); + cvf::Vec2d cellDiagonal(m_sampleSpacing * 0.5, m_sampleSpacing * 0.5); + cvf::Vec2ui pickedCell = ijFromLocalPos(m_pickPoint); + cvf::Vec2d cellCenter = cellCenterPosition(pickedCell.x(), pickedCell.y()); cvf::Vec2d cellCorner = cellCenter - cellDiagonal; #ifndef NDEBUG - points.push_back(cvf::Vec3d(cellCorner, zPos)); - points.push_back(cvf::Vec3d(cellCorner + cvf::Vec2d(m_sampleSpacing, 0.0), zPos)); - points.push_back(cvf::Vec3d(cellCorner + cvf::Vec2d(m_sampleSpacing, 0.0), zPos)); - points.push_back(cvf::Vec3d(cellCorner + cvf::Vec2d(m_sampleSpacing, m_sampleSpacing), zPos)); - points.push_back(cvf::Vec3d(cellCorner + cvf::Vec2d(m_sampleSpacing, m_sampleSpacing), zPos)); - points.push_back(cvf::Vec3d(cellCorner + cvf::Vec2d(0.0, m_sampleSpacing), zPos)); - points.push_back(cvf::Vec3d(cellCorner + cvf::Vec2d(0.0, m_sampleSpacing), zPos)); - points.push_back(cvf::Vec3d(cellCorner, zPos)); + points.push_back(cvf::Vec3d(cellCorner, 0.0)); + points.push_back(cvf::Vec3d(cellCorner + cvf::Vec2d(m_sampleSpacing, 0.0), 0.0)); + points.push_back(cvf::Vec3d(cellCorner + cvf::Vec2d(m_sampleSpacing, 0.0), 0.0)); + points.push_back(cvf::Vec3d(cellCorner + cvf::Vec2d(m_sampleSpacing, m_sampleSpacing), 0.0)); + points.push_back(cvf::Vec3d(cellCorner + cvf::Vec2d(m_sampleSpacing, m_sampleSpacing), 0.0)); + points.push_back(cvf::Vec3d(cellCorner + cvf::Vec2d(0.0, m_sampleSpacing), 0.0)); + points.push_back(cvf::Vec3d(cellCorner + cvf::Vec2d(0.0, m_sampleSpacing), 0.0)); + points.push_back(cvf::Vec3d(cellCorner, 0.0)); #endif - points.push_back(cvf::Vec3d(m_pickPoint - cvf::Vec2d(0.5 * m_sampleSpacing, 0.0), zPos)); - points.push_back(cvf::Vec3d(m_pickPoint + cvf::Vec2d(0.5 * m_sampleSpacing, 0.0), zPos)); - points.push_back(cvf::Vec3d(m_pickPoint - cvf::Vec2d(0.0, 0.5 * m_sampleSpacing), zPos)); - points.push_back(cvf::Vec3d(m_pickPoint + cvf::Vec2d(0.0, 0.5 * m_sampleSpacing), zPos)); - } - - pickPolygon = new cvf::Vec3fArray(points.size()); - - for (size_t i = 0; i < points.size(); ++i) - { - cvf::Vec3d displayPoint = displayCoordTransform->transformToDisplayCoord(points[i]); - (*pickPolygon)[i] = cvf::Vec3f(displayPoint); + points.push_back(cvf::Vec3d(m_pickPoint - cvf::Vec2d(0.5 * m_sampleSpacing, 0.0), 0.0)); + points.push_back(cvf::Vec3d(m_pickPoint + cvf::Vec2d(0.5 * m_sampleSpacing, 0.0), 0.0)); + points.push_back(cvf::Vec3d(m_pickPoint - cvf::Vec2d(0.0, 0.5 * m_sampleSpacing), 0.0)); + points.push_back(cvf::Vec3d(m_pickPoint + cvf::Vec2d(0.0, 0.5 * m_sampleSpacing), 0.0)); } } - return pickPolygon; + return points; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RimContourMapProjection::generateResults() +void RimContourMapProjection::clearGeometry() { - updateGridInformation(); - - generateGridMapping(); - - size_t nCells = numberOfCells(); - size_t nVertices = numberOfVertices(); - - m_aggregatedResults = std::vector(nCells, std::numeric_limits::infinity()); - m_aggregatedVertexResults = std::vector(nVertices, std::numeric_limits::infinity()); - int timeStep = view()->currentTimeStep(); - RimEclipseCellColors* cellColors = view()->cellResult(); - - RimEclipseResultCase* eclipseCase = this->eclipseCase(); - { - if (!cellColors->isTernarySaturationSelected()) - { - RigCaseCellResultsData* resultData = eclipseCase->results(RiaDefines::MATRIX_MODEL); - - if (isColumnResult()) - { - resultData->findOrLoadScalarResult(RiaDefines::STATIC_NATIVE, "PORO"); - resultData->findOrLoadScalarResult(RiaDefines::STATIC_NATIVE, "NTG"); - resultData->findOrLoadScalarResult(RiaDefines::STATIC_NATIVE, "DZ"); - if (m_resultAggregation == RESULTS_OIL_COLUMN || m_resultAggregation == RESULTS_HC_COLUMN) - { - resultData->findOrLoadScalarResultForTimeStep(RiaDefines::DYNAMIC_NATIVE, "SOIL", timeStep); - } - if (m_resultAggregation == RESULTS_GAS_COLUMN || m_resultAggregation == RESULTS_HC_COLUMN) - { - resultData->findOrLoadScalarResultForTimeStep(RiaDefines::DYNAMIC_NATIVE, "SGAS", timeStep); - } - } - else - { - m_resultAccessor = RigResultAccessorFactory::createFromResultDefinition(eclipseCase->eclipseCaseData(), 0, timeStep, cellColors); - - if (m_resultAccessor.isNull()) - { - m_resultAccessor = new RigHugeValResultAccessor; - } - } - -#pragma omp parallel for - for (int index = 0; index < static_cast(nCells); ++index) - { - cvf::Vec2ui ij = ijFromCellIndex(index); - m_aggregatedResults[index] = calculateValueInCell(ij.x(), ij.y()); - } + m_contourPolygons.clear(); + m_trianglesWithVertexValues.clear(); +} -#pragma omp parallel for - for (int index = 0; index < static_cast(nVertices); ++index) - { - cvf::Vec2ui ij = ijFromVertexIndex(index); - m_aggregatedVertexResults[index] = calculateValueAtVertex(ij.x(), ij.y()); - } - } - } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +const std::vector& RimContourMapProjection::contourPolygons() const +{ + return m_contourPolygons; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -RimContourMapProjection::ResultAggregation RimContourMapProjection::resultAggregation() const +const std::vector& RimContourMapProjection::trianglesWithVertexValues() { - return m_resultAggregation(); + return m_trianglesWithVertexValues; } //-------------------------------------------------------------------------------------------------- @@ -325,69 +249,21 @@ QString RimContourMapProjection::resultAggregationText() const return m_resultAggregation().uiText(); } -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -QString RimContourMapProjection::resultDescriptionText() const -{ - QString resultText = resultAggregationText(); - if (!isColumnResult()) - { - resultText += QString(", %1").arg(view()->cellResult()->resultVariable()); - } - - return resultText; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -QString RimContourMapProjection::weightingParameter() const -{ - QString parameter = "None"; - if (m_weightByParameter() && !m_weightingResult->isTernarySaturationSelected()) - { - parameter = m_weightingResult->resultVariableUiShortName(); - } - return parameter; -} - //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- double RimContourMapProjection::maxValue() const { - double maxV = -std::numeric_limits::infinity(); - - int nVertices = numberOfCells(); - - for (int index = 0; index < nVertices; ++index) - { - if (m_aggregatedResults[index] != std::numeric_limits::infinity()) - { - maxV = std::max(maxV, m_aggregatedResults[index]); - } - } - return maxV; + return maxValue(m_aggregatedResults); } + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- double RimContourMapProjection::minValue() const { - double minV = std::numeric_limits::infinity(); - - int nVertices = numberOfCells(); - - for (int index = 0; index < nVertices; ++index) - { - if (m_aggregatedResults[index] != std::numeric_limits::infinity()) - { - minV = std::min(minV, m_aggregatedResults[index]); - } - } - return minV; + return minValue(m_aggregatedResults); } //-------------------------------------------------------------------------------------------------- @@ -405,9 +281,7 @@ double RimContourMapProjection::sumAllValues() const { double sum = 0.0; - int nVertices = numberOfCells(); - - for (int index = 0; index < nVertices; ++index) + for (size_t index = 0; index < m_aggregatedResults.size(); ++index) { if (m_aggregatedResults[index] != std::numeric_limits::infinity()) { @@ -441,8 +315,7 @@ cvf::Vec2ui RimContourMapProjection::numberOfVerticesIJ() const //-------------------------------------------------------------------------------------------------- bool RimContourMapProjection::isColumnResult() const { - return m_resultAggregation() == RESULTS_OIL_COLUMN || - m_resultAggregation() == RESULTS_GAS_COLUMN || + return m_resultAggregation() == RESULTS_OIL_COLUMN || m_resultAggregation() == RESULTS_GAS_COLUMN || m_resultAggregation() == RESULTS_HC_COLUMN; } @@ -457,62 +330,6 @@ double RimContourMapProjection::valueAtVertex(uint i, uint j) const return m_aggregatedVertexResults.at(index); } return std::numeric_limits::infinity(); - -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -bool RimContourMapProjection::hasResultAtVertex(uint i, uint j) const -{ - size_t index = vertexIndexFromIJ(i, j); - return m_aggregatedVertexResults[index] != std::numeric_limits::infinity(); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -RimRegularLegendConfig* RimContourMapProjection::legendConfig() const -{ - return view()->cellResult()->legendConfig(); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RimContourMapProjection::updateLegend() -{ - RimEclipseCellColors* cellColors = view()->cellResult(); - - if (getLegendRangeFrom3dGrid()) - { - cellColors->updateLegendData(view()->currentTimeStep(), legendConfig()); - } - else - { - double minVal = minValue(); - double maxVal = maxValue(); - - legendConfig()->setAutomaticRanges(minVal, maxVal, minVal, maxVal); - } - - if (m_resultAggregation() == RESULTS_OIL_COLUMN || - m_resultAggregation() == RESULTS_GAS_COLUMN || - m_resultAggregation() == RESULTS_HC_COLUMN) - { - legendConfig()->setTitle(QString("Map Projection\n%1").arg(m_resultAggregation().uiText())); - } - else - { - QString projectionLegendText = QString("Map Projection\n%1").arg(m_resultAggregation().uiText()); - if (weightingParameter() != "None") - { - projectionLegendText += QString("(W: %1)").arg(weightingParameter()); - } - projectionLegendText += QString("\nResult: %1").arg(cellColors->resultVariableUiShortName()); - - legendConfig()->setTitle(projectionLegendText); - } } //-------------------------------------------------------------------------------------------------- @@ -549,58 +366,25 @@ size_t RimContourMapProjection::numberOfVertices() const return static_cast(gridSize.x()) * static_cast(gridSize.y()); } - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RimContourMapProjection::updatedWeightingResult() -{ - this->updateConnectedEditors(); - this->generateResults(); - this->updateLegend(); - - RimProject* proj; - this->firstAncestorOrThisOfTypeAsserted(proj); - proj->scheduleCreateDisplayModelAndRedrawAllViews(); -} - //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -bool RimContourMapProjection::checkForMapIntersection(const cvf::Vec3d& localPoint3d, cvf::Vec2d* contourMapPoint, cvf::Vec2ui* contourMapCell, double* valueAtPoint) const +bool RimContourMapProjection::checkForMapIntersection(const cvf::Vec3d& localPoint3d, + cvf::Vec2d* contourMapPoint, + double* valueAtPoint) const { CVF_TIGHT_ASSERT(contourMapPoint); CVF_TIGHT_ASSERT(valueAtPoint); - cvf::Vec3d localPos3d(localPoint3d.x(), localPoint3d.y(), 0.0); - cvf::Vec2d localPos2d(localPos3d.x(), localPos3d.y()); - cvf::Vec2ui pickedCell = ijFromLocalPos(localPos2d); - *contourMapCell = pickedCell; - - if (true || hasResultInCell(pickedCell.x(), pickedCell.y())) - { - cvf::Vec2d gridorigin(m_fullBoundingBox.min().x(), m_fullBoundingBox.min().y()); - cvf::Vec2d cellCenter = globalCellCenterPosition(pickedCell.x(), pickedCell.y()) - gridorigin; - std::array x; - x[0] = cvf::Vec3d(cellCenter + cvf::Vec2d(-m_sampleSpacing * 0.5, -m_sampleSpacing * 0.5), 0.0); - x[1] = cvf::Vec3d(cellCenter + cvf::Vec2d(m_sampleSpacing*0.5, -m_sampleSpacing * 0.5), 0.0); - x[2] = cvf::Vec3d(cellCenter + cvf::Vec2d(m_sampleSpacing*0.5, m_sampleSpacing * 0.5), 0.0); - x[3] = cvf::Vec3d(cellCenter + cvf::Vec2d(-m_sampleSpacing * 0.5, m_sampleSpacing * 0.5), 0.0); - cvf::Vec4d baryCentricCoords = cvf::GeometryTools::barycentricCoords(x[0], x[1], x[2], x[3], localPos3d); - - std::array v; - v[0] = pickedCell; - v[1] = cvf::Vec2ui(pickedCell.x() + 1u, pickedCell.y()); - v[2] = cvf::Vec2ui(pickedCell.x() + 1u, pickedCell.y() + 1u); - v[3] = cvf::Vec2ui(pickedCell.x(), pickedCell.y() + 1u); - - double value = 0.0; - for (int i = 0; i < 4; ++i) - { - value += baryCentricCoords[i] * valueAtVertex(v[i].x(), v[i].y()); - } - *valueAtPoint = value; - *contourMapPoint = localPos2d + gridorigin; + cvf::Vec3d mapPos3d = localPoint3d - m_expandedBoundingBox.min() + m_gridBoundingBox.min(); + cvf::Vec2d mapPos2d(mapPos3d.x(), mapPos3d.y()); + cvf::Vec2d gridorigin(m_expandedBoundingBox.min().x(), m_expandedBoundingBox.min().y()); + + double value = interpolateValue(mapPos2d); + if (value != std::numeric_limits::infinity()) + { + *valueAtPoint = value; + *contourMapPoint = mapPos2d + gridorigin; return true; } @@ -610,195 +394,49 @@ bool RimContourMapProjection::checkForMapIntersection(const cvf::Vec3d& localPoi //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RimContourMapProjection::setPickPoint(cvf::Vec2d pickedPoint) -{ - m_pickPoint = pickedPoint; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RimContourMapProjection::fieldChangedByUi(const caf::PdmFieldHandle* changedField, - const QVariant& oldValue, - const QVariant& newValue) -{ - legendConfig()->disableAllTimeStepsRange(!getLegendRangeFrom3dGrid()); - - m_weightingResult->loadResult(); - - view()->updateConnectedEditors(); - - RimProject* proj; - firstAncestorOrThisOfTypeAsserted(proj); - proj->scheduleCreateDisplayModelAndRedrawAllViews(); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RimContourMapProjection::defineEditorAttribute(const caf::PdmFieldHandle* field, - QString uiConfigName, - caf::PdmUiEditorAttribute* attribute) -{ - if (&m_relativeSampleSpacing == field) - { - caf::PdmUiDoubleSliderEditorAttribute* myAttr = dynamic_cast(attribute); - if (myAttr) - { - myAttr->m_minimum = 0.25; - myAttr->m_maximum = 2.0; - } - } -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RimContourMapProjection::defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering) +void RimContourMapProjection::setPickPoint(cvf::Vec2d globalPickPoint) { - caf::PdmUiGroup* mainGroup = uiOrdering.addNewGroup("Projection Settings"); - mainGroup->add(&m_relativeSampleSpacing); - mainGroup->add(&m_showContourLines); - mainGroup->add(&m_resultAggregation); - - caf::PdmUiGroup* weightingGroup = uiOrdering.addNewGroup("Mean Weighting Options"); - weightingGroup->add(&m_weightByParameter); - weightingGroup->setCollapsedByDefault(true); - - m_weightByParameter.uiCapability()->setUiReadOnly(!isMeanResult()); - if (!isMeanResult()) - { - m_weightByParameter = false; - } - - if (m_weightByParameter()) - { - m_weightingResult->uiOrdering(uiConfigName, *weightingGroup); - } - - uiOrdering.skipRemainingFields(true); + m_pickPoint = globalPickPoint - origin2d(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RimContourMapProjection::defineUiTreeOrdering(caf::PdmUiTreeOrdering& uiTreeOrdering, QString uiConfigName /*= ""*/) +cvf::Vec3d RimContourMapProjection::origin3d() const { - uiTreeOrdering.skipRemainingChildren(true); + return m_expandedBoundingBox.min(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RimContourMapProjection::initAfterRead() +size_t RimContourMapProjection::gridResultIndex(size_t globalCellIdx) const { - legendConfig()->disableAllTimeStepsRange(!getLegendRangeFrom3dGrid()); - if (eclipseCase()) - { - m_weightingResult->setEclipseCase(eclipseCase()); - } + return globalCellIdx; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RimContourMapProjection::generateGridMapping() +double RimContourMapProjection::calculateValueInMapCell(uint i, uint j, const std::vector& gridCellValues) const { - m_cellGridIdxVisibility = view()->currentTotalCellVisibility(); - - int nCells = numberOfCells(); - m_projected3dGridIndices.resize(nCells); - - const std::vector* weightingResultValues = nullptr; - if (m_weightByParameter()) + const std::vector>& matchingCells = cellsAtIJ(i, j); + if (!matchingCells.empty()) { - size_t gridScalarResultIdx = m_weightingResult->scalarResultIndex(); - if (gridScalarResultIdx != cvf::UNDEFINED_SIZE_T) + switch (m_resultAggregation()) { - m_weightingResult->loadResult(); - int timeStep = 0; - if (m_weightingResult->hasDynamicResult()) + case RESULTS_TOP_VALUE: { - timeStep = view()->currentTimeStep(); - } - weightingResultValues = - &(m_weightingResult->currentGridCellResults()->cellScalarResults(gridScalarResultIdx)[timeStep]); - } - } - - if (isStraightSummationResult()) - { - for (int index = 0; index < nCells; ++index) - { - cvf::Vec2ui ij = ijFromCellIndex(index); - - cvf::Vec2d globalPos = globalCellCenterPosition(ij.x(), ij.y()); - m_projected3dGridIndices[index] = visibleCellsAndLengthInCellFrom2dPoint(globalPos, weightingResultValues); - } - } - else - { -#pragma omp parallel for - for (int index = 0; index < nCells; ++index) - { - cvf::Vec2ui ij = ijFromCellIndex(index); - - cvf::Vec2d globalPos = globalCellCenterPosition(ij.x(), ij.y()); - m_projected3dGridIndices[index] = visibleCellsAndOverlapVolumeFrom2dPoint(globalPos, weightingResultValues); - } - } -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -double RimContourMapProjection::valueInCell(uint i, uint j) const -{ - size_t index = cellIndexFromIJ(i, j); - if (index < numberOfCells()) - { - return m_aggregatedResults.at(index); - } - return std::numeric_limits::infinity(); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -bool RimContourMapProjection::hasResultInCell(uint i, uint j) const -{ - RimEclipseCellColors* cellColors = view()->cellResult(); - - if (cellColors->isTernarySaturationSelected()) - { - return false; - } - return !cellsAtIJ(i, j).empty(); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -double RimContourMapProjection::calculateValueInCell(uint i, uint j) const -{ - if (!isColumnResult()) - { - if (!view()->cellResult()->isFlowDiagOrInjectionFlooding() && - view()->cellResult()->scalarResultIndex() == cvf::UNDEFINED_SIZE_T) - { - return 0.0; // Special case of NONE-result. Show 0 all over to ensure we see something. - } - } - const std::vector>& matchingCells = cellsAtIJ(i, j); - if (!matchingCells.empty()) - { - switch (m_resultAggregation()) - { - case RESULTS_TOP_VALUE: - { - size_t cellIdx = matchingCells.front().first; - double cellValue = m_resultAccessor->cellScalarGlobIdx(cellIdx); - return cellValue; + for (auto cellIdxAndWeight : matchingCells) + { + size_t cellIdx = cellIdxAndWeight.first; + double cellValue = gridCellValues[cellIdx]; + if (cellValue != std::numeric_limits::infinity()) + { + return cellValue; + } + } + return std::numeric_limits::infinity(); } case RESULTS_MEAN_VALUE: { @@ -806,8 +444,11 @@ double RimContourMapProjection::calculateValueInCell(uint i, uint j) const for (auto cellIdxAndWeight : matchingCells) { size_t cellIdx = cellIdxAndWeight.first; - double cellValue = m_resultAccessor->cellScalarGlobIdx(cellIdx); - calculator.addValueAndWeight(cellValue, cellIdxAndWeight.second); + double cellValue = gridCellValues[cellIdx]; + if (cellValue != std::numeric_limits::infinity()) + { + calculator.addValueAndWeight(cellValue, cellIdxAndWeight.second); + } } if (calculator.validAggregatedWeight()) { @@ -821,12 +462,15 @@ double RimContourMapProjection::calculateValueInCell(uint i, uint j) const for (auto cellIdxAndWeight : matchingCells) { size_t cellIdx = cellIdxAndWeight.first; - double cellValue = m_resultAccessor->cellScalarGlobIdx(cellIdx); + double cellValue = gridCellValues[cellIdx]; if (cellValue < 1.0e-8) { return 0.0; } - calculator.addValueAndWeight(cellValue, cellIdxAndWeight.second); + if (cellValue != std::numeric_limits::infinity()) + { + calculator.addValueAndWeight(cellValue, cellIdxAndWeight.second); + } } if (calculator.validAggregatedWeight()) { @@ -840,12 +484,15 @@ double RimContourMapProjection::calculateValueInCell(uint i, uint j) const for (auto cellIdxAndWeight : matchingCells) { size_t cellIdx = cellIdxAndWeight.first; - double cellValue = m_resultAccessor->cellScalarGlobIdx(cellIdx); + double cellValue = gridCellValues[cellIdx]; if (std::fabs(cellValue) < 1.0e-8) { return 0.0; } - calculator.addValueAndWeight(cellValue, cellIdxAndWeight.second); + if (cellValue != std::numeric_limits::infinity()) + { + calculator.addValueAndWeight(cellValue, cellIdxAndWeight.second); + } } if (calculator.validAggregatedWeight()) { @@ -859,8 +506,15 @@ double RimContourMapProjection::calculateValueInCell(uint i, uint j) const for (auto cellIdxAndWeight : matchingCells) { size_t cellIdx = cellIdxAndWeight.first; - double cellValue = m_resultAccessor->cellScalarGlobIdx(cellIdx); - maxValue = std::max(maxValue, cellValue); + double cellValue = gridCellValues[cellIdx]; + if (cellValue != std::numeric_limits::infinity()) + { + maxValue = std::max(maxValue, cellValue); + } + } + if (maxValue == -std::numeric_limits::infinity()) + { + maxValue = std::numeric_limits::infinity(); } return maxValue; } @@ -870,224 +524,853 @@ double RimContourMapProjection::calculateValueInCell(uint i, uint j) const for (auto cellIdxAndWeight : matchingCells) { size_t cellIdx = cellIdxAndWeight.first; - double cellValue = m_resultAccessor->cellScalarGlobIdx(cellIdx); + double cellValue = gridCellValues[cellIdx]; minValue = std::min(minValue, cellValue); } return minValue; } case RESULTS_VOLUME_SUM: case RESULTS_SUM: + case RESULTS_OIL_COLUMN: + case RESULTS_GAS_COLUMN: + case RESULTS_HC_COLUMN: { double sum = 0.0; for (auto cellIdxAndWeight : matchingCells) { size_t cellIdx = cellIdxAndWeight.first; - double cellValue = m_resultAccessor->cellScalarGlobIdx(cellIdx); - sum += cellValue * cellIdxAndWeight.second; + double cellValue = gridCellValues[cellIdx]; + if (cellValue != std::numeric_limits::infinity()) + { + sum += cellValue * cellIdxAndWeight.second; + } } return sum; } - case RESULTS_OIL_COLUMN: - case RESULTS_GAS_COLUMN: - case RESULTS_HC_COLUMN: + default: + CVF_TIGHT_ASSERT(false); + } + } + return std::numeric_limits::infinity(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RimContourMapProjection::gridMappingNeedsUpdating() const +{ + if (m_projected3dGridIndices.size() != numberOfCells()) + { + return true; + } + + if (m_cellGridIdxVisibility.isNull()) + { + return true; + } + cvf::ref currentVisibility = getCellVisibility(); + + CVF_ASSERT(currentVisibility->size() == m_cellGridIdxVisibility->size()); + for (size_t i = 0; i < currentVisibility->size(); ++i) + { + if ((*currentVisibility)[i] != (*m_cellGridIdxVisibility)[i]) return true; + } + + return false; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RimContourMapProjection::resultsNeedsUpdating(int timeStep) const +{ + if (m_aggregatedResults.size() != numberOfCells()) + { + return true; + } + + if (m_aggregatedVertexResults.size() != numberOfVertices()) + { + return true; + } + + if (timeStep != m_currentResultTimestep) + { + return true; + } + return false; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RimContourMapProjection::geometryNeedsUpdating() const +{ + return m_contourPolygons.empty() || m_trianglesWithVertexValues.empty(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RimContourMapProjection::resultRangeIsValid() const +{ + if (m_minResultAllTimeSteps == std::numeric_limits::infinity() || + m_maxResultAllTimeSteps == -std::numeric_limits::infinity()) + { + return false; + } + return true; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimContourMapProjection::clearGridMapping() +{ + clearResults(); + clearTimeStepRange(); + m_projected3dGridIndices.clear(); + m_mapCellVisibility.clear(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimContourMapProjection::clearResults() +{ + clearGeometry(); + + m_aggregatedResults.clear(); + m_aggregatedVertexResults.clear(); + m_currentResultTimestep = -1; + + clearResultVariable(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimContourMapProjection::clearTimeStepRange() +{ + m_minResultAllTimeSteps = std::numeric_limits::infinity(); + m_maxResultAllTimeSteps = -std::numeric_limits::infinity(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +double RimContourMapProjection::maxValue(const std::vector& aggregatedResults) const +{ + double maxV = -std::numeric_limits::infinity(); + + for (size_t index = 0; index < aggregatedResults.size(); ++index) + { + if (aggregatedResults[index] != std::numeric_limits::infinity()) + { + maxV = std::max(maxV, aggregatedResults[index]); + } + } + return maxV; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +double RimContourMapProjection::minValue(const std::vector& aggregatedResults) const +{ + double minV = std::numeric_limits::infinity(); + + for (size_t index = 0; index < aggregatedResults.size(); ++index) + { + if (aggregatedResults[index] != std::numeric_limits::infinity()) + { + minV = std::min(minV, aggregatedResults[index]); + } + } + return minV; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::pair RimContourMapProjection::minmaxValuesAllTimeSteps() +{ + if (!resultRangeIsValid()) + { + clearTimeStepRange(); + + m_minResultAllTimeSteps = std::min(m_minResultAllTimeSteps, minValue(m_aggregatedResults)); + m_maxResultAllTimeSteps = std::max(m_maxResultAllTimeSteps, maxValue(m_aggregatedResults)); + + for (int i = 0; i < (int)baseView()->ownerCase()->timeStepStrings().size() - 1; ++i) + { + if (i != m_currentResultTimestep) + { + std::vector aggregatedResults = generateResults(i); + m_minResultAllTimeSteps = std::min(m_minResultAllTimeSteps, minValue(aggregatedResults)); + m_maxResultAllTimeSteps = std::max(m_maxResultAllTimeSteps, maxValue(aggregatedResults)); + } + } + } + return std::make_pair(m_minResultAllTimeSteps, m_maxResultAllTimeSteps); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +cvf::ref RimContourMapProjection::getCellVisibility() const +{ + return baseView()->currentTotalCellVisibility(); +} + +//-------------------------------------------------------------------------------------------------- +/// Empty default implementation +//-------------------------------------------------------------------------------------------------- +std::vector RimContourMapProjection::getMapCellVisibility() +{ + return std::vector(numberOfCells(), true); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RimContourMapProjection::mapCellVisibilityNeedsUpdating() +{ + std::vector mapCellVisiblity = getMapCellVisibility(); + return !(mapCellVisiblity == m_mapCellVisibility); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector>> RimContourMapProjection::generateGridMapping() +{ + m_cellGridIdxVisibility = getCellVisibility(); + + int nCells = numberOfCells(); + std::vector>> projected3dGridIndices(nCells); + + std::vector weightingResultValues = retrieveParameterWeights(); + + if (isStraightSummationResult()) + { +#pragma omp parallel for + for (int index = 0; index < nCells; ++index) + { + cvf::Vec2ui ij = ijFromCellIndex(index); + + cvf::Vec2d globalPos = cellCenterPosition(ij.x(), ij.y()) + origin2d(); + projected3dGridIndices[index] = cellRayIntersectionAndResults(globalPos, weightingResultValues); + } + } + else + { +#pragma omp parallel for + for (int index = 0; index < nCells; ++index) + { + cvf::Vec2ui ij = ijFromCellIndex(index); + + cvf::Vec2d globalPos = cellCenterPosition(ij.x(), ij.y()) + origin2d(); + projected3dGridIndices[index] = cellOverlapVolumesAndResults(globalPos, weightingResultValues); + } + } + + return projected3dGridIndices; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimContourMapProjection::generateVertexResults() +{ + size_t nCells = numberOfCells(); + if (nCells != m_aggregatedResults.size()) + return; + + size_t nVertices = numberOfVertices(); + m_aggregatedVertexResults = std::vector(nVertices, std::numeric_limits::infinity()); +#pragma omp parallel for + for (int index = 0; index < static_cast(nVertices); ++index) + { + cvf::Vec2ui ij = ijFromVertexIndex(index); + m_aggregatedVertexResults[index] = calculateValueAtVertex(ij.x(), ij.y()); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimContourMapProjection::generateTrianglesWithVertexValues() +{ + std::vector vertices = generateVertices(); + + cvf::Vec2ui patchSize = numberOfVerticesIJ(); + cvf::ref faceList = new cvf::UIntArray; + cvf::GeometryUtils::tesselatePatchAsTriangles(patchSize.x(), patchSize.y(), 0u, true, faceList.p()); + + bool discrete = false; + std::vector contourLevels; + if (legendConfig()->mappingMode() != RimRegularLegendConfig::CATEGORY_INTEGER) + { + legendConfig()->scalarMapper()->majorTickValues(&contourLevels); + if (legendConfig()->mappingMode() == RimRegularLegendConfig::LINEAR_DISCRETE || + legendConfig()->mappingMode() == RimRegularLegendConfig::LOG10_DISCRETE) + { + discrete = true; + } + } + + const double cellArea = m_sampleSpacing * m_sampleSpacing; + const double areaThreshold = 1.0e-5 * 0.5 * cellArea; + + std::vector>> subtractPolygons; + if (!m_contourPolygons.empty()) + { + subtractPolygons.resize(m_contourPolygons.size()); + for (size_t i = 0; i < m_contourPolygons.size() - 1; ++i) + { + for (size_t j = 0; j < m_contourPolygons[i + 1].size(); ++j) + { + subtractPolygons[i].push_back(m_contourPolygons[i + 1][j].vertices); + } + } + } + std::vector>> threadTriangles(omp_get_max_threads()); + +#pragma omp parallel + { + int myThread = omp_get_thread_num(); + threadTriangles[myThread].resize(std::max((size_t) 1, m_contourPolygons.size())); + +#pragma omp for schedule(dynamic) + for (int64_t i = 0; i < (int64_t)faceList->size(); i += 3) + { + std::vector triangle(3); + std::vector triangleWithValues(3); + bool anyValidVertex = false; + for (size_t n = 0; n < 3; ++n) + { + uint vn = (*faceList)[i + n]; + double value = vn < m_aggregatedVertexResults.size() ? m_aggregatedVertexResults[vn] + : std::numeric_limits::infinity(); + triangle[n] = vertices[vn]; + triangleWithValues[n] = cvf::Vec4d(vertices[vn], value); + if (value != std::numeric_limits::infinity()) + { + anyValidVertex = true; + } + } + + if (!anyValidVertex) + { + continue; + } + + if (m_contourPolygons.empty()) + { + threadTriangles[myThread][0].insert( + threadTriangles[myThread][0].end(), triangleWithValues.begin(), triangleWithValues.end()); + continue; + } + + bool outsideOuterLimit = false; + for (size_t c = 0; c < m_contourPolygons.size() && !outsideOuterLimit; ++c) + { + std::vector> intersectPolygons; + for (size_t j = 0; j < m_contourPolygons[c].size(); ++j) + { + bool containsAtLeastOne = false; + for (size_t t = 0; t < 3; ++t) + { + if (m_contourPolygons[c][j].bbox.contains(triangle[t])) + { + containsAtLeastOne = true; + } + } + if (containsAtLeastOne) + { + std::vector> clippedPolygons = + RigCellGeometryTools::intersectPolygons(triangle, m_contourPolygons[c][j].vertices); + intersectPolygons.insert(intersectPolygons.end(), clippedPolygons.begin(), clippedPolygons.end()); + } + } + + if (intersectPolygons.empty()) + { + outsideOuterLimit = true; + continue; + } + + std::vector> clippedPolygons; + + if (!subtractPolygons[c].empty()) + { + for (const std::vector& polygon : intersectPolygons) + { + std::vector> fullyClippedPolygons = + RigCellGeometryTools::subtractPolygons(polygon, subtractPolygons[c]); + clippedPolygons.insert(clippedPolygons.end(), fullyClippedPolygons.begin(), fullyClippedPolygons.end()); + } + } + else + { + clippedPolygons.swap(intersectPolygons); + } + + { + std::vector clippedTriangles; + for (std::vector& clippedPolygon : clippedPolygons) + { + std::vector> polygonTriangles; + if (clippedPolygon.size() == 3u) + { + polygonTriangles.push_back(clippedPolygon); + } + else + { + cvf::Vec3d baryCenter = cvf::Vec3d::ZERO; + for (size_t v = 0; v < clippedPolygon.size(); ++v) + { + cvf::Vec3d& clippedVertex = clippedPolygon[v]; + baryCenter += clippedVertex; + } + baryCenter /= clippedPolygon.size(); + for (size_t v = 0; v < clippedPolygon.size(); ++v) + { + std::vector clippedTriangle; + if (v == clippedPolygon.size() - 1) + { + clippedTriangle = {clippedPolygon[v], clippedPolygon[0], baryCenter}; + } + else + { + clippedTriangle = {clippedPolygon[v], clippedPolygon[v + 1], baryCenter}; + } + polygonTriangles.push_back(clippedTriangle); + } + } + for (const std::vector& polygonTriangle : polygonTriangles) + { + // Check triangle area + double area = 0.5 * ((polygonTriangle[1] - polygonTriangle[0]) ^ (polygonTriangle[2] - polygonTriangle[0])).length(); + if (area < areaThreshold) + continue; + for (const cvf::Vec3d& localVertex : polygonTriangle) + { + double value = std::numeric_limits::infinity(); + if (discrete) + { + value = contourLevels[c] + + 0.01 * (contourLevels.back() - contourLevels.front()) / contourLevels.size(); + } + else + { + for (size_t n = 0; n < 3; ++n) + { + if ((triangle[n] - localVertex).length() < m_sampleSpacing * 0.01 && + triangleWithValues[n].w() != std::numeric_limits::infinity()) + { + value = triangleWithValues[n].w(); + break; + } + } + if (value == std::numeric_limits::infinity()) + { + value = interpolateValue(cvf::Vec2d(localVertex.x(), localVertex.y())); + if (value == std::numeric_limits::infinity()) + { + value = contourLevels[c]; + } + } + } + + cvf::Vec4d globalVertex(localVertex, value); + clippedTriangles.push_back(globalVertex); + } + } + } + threadTriangles[myThread][c].insert( + threadTriangles[myThread][c].end(), clippedTriangles.begin(), clippedTriangles.end()); + } + } + } + } + + std::vector> trianglesPerLevel(std::max((size_t)1, m_contourPolygons.size())); + for (size_t c = 0; c < trianglesPerLevel.size(); ++c) + { + std::vector allTrianglesThisLevel; + for (size_t i = 0; i < threadTriangles.size(); ++i) + { + allTrianglesThisLevel.insert(allTrianglesThisLevel.end(), threadTriangles[i][c].begin(), threadTriangles[i][c].end()); + } + + double triangleAreasThisLevel = sumTriangleAreas(allTrianglesThisLevel); + if (c >= m_contourLevelCumulativeAreas.size() || triangleAreasThisLevel > 1.0e-3 * m_contourLevelCumulativeAreas[c]) + { + trianglesPerLevel[c] = allTrianglesThisLevel; + } + } + + std::vector finalTriangles; + for (size_t i = 0; i < trianglesPerLevel.size(); ++i) + { + finalTriangles.insert(finalTriangles.end(), trianglesPerLevel[i].begin(), trianglesPerLevel[i].end()); + } + + m_trianglesWithVertexValues = finalTriangles; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector RimContourMapProjection::generateVertices() const +{ + size_t nVertices = numberOfVertices(); + std::vector vertices(nVertices, cvf::Vec3d::ZERO); + +#pragma omp parallel for + for (int index = 0; index < static_cast(nVertices); ++index) + { + cvf::Vec2ui ij = ijFromVertexIndex(index); + cvf::Vec2d mapPos = cellCenterPosition(ij.x(), ij.y()); + // Shift away from sample point to vertex + mapPos.x() -= m_sampleSpacing * 0.5; + mapPos.y() -= m_sampleSpacing * 0.5; + + cvf::Vec3d vertexPos(mapPos, 0.0); + vertices[index] = vertexPos; + } + return vertices; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimContourMapProjection::generateContourPolygons() +{ + std::vector contourPolygons; + + std::vector contourLevels; + if (resultRangeIsValid() && legendConfig()->mappingMode() != RimRegularLegendConfig::CATEGORY_INTEGER) + { + legendConfig()->scalarMapper()->majorTickValues(&contourLevels); + int nContourLevels = static_cast(contourLevels.size()); + + if (minValue() != std::numeric_limits::infinity() && maxValue() != -std::numeric_limits::infinity() && + std::fabs(maxValue() - minValue()) > 1.0e-8) + { + if (nContourLevels > 2) + { + if (legendConfig()->mappingMode() == RimRegularLegendConfig::LINEAR_DISCRETE || + legendConfig()->mappingMode() == RimRegularLegendConfig::LINEAR_CONTINUOUS) + { + contourLevels.front() -= 0.01 * (contourLevels.back() - contourLevels.front()); + } + else + { + contourLevels.front() *= 0.5; + } + + double simplifyEpsilon = m_smoothContourLines() ? 5.0e-2 * m_sampleSpacing : 1.0e-3 * m_sampleSpacing; + + if (nContourLevels >= 10) + { + simplifyEpsilon *= 2.0; + } + if (numberOfCells() > 100000) + { + simplifyEpsilon *= 2.0; + } + + std::vector unorderedLineSegmentsPerLevel = + caf::ContourLines::create(m_aggregatedVertexResults, xVertexPositions(), yVertexPositions(), contourLevels); + + contourPolygons = std::vector(unorderedLineSegmentsPerLevel.size()); + +#pragma omp parallel for + for (int i = 0; i < (int)unorderedLineSegmentsPerLevel.size(); ++i) + { + contourPolygons[i] = createContourPolygonsFromLineSegments(unorderedLineSegmentsPerLevel[i], contourLevels[i]); + + if (m_smoothContourLines()) + { + smoothContourPolygons(&contourPolygons[i], true); + } + + for (ContourPolygon& polygon : contourPolygons[i]) + { + RigCellGeometryTools::simplifyPolygon(&polygon.vertices, simplifyEpsilon); + } + } + + if (m_smoothContourLines()) + { + for (size_t i = 1; i < contourPolygons.size(); ++i) + { + clipContourPolygons(&contourPolygons[i], &contourPolygons[i - 1]); + } + } + + m_contourLevelCumulativeAreas.resize(contourPolygons.size(), 0.0); + for (int64_t i = (int64_t)contourPolygons.size() - 1; i >= 0; --i) + { + double levelOuterArea = sumPolygonArea(contourPolygons[i]); + m_contourLevelCumulativeAreas[i] = levelOuterArea; + } + } + } + } + m_contourPolygons = contourPolygons; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimContourMapProjection::ContourPolygons +RimContourMapProjection::createContourPolygonsFromLineSegments(caf::ContourLines::ListOfLineSegments& unorderedLineSegments, + double contourValue) +{ + const double areaThreshold = 1.5 * (m_sampleSpacing * m_sampleSpacing) / (sampleSpacingFactor() * sampleSpacingFactor()); + + ContourPolygons contourPolygons; + + std::vector> polygons; + RigCellGeometryTools::createPolygonFromLineSegments(unorderedLineSegments, polygons, 1.0e-8); + for (size_t j = 0; j < polygons.size(); ++j) + { + double signedArea = cvf::GeometryTools::signedAreaPlanarPolygon(cvf::Vec3d::Z_AXIS, polygons[j]); + ContourPolygon contourPolygon; + contourPolygon.value = contourValue; + if (signedArea < 0.0) + { + contourPolygon.vertices.insert( + contourPolygon.vertices.end(), polygons[j].rbegin(), polygons[j].rend()); + } + else + { + contourPolygon.vertices = polygons[j]; + } + + contourPolygon.area = cvf::GeometryTools::signedAreaPlanarPolygon(cvf::Vec3d::Z_AXIS, contourPolygon.vertices); + if (contourPolygon.area > areaThreshold) + { + for (const cvf::Vec3d& vertex : contourPolygon.vertices) { - double sum = 0.0; - for (auto cellIdxAndWeight : matchingCells) - { - size_t cellIdx = cellIdxAndWeight.first; - double cellValue = findColumnResult(m_resultAggregation(), cellIdx); - sum += cellValue * cellIdxAndWeight.second; - } - return sum; + contourPolygon.bbox.add(vertex); } - default: - CVF_TIGHT_ASSERT(false); + contourPolygons.push_back(contourPolygon); } } - return std::numeric_limits::infinity(); + return contourPolygons; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -double RimContourMapProjection::calculateValueAtVertex(uint vi, uint vj) const +void RimContourMapProjection::smoothContourPolygons(ContourPolygons* contourPolygons, + bool favourExpansion) { - std::vector averageIs; - std::vector averageJs; + CVF_ASSERT(contourPolygons); + for (size_t i = 0; i < contourPolygons->size(); ++i) + { + ContourPolygon& polygon = contourPolygons->at(i); - if (vi > 0u) averageIs.push_back(vi - 1); - if (vj > 0u) averageJs.push_back(vj - 1); - if (vi < m_mapSize.x()) averageIs.push_back(vi); - if (vj < m_mapSize.y()) averageJs.push_back(vj); + for (size_t n = 0; n < 20; ++n) + { + std::vector newVertices; + newVertices.resize(polygon.vertices.size()); + double maxChange = 0.0; + for (size_t j = 0; j < polygon.vertices.size(); ++j) + { + cvf::Vec3d vm1 = polygon.vertices.back(); + cvf::Vec3d v = polygon.vertices[j]; + cvf::Vec3d vp1 = polygon.vertices.front(); + if (j > 0u) + { + vm1 = polygon.vertices[j - 1]; + } + if (j < polygon.vertices.size() - 1) + { + vp1 = polygon.vertices[j + 1]; + } + // Only expand. + cvf::Vec3d modifiedVertex = 0.5 * (v + 0.5 * (vm1 + vp1)); + cvf::Vec3d delta = modifiedVertex - v; + cvf::Vec3d tangent3d = vp1 - vm1; + cvf::Vec2d tangent2d(tangent3d.x(), tangent3d.y()); + cvf::Vec3d norm3d(tangent2d.getNormalized().perpendicularVector()); + if (delta * norm3d > 0 && favourExpansion) + { + // Normal is always inwards facing so a positive dot product means inward movement + // Favour expansion rather than contraction by only contracting by a fraction. + // The fraction is empirically found to give a decent result. + modifiedVertex = v + 0.2 * delta; + } + newVertices[j] = modifiedVertex; + maxChange = std::max(maxChange, (modifiedVertex - v).length()); + } + polygon.vertices.swap(newVertices); + if (maxChange < m_sampleSpacing * 1.0e-2) break; + } + } +} - RiaWeightedMeanCalculator calc; - for (uint j : averageJs) +void RimContourMapProjection::clipContourPolygons(ContourPolygons* contourPolygons, + const ContourPolygons* clipBy) +{ + CVF_ASSERT(clipBy); + for (size_t i = 0; i < contourPolygons->size(); ++i) { - for (uint i : averageIs) + ContourPolygon& polygon = contourPolygons->at(i); + for (size_t j = 0; j < clipBy->size(); ++j) { - if (hasResultInCell(i, j)) + std::vector> intersections = + RigCellGeometryTools::intersectPolygons(polygon.vertices, clipBy->at(j).vertices); + if (!intersections.empty()) { - calc.addValueAndWeight(valueInCell(i, j), 1.0); + polygon.vertices = intersections.front(); + polygon.area = std::abs(cvf::GeometryTools::signedAreaPlanarPolygon(cvf::Vec3d::Z_AXIS, polygon.vertices)); } } } - if (calc.validAggregatedWeight()) +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +double RimContourMapProjection::sumPolygonArea(const ContourPolygons& contourPolygons) +{ + double sumArea = 0.0; + for (const ContourPolygon& polygon : contourPolygons) { - return calc.weightedMean(); + sumArea += polygon.area; } - return std::numeric_limits::infinity(); + return sumArea; } - //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -std::vector> RimContourMapProjection::cellsAtIJ(uint i, uint j) const +double RimContourMapProjection::sumTriangleAreas(const std::vector& triangles) { - size_t cellIndex = this->cellIndexFromIJ(i, j); - if (cellIndex < m_projected3dGridIndices.size()) + double sumArea = 0.0; + for (size_t i = 0; i < triangles.size(); i += 3) { - return m_projected3dGridIndices[cellIndex]; + cvf::Vec3d v1(triangles[i].x(), triangles[i].y(), triangles[i].z()); + cvf::Vec3d v2(triangles[i + 1].x(), triangles[i + 1].y(), triangles[i + 1].z()); + cvf::Vec3d v3(triangles[i + 2].x(), triangles[i + 2].y(), triangles[i + 2].z()); + double area = 0.5 * ((v3 - v1) ^ (v2 - v1)).length(); + sumArea += area; } - return std::vector>(); + return sumArea; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -std::vector> - RimContourMapProjection::visibleCellsAndOverlapVolumeFrom2dPoint(const cvf::Vec2d& globalPos2d, - const std::vector* weightingResultValues) const +std::vector + RimContourMapProjection::cellOverlapVolumesAndResults(const cvf::Vec2d& globalPos2d, + const std::vector& weightingResultValues) const { - cvf::Vec3d top2dElementCentroid(globalPos2d, m_fullBoundingBox.max().z()); - cvf::Vec3d bottom2dElementCentroid(globalPos2d, m_fullBoundingBox.min().z()); + cvf::Vec3d top2dElementCentroid(globalPos2d, m_expandedBoundingBox.max().z()); + cvf::Vec3d bottom2dElementCentroid(globalPos2d, m_expandedBoundingBox.min().z()); cvf::Vec3d planarDiagonalVector(0.5 * m_sampleSpacing, 0.5 * m_sampleSpacing, 0.0); cvf::Vec3d topNECorner = top2dElementCentroid + planarDiagonalVector; cvf::Vec3d bottomSWCorner = bottom2dElementCentroid - planarDiagonalVector; cvf::BoundingBox bbox2dElement(bottomSWCorner, topNECorner); - std::vector allCellIndices; - m_mainGrid->findIntersectingCells(bbox2dElement, &allCellIndices); + std::vector> matchingVisibleCellsAndWeight; + + // Bounding box has been expanded, so 2d element may be outside actual 3d grid + if (!bbox2dElement.intersects(m_gridBoundingBox)) + { + return matchingVisibleCellsAndWeight; + } + + std::vector allCellIndices = findIntersectingCells(bbox2dElement); - typedef std::map>> KLayerCellWeightMap; - KLayerCellWeightMap matchingVisibleCellsWeightPerKLayer; + std::map> kLayerIndexMap; - std::array hexCorners; for (size_t globalCellIdx : allCellIndices) { if ((*m_cellGridIdxVisibility)[globalCellIdx]) { - RigCell cell = m_mainGrid->globalCellArray()[globalCellIdx]; - - size_t mainGridCellIdx = cell.mainGridCellIndex(); - size_t i, j, k; - m_mainGrid->ijkFromCellIndex(mainGridCellIdx, &i, &j, &k); - - size_t localCellIdx = cell.gridLocalCellIndex(); - RigGridBase* localGrid = cell.hostGrid(); - - localGrid->cellCornerVertices(localCellIdx, hexCorners.data()); - - cvf::BoundingBox overlapBBox; - std::array overlapCorners = - RigCellGeometryTools::estimateHexOverlapWithBoundingBox(hexCorners, bbox2dElement, &overlapBBox); - - double overlapVolume = RigCellGeometryTools::calculateCellVolume(overlapCorners); + kLayerIndexMap[kLayer(globalCellIdx)].push_back(globalCellIdx); + } + } + for (const auto& kLayerIndexPair : kLayerIndexMap) + { + for (size_t globalCellIdx : kLayerIndexPair.second) + { + double overlapVolume = calculateOverlapVolume(globalCellIdx, bbox2dElement); if (overlapVolume > 0.0) { - double weight = overlapVolume; - if (weightingResultValues) - { - const RigActiveCellInfo* activeCellInfo = - eclipseCase()->eclipseCaseData()->activeCellInfo(RiaDefines::MATRIX_MODEL); - size_t cellResultIdx = activeCellInfo->cellResultIndex(globalCellIdx); - double result = std::max((*weightingResultValues)[cellResultIdx], 0.0); - if (result < 1.0e-6) - { - result = 0.0; - } - weight *= result; - } + size_t resultIndex = gridResultIndex(globalCellIdx); + double weight = overlapVolume * getParameterWeightForCell(resultIndex, weightingResultValues); if (weight > 0.0) { - matchingVisibleCellsWeightPerKLayer[k].push_back(std::make_pair(globalCellIdx, weight)); + matchingVisibleCellsAndWeight.push_back(std::make_pair(resultIndex, weight)); } } } } - std::vector> matchingVisibleCellsAndWeight; - for (auto kLayerCellWeight : matchingVisibleCellsWeightPerKLayer) - { - for (auto cellWeight : kLayerCellWeight.second) - { - matchingVisibleCellsAndWeight.push_back(std::make_pair(cellWeight.first, cellWeight.second)); - } - } - return matchingVisibleCellsAndWeight; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -std::vector> RimContourMapProjection::visibleCellsAndLengthInCellFrom2dPoint( - const cvf::Vec2d& globalPos2d, - const std::vector* weightingResultValues /*= nullptr*/) const +std::vector RimContourMapProjection::cellRayIntersectionAndResults(const cvf::Vec2d& globalPos2d, + const std::vector& weightingResultValues) const { - cvf::Vec3d highestPoint(globalPos2d, m_fullBoundingBox.max().z()); - cvf::Vec3d lowestPoint(globalPos2d, m_fullBoundingBox.min().z()); + std::vector> matchingVisibleCellsAndWeight; + + cvf::Vec3d highestPoint(globalPos2d, m_expandedBoundingBox.max().z()); + cvf::Vec3d lowestPoint(globalPos2d, m_expandedBoundingBox.min().z()); + + // Bounding box has been expanded, so ray may be outside actual 3d grid + if (!m_gridBoundingBox.contains(highestPoint)) + { + return matchingVisibleCellsAndWeight; + } cvf::BoundingBox rayBBox; rayBBox.add(highestPoint); rayBBox.add(lowestPoint); - std::vector allCellIndices; - m_mainGrid->findIntersectingCells(rayBBox, &allCellIndices); + std::vector allCellIndices = findIntersectingCells(rayBBox); - std::map>> matchingVisibleCellsAndWeightPerKLayer; + std::map> kLayerIndexMap; - cvf::Vec3d hexCorners[8]; for (size_t globalCellIdx : allCellIndices) { if ((*m_cellGridIdxVisibility)[globalCellIdx]) { - RigCell cell = m_mainGrid->globalCellArray()[globalCellIdx]; - - size_t mainGridCellIdx = cell.mainGridCellIndex(); - size_t i, j, k; - m_mainGrid->ijkFromCellIndex(mainGridCellIdx, &i, &j, &k); - - size_t localCellIdx = cell.gridLocalCellIndex(); - RigGridBase* localGrid = cell.hostGrid(); - - localGrid->cellCornerVertices(localCellIdx, hexCorners); - std::vector intersections; - - if (RigHexIntersectionTools::lineHexCellIntersection(highestPoint, lowestPoint, hexCorners, 0, &intersections)) - { - double lengthInCell = - (intersections.back().m_intersectionPoint - intersections.front().m_intersectionPoint).length(); - matchingVisibleCellsAndWeightPerKLayer[k].push_back(std::make_pair(globalCellIdx, lengthInCell)); - } + kLayerIndexMap[kLayer(globalCellIdx)].push_back(globalCellIdx); } } - std::vector> matchingVisibleCellsAndWeight; - for (auto kLayerCellWeight : matchingVisibleCellsAndWeightPerKLayer) + for (const auto& kLayerIndexPair : kLayerIndexMap) { - // Make sure the sum of all weights in the same K-layer is 1. double weightSumThisKLayer = 0.0; - for (auto cellWeight : kLayerCellWeight.second) + std::vector> cellsAndWeightsThisLayer; + for (size_t globalCellIdx : kLayerIndexPair.second) { - weightSumThisKLayer += cellWeight.second; + double lengthInCell = calculateRayLengthInCell(globalCellIdx, highestPoint, lowestPoint); + if (lengthInCell > 0.0) + { + cellsAndWeightsThisLayer.push_back(std::make_pair(gridResultIndex(globalCellIdx), lengthInCell)); + weightSumThisKLayer += lengthInCell; + } } - - for (auto cellWeight : kLayerCellWeight.second) + for (auto& cellWeightPair : cellsAndWeightsThisLayer) { - matchingVisibleCellsAndWeight.push_back(std::make_pair(cellWeight.first, cellWeight.second / weightSumThisKLayer)); + cellWeightPair.second /= weightSumThisKLayer; + matchingVisibleCellsAndWeight.push_back(cellWeightPair); } } @@ -1097,91 +1380,147 @@ std::vector> RimContourMapProjection::visibleCellsAndL //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -double RimContourMapProjection::findColumnResult(ResultAggregation resultAggregation, size_t cellGlobalIdx) const +bool RimContourMapProjection::isMeanResult() const { - const RigCaseCellResultsData* resultData = eclipseCase()->results(RiaDefines::MATRIX_MODEL); - size_t poroResultIndex = resultData->findScalarResultIndex(RiaDefines::STATIC_NATIVE, "PORO"); - size_t ntgResultIndex = resultData->findScalarResultIndex(RiaDefines::STATIC_NATIVE, "NTG"); - size_t dzResultIndex = resultData->findScalarResultIndex(RiaDefines::STATIC_NATIVE, "DZ"); - - if (poroResultIndex == cvf::UNDEFINED_SIZE_T || ntgResultIndex == cvf::UNDEFINED_SIZE_T) - { - return std::numeric_limits::infinity(); - } + return m_resultAggregation() == RESULTS_MEAN_VALUE || m_resultAggregation() == RESULTS_HARM_VALUE || + m_resultAggregation() == RESULTS_GEOM_VALUE; +} - const std::vector& poroResults = resultData->cellScalarResults(poroResultIndex)[0]; - const std::vector& ntgResults = resultData->cellScalarResults(ntgResultIndex)[0]; - const std::vector& dzResults = resultData->cellScalarResults(dzResultIndex)[0]; +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RimContourMapProjection::isStraightSummationResult() const +{ + return isStraightSummationResult(m_resultAggregation()); +} - const RigActiveCellInfo* activeCellInfo = eclipseCase()->eclipseCaseData()->activeCellInfo(RiaDefines::MATRIX_MODEL); - size_t cellResultIdx = activeCellInfo->cellResultIndex(cellGlobalIdx); +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RimContourMapProjection::isStraightSummationResult(ResultAggregationEnum aggregationType) +{ + return aggregationType == RESULTS_OIL_COLUMN || aggregationType == RESULTS_GAS_COLUMN || + aggregationType == RESULTS_HC_COLUMN || aggregationType == RESULTS_SUM; +} - if (cellResultIdx >= poroResults.size() || cellResultIdx >= ntgResults.size()) +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +double RimContourMapProjection::interpolateValue(const cvf::Vec2d& gridPos2d) const +{ + cvf::Vec2ui cellContainingPoint = ijFromLocalPos(gridPos2d); + cvf::Vec2d cellCenter = cellCenterPosition(cellContainingPoint.x(), cellContainingPoint.y()); + + std::array x; + x[0] = cvf::Vec3d(cellCenter + cvf::Vec2d(-m_sampleSpacing * 0.5, -m_sampleSpacing * 0.5), 0.0); + x[1] = cvf::Vec3d(cellCenter + cvf::Vec2d(m_sampleSpacing * 0.5, -m_sampleSpacing * 0.5), 0.0); + x[2] = cvf::Vec3d(cellCenter + cvf::Vec2d(m_sampleSpacing * 0.5, m_sampleSpacing * 0.5), 0.0); + x[3] = cvf::Vec3d(cellCenter + cvf::Vec2d(-m_sampleSpacing * 0.5, m_sampleSpacing * 0.5), 0.0); + + cvf::Vec4d baryCentricCoords = cvf::GeometryTools::barycentricCoords(x[0], x[1], x[2], x[3], cvf::Vec3d(gridPos2d, 0.0)); + + std::array v; + v[0] = cellContainingPoint; + v[1] = cvf::Vec2ui(cellContainingPoint.x() + 1u, cellContainingPoint.y()); + v[2] = cvf::Vec2ui(cellContainingPoint.x() + 1u, cellContainingPoint.y() + 1u); + v[3] = cvf::Vec2ui(cellContainingPoint.x(), cellContainingPoint.y() + 1u); + + std::array vertexValues; + double validBarycentricCoordsSum = 0.0; + for (int i = 0; i < 4; ++i) { - return std::numeric_limits::infinity(); + double vertexValue = valueAtVertex(v[i].x(), v[i].y()); + if (vertexValue == std::numeric_limits::infinity()) + { + baryCentricCoords[i] = 0.0; + vertexValues[i] = 0.0; + return std::numeric_limits::infinity(); + } + else + { + vertexValues[i] = vertexValue; + validBarycentricCoordsSum += baryCentricCoords[i]; + } } - double poro = poroResults.at(cellResultIdx); - double ntg = ntgResults.at(cellResultIdx); - double dz = dzResults.at(cellResultIdx); - - int timeStep = view()->currentTimeStep(); - - double resultValue = 0.0; - if (resultAggregation == RESULTS_OIL_COLUMN || resultAggregation == RESULTS_HC_COLUMN) + if (validBarycentricCoordsSum < 1.0e-8) { - size_t soilResultIndex = resultData->findScalarResultIndex(RiaDefines::DYNAMIC_NATIVE, "SOIL"); - const std::vector& soilResults = resultData->cellScalarResults(soilResultIndex)[timeStep]; - if (cellResultIdx < soilResults.size()) - { - resultValue = soilResults.at(cellResultIdx); - } + return std::numeric_limits::infinity(); } - if (resultAggregation == RESULTS_GAS_COLUMN || resultAggregation == RESULTS_HC_COLUMN) + + // Calculate final value + double value = 0.0; + for (int i = 0; i < 4; ++i) { - size_t sgasResultIndex = resultData->findScalarResultIndex(RiaDefines::DYNAMIC_NATIVE, "SGAS"); - const std::vector& sgasResults = resultData->cellScalarResults(sgasResultIndex)[timeStep]; - if (cellResultIdx < sgasResults.size()) - { - resultValue += sgasResults.at(cellResultIdx); - } + value += baryCentricCoords[i] / validBarycentricCoordsSum * vertexValues[i]; } - return resultValue * poro * ntg * dz; + return value; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -bool RimContourMapProjection::isMeanResult() const +double RimContourMapProjection::valueInCell(uint i, uint j) const { - return m_resultAggregation() == RESULTS_MEAN_VALUE || m_resultAggregation() == RESULTS_HARM_VALUE || - m_resultAggregation() == RESULTS_GEOM_VALUE; + size_t index = cellIndexFromIJ(i, j); + if (index < numberOfCells()) + { + return m_aggregatedResults.at(index); + } + return std::numeric_limits::infinity(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -bool RimContourMapProjection::isSummationResult() const -{ - return isStraightSummationResult() || m_resultAggregation() == RESULTS_VOLUME_SUM; +bool RimContourMapProjection::hasResultInCell(uint i, uint j) const +{ + return !cellsAtIJ(i, j).empty(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -bool RimContourMapProjection::isStraightSummationResult() const +double RimContourMapProjection::calculateValueAtVertex(uint vi, uint vj) const { - return isStraightSummationResult(m_resultAggregation()); + std::vector averageIs; + std::vector averageJs; + + if (vi > 0u) averageIs.push_back(vi - 1); + if (vj > 0u) averageJs.push_back(vj - 1); + if (vi < m_mapSize.x()) averageIs.push_back(vi); + if (vj < m_mapSize.y()) averageJs.push_back(vj); + + RiaWeightedMeanCalculator calc; + for (uint j : averageJs) + { + for (uint i : averageIs) + { + if (hasResultInCell(i, j)) + { + calc.addValueAndWeight(valueInCell(i, j), 1.0); + } + } + } + if (calc.validAggregatedWeight()) + { + return calc.weightedMean(); + } + return std::numeric_limits::infinity(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -bool RimContourMapProjection::isStraightSummationResult(ResultAggregationEnum aggregationType) +std::vector> RimContourMapProjection::cellsAtIJ(uint i, uint j) const { - return aggregationType == RESULTS_OIL_COLUMN || aggregationType == RESULTS_GAS_COLUMN || - aggregationType == RESULTS_HC_COLUMN || aggregationType == RESULTS_SUM; + size_t cellIndex = this->cellIndexFromIJ(i, j); + if (cellIndex < m_projected3dGridIndices.size()) + { + return m_projected3dGridIndices[cellIndex]; + } + return std::vector>(); } //-------------------------------------------------------------------------------------------------- @@ -1242,30 +1581,35 @@ cvf::Vec2ui RimContourMapProjection::ijFromLocalPos(const cvf::Vec2d& localPos2d //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -cvf::Vec2d RimContourMapProjection::globalCellCenterPosition(uint i, uint j) const +cvf::Vec2d RimContourMapProjection::cellCenterPosition(uint i, uint j) const { - cvf::Vec3d gridExtent = m_fullBoundingBox.extent(); - cvf::Vec2d origin(m_fullBoundingBox.min().x(), m_fullBoundingBox.min().y()); - - cvf::Vec2d cellCorner = origin + cvf::Vec2d((i * gridExtent.x()) / (m_mapSize.x()), (j * gridExtent.y()) / (m_mapSize.y())); + cvf::Vec3d gridExtent = m_expandedBoundingBox.extent(); + cvf::Vec2d cellCorner = cvf::Vec2d((i * gridExtent.x()) / (m_mapSize.x()), (j * gridExtent.y()) / (m_mapSize.y())); return cellCorner + cvf::Vec2d(m_sampleSpacing * 0.5, m_sampleSpacing * 0.5); } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +cvf::Vec2d RimContourMapProjection::origin2d() const +{ + return cvf::Vec2d(m_expandedBoundingBox.min().x(), m_expandedBoundingBox.min().y()); +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- std::vector RimContourMapProjection::xVertexPositions() const { - double gridExtent = m_fullBoundingBox.extent().x(); - double origin = m_fullBoundingBox.min().x(); + double gridExtent = m_expandedBoundingBox.extent().x(); cvf::Vec2ui gridSize = numberOfVerticesIJ(); std::vector positions; positions.reserve(gridSize.x()); for (uint i = 0; i < gridSize.x(); ++i) { - positions.push_back(origin + (i * gridExtent) / (gridSize.x() - 1)); + positions.push_back((i * gridExtent) / (gridSize.x() - 1)); } return positions; @@ -1276,15 +1620,14 @@ std::vector RimContourMapProjection::xVertexPositions() const //-------------------------------------------------------------------------------------------------- std::vector RimContourMapProjection::yVertexPositions() const { - double gridExtent = m_fullBoundingBox.extent().y(); - double origin = m_fullBoundingBox.min().y(); + double gridExtent = m_expandedBoundingBox.extent().y(); cvf::Vec2ui gridSize = numberOfVerticesIJ(); std::vector positions; positions.reserve(gridSize.y()); for (uint j = 0; j < gridSize.y(); ++j) { - positions.push_back(origin + (j * gridExtent) / (gridSize.y() - 1)); + positions.push_back((j * gridExtent) / (gridSize.y() - 1)); } return positions; @@ -1293,66 +1636,110 @@ std::vector RimContourMapProjection::yVertexPositions() const //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -bool RimContourMapProjection::getLegendRangeFrom3dGrid() const +cvf::Vec2ui RimContourMapProjection::calculateMapSize() const +{ + cvf::Vec3d gridExtent = m_expandedBoundingBox.extent(); + + uint projectionSizeX = static_cast(std::ceil(gridExtent.x() / m_sampleSpacing)); + uint projectionSizeY = static_cast(std::ceil(gridExtent.y() / m_sampleSpacing)); + + return cvf::Vec2ui(projectionSizeX, projectionSizeY); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +double RimContourMapProjection::gridEdgeOffset() const +{ + return m_sampleSpacing * 2.0; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimContourMapProjection::fieldChangedByUi(const caf::PdmFieldHandle* changedField, + const QVariant& oldValue, + const QVariant& newValue) { - if (isMeanResult()) + if (changedField == &m_resultAggregation) { - return true; + ResultAggregation previousAggregation = static_cast(oldValue.toInt()); + if (isStraightSummationResult(previousAggregation) != isStraightSummationResult()) + { + clearGridMapping(); + } + else + { + clearResults(); + } + clearTimeStepRange(); } - else if (m_resultAggregation == RESULTS_TOP_VALUE) + else if (changedField == &m_smoothContourLines) { - return true; + clearGeometry(); } - return false; + else if (changedField == &m_relativeSampleSpacing) + { + clearGridMapping(); + clearResults(); + clearTimeStepRange(); + } + + baseView()->updateConnectedEditors(); + + RimProject* proj; + firstAncestorOrThisOfTypeAsserted(proj); + proj->scheduleCreateDisplayModelAndRedrawAllViews(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RimContourMapProjection::updateGridInformation() +void RimContourMapProjection::defineEditorAttribute(const caf::PdmFieldHandle* field, + QString uiConfigName, + caf::PdmUiEditorAttribute* attribute) { - m_mainGrid = eclipseCase()->eclipseCaseData()->mainGrid(); - m_sampleSpacing = m_relativeSampleSpacing * m_mainGrid->characteristicIJCellSize(); - m_fullBoundingBox = eclipseCase()->activeCellsBoundingBox(); - m_mapSize = calculateMapSize(); - - // Re-jig max point to be an exact multiple of cell size - cvf::Vec3d minPoint = m_fullBoundingBox.min(); - cvf::Vec3d maxPoint = m_fullBoundingBox.max(); - maxPoint.x() = minPoint.x() + m_mapSize.x() * m_sampleSpacing; - maxPoint.y() = minPoint.y() + m_mapSize.y() * m_sampleSpacing; - m_fullBoundingBox = cvf::BoundingBox(minPoint, maxPoint); + if (&m_relativeSampleSpacing == field) + { + caf::PdmUiDoubleSliderEditorAttribute* myAttr = dynamic_cast(attribute); + if (myAttr) + { + myAttr->m_minimum = 0.2; + myAttr->m_maximum = 2.0; + myAttr->m_sliderTickCount = 9; + myAttr->m_delaySliderUpdateUntilRelease = true; + } + } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -cvf::Vec2ui RimContourMapProjection::calculateMapSize() const +void RimContourMapProjection::defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering) { - cvf::Vec3d gridExtent = m_fullBoundingBox.extent(); - - uint projectionSizeX = static_cast(std::ceil(gridExtent.x() / m_sampleSpacing)); - uint projectionSizeY = static_cast(std::ceil(gridExtent.y() / m_sampleSpacing)); - - return cvf::Vec2ui(projectionSizeX, projectionSizeY); + caf::PdmUiGroup* mainGroup = uiOrdering.addNewGroup("Projection Settings"); + mainGroup->add(&m_resultAggregation); + legendConfig()->uiOrdering("NumLevelsOnly", *mainGroup); + mainGroup->add(&m_relativeSampleSpacing); + mainGroup->add(&m_showContourLines); + mainGroup->add(&m_showContourLabels); + m_showContourLabels.uiCapability()->setUiReadOnly(!m_showContourLines()); + mainGroup->add(&m_smoothContourLines); + m_smoothContourLines.uiCapability()->setUiReadOnly(!m_showContourLines()); + uiOrdering.skipRemainingFields(true); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -RimEclipseResultCase* RimContourMapProjection::eclipseCase() const +void RimContourMapProjection::defineUiTreeOrdering(caf::PdmUiTreeOrdering& uiTreeOrdering, QString uiConfigName /*= ""*/) { - RimEclipseResultCase* eclipseCase = nullptr; - firstAncestorOrThisOfType(eclipseCase); - return eclipseCase; + uiTreeOrdering.skipRemainingChildren(true); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -RimContourMapView* RimContourMapProjection::view() const +void RimContourMapProjection::initAfterRead() { - RimContourMapView* view = nullptr; - firstAncestorOrThisOfTypeAsserted(view); - return view; } diff --git a/ApplicationCode/ProjectDataModel/RimContourMapProjection.h b/ApplicationCode/ProjectDataModel/RimContourMapProjection.h index 05c5fbedc9..e8a5dfd851 100644 --- a/ApplicationCode/ProjectDataModel/RimContourMapProjection.h +++ b/ApplicationCode/ProjectDataModel/RimContourMapProjection.h @@ -1,18 +1,17 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) Statoil ASA -// Copyright (C) Ceetron Solutions AS -// +// Copyright (C) 2018- Equinor ASA +// // ResInsight 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 3 of the License, or // (at your option) any later version. -// +// // ResInsight 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 at +// +// See the GNU General Public License at // for more details. // ///////////////////////////////////////////////////////////////////////////////// @@ -22,29 +21,39 @@ #include "RimCheckableNamedObject.h" #include "RimRegularLegendConfig.h" +#include "cafContourLines.h" #include "cafDisplayCoordTransform.h" #include "cafPdmChildField.h" #include "cafPdmField.h" #include "cafPdmObject.h" +#include "cvfArray.h" #include "cvfBoundingBox.h" #include "cvfGeometryBuilderFaceList.h" +#include "cvfString.h" #include "cvfVector2.h" -class RigMainGrid; -class RigResultAccessor; -class RimContourMapView; -class RimEclipseResultCase; -class RimEclipseResultDefinition; +class RimGridView; //================================================================================================== -/// -/// +/// +/// //================================================================================================== class RimContourMapProjection : public RimCheckableNamedObject { CAF_PDM_HEADER_INIT; + public: + typedef std::pair CellIndexAndResult; + + struct ContourPolygon + { + std::vector vertices; + double value; + double area; + cvf::BoundingBox bbox; + }; + enum ResultAggregationEnum { RESULTS_TOP_VALUE, @@ -60,121 +69,162 @@ class RimContourMapProjection : public RimCheckableNamedObject RESULTS_HC_COLUMN }; typedef caf::AppEnum ResultAggregation; - typedef std::vector> ContourPolygons; + typedef std::vector ContourPolygons; RimContourMapProjection(); ~RimContourMapProjection() override; - void generateVertices(cvf::Vec3fArray* vertices, const caf::DisplayCoordTransform* displayCoordTransform); - ContourPolygons generateContourPolygons(const caf::DisplayCoordTransform* displayCoordTransform); - cvf::ref generatePickPointPolygon(const caf::DisplayCoordTransform* displayCoordTransform); - void generateResults(); - - ResultAggregation resultAggregation() const; - double sampleSpacing() const; - double sampleSpacingFactor() const; - bool showContourLines() const; - - QString resultAggregationText() const; - QString resultDescriptionText() const; - QString weightingParameter() const; + void generateResultsIfNecessary(int timeStep); + void generateGeometryIfNecessary(); + void clearGeometry(); - double maxValue() const; - double minValue() const; - double meanValue() const; - double sumAllValues() const; + std::vector generatePickPointPolygon(); - cvf::Vec2ui numberOfElementsIJ() const; - cvf::Vec2ui numberOfVerticesIJ() const; + const std::vector& contourPolygons() const; + const std::vector& trianglesWithVertexValues(); - bool isColumnResult() const; + double sampleSpacing() const; + double sampleSpacingFactor() const; + bool showContourLines() const; - double valueAtVertex(uint i, uint j) const; - bool hasResultAtVertex(uint i, uint j) const; + QString resultAggregationText() const; - RimRegularLegendConfig* legendConfig() const; - void updateLegend(); + double maxValue() const; + double minValue() const; - uint numberOfCells() const; - uint numberOfValidCells() const; - size_t numberOfVertices() const; + double meanValue() const; + double sumAllValues() const; - void updatedWeightingResult(); + cvf::Vec2ui numberOfElementsIJ() const; + cvf::Vec2ui numberOfVerticesIJ() const; - bool checkForMapIntersection(const cvf::Vec3d& localPoint3d, cvf::Vec2d* contourMapPoint, cvf::Vec2ui* contourMapCell, double* valueAtPoint) const; - void setPickPoint(cvf::Vec2d pickedPoint); + bool isColumnResult() const; -protected: - void fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue) override; - void defineEditorAttribute(const caf::PdmFieldHandle* field, - QString uiConfigName, - caf::PdmUiEditorAttribute* attribute) override; - void defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering) override; - void defineUiTreeOrdering(caf::PdmUiTreeOrdering& uiTreeOrdering, QString uiConfigName = "") override; - void initAfterRead() override; - -private: - typedef std::pair CellIndexAndResult; + double valueAtVertex(uint i, uint j) const; -private: - void generateGridMapping(); + uint numberOfCells() const; + uint numberOfValidCells() const; + size_t numberOfVertices() const; - double valueInCell(uint i, uint j) const; - bool hasResultInCell(uint i, uint j) const; + bool checkForMapIntersection(const cvf::Vec3d& localPoint3d, cvf::Vec2d* contourMapPoint, double* valueAtPoint) const; + void setPickPoint(cvf::Vec2d globalPickPoint); + cvf::Vec3d origin3d() const; - double calculateValueInCell(uint i, uint j) const; - double calculateValueAtVertex(uint i, uint j) const; + // Pure-virtual public methods which should be overridden by Eclipse and Geo-mechanical contour map implementations + virtual QString resultDescriptionText() const = 0; + virtual RimRegularLegendConfig* legendConfig() const = 0; + virtual void updateLegend() = 0; +protected: + // Protected virtual methods to be overridden by Eclipse and Geo-mechanical contour map implementations + virtual void updateGridInformation() = 0; + virtual std::vector retrieveParameterWeights() = 0; + virtual std::vector generateResults(int timeStep) = 0; + virtual bool resultVariableChanged() const = 0; + virtual void clearResultVariable() = 0; + virtual RimGridView* baseView() const = 0; + virtual size_t kLayer(size_t globalCellIdx) const = 0; + virtual std::vector findIntersectingCells(const cvf::BoundingBox& bbox) const = 0; + virtual double calculateOverlapVolume(size_t globalCellIdx, const cvf::BoundingBox& bbox) const = 0; + virtual double calculateRayLengthInCell(size_t globalCellIdx, const cvf::Vec3d& highestPoint, const cvf::Vec3d& lowestPoint) const = 0; + virtual double getParameterWeightForCell(size_t globalCellIdx, const std::vector& parameterWeights) const = 0; + + virtual size_t gridResultIndex(size_t globalCellIdx) const; + + double calculateValueInMapCell(uint i, uint j, const std::vector& gridCellValues) const; +protected: + // Keep track of whether cached data needs updating + bool gridMappingNeedsUpdating() const; + bool resultsNeedsUpdating(int timeStep) const; + bool geometryNeedsUpdating() const; + bool resultRangeIsValid() const; + void clearGridMapping(); + void clearResults(); + void clearTimeStepRange(); + + double maxValue(const std::vector& aggregatedResults) const; + double minValue(const std::vector& aggregatedResults) const; + std::pair minmaxValuesAllTimeSteps(); + + virtual cvf::ref getCellVisibility() const; + virtual std::vector getMapCellVisibility(); + bool mapCellVisibilityNeedsUpdating(); + std::vector>> generateGridMapping(); + + void generateVertexResults(); + void generateTrianglesWithVertexValues(); + std::vector generateVertices() const; + void generateContourPolygons(); + ContourPolygons createContourPolygonsFromLineSegments(caf::ContourLines::ListOfLineSegments& unorderedLineSegments, double contourValue); + void smoothContourPolygons(ContourPolygons* contourPolygons, bool favourExpansion); + void clipContourPolygons(ContourPolygons* contourPolygons, const ContourPolygons* clipBy); + static double sumPolygonArea(const ContourPolygons& contourPolygons); + static double sumTriangleAreas(const std::vector& triangles); + + std::vector cellOverlapVolumesAndResults(const cvf::Vec2d& globalPos2d, + const std::vector& weightingResultValues) const; + std::vector cellRayIntersectionAndResults(const cvf::Vec2d& globalPos2d, + const std::vector& weightingResultValues) const; + + bool isMeanResult() const; + bool isStraightSummationResult() const; + static bool isStraightSummationResult(ResultAggregationEnum aggregationType); + + double interpolateValue(const cvf::Vec2d& gridPosition2d) const; + double valueInCell(uint i, uint j) const; + bool hasResultInCell(uint i, uint j) const; + double calculateValueAtVertex(uint i, uint j) const; + + // Cell index and position conversion std::vector cellsAtIJ(uint i, uint j) const; - - std::vector visibleCellsAndOverlapVolumeFrom2dPoint(const cvf::Vec2d& globalPos2d, const std::vector* weightingResultValues = nullptr) const; - std::vector visibleCellsAndLengthInCellFrom2dPoint(const cvf::Vec2d& globalPos2d, const std::vector* weightingResultValues = nullptr) const; - double findColumnResult(ResultAggregation resultAggregation, size_t cellGlobalIdx) const; - - bool isMeanResult() const; - bool isSummationResult() const; - bool isStraightSummationResult() const; - static bool isStraightSummationResult(ResultAggregationEnum aggregationType); - size_t cellIndexFromIJ(uint i, uint j) const; size_t vertexIndexFromIJ(uint i, uint j) const; - cvf::Vec2ui ijFromVertexIndex(size_t gridIndex) const; cvf::Vec2ui ijFromCellIndex(size_t mapIndex) const; cvf::Vec2ui ijFromLocalPos(const cvf::Vec2d& localPos2d) const; - cvf::Vec2d globalCellCenterPosition(uint i, uint j) const; - - std::vector xVertexPositions() const; - std::vector yVertexPositions() const; - - bool getLegendRangeFrom3dGrid() const; - void updateGridInformation(); - cvf::Vec2ui calculateMapSize() const; + cvf::Vec2d cellCenterPosition(uint i, uint j) const; + cvf::Vec2d origin2d() const; - RimEclipseResultCase* eclipseCase() const; - RimContourMapView* view() const; + std::vector xVertexPositions() const; + std::vector yVertexPositions() const; + cvf::Vec2ui calculateMapSize() const; + double gridEdgeOffset() const; + + protected: + // Framework overrides + void fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue) override; + void defineEditorAttribute(const caf::PdmFieldHandle* field, + QString uiConfigName, + caf::PdmUiEditorAttribute* attribute) override; + void defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering) override; + void defineUiTreeOrdering(caf::PdmUiTreeOrdering& uiTreeOrdering, QString uiConfigName = "") override; + void initAfterRead() override; + protected: - caf::PdmField m_relativeSampleSpacing; - caf::PdmField m_resultAggregation; - caf::PdmField m_showContourLines; - caf::PdmField m_weightByParameter; - caf::PdmChildField m_weightingResult; - cvf::ref m_cellGridIdxVisibility; + caf::PdmField m_relativeSampleSpacing; + caf::PdmField m_resultAggregation; + caf::PdmField m_showContourLines; + caf::PdmField m_showContourLabels; + caf::PdmField m_smoothContourLines; + cvf::ref m_cellGridIdxVisibility; std::vector m_aggregatedResults; std::vector m_aggregatedVertexResults; - std::vector>> m_projected3dGridIndices; - cvf::ref m_resultAccessor; - - cvf::Vec2d m_pickPoint; - - caf::PdmPointer m_eclipseCase; - cvf::ref m_mainGrid; - cvf::Vec2ui m_mapSize; - cvf::BoundingBox m_fullBoundingBox; - double m_sampleSpacing; + cvf::Vec2d m_pickPoint; + cvf::Vec2ui m_mapSize; + cvf::BoundingBox m_expandedBoundingBox; + cvf::BoundingBox m_gridBoundingBox; + double m_sampleSpacing; + std::vector m_contourPolygons; + std::vector m_contourLevelCumulativeAreas; + std::vector m_trianglesWithVertexValues; + int m_currentResultTimestep; + std::vector m_mapCellVisibility; + + double m_minResultAllTimeSteps; + double m_maxResultAllTimeSteps; }; diff --git a/ApplicationCode/ProjectDataModel/RimContourMapView.cpp b/ApplicationCode/ProjectDataModel/RimContourMapView.cpp deleted file mode 100644 index db7fbc9101..0000000000 --- a/ApplicationCode/ProjectDataModel/RimContourMapView.cpp +++ /dev/null @@ -1,380 +0,0 @@ -///////////////////////////////////////////////////////////////////////////////// -// -// Copyright (C) 2018- Equinor ASA -// -// ResInsight 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 3 of the License, or -// (at your option) any later version. -// -// ResInsight 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 at -// for more details. -// -///////////////////////////////////////////////////////////////////////////////// - -#include "RimContourMapView.h" - -#include "RivContourMapProjectionPartMgr.h" -#include "RiuViewer.h" - -#include "Rim3dOverlayInfoConfig.h" -#include "RimCase.h" -#include "RimCellRangeFilterCollection.h" -#include "RimContourMapNameConfig.h" -#include "RimContourMapProjection.h" -#include "RimEclipseCellColors.h" -#include "RimEclipseFaultColors.h" -#include "RimEclipsePropertyFilterCollection.h" -#include "RimFaultInViewCollection.h" -#include "RimGridCollection.h" -#include "RimSimWellInViewCollection.h" - -#include "cafPdmUiTreeOrdering.h" - -#include "cvfCamera.h" -#include "cvfModelBasicList.h" -#include "cvfPart.h" -#include "cvfScene.h" - -CAF_PDM_SOURCE_INIT(RimContourMapView, "RimContourMapView"); - -const cvf::Mat4d defaultViewMatrix(1, 0, 0, 0, - 0, 1, 0, 0, - 0, 0, 1, 1000, - 0, 0, 0, 1); - -RimContourMapView::RimContourMapView() -{ - CAF_PDM_InitObject("Contour Map View", ":/2DMap16x16.png", "", ""); - - CAF_PDM_InitFieldNoDefault(&m_contourMapProjection, "ContourMapProjection", "Contour Map Projection", "", "", ""); - m_contourMapProjection = new RimContourMapProjection(); - - CAF_PDM_InitField(&m_showAxisLines, "ShowAxisLines", true, "Show Axis Lines", "", "", ""); - - m_gridCollection->setActive(false); // This is also not added to the tree view, so cannot be enabled. - setFaultVisParameters(); - - CAF_PDM_InitFieldNoDefault(&m_nameConfig, "NameConfig", "", "", "", ""); - m_nameConfig = new RimContourMapNameConfig(this); - - m_contourMapProjectionPartMgr = new RivContourMapProjectionPartMgr(contourMapProjection(), this); - - ((RiuViewerToViewInterface*)this)->setCameraPosition(defaultViewMatrix); - -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -RimContourMapProjection* RimContourMapView::contourMapProjection() const -{ - return m_contourMapProjection().p(); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -QString RimContourMapView::createAutoName() const -{ - QStringList autoName; - - if (!m_nameConfig->customName().isEmpty()) - { - autoName.push_back(m_nameConfig->customName()); - } - - QStringList generatedAutoTags; - - RimCase* ownerCase = nullptr; - this->firstAncestorOrThisOfTypeAsserted(ownerCase); - - if (m_nameConfig->addCaseName()) - { - generatedAutoTags.push_back(ownerCase->caseUserDescription()); - } - - if (m_nameConfig->addAggregationType()) - { - generatedAutoTags.push_back(contourMapProjection()->resultAggregationText()); - } - - if (m_nameConfig->addProperty() && !contourMapProjection()->isColumnResult()) - { - generatedAutoTags.push_back(cellResult()->resultVariable()); - } - - if (m_nameConfig->addSampleSpacing()) - { - generatedAutoTags.push_back(QString("%1").arg(contourMapProjection()->sampleSpacingFactor(), 3, 'f', 2)); - } - - if (!generatedAutoTags.empty()) - { - autoName.push_back(generatedAutoTags.join(", ")); - } - return autoName.join(": "); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RimContourMapView::initAfterRead() -{ - m_gridCollection->setActive(false); // This is also not added to the tree view, so cannot be enabled. - disablePerspectiveProjectionField(); - setShowGridBox(false); - meshMode.setValue(NO_MESH); - surfaceMode.setValue(FAULTS); - setFaultVisParameters(); - scheduleCreateDisplayModelAndRedraw(); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RimContourMapView::createDisplayModel() -{ - RimEclipseView::createDisplayModel(); - - if (!this->isTimeStepDependentDataVisible()) - { - // Need to add geometry even if it hasn't happened during dynamic time step update. - updateGeometry(); - } - - if (this->viewer()->mainCamera()->viewMatrix() == defaultViewMatrix) - { - this->zoomAll(); - } -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RimContourMapView::defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering) -{ - caf::PdmUiGroup* viewGroup = uiOrdering.addNewGroup("Viewer"); - viewGroup->add(this->userDescriptionField()); - viewGroup->add(this->backgroundColorField()); - viewGroup->add(&m_showAxisLines); - - caf::PdmUiGroup* nameGroup = uiOrdering.addNewGroup("Contour Map Name"); - m_nameConfig->uiOrdering(uiConfigName, *nameGroup); - - uiOrdering.skipRemainingFields(true); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RimContourMapView::defineUiTreeOrdering(caf::PdmUiTreeOrdering& uiTreeOrdering, QString uiConfigName /*= ""*/) -{ - uiTreeOrdering.add(m_overlayInfoConfig()); - uiTreeOrdering.add(m_contourMapProjection); - uiTreeOrdering.add(cellResult()); - cellResult()->uiCapability()->setUiReadOnly(m_contourMapProjection->isColumnResult()); - uiTreeOrdering.add(wellCollection()); - uiTreeOrdering.add(faultCollection()); - uiTreeOrdering.add(m_rangeFilterCollection()); - uiTreeOrdering.add(nativePropertyFilterCollection()); - - uiTreeOrdering.skipRemainingChildren(); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RimContourMapView::updateCurrentTimeStep() -{ - static_cast(nativePropertyFilterCollection())->updateFromCurrentTimeStep(); - updateGeometry(); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RimContourMapView::updateGeometry() -{ - this->updateVisibleGeometriesAndCellColors(); - - if (m_contourMapProjection->isChecked()) - { - m_contourMapProjection->generateResults(); - } - updateLegends(); // To make sure the scalar mappers are set up correctly - - appendWellsAndFracturesToModel(); - - appendContourMapProjectionToModel(); - - appendPickPointVisToModel(); - - m_overlayInfoConfig()->update3DInfo(); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RimContourMapView::setFaultVisParameters() -{ - faultCollection()->setShowFaultsOutsideFilter(false); - faultCollection()->showOppositeFaultFaces = true; - faultCollection()->faultResult = RimFaultInViewCollection::FAULT_NO_FACE_CULLING; - faultResultSettings()->showCustomFaultResult = true; - faultResultSettings()->customFaultResult()->setResultVariable("None"); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RimContourMapView::appendContourMapProjectionToModel() -{ - if (m_viewer && m_contourMapProjection->isChecked()) - { - cvf::Scene* frameScene = m_viewer->frame(m_currentTimeStep); - if (frameScene) - { - cvf::String name = "ContourMapProjection"; - this->removeModelByName(frameScene, name); - - cvf::ref contourMapProjectionModelBasicList = new cvf::ModelBasicList; - contourMapProjectionModelBasicList->setName(name); - - cvf::ref transForm = this->displayCoordTransform(); - - m_contourMapProjectionPartMgr->appendProjectionToModel(contourMapProjectionModelBasicList.p(), transForm.p()); - contourMapProjectionModelBasicList->updateBoundingBoxesRecursive(); - frameScene->addModel(contourMapProjectionModelBasicList.p()); - } - } -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RimContourMapView::appendPickPointVisToModel() -{ - if (m_viewer && m_contourMapProjection->isChecked()) - { - cvf::Scene* frameScene = m_viewer->frame(m_currentTimeStep); - if (frameScene) - { - cvf::String name = "ContourMapPickPoint"; - this->removeModelByName(frameScene, name); - - cvf::ref contourMapProjectionModelBasicList = new cvf::ModelBasicList; - contourMapProjectionModelBasicList->setName(name); - - cvf::ref transForm = this->displayCoordTransform(); - - m_contourMapProjectionPartMgr->appendPickPointVisToModel(contourMapProjectionModelBasicList.p(), transForm.p()); - contourMapProjectionModelBasicList->updateBoundingBoxesRecursive(); - frameScene->addModel(contourMapProjectionModelBasicList.p()); - } - } -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RimContourMapView::updateLegends() -{ - if (m_viewer) - { - m_viewer->removeAllColorLegends(); - - if (m_contourMapProjection && m_contourMapProjection->isChecked()) - { - RimRegularLegendConfig* projectionLegend = m_contourMapProjection->legendConfig(); - if (projectionLegend) - { - m_contourMapProjection->updateLegend(); - if (projectionLegend->showLegend()) - { - m_viewer->addColorLegendToBottomLeftCorner(projectionLegend->titledOverlayFrame()); - } - } - } - } -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RimContourMapView::updateViewWidgetAfterCreation() -{ - if (m_viewer) - { - m_viewer->showAxisCross(false); - m_viewer->showEdgeTickMarksXY(true, m_showAxisLines()); - m_viewer->enableNavigationRotation(false); - } - - Rim3dView::updateViewWidgetAfterCreation(); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RimContourMapView::updateViewFollowingRangeFilterUpdates() -{ - m_contourMapProjection->setCheckState(true); - scheduleCreateDisplayModelAndRedraw(); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RimContourMapView::onLoadDataAndUpdate() -{ - RimEclipseView::onLoadDataAndUpdate(); - if (m_viewer) - { - m_viewer->setView(cvf::Vec3d(0, 0, -1), cvf::Vec3d(0, 1, 0)); - } -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RimContourMapView::fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue) -{ - RimEclipseView::fieldChangedByUi(changedField, oldValue, newValue); - - if (changedField == &m_showAxisLines) - { - m_viewer->showEdgeTickMarksXY(true, m_showAxisLines()); - scheduleCreateDisplayModelAndRedraw(); - } - else if (changedField == backgroundColorField()) - { - scheduleCreateDisplayModelAndRedraw(); - } -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -caf::PdmFieldHandle* RimContourMapView::userDescriptionField() -{ - return m_nameConfig()->nameField(); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -std::set RimContourMapView::allVisibleFaultGeometryTypes() const -{ - std::set faultGeoTypes; - // Normal eclipse views always shows faults for active and visible eclipse cells. - if (faultCollection()->showFaultCollection()) - { - faultGeoTypes = RimEclipseView::allVisibleFaultGeometryTypes(); - } - return faultGeoTypes; -} diff --git a/ApplicationCode/ProjectDataModel/RimContourMapView.h b/ApplicationCode/ProjectDataModel/RimContourMapView.h deleted file mode 100644 index aa35cdd7ac..0000000000 --- a/ApplicationCode/ProjectDataModel/RimContourMapView.h +++ /dev/null @@ -1,62 +0,0 @@ -///////////////////////////////////////////////////////////////////////////////// -// -// Copyright (C) 2018- Equinor ASA -// -// ResInsight 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 3 of the License, or -// (at your option) any later version. -// -// ResInsight 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 at -// for more details. -// -///////////////////////////////////////////////////////////////////////////////// - -#pragma once - -#include "RimEclipseView.h" -#include "RimNameConfig.h" - -class RimContourMapNameConfig; -class RivContourMapProjectionPartMgr; - -class RimContourMapView : public RimEclipseView, public RimNameConfigHolderInterface -{ - CAF_PDM_HEADER_INIT; -public: - RimContourMapView(); - RimContourMapProjection* contourMapProjection() const; - - QString createAutoName() const override; - -protected: - void initAfterRead() override; - void createDisplayModel() override; - void defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering) override; - void defineUiTreeOrdering(caf::PdmUiTreeOrdering& uiTreeOrdering, QString uiConfigName = "") override; - void updateCurrentTimeStep() override; - void updateGeometry(); - void setFaultVisParameters(); - void appendContourMapProjectionToModel(); - void appendPickPointVisToModel(); - void updateLegends() override; - void updateViewWidgetAfterCreation() override; - void updateViewFollowingRangeFilterUpdates() override; - void onLoadDataAndUpdate() override; - void fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue) override; - - caf::PdmFieldHandle* userDescriptionField() override; - - virtual std::set allVisibleFaultGeometryTypes() const override; - -private: - cvf::ref m_contourMapProjectionPartMgr; - caf::PdmChildField m_contourMapProjection; - caf::PdmField m_showAxisLines; - caf::PdmChildField m_nameConfig; -}; - diff --git a/ApplicationCode/ProjectDataModel/RimContourMapViewCollection.cpp b/ApplicationCode/ProjectDataModel/RimContourMapViewCollection.cpp deleted file mode 100644 index abeaeda2b6..0000000000 --- a/ApplicationCode/ProjectDataModel/RimContourMapViewCollection.cpp +++ /dev/null @@ -1,42 +0,0 @@ -#include "RimContourMapViewCollection.h" - -#include "RimContourMapView.h" -#include "RimCase.h" - -CAF_PDM_SOURCE_INIT(RimContourMapViewCollection, "Eclipse2dViewCollection"); - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -RimContourMapViewCollection::RimContourMapViewCollection() -{ - CAF_PDM_InitObject("Contour Maps", ":/2DMaps16x16.png", "", ""); - - CAF_PDM_InitFieldNoDefault(&m_contourMapViews, "EclipseViews", "Contour Maps", ":/CrossSection16x16.png", "", ""); - m_contourMapViews.uiCapability()->setUiTreeHidden(true); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -RimContourMapViewCollection::~RimContourMapViewCollection() -{ - -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -std::vector RimContourMapViewCollection::views() -{ - return m_contourMapViews.childObjects(); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RimContourMapViewCollection::push_back(RimContourMapView* contourMap) -{ - m_contourMapViews.push_back(contourMap); -} - diff --git a/ApplicationCode/ProjectDataModel/RimContourMapViewCollection.h b/ApplicationCode/ProjectDataModel/RimContourMapViewCollection.h deleted file mode 100644 index 741cfa3b5f..0000000000 --- a/ApplicationCode/ProjectDataModel/RimContourMapViewCollection.h +++ /dev/null @@ -1,41 +0,0 @@ -///////////////////////////////////////////////////////////////////////////////// -// -// Copyright (C) 2018- Equinor ASA -// -// ResInsight 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 3 of the License, or -// (at your option) any later version. -// -// ResInsight 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 at -// for more details. -// -///////////////////////////////////////////////////////////////////////////////// - -#pragma once - -#include "cafPdmObject.h" -#include "cafPdmField.h" -#include "cafPdmChildArrayField.h" - -class RimContourMapView; - -class RimContourMapViewCollection : public caf::PdmObject -{ - CAF_PDM_HEADER_INIT; -public: - RimContourMapViewCollection(); - ~RimContourMapViewCollection() override; - - std::vector views(); - void push_back(RimContourMapView* contourMap); -private: - caf::PdmChildArrayField m_contourMapViews; -}; - - - diff --git a/ApplicationCode/ProjectDataModel/RimDialogData.cpp b/ApplicationCode/ProjectDataModel/RimDialogData.cpp index f72b16766b..7042a619b0 100644 --- a/ApplicationCode/ProjectDataModel/RimDialogData.cpp +++ b/ApplicationCode/ProjectDataModel/RimDialogData.cpp @@ -21,6 +21,7 @@ #include "RimMockModelSettings.h" #include "ExportCommands/RicExportCarfinUi.h" +#include "ExportCommands/RicExportEclipseSectorModelUi.h" #include "CompletionExportCommands/RicExportCompletionDataSettingsUi.h" #include "FractureCommands/RicCreateMultipleFracturesUi.h" #include "HoloLensCommands/RicHoloLensExportToFolderUi.h" @@ -54,6 +55,9 @@ RimDialogData::RimDialogData() CAF_PDM_InitFieldNoDefault(&m_exportLgrData, "ExportLgr", "LGR Export", "", "", ""); m_exportLgrData = new RicExportLgrUi(); + CAF_PDM_InitFieldNoDefault(&m_exportSectorModelData, "ExportSectorModel", "Export Sector Model", "", "", ""); + m_exportSectorModelData = new RicExportEclipseSectorModelUi(); + CAF_PDM_InitFieldNoDefault(&m_mockModelSettings, "MockModelSettings", "Mock Model Settings", "", "", ""); m_mockModelSettings = new RimMockModelSettings(); } @@ -131,6 +135,14 @@ RicExportLgrUi* RimDialogData::exportLgrData() const return m_exportLgrData; } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RicExportEclipseSectorModelUi* RimDialogData::exportSectorModelUi() const +{ + return m_exportSectorModelData; +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/ProjectDataModel/RimDialogData.h b/ApplicationCode/ProjectDataModel/RimDialogData.h index 50c1cdea8a..af71e71276 100644 --- a/ApplicationCode/ProjectDataModel/RimDialogData.h +++ b/ApplicationCode/ProjectDataModel/RimDialogData.h @@ -23,6 +23,7 @@ class RicExportCarfinUi; class RicExportCompletionDataSettingsUi; +class RicExportEclipseSectorModelUi; class RiuCreateMultipleFractionsUi; class RicHoloLensExportToFolderUi; class RicExportWellPathsUi; @@ -54,11 +55,12 @@ class RimDialogData : public caf::PdmObject RicExportCompletionDataSettingsUi* exportCompletionData() const; - RiuCreateMultipleFractionsUi* multipleFractionsData() const; - RicHoloLensExportToFolderUi* holoLensExportToFolderData() const; - RicExportWellPathsUi* wellPathsExportData() const; - RicExportLgrUi* exportLgrData() const; - RimMockModelSettings* mockModelSettings() const; + RiuCreateMultipleFractionsUi* multipleFractionsData() const; + RicHoloLensExportToFolderUi* holoLensExportToFolderData() const; + RicExportWellPathsUi* wellPathsExportData() const; + RicExportLgrUi* exportLgrData() const; + RicExportEclipseSectorModelUi* exportSectorModelUi() const; + RimMockModelSettings* mockModelSettings() const; private: caf::PdmChildField m_exportCarfin; @@ -67,5 +69,6 @@ class RimDialogData : public caf::PdmObject caf::PdmChildField m_holoLenseExportToFolderData; caf::PdmChildField m_exportWellPathsData; caf::PdmChildField m_exportLgrData; + caf::PdmChildField m_exportSectorModelData; caf::PdmChildField m_mockModelSettings; }; diff --git a/ApplicationCode/ProjectDataModel/RimEclipseCase.cpp b/ApplicationCode/ProjectDataModel/RimEclipseCase.cpp index 9319263aca..e5b9acec89 100644 --- a/ApplicationCode/ProjectDataModel/RimEclipseCase.cpp +++ b/ApplicationCode/ProjectDataModel/RimEclipseCase.cpp @@ -24,10 +24,12 @@ #include "RiaColorTables.h" #include "RiaFieldHandleTools.h" #include "RiaPreferences.h" +#include "RiaQDateTimeTools.h" -#include "CompletionExportCommands/RicExportCompletionDataSettingsUi.h" #include "CompletionExportCommands/RicWellPathExportCompletionDataFeatureImpl.h" +#include "RifReaderSettings.h" + #include "RigActiveCellInfo.h" #include "RigCaseCellResultsData.h" #include "RigEclipseCaseData.h" @@ -35,20 +37,16 @@ #include "RigSimWellData.h" #include "RigVirtualPerforationTransmissibilities.h" -#include "RimContourMapView.h" -#include "RimContourMapViewCollection.h" -#include "Rim2dIntersectionView.h" #include "Rim2dIntersectionViewCollection.h" #include "RimCaseCollection.h" #include "RimCellEdgeColors.h" -#include "RimCommandObject.h" #include "RimEclipseCellColors.h" +#include "RimEclipseContourMapView.h" +#include "RimEclipseContourMapViewCollection.h" #include "RimEclipsePropertyFilter.h" #include "RimEclipsePropertyFilterCollection.h" #include "RimEclipseStatisticsCase.h" #include "RimEclipseView.h" -#include "RimFlowCharacteristicsPlot.h" -#include "RimFlowPlotCollection.h" #include "RimFormationNames.h" #include "RimGridCollection.h" #include "RimIntersectionCollection.h" @@ -56,17 +54,9 @@ #include "RimOilField.h" #include "RimPerforationCollection.h" #include "RimProject.h" -#include "RimRegularLegendConfig.h" +#include "RimReloadCaseTools.h" #include "RimReservoirCellResultsStorage.h" #include "RimStimPlanColors.h" -#include "RimSummaryCase.h" -#include "RimSummaryCaseMainCollection.h" -#include "RimSummaryPlot.h" -#include "RimSummaryPlotCollection.h" -#include "RimTools.h" -#include "RimVirtualPerforationResults.h" -#include "RimWellAllocationPlot.h" -#include "RimWellLogPlot.h" #include "RimWellLogPlotCollection.h" #include "RimWellPath.h" #include "RimWellPathCollection.h" @@ -75,9 +65,7 @@ #include "cafPdmUiTreeOrdering.h" #include "cafProgressInfo.h" -#include -#include -#include +#include "cafUtils.h" #include CAF_PDM_XML_ABSTRACT_SOURCE_INIT(RimEclipseCase, "RimReservoir"); @@ -102,7 +90,7 @@ RimEclipseCase::RimEclipseCase() m_filesContainingFaultsSemColSeparated.uiCapability()->setUiHidden(true); CAF_PDM_InitFieldNoDefault(&m_contourMapCollection, "ContourMaps", "2d Contour Maps", "", "", ""); - m_contourMapCollection = new RimContourMapViewCollection; + m_contourMapCollection = new RimEclipseContourMapViewCollection; m_contourMapCollection.uiCapability()->setUiTreeHidden(true); // Obsolete fields @@ -171,6 +159,33 @@ const RigEclipseCaseData* RimEclipseCase::eclipseCaseData() const return m_rigEclipseCase.p(); } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimEclipseCase::ensureDeckIsParsedForEquilData() +{ + if (m_rigEclipseCase.notNull()) + { + QString includeFileAbsolutePathPrefix; + { + RiaPreferences* prefs = RiaApplication::instance()->preferences(); + if (prefs->readerSettings()) + { + includeFileAbsolutePathPrefix = prefs->readerSettings()->includeFileAbsolutePathPrefix(); + } + } + + QString dataDeckFile; + { + QFileInfo fi(gridFileName()); + + dataDeckFile = caf::Utils::constructFullFileName(fi.absolutePath(), fi.baseName(), ".DATA"); + } + + m_rigEclipseCase->ensureDeckIsParsedForEquilData(dataDeckFile, includeFileAbsolutePathPrefix); + } +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -239,7 +254,7 @@ void RimEclipseCase::initAfterRead() riv->setEclipseCase(this); } - for (RimContourMapView* contourMap : m_contourMapCollection->views()) + for (RimEclipseContourMapView* contourMap : m_contourMapCollection->views()) { contourMap->setEclipseCase(this); } @@ -276,9 +291,6 @@ RimEclipseView* RimEclipseCase::createAndAddReservoirView() caf::PdmDocument::updateUiIconStateRecursively(rimEclipseView); - size_t i = reservoirViews().size(); - rimEclipseView->setName(QString("View %1").arg(i + 1)); - reservoirViews().push_back(rimEclipseView); return rimEclipseView; @@ -417,7 +429,7 @@ void RimEclipseCase::fieldChangedByUi(const caf::PdmFieldHandle* changedField, c { if (changedField == &m_releaseResultMemory) { - reloadDataAndUpdate(); + RimReloadCaseTools::reloadAllEclipseGridData(this); m_releaseResultMemory = oldValue.toBool(); } @@ -456,11 +468,11 @@ void RimEclipseCase::updateFormationNamesData() { if (activeFormationNames()) { - rigEclipseCase->setActiveFormationNames(activeFormationNames()->formationNamesData()); + rigEclipseCase->setActiveFormationNamesAndUpdatePlots(activeFormationNames()->formationNamesData()); } else { - rigEclipseCase->setActiveFormationNames(nullptr); + rigEclipseCase->setActiveFormationNamesAndUpdatePlots(nullptr); } std::vector views = this->views(); for (Rim3dView* view : views) @@ -480,7 +492,7 @@ void RimEclipseCase::updateFormationNamesData() RimEclipsePropertyFilterCollection* eclFilColl = eclView->eclipsePropertyFilterCollection(); for (RimEclipsePropertyFilter* propFilter : eclFilColl->propertyFilters) { - if (propFilter->resultDefinition->resultType() == RiaDefines::FORMATION_NAMES) + if (propFilter->resultDefinition()->resultType() == RiaDefines::FORMATION_NAMES) { propFilter->resultDefinition()->setResultVariable(RiaDefines::undefinedResultName()); } @@ -490,7 +502,7 @@ void RimEclipseCase::updateFormationNamesData() RimEclipsePropertyFilterCollection* eclFilColl = eclView->eclipsePropertyFilterCollection(); for (RimEclipsePropertyFilter* propFilter : eclFilColl->propertyFilters) { - if (propFilter->resultDefinition->resultType() == RiaDefines::FORMATION_NAMES) + if (propFilter->resultDefinition()->resultType() == RiaDefines::FORMATION_NAMES) { propFilter->setToDefaultValues(); propFilter->updateConnectedEditors(); @@ -520,10 +532,12 @@ void RimEclipseCase::defineUiTreeOrdering(caf::PdmUiTreeOrdering& uiTreeOrdering { uiTreeOrdering.add(&m_2dIntersectionViewCollection); } + if (!m_contourMapCollection->views().empty()) { uiTreeOrdering.add(&m_contourMapCollection); } + uiTreeOrdering.skipRemainingChildren(true); } @@ -536,31 +550,33 @@ void RimEclipseCase::computeCachedData() if (rigEclipseCase) { caf::ProgressInfo pInf(30, ""); - pInf.setNextProgressIncrement(1); - rigEclipseCase->computeActiveCellBoundingBoxes(); - pInf.incrementProgress(); - - pInf.setNextProgressIncrement(10); - pInf.setProgressDescription("Calculating Cell Search Tree"); - rigEclipseCase->mainGrid()->computeCachedData(); - pInf.incrementProgress(); - pInf.setNextProgressIncrement(17); - pInf.setProgressDescription("Calculating faults"); - rigEclipseCase->mainGrid()->calculateFaults(rigEclipseCase->activeCellInfo(RiaDefines::MATRIX_MODEL)); - pInf.incrementProgress(); + { + auto task = pInf.task("", 1); + rigEclipseCase->computeActiveCellBoundingBoxes(); + } - pInf.setProgressDescription("Calculating Formation Names Result"); - if (activeFormationNames()) { - rigEclipseCase->setActiveFormationNames(activeFormationNames()->formationNamesData()); + auto task = pInf.task("Calculating Cell Search Tree", 10); + rigEclipseCase->mainGrid()->computeCachedData(); } - else + { - rigEclipseCase->setActiveFormationNames(nullptr); + auto task = pInf.task("Calculating faults", 17); + rigEclipseCase->mainGrid()->calculateFaults(rigEclipseCase->activeCellInfo(RiaDefines::MATRIX_MODEL)); } - pInf.incrementProgress(); + { + auto task = pInf.task("Calculating Formation Names Result", 2); + if (activeFormationNames()) + { + rigEclipseCase->setActiveFormationNames(activeFormationNames()->formationNamesData()); + } + else + { + rigEclipseCase->setActiveFormationNames(nullptr); + } + } } } @@ -575,7 +591,7 @@ RimCaseCollection* RimEclipseCase::parentCaseCollection() //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -RimContourMapViewCollection* RimEclipseCase::contourMapCollection() +RimEclipseContourMapViewCollection* RimEclipseCase::contourMapCollection() { return m_contourMapCollection; } @@ -605,7 +621,7 @@ void RimEclipseCase::createTimeStepFormatString() { std::vector timeStepDates = this->timeStepDates(); - m_timeStepFormatString = RimTools::createTimeFormatStringFromDates(timeStepDates); + m_timeStepFormatString = RiaQDateTimeTools::createTimeFormatStringFromDates(timeStepDates); } //-------------------------------------------------------------------------------------------------- @@ -692,8 +708,7 @@ bool RimEclipseCase::loadStaticResultsByName(const std::vector& resultN { for (const auto& resultName : resultNames) { - size_t resultIdx = cellResultsData->findOrLoadScalarResult(RiaDefines::STATIC_NATIVE, resultName); - if (resultIdx == cvf::UNDEFINED_SIZE_T) + if (!cellResultsData->ensureKnownResultLoaded(RigEclipseResultAddress(RiaDefines::STATIC_NATIVE, resultName))) { foundDataForAllResults = false; } @@ -763,6 +778,19 @@ void RimEclipseCase::setFilesContainingFaults(const std::vector& val) m_filesContainingFaultsSemColSeparated = separatedPaths; } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RimEclipseCase::ensureReservoirCaseIsOpen() +{ + if (m_rigEclipseCase.notNull()) + { + return true; + } + + return openReserviorCase(); +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -790,33 +818,37 @@ bool RimEclipseCase::openReserviorCase() results->createPlaceholderResultEntries(); // After the placeholder result for combined transmissibility is created, // make sure the nnc transmissibilities can be addressed by this scalarResultIndex as well - size_t combinedTransResIdx = - results->findScalarResultIndex(RiaDefines::STATIC_NATIVE, RiaDefines::combinedTransmissibilityResultName()); - if (combinedTransResIdx != cvf::UNDEFINED_SIZE_T) + + RigEclipseResultAddress combinedTransmissibilityResAddr(RiaDefines::STATIC_NATIVE, + RiaDefines::combinedTransmissibilityResultName()); + if (results->hasResultEntry(combinedTransmissibilityResAddr)) { - eclipseCaseData()->mainGrid()->nncData()->setScalarResultIndex(RigNNCData::propertyNameCombTrans(), - combinedTransResIdx); + eclipseCaseData()->mainGrid()->nncData()->setEclResultAddress(RigNNCData::propertyNameCombTrans(), + combinedTransmissibilityResAddr); } - size_t combinedWatFluxResIdx = - results->findScalarResultIndex(RiaDefines::DYNAMIC_NATIVE, RiaDefines::combinedWaterFluxResultName()); - if (combinedWatFluxResIdx != cvf::UNDEFINED_SIZE_T) + + RigEclipseResultAddress combinedWaterFluxResAddr(RiaDefines::DYNAMIC_NATIVE, + RiaDefines::combinedWaterFluxResultName()); + if (results->hasResultEntry(combinedWaterFluxResAddr)) { - eclipseCaseData()->mainGrid()->nncData()->setScalarResultIndex(RigNNCData::propertyNameFluxWat(), - combinedWatFluxResIdx); + eclipseCaseData()->mainGrid()->nncData()->setEclResultAddress(RigNNCData::propertyNameFluxWat(), + combinedWaterFluxResAddr); } - size_t combinedOilFluxResIdx = - results->findScalarResultIndex(RiaDefines::DYNAMIC_NATIVE, RiaDefines::combinedOilFluxResultName()); - if (combinedOilFluxResIdx != cvf::UNDEFINED_SIZE_T) + + RigEclipseResultAddress combinedOilFluxResAddr(RiaDefines::DYNAMIC_NATIVE, + RiaDefines::combinedOilFluxResultName()); + if (results->hasResultEntry(combinedOilFluxResAddr)) { - eclipseCaseData()->mainGrid()->nncData()->setScalarResultIndex(RigNNCData::propertyNameFluxOil(), - combinedOilFluxResIdx); + eclipseCaseData()->mainGrid()->nncData()->setEclResultAddress(RigNNCData::propertyNameFluxOil(), + combinedOilFluxResAddr); } - size_t combinedGasFluxResIdx = - results->findScalarResultIndex(RiaDefines::DYNAMIC_NATIVE, RiaDefines::combinedGasFluxResultName()); - if (combinedGasFluxResIdx != cvf::UNDEFINED_SIZE_T) + RigEclipseResultAddress combinedGasFluxResAddr(RiaDefines::DYNAMIC_NATIVE, + RiaDefines::combinedGasFluxResultName()); + + if (results->hasResultEntry(combinedGasFluxResAddr)) { - eclipseCaseData()->mainGrid()->nncData()->setScalarResultIndex(RigNNCData::propertyNameFluxGas(), - combinedGasFluxResIdx); + eclipseCaseData()->mainGrid()->nncData()->setEclResultAddress(RigNNCData::propertyNameFluxGas(), + combinedGasFluxResAddr); } } } @@ -869,7 +901,7 @@ std::vector RimEclipseCase::allSpecialViews() const views.push_back(view); } - for (RimContourMapView* view : m_contourMapCollection->views()) + for (RimEclipseContourMapView* view : m_contourMapCollection->views()) { views.push_back(view); } @@ -913,88 +945,6 @@ QString RimEclipseCase::timeStepName(int frameIdx) const return QString(""); } -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RimEclipseCase::reloadDataAndUpdate() -{ - if (this->eclipseCaseData()) - { - RigCaseCellResultsData* matrixModelResults = eclipseCaseData()->results(RiaDefines::MATRIX_MODEL); - if (matrixModelResults) - { - matrixModelResults->clearAllResults(); - } - - RigCaseCellResultsData* fractureModelResults = eclipseCaseData()->results(RiaDefines::FRACTURE_MODEL); - if (fractureModelResults) - { - fractureModelResults->clearAllResults(); - } - - reloadEclipseGridFile(); - - for (size_t i = 0; i < reservoirViews().size(); i++) - { - RimEclipseView* reservoirView = reservoirViews()[i]; - CVF_ASSERT(reservoirView); - reservoirView->loadDataAndUpdate(); - reservoirView->updateGridBoxData(); - reservoirView->updateAnnotationItems(); - } - - for (RimContourMapView* contourMap : m_contourMapCollection->views()) - { - CVF_ASSERT(contourMap); - contourMap->loadDataAndUpdate(); - contourMap->updateGridBoxData(); - contourMap->updateAnnotationItems(); - } - - for (Rim2dIntersectionView* view : intersectionViewCollection()->views()) - { - view->createDisplayModelAndRedraw(); - } - - RimProject* project = RiaApplication::instance()->project(); - if (project) - { - RimSummaryCaseMainCollection* sumCaseColl = - project->activeOilField() ? project->activeOilField()->summaryCaseMainCollection() : nullptr; - if (sumCaseColl) - { - sumCaseColl->loadAllSummaryCaseData(); - } - - if (project->mainPlotCollection()) - { - RimWellLogPlotCollection* wellPlotCollection = project->mainPlotCollection()->wellLogPlotCollection(); - RimSummaryPlotCollection* summaryPlotCollection = project->mainPlotCollection()->summaryPlotCollection(); - RimFlowPlotCollection* flowPlotCollection = project->mainPlotCollection()->flowPlotCollection(); - - if (wellPlotCollection) - { - for (size_t i = 0; i < wellPlotCollection->wellLogPlots().size(); ++i) - { - wellPlotCollection->wellLogPlots()[i]->loadDataAndUpdate(); - } - } - if (summaryPlotCollection) - { - for (size_t i = 0; i < summaryPlotCollection->summaryPlots().size(); ++i) - { - summaryPlotCollection->summaryPlots()[i]->loadDataAndUpdate(); - } - } - if (flowPlotCollection) - { - flowPlotCollection->loadDataAndUpdate(); - } - } - } - } -} - //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -1017,7 +967,7 @@ void RimEclipseCase::setFormationNames(RimFormationNames* formationNames) activeFormationNames = formationNames; if (m_rigEclipseCase.notNull() && formationNames != nullptr) { - m_rigEclipseCase->setActiveFormationNames(formationNames->formationNamesData()); + m_rigEclipseCase->setActiveFormationNamesAndUpdatePlots(formationNames->formationNamesData()); } } diff --git a/ApplicationCode/ProjectDataModel/RimEclipseCase.h b/ApplicationCode/ProjectDataModel/RimEclipseCase.h index 7b8f4d48d6..ab94d5c59d 100644 --- a/ApplicationCode/ProjectDataModel/RimEclipseCase.h +++ b/ApplicationCode/ProjectDataModel/RimEclipseCase.h @@ -45,8 +45,8 @@ class RigMainGrid; class RimCaseCollection; class RimIdenticalGridCaseGroup; class RimReservoirCellResultsStorage; -class RimContourMapView; -class RimContourMapViewCollection; +class RimEclipseContourMapView; +class RimEclipseContourMapViewCollection; class RimEclipseView; class RigVirtualPerforationTransmissibilities; @@ -69,11 +69,13 @@ class RimEclipseCase : public RimCase std::vector filesContainingFaults() const; void setFilesContainingFaults(const std::vector& val); + bool ensureReservoirCaseIsOpen(); bool openReserviorCase(); virtual bool openEclipseGridFile() = 0; RigEclipseCaseData* eclipseCaseData(); const RigEclipseCaseData* eclipseCaseData() const; + void ensureDeckIsParsedForEquilData(); cvf::Color3f defaultWellColor(const QString& wellName); const RigMainGrid* mainGrid() const; @@ -95,33 +97,32 @@ class RimEclipseCase : public RimCase RimCaseCollection* parentCaseCollection(); - RimContourMapViewCollection* contourMapCollection(); + RimEclipseContourMapViewCollection* contourMapCollection(); - QStringList timeStepStrings() const override; - QString timeStepName(int frameIdx) const override; - std::vector timeStepDates() const override; + QStringList timeStepStrings() const override; + QString timeStepName(int frameIdx) const override; + std::vector timeStepDates() const override; cvf::BoundingBox activeCellsBoundingBox() const override; cvf::BoundingBox allCellsBoundingBox() const override; cvf::Vec3d displayModelOffset() const override; - void reloadDataAndUpdate(); virtual void reloadEclipseGridFile() = 0; - double characteristicCellSize() const override; + double characteristicCellSize() const override; - void setFormationNames(RimFormationNames* formationNames) override; + void setFormationNames(RimFormationNames* formationNames) override; std::set sortedSimWellNames() const; protected: void initAfterRead() override; void fieldChangedByUi( const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue ) override; - void defineUiTreeOrdering(caf::PdmUiTreeOrdering& uiTreeOrdering, QString uiConfigName = "") override; + void defineUiTreeOrdering(caf::PdmUiTreeOrdering& uiTreeOrdering, QString uiConfigName = "") override; - void updateFormationNamesData() override; + void updateFormationNamesData() override; // Internal methods protected: @@ -130,7 +131,7 @@ class RimEclipseCase : public RimCase private: void createTimeStepFormatString(); - std::vector allSpecialViews() const override; + std::vector allSpecialViews() const override; protected: caf::PdmField m_flipXAxis; @@ -140,7 +141,7 @@ class RimEclipseCase : public RimCase caf::PdmField m_filesContainingFaultsSemColSeparated; caf::PdmField m_releaseResultMemory; - caf::PdmChildField m_contourMapCollection; + caf::PdmChildField m_contourMapCollection; cvf::ref m_rigEclipseCase; QString m_timeStepFormatString; diff --git a/ApplicationCode/ProjectDataModel/RimEclipseCellColors.cpp b/ApplicationCode/ProjectDataModel/RimEclipseCellColors.cpp index b1c08d4afd..c188b672e7 100644 --- a/ApplicationCode/ProjectDataModel/RimEclipseCellColors.cpp +++ b/ApplicationCode/ProjectDataModel/RimEclipseCellColors.cpp @@ -52,15 +52,15 @@ RimEclipseCellColors::RimEclipseCellColors() { CAF_PDM_InitObject("Cell Result", ":/CellResult.png", "", ""); - CAF_PDM_InitFieldNoDefault(&obsoleteField_legendConfig, "LegendDefinition", "Legend Definition", "", "", ""); + CAF_PDM_InitFieldNoDefault(&obsoleteField_legendConfig, "LegendDefinition", "Color Legend", "", "", ""); this->obsoleteField_legendConfig.xmlCapability()->setIOWritable(false); CAF_PDM_InitFieldNoDefault(&m_legendConfigData, "ResultVarLegendDefinitionList", "", "", "", ""); - CAF_PDM_InitFieldNoDefault(&m_ternaryLegendConfig, "TernaryLegendDefinition", "Ternary Legend Definition", "", "", ""); + CAF_PDM_InitFieldNoDefault(&m_ternaryLegendConfig, "TernaryLegendDefinition", "Ternary Color Legend", "", "", ""); this->m_ternaryLegendConfig = new RimTernaryLegendConfig(); - CAF_PDM_InitFieldNoDefault(&m_legendConfigPtrField, "LegendDefinitionPtrField", "Legend Definition PtrField", "", "", ""); + CAF_PDM_InitFieldNoDefault(&m_legendConfigPtrField, "LegendDefinitionPtrField", "Color Legend PtrField", "", "", ""); // Make sure we have a created legend for the default/undefined result variable changeLegendConfig(this->resultVariable()); @@ -183,6 +183,19 @@ void RimEclipseCellColors::initAfterRead() updateIconState(); } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimEclipseCellColors::defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering) +{ + RimEclipseResultDefinition::defineUiOrdering(uiConfigName, uiOrdering); + + if (uiConfigName == "AddLegendLevels") + { + legendConfig()->uiOrdering("NumIntervalsOnly", uiOrdering); + } +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -229,11 +242,21 @@ void RimEclipseCellColors::updateLegendCategorySettings() //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RimEclipseCellColors::setReservoirView(RimEclipseView* ownerReservoirView) +void RimEclipseCellColors::uiTreeOrdering(caf::PdmUiTreeOrdering& uiTreeOrdering, QString uiConfigName /*= ""*/) { - this->setEclipseCase(ownerReservoirView->eclipseCase()); + defineUiTreeOrdering(uiTreeOrdering, uiConfigName); +} +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimEclipseCellColors::setReservoirView(RimEclipseView* ownerReservoirView) +{ m_reservoirView = ownerReservoirView; + if (ownerReservoirView) + { + this->setEclipseCase(ownerReservoirView->eclipseCase()); + } } //-------------------------------------------------------------------------------------------------- @@ -274,7 +297,8 @@ public : //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RimEclipseCellColors::updateLegendData(size_t currentTimeStep, +void RimEclipseCellColors::updateLegendData(RimEclipseCase* rimEclipseCase, + int currentTimeStep, RimRegularLegendConfig* legendConfig, RimTernaryLegendConfig* ternaryLegendConfig) { @@ -285,22 +309,22 @@ void RimEclipseCellColors::updateLegendData(size_t currentTimeStep, { if ( this->isFlowDiagOrInjectionFlooding() ) { + CVF_ASSERT(currentTimeStep >= 0); + double globalMin, globalMax; double globalPosClosestToZero, globalNegClosestToZero; RigFlowDiagResults* flowResultsData = this->flowDiagSolution()->flowDiagResults(); RigFlowDiagResultAddress resAddr = this->flowDiagResAddress(); - int integerTimeStep = static_cast(currentTimeStep); - - flowResultsData->minMaxScalarValues(resAddr, integerTimeStep, &globalMin, &globalMax); - flowResultsData->posNegClosestToZero(resAddr, integerTimeStep, &globalPosClosestToZero, &globalNegClosestToZero); + flowResultsData->minMaxScalarValues(resAddr, currentTimeStep, &globalMin, &globalMax); + flowResultsData->posNegClosestToZero(resAddr, currentTimeStep, &globalPosClosestToZero, &globalNegClosestToZero); double localMin, localMax; double localPosClosestToZero, localNegClosestToZero; if ( this->hasDynamicResult() ) { - flowResultsData->minMaxScalarValues(resAddr, integerTimeStep, &localMin, &localMax); - flowResultsData->posNegClosestToZero(resAddr, integerTimeStep, &localPosClosestToZero, &localNegClosestToZero); + flowResultsData->minMaxScalarValues(resAddr, currentTimeStep, &localMin, &localMax); + flowResultsData->posNegClosestToZero(resAddr, currentTimeStep, &localPosClosestToZero, &localNegClosestToZero); } else { @@ -318,7 +342,7 @@ void RimEclipseCellColors::updateLegendData(size_t currentTimeStep, localPosClosestToZero, localNegClosestToZero); legendConfig->setAutomaticRanges(globalMin, globalMax, localMin, localMax); - if ( this->hasCategoryResult() ) + if ( this->hasCategoryResult() && m_reservoirView) { std::set, TupleCompare > categories; //std::set > categories; @@ -346,8 +370,6 @@ void RimEclipseCellColors::updateLegendData(size_t currentTimeStep, } else { - RimEclipseCase* rimEclipseCase = nullptr; - this->firstAncestorOrThisOfType(rimEclipseCase); CVF_ASSERT(rimEclipseCase); if ( !rimEclipseCase ) return; @@ -360,15 +382,16 @@ void RimEclipseCellColors::updateLegendData(size_t currentTimeStep, double globalMin, globalMax; double globalPosClosestToZero, globalNegClosestToZero; - cellResultsData->minMaxCellScalarValues(this->scalarResultIndex(), globalMin, globalMax); - cellResultsData->posNegClosestToZero(this->scalarResultIndex(), globalPosClosestToZero, globalNegClosestToZero); + + cellResultsData->minMaxCellScalarValues(this->eclipseResultAddress(), globalMin, globalMax); + cellResultsData->posNegClosestToZero(this->eclipseResultAddress(), globalPosClosestToZero, globalNegClosestToZero); double localMin, localMax; double localPosClosestToZero, localNegClosestToZero; - if ( this->hasDynamicResult() ) + if ( this->hasDynamicResult() && currentTimeStep >= 0) { - cellResultsData->minMaxCellScalarValues(this->scalarResultIndex(), currentTimeStep, localMin, localMax); - cellResultsData->posNegClosestToZero(this->scalarResultIndex(), currentTimeStep, localPosClosestToZero, localNegClosestToZero); + cellResultsData->minMaxCellScalarValues(this->eclipseResultAddress(), currentTimeStep, localMin, localMax); + cellResultsData->posNegClosestToZero(this->eclipseResultAddress(), currentTimeStep, localPosClosestToZero, localNegClosestToZero); } else { @@ -394,7 +417,7 @@ void RimEclipseCellColors::updateLegendData(size_t currentTimeStep, } else if ( this->resultType() == RiaDefines::DYNAMIC_NATIVE && this->resultVariable() == RiaDefines::completionTypeResultName() ) { - const std::vector& visibleCategories = cellResultsData->uniqueCellScalarValues(this->scalarResultIndex()); + const std::vector& visibleCategories = cellResultsData->uniqueCellScalarValues(this->eclipseResultAddress()); std::vector supportedCompletionTypes = { RiaDefines::WELL_PATH, RiaDefines::FISHBONES, RiaDefines::PERFORATION_INTERVAL, RiaDefines::FRACTURE }; @@ -415,7 +438,7 @@ void RimEclipseCellColors::updateLegendData(size_t currentTimeStep, } else { - legendConfig->setIntegerCategories(cellResultsData->uniqueCellScalarValues(this->scalarResultIndex())); + legendConfig->setIntegerCategories(cellResultsData->uniqueCellScalarValues(this->eclipseResultAddress())); } } } @@ -423,8 +446,6 @@ void RimEclipseCellColors::updateLegendData(size_t currentTimeStep, // Ternary legend update { - RimEclipseCase* rimEclipseCase = nullptr; - this->firstAncestorOrThisOfType(rimEclipseCase); CVF_ASSERT(rimEclipseCase); if ( !rimEclipseCase ) return; @@ -440,48 +461,51 @@ void RimEclipseCellColors::updateLegendData(size_t currentTimeStep, { RigCaseCellResultsData* gridCellResults = this->currentGridCellResults(); { - size_t scalarSetIndex = gridCellResults->findOrLoadScalarResult(RiaDefines::DYNAMIC_NATIVE, "SOIL"); - if ( scalarSetIndex != cvf::UNDEFINED_SIZE_T ) + RigEclipseResultAddress resAddr(RiaDefines::DYNAMIC_NATIVE, "SOIL"); + + if ( gridCellResults->ensureKnownResultLoaded(resAddr) ) { double globalMin = 0.0; double globalMax = 1.0; double localMin = 0.0; double localMax = 1.0; - cellResultsData->minMaxCellScalarValues(scalarSetIndex, globalMin, globalMax); - cellResultsData->minMaxCellScalarValues(scalarSetIndex, currentTimeStep, localMin, localMax); + cellResultsData->minMaxCellScalarValues(resAddr, globalMin, globalMax); + cellResultsData->minMaxCellScalarValues(resAddr, currentTimeStep, localMin, localMax); ternaryLegendConfig->setAutomaticRanges(RimTernaryLegendConfig::TERNARY_SOIL_IDX, globalMin, globalMax, localMin, localMax); } } { - size_t scalarSetIndex = gridCellResults->findOrLoadScalarResult(RiaDefines::DYNAMIC_NATIVE, "SGAS"); - if ( scalarSetIndex != cvf::UNDEFINED_SIZE_T ) + RigEclipseResultAddress resAddr(RiaDefines::DYNAMIC_NATIVE, "SGAS"); + + if ( gridCellResults->ensureKnownResultLoaded(resAddr) ) { double globalMin = 0.0; double globalMax = 1.0; double localMin = 0.0; double localMax = 1.0; - cellResultsData->minMaxCellScalarValues(scalarSetIndex, globalMin, globalMax); - cellResultsData->minMaxCellScalarValues(scalarSetIndex, currentTimeStep, localMin, localMax); + cellResultsData->minMaxCellScalarValues(resAddr, globalMin, globalMax); + cellResultsData->minMaxCellScalarValues(resAddr, currentTimeStep, localMin, localMax); ternaryLegendConfig->setAutomaticRanges(RimTernaryLegendConfig::TERNARY_SGAS_IDX, globalMin, globalMax, localMin, localMax); } } { - size_t scalarSetIndex = gridCellResults->findOrLoadScalarResult(RiaDefines::DYNAMIC_NATIVE, "SWAT"); - if ( scalarSetIndex != cvf::UNDEFINED_SIZE_T ) + RigEclipseResultAddress resAddr(RiaDefines::DYNAMIC_NATIVE, "SWAT"); + + if ( gridCellResults->ensureKnownResultLoaded(resAddr) ) { double globalMin = 0.0; double globalMax = 1.0; double localMin = 0.0; double localMax = 1.0; - cellResultsData->minMaxCellScalarValues(scalarSetIndex, globalMin, globalMax); - cellResultsData->minMaxCellScalarValues(scalarSetIndex, currentTimeStep, localMin, localMax); + cellResultsData->minMaxCellScalarValues(resAddr, globalMin, globalMax); + cellResultsData->minMaxCellScalarValues(resAddr, currentTimeStep, localMin, localMax); ternaryLegendConfig->setAutomaticRanges(RimTernaryLegendConfig::TERNARY_SWAT_IDX, globalMin, globalMax, localMin, localMax); } @@ -521,16 +545,18 @@ RimTernaryLegendConfig* RimEclipseCellColors::ternaryLegendConfig() //-------------------------------------------------------------------------------------------------- void RimEclipseCellColors::updateIconState() { - RimViewController* viewController = m_reservoirView->viewController(); - if (viewController && viewController->isResultColorControlled()) + if (m_reservoirView) { - updateUiIconFromState(false); - } - else - { - updateUiIconFromState(true); + RimViewController* viewController = m_reservoirView->viewController(); + if (viewController && viewController->isResultColorControlled()) + { + updateUiIconFromState(false); + } + else + { + updateUiIconFromState(true); + } } - uiCapability()->updateConnectedEditors(); } diff --git a/ApplicationCode/ProjectDataModel/RimEclipseCellColors.h b/ApplicationCode/ProjectDataModel/RimEclipseCellColors.h index 1626f83580..f8d96297b1 100644 --- a/ApplicationCode/ProjectDataModel/RimEclipseCellColors.h +++ b/ApplicationCode/ProjectDataModel/RimEclipseCellColors.h @@ -26,6 +26,7 @@ #include "cafPdmChildField.h" #include "cafPdmPtrField.h" +class RimEclipseCase; class RimTernaryLegendConfig; class RimRegularLegendConfig; @@ -43,10 +44,10 @@ class RimEclipseCellColors : public RimEclipseResultDefinition void setReservoirView(RimEclipseView* ownerReservoirView); RimEclipseView* reservoirView(); - void updateLegendData(size_t timestep, + void updateLegendData(RimEclipseCase* rimEclipseCase, + int timestep, RimRegularLegendConfig* legendConfig = nullptr, RimTernaryLegendConfig* ternaryLegendConfig = nullptr); - RimRegularLegendConfig* legendConfig(); RimTernaryLegendConfig* ternaryLegendConfig(); @@ -55,7 +56,7 @@ class RimEclipseCellColors : public RimEclipseResultDefinition void updateIconState(); void updateLegendCategorySettings() override; - + void uiTreeOrdering(caf::PdmUiTreeOrdering& uiTreeOrdering, QString uiConfigName = ""); protected: // Overridden methods void fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue) override; @@ -65,6 +66,9 @@ class RimEclipseCellColors : public RimEclipseResultDefinition friend class RimCellEdgeColors; void initAfterRead() override; + + void defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering) override; + private: void changeLegendConfig(QString resultVarNameOfNewLegend); diff --git a/ApplicationCode/ProjectDataModel/RimEclipseContourMapProjection.cpp b/ApplicationCode/ProjectDataModel/RimEclipseContourMapProjection.cpp new file mode 100644 index 0000000000..9ee5933e0a --- /dev/null +++ b/ApplicationCode/ProjectDataModel/RimEclipseContourMapProjection.cpp @@ -0,0 +1,517 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2018- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "RimEclipseContourMapProjection.h" + +#include "RiaWeightedGeometricMeanCalculator.h" +#include "RiaWeightedHarmonicMeanCalculator.h" +#include "RiaWeightedMeanCalculator.h" + +#include "RigActiveCellInfo.h" +#include "RigCaseCellResultsData.h" +#include "RigCell.h" +#include "RigCellGeometryTools.h" +#include "RigEclipseCaseData.h" +#include "RigHexIntersectionTools.h" +#include "RigMainGrid.h" + +#include "RimCellRangeFilterCollection.h" +#include "RimEclipseCase.h" +#include "RimEclipseCellColors.h" +#include "RimEclipseContourMapView.h" +#include "RimEclipseResultDefinition.h" +#include "RimEclipseView.h" +#include "RimProject.h" +#include "RimRegularLegendConfig.h" +#include "RimTextAnnotation.h" + +#include "cafContourLines.h" +#include "cafPdmUiDoubleSliderEditor.h" +#include "cafPdmUiTreeOrdering.h" + +#include "cvfArray.h" +#include "cvfCellRange.h" +#include "cvfGeometryTools.h" +#include "cvfGeometryUtils.h" +#include "cvfScalarMapper.h" +#include "cvfStructGridGeometryGenerator.h" + +#include +#include + +CAF_PDM_SOURCE_INIT(RimEclipseContourMapProjection, "RimEclipseContourMapProjection"); + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimEclipseContourMapProjection::RimEclipseContourMapProjection() + : RimContourMapProjection() +{ + CAF_PDM_InitObject("RimEclipseContourMapProjection", ":/2DMapProjection16x16.png", "", ""); + + CAF_PDM_InitField(&m_weightByParameter, "WeightByParameter", false, "Weight by Result Parameter", "", "", ""); + CAF_PDM_InitFieldNoDefault(&m_weightingResult, "WeightingResult", "", "", "", ""); + m_weightingResult.uiCapability()->setUiHidden(true); + m_weightingResult.uiCapability()->setUiTreeChildrenHidden(true); + m_weightingResult = new RimEclipseResultDefinition; + m_weightingResult->findField("MResultType")->uiCapability()->setUiName("Result Type"); + + setName("Map Projection"); + nameField()->uiCapability()->setUiReadOnly(true); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimEclipseContourMapProjection::~RimEclipseContourMapProjection() +{ + +} +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RimEclipseContourMapProjection::resultDescriptionText() const +{ + QString resultText = resultAggregationText(); + if (!isColumnResult()) + { + resultText += QString(", %1").arg(view()->cellResult()->resultVariable()); + } + + return resultText; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RimEclipseContourMapProjection::weightingParameter() const +{ + QString parameter = "None"; + if (m_weightByParameter() && !m_weightingResult->isTernarySaturationSelected()) + { + parameter = m_weightingResult->resultVariableUiShortName(); + } + return parameter; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimRegularLegendConfig* RimEclipseContourMapProjection::legendConfig() const +{ + return view()->cellResult()->legendConfig(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimEclipseContourMapProjection::updateLegend() +{ + RimEclipseCellColors* cellColors = view()->cellResult(); + + double minVal = minValue(m_aggregatedResults); + double maxVal = maxValue(m_aggregatedResults); + + std::pair minmaxValAllTimeSteps = minmaxValuesAllTimeSteps(); + + legendConfig()->setAutomaticRanges(minmaxValAllTimeSteps.first, minmaxValAllTimeSteps.second, minVal, maxVal); + + if (m_resultAggregation() == RESULTS_OIL_COLUMN || + m_resultAggregation() == RESULTS_GAS_COLUMN || + m_resultAggregation() == RESULTS_HC_COLUMN) + { + legendConfig()->setTitle(QString("Map Projection\n%1").arg(m_resultAggregation().uiText())); + } + else + { + QString projectionLegendText = QString("Map Projection\n%1").arg(m_resultAggregation().uiText()); + if (weightingParameter() != "None") + { + projectionLegendText += QString("(W: %1)").arg(weightingParameter()); + } + projectionLegendText += QString("\nResult: %1").arg(cellColors->resultVariableUiShortName()); + + legendConfig()->setTitle(projectionLegendText); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimEclipseContourMapProjection::updatedWeightingResult() +{ + this->clearGridMapping(); + this->updateConnectedEditors(); + this->generateResultsIfNecessary(view()->currentTimeStep()); + this->updateLegend(); + + RimProject* proj; + this->firstAncestorOrThisOfTypeAsserted(proj); + proj->scheduleCreateDisplayModelAndRedrawAllViews(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector RimEclipseContourMapProjection::generateResults(int timeStep) +{ + m_weightingResult->loadResult(); + + size_t nCells = numberOfCells(); + + std::vector aggregatedResults = std::vector(nCells, std::numeric_limits::infinity()); + + RimEclipseCellColors* cellColors = view()->cellResult(); + RimEclipseCase* eclipseCase = this->eclipseCase(); + { + if (!cellColors->isTernarySaturationSelected()) + { + RigCaseCellResultsData* resultData = eclipseCase->results(RiaDefines::MATRIX_MODEL); + std::vector gridResultValues; + if (isColumnResult()) + { + m_currentResultName = ""; + resultData->ensureKnownResultLoaded(RigEclipseResultAddress(RiaDefines::STATIC_NATIVE, "PORO")); + resultData->ensureKnownResultLoaded(RigEclipseResultAddress(RiaDefines::STATIC_NATIVE, "NTG")); + resultData->ensureKnownResultLoaded(RigEclipseResultAddress(RiaDefines::STATIC_NATIVE, "DZ")); + if (m_resultAggregation == RESULTS_OIL_COLUMN || m_resultAggregation == RESULTS_HC_COLUMN) + { + resultData->ensureKnownResultLoadedForTimeStep(RigEclipseResultAddress(RiaDefines::DYNAMIC_NATIVE, "SOIL"), timeStep); + } + if (m_resultAggregation == RESULTS_GAS_COLUMN || m_resultAggregation == RESULTS_HC_COLUMN) + { + resultData->ensureKnownResultLoadedForTimeStep(RigEclipseResultAddress(RiaDefines::DYNAMIC_NATIVE, "SGAS"), timeStep); + } + gridResultValues = calculateColumnResult(m_resultAggregation()); + } + else if (!(cellColors->hasStaticResult() && timeStep > 0)) + { + m_currentResultName = cellColors->resultVariable(); + RigEclipseResultAddress resAddr(cellColors->resultType(), cellColors->resultVariable()); + if (resAddr.isValid() && resultData->hasResultEntry(resAddr)) + { + gridResultValues = resultData->cellScalarResults(resAddr, timeStep); + } + } + + if (!gridResultValues.empty()) + { +#pragma omp parallel for + for (int index = 0; index < static_cast(nCells); ++index) + { + cvf::Vec2ui ij = ijFromCellIndex(index); + aggregatedResults[index] = calculateValueInMapCell(ij.x(), ij.y(), gridResultValues); + } + } + } + } + return aggregatedResults; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RimEclipseContourMapProjection::resultVariableChanged() const +{ + if (!m_currentResultName.isEmpty()) + { + RimEclipseCellColors* cellColors = view()->cellResult(); + if (cellColors->resultVariable() != m_currentResultName) + { + return true; + } + } + return false; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimEclipseContourMapProjection::clearResultVariable() +{ + m_currentResultName = ""; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector RimEclipseContourMapProjection::calculateColumnResult(ResultAggregation resultAggregation) const +{ + const RigCaseCellResultsData* resultData = eclipseCase()->results(RiaDefines::MATRIX_MODEL); + bool hasPoroResult = resultData->hasResultEntry(RigEclipseResultAddress(RiaDefines::STATIC_NATIVE, "PORO")); + bool hasNtgResult = resultData->hasResultEntry(RigEclipseResultAddress(RiaDefines::STATIC_NATIVE, "NTG" )); + bool haDzResult = resultData->hasResultEntry(RigEclipseResultAddress(RiaDefines::STATIC_NATIVE, "DZ" )); + + if (! (hasPoroResult && hasNtgResult && haDzResult) ) + { + return std::vector(); + } + + const std::vector& poroResults = resultData->cellScalarResults(RigEclipseResultAddress(RiaDefines::STATIC_NATIVE, "PORO"), 0); + const std::vector& ntgResults = resultData->cellScalarResults(RigEclipseResultAddress(RiaDefines::STATIC_NATIVE, "NTG" ), 0); + const std::vector& dzResults = resultData->cellScalarResults(RigEclipseResultAddress(RiaDefines::STATIC_NATIVE, "DZ" ), 0); + + CVF_ASSERT(poroResults.size() == ntgResults.size() && ntgResults.size() == dzResults.size()); + + int timeStep = view()->currentTimeStep(); + + std::vector resultValues(poroResults.size(), 0.0); + + if (resultAggregation == RESULTS_OIL_COLUMN || resultAggregation == RESULTS_HC_COLUMN) + { + const std::vector& soilResults = resultData->cellScalarResults(RigEclipseResultAddress(RiaDefines::DYNAMIC_NATIVE, "SOIL"), timeStep); + for (size_t cellResultIdx = 0; cellResultIdx < resultValues.size(); ++cellResultIdx) + { + resultValues[cellResultIdx] = soilResults[cellResultIdx]; + } + } + + if (resultAggregation == RESULTS_GAS_COLUMN || resultAggregation == RESULTS_HC_COLUMN) + { + const std::vector& sgasResults = resultData->cellScalarResults(RigEclipseResultAddress(RiaDefines::DYNAMIC_NATIVE, "SGAS"), timeStep); + for (size_t cellResultIdx = 0; cellResultIdx < resultValues.size(); ++cellResultIdx) + { + resultValues[cellResultIdx] += sgasResults[cellResultIdx]; + } + } + + for (size_t cellResultIdx = 0; cellResultIdx < resultValues.size(); ++cellResultIdx) + { + resultValues[cellResultIdx] *= poroResults[cellResultIdx] * ntgResults[cellResultIdx] * dzResults[cellResultIdx]; + } + return resultValues; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimEclipseContourMapProjection::updateGridInformation() +{ + m_mainGrid = eclipseCase()->eclipseCaseData()->mainGrid(); + m_sampleSpacing = m_relativeSampleSpacing * m_mainGrid->characteristicIJCellSize(); + m_gridBoundingBox = eclipseCase()->activeCellsBoundingBox(); + cvf::Vec3d minExpandedPoint = m_gridBoundingBox.min() - cvf::Vec3d(gridEdgeOffset(), gridEdgeOffset(), 0.0); + cvf::Vec3d maxExpandedPoint = m_gridBoundingBox.max() + cvf::Vec3d(gridEdgeOffset(), gridEdgeOffset(), 0.0); + m_expandedBoundingBox = cvf::BoundingBox(minExpandedPoint, maxExpandedPoint); + + m_mapSize = calculateMapSize(); + + // Re-jig max point to be an exact multiple of cell size + cvf::Vec3d minPoint = m_expandedBoundingBox.min(); + cvf::Vec3d maxPoint = m_expandedBoundingBox.max(); + maxPoint.x() = minPoint.x() + m_mapSize.x() * m_sampleSpacing; + maxPoint.y() = minPoint.y() + m_mapSize.y() * m_sampleSpacing; + m_expandedBoundingBox = cvf::BoundingBox(minPoint, maxPoint); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector RimEclipseContourMapProjection::retrieveParameterWeights() +{ + std::vector weights; + if (m_weightByParameter()) + { + RigEclipseResultAddress gridScalarResultIdx = m_weightingResult->eclipseResultAddress(); + if (gridScalarResultIdx.isValid()) + { + m_weightingResult->loadResult(); + int timeStep = 0; + if (m_weightingResult->hasDynamicResult()) + { + timeStep = view()->currentTimeStep(); + } + weights = m_weightingResult->currentGridCellResults()->cellScalarResults(gridScalarResultIdx, timeStep); + } + } + return weights; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimEclipseCase* RimEclipseContourMapProjection::eclipseCase() const +{ + RimEclipseCase* eclipseCase = nullptr; + firstAncestorOrThisOfType(eclipseCase); + return eclipseCase; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimGridView* RimEclipseContourMapProjection::baseView() const +{ + return view(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector RimEclipseContourMapProjection::findIntersectingCells(const cvf::BoundingBox& bbox) const +{ + std::vector allCellIndices; + m_mainGrid->findIntersectingCells(bbox, &allCellIndices); + return allCellIndices; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +size_t RimEclipseContourMapProjection::kLayer(size_t globalCellIdx) const +{ + const RigCell& cell = m_mainGrid->globalCellArray()[globalCellIdx]; + size_t mainGridCellIdx = cell.mainGridCellIndex(); + size_t i, j, k; + m_mainGrid->ijkFromCellIndex(mainGridCellIdx, &i, &j, &k); + return k; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +double RimEclipseContourMapProjection::calculateOverlapVolume(size_t globalCellIdx, const cvf::BoundingBox& bbox) const +{ + std::array hexCorners; + + const RigCell& cell = m_mainGrid->globalCellArray()[globalCellIdx]; + + size_t localCellIdx = cell.gridLocalCellIndex(); + RigGridBase* localGrid = cell.hostGrid(); + + localGrid->cellCornerVertices(localCellIdx, hexCorners.data()); + + cvf::BoundingBox overlapBBox; + std::array overlapCorners; + if (RigCellGeometryTools::estimateHexOverlapWithBoundingBox(hexCorners, bbox, &overlapCorners, &overlapBBox)) + { + double overlapVolume = RigCellGeometryTools::calculateCellVolume(overlapCorners); + return overlapVolume; + } + return 0.0; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +double RimEclipseContourMapProjection::calculateRayLengthInCell(size_t globalCellIdx, + const cvf::Vec3d& highestPoint, + const cvf::Vec3d& lowestPoint) const +{ + std::array hexCorners; + + RigCell cell = m_mainGrid->globalCellArray()[globalCellIdx]; + + size_t localCellIdx = cell.gridLocalCellIndex(); + RigGridBase* localGrid = cell.hostGrid(); + + localGrid->cellCornerVertices(localCellIdx, hexCorners.data()); + std::vector intersections; + + if (RigHexIntersectionTools::lineHexCellIntersection(highestPoint, lowestPoint, hexCorners.data(), 0, &intersections)) + { + double lengthInCell = (intersections.back().m_intersectionPoint - intersections.front().m_intersectionPoint).length(); + return lengthInCell; + } + return 0.0; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +double RimEclipseContourMapProjection::getParameterWeightForCell(size_t cellResultIdx, const std::vector& cellWeights) const +{ + if (cellWeights.empty()) return 1.0; + + double result = std::max(cellWeights[cellResultIdx], 0.0); + if (result < 1.0e-6) + { + result = 0.0; + } + return result; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +size_t RimEclipseContourMapProjection::gridResultIndex(size_t globalCellIdx) const +{ + const RigActiveCellInfo* activeCellInfo = eclipseCase()->eclipseCaseData()->activeCellInfo(RiaDefines::MATRIX_MODEL); + return activeCellInfo->cellResultIndex(globalCellIdx); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimEclipseContourMapView* RimEclipseContourMapProjection::view() const +{ + RimEclipseContourMapView* view = nullptr; + firstAncestorOrThisOfTypeAsserted(view); + return view; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimEclipseContourMapProjection::fieldChangedByUi(const caf::PdmFieldHandle* changedField, + const QVariant& oldValue, + const QVariant& newValue) +{ + RimContourMapProjection::fieldChangedByUi(changedField, oldValue, newValue); + if (changedField == &m_weightByParameter || changedField == &m_weightingResult) + { + clearGridMapping(); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimEclipseContourMapProjection::defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering) +{ + RimContourMapProjection::defineUiOrdering(uiConfigName, uiOrdering); + + caf::PdmUiGroup* weightingGroup = uiOrdering.addNewGroup("Mean Weighting Options"); + weightingGroup->add(&m_weightByParameter); + weightingGroup->setCollapsedByDefault(true); + + m_weightByParameter.uiCapability()->setUiReadOnly(!isMeanResult()); + if (!isMeanResult()) + { + m_weightByParameter = false; + } + + if (m_weightByParameter()) + { + m_weightingResult->uiOrdering(uiConfigName, *weightingGroup); + } + + uiOrdering.skipRemainingFields(true); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimEclipseContourMapProjection::initAfterRead() +{ + RimContourMapProjection::initAfterRead(); + if (eclipseCase()) + { + m_weightingResult->setEclipseCase(eclipseCase()); + } +} diff --git a/ApplicationCode/ProjectDataModel/RimEclipseContourMapProjection.h b/ApplicationCode/ProjectDataModel/RimEclipseContourMapProjection.h new file mode 100644 index 0000000000..78ddef9866 --- /dev/null +++ b/ApplicationCode/ProjectDataModel/RimEclipseContourMapProjection.h @@ -0,0 +1,96 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2018- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "RimCheckableNamedObject.h" +#include "RimContourMapProjection.h" +#include "RimRegularLegendConfig.h" + +#include "cafDisplayCoordTransform.h" +#include "cafPdmChildField.h" +#include "cafPdmField.h" +#include "cafPdmObject.h" + +#include "cvfBoundingBox.h" +#include "cvfGeometryBuilderFaceList.h" +#include "cvfString.h" +#include "cvfVector2.h" + +class RigMainGrid; +class RigResultAccessor; +class RimEclipseContourMapView; +class RimEclipseCase; +class RimEclipseResultDefinition; + +//================================================================================================== +/// +/// +//================================================================================================== +class RimEclipseContourMapProjection : public RimContourMapProjection +{ + CAF_PDM_HEADER_INIT; +public: + + RimEclipseContourMapProjection(); + ~RimEclipseContourMapProjection() override; + + QString weightingParameter() const; + void updatedWeightingResult(); + + // Eclipse case overrides for contour map methods + QString resultDescriptionText() const override; + RimRegularLegendConfig* legendConfig() const override; + void updateLegend() override; + +protected: + typedef RimContourMapProjection::CellIndexAndResult CellIndexAndResult; + + void updateGridInformation() override; + std::vector retrieveParameterWeights() override; + std::vector generateResults(int timeStep) override; + bool resultVariableChanged() const override; + void clearResultVariable() override; + RimGridView* baseView() const override; + std::vector findIntersectingCells(const cvf::BoundingBox& bbox) const override; + size_t kLayer(size_t globalCellIdx) const override; + double calculateOverlapVolume(size_t globalCellIdx, const cvf::BoundingBox& bbox) const override; + double calculateRayLengthInCell(size_t globalCellIdx, const cvf::Vec3d& highestPoint, const cvf::Vec3d& lowestPoint) const override; + double getParameterWeightForCell(size_t cellResultIdx, const std::vector& parameterWeights) const override; + size_t gridResultIndex(size_t globalCellIdx) const override; + + // Eclipse implementation specific data generation methods + std::vector calculateColumnResult(ResultAggregation resultAggregation) const; + + RimEclipseCase* eclipseCase() const; + RimEclipseContourMapView* view() const; + + +protected: + // Framework overrides + void fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue) override; + void defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering) override; + void initAfterRead() override; + +protected: + caf::PdmField m_weightByParameter; + caf::PdmChildField m_weightingResult; + + cvf::ref m_mainGrid; + QString m_currentResultName; +}; diff --git a/ApplicationCode/ProjectDataModel/RimEclipseContourMapView.cpp b/ApplicationCode/ProjectDataModel/RimEclipseContourMapView.cpp new file mode 100644 index 0000000000..adeba1b849 --- /dev/null +++ b/ApplicationCode/ProjectDataModel/RimEclipseContourMapView.cpp @@ -0,0 +1,514 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2018- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "RimEclipseContourMapView.h" + +#include "RivContourMapProjectionPartMgr.h" +#include "RiuViewer.h" + +#include "Rim3dOverlayInfoConfig.h" +#include "RimAnnotationInViewCollection.h" +#include "RimCase.h" +#include "RimCellRangeFilterCollection.h" +#include "RimViewNameConfig.h" +#include "RimEclipseContourMapProjection.h" +#include "RimEclipseCellColors.h" +#include "RimEclipseFaultColors.h" +#include "RimEclipsePropertyFilterCollection.h" +#include "RimFaultInViewCollection.h" +#include "RimGridCollection.h" +#include "RimSimWellInViewCollection.h" +#include "RimScaleLegendConfig.h" + +#include "cafPdmUiTreeOrdering.h" +#include "cafProgressInfo.h" + +#include "cvfCamera.h" +#include "cvfModelBasicList.h" +#include "cvfPart.h" +#include "cvfScene.h" + +CAF_PDM_SOURCE_INIT(RimEclipseContourMapView, "RimContourMapView"); + +const cvf::Mat4d RimEclipseContourMapView::sm_defaultViewMatrix = cvf::Mat4d(1, 0, 0, 0, + 0, 1, 0, 0, + 0, 0, 1, 1000, + 0, 0, 0, 1); + + +RimEclipseContourMapView::RimEclipseContourMapView() + : m_cameraPositionLastUpdate(cvf::Vec3d::UNDEFINED) +{ + CAF_PDM_InitObject("Contour Map View", ":/2DMap16x16.png", "", ""); + + CAF_PDM_InitFieldNoDefault(&m_contourMapProjection, "ContourMapProjection", "Contour Map Projection", "", "", ""); + m_contourMapProjection = new RimEclipseContourMapProjection(); + + CAF_PDM_InitField(&m_showAxisLines, "ShowAxisLines", true, "Show Axis Lines", "", "", ""); + CAF_PDM_InitField(&m_showScaleLegend, "ShowScaleLegend", true, "Show Scale Legend", "", "", ""); + + m_gridCollection->setActive(false); // This is also not added to the tree view, so cannot be enabled. + setFaultVisParameters(); + + setDefaultCustomName(); + + m_contourMapProjectionPartMgr = new RivContourMapProjectionPartMgr(contourMapProjection(), this); + + ((RiuViewerToViewInterface*)this)->setCameraPosition(sm_defaultViewMatrix); + + cellResult()->setTernaryEnabled(false); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimEclipseContourMapProjection* RimEclipseContourMapView::contourMapProjection() const +{ + return m_contourMapProjection().p(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RimEclipseContourMapView::createAutoName() const +{ + QStringList autoName; + + if (!nameConfig()->customName().isEmpty()) + { + autoName.push_back(nameConfig()->customName()); + } + + QStringList generatedAutoTags; + + RimCase* ownerCase = nullptr; + this->firstAncestorOrThisOfTypeAsserted(ownerCase); + + if (nameConfig()->addCaseName()) + { + generatedAutoTags.push_back(ownerCase->caseUserDescription()); + } + + if (nameConfig()->addAggregationType()) + { + generatedAutoTags.push_back(contourMapProjection()->resultAggregationText()); + } + + if (nameConfig()->addProperty() && !contourMapProjection()->isColumnResult()) + { + generatedAutoTags.push_back(cellResult()->resultVariable()); + } + + if (nameConfig()->addSampleSpacing()) + { + generatedAutoTags.push_back(QString("%1").arg(contourMapProjection()->sampleSpacingFactor(), 3, 'f', 2)); + } + + if (!generatedAutoTags.empty()) + { + autoName.push_back(generatedAutoTags.join(", ")); + } + return autoName.join(": "); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimEclipseContourMapView::setDefaultCustomName() +{ + nameConfig()->setCustomName("Contour Map"); + nameConfig()->hideCaseNameField(false); + nameConfig()->hideAggregationTypeField(false); + nameConfig()->hidePropertyField(false); + nameConfig()->hideSampleSpacingField(false); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimEclipseContourMapView::updatePickPointAndRedraw() +{ + appendPickPointVisToModel(); + if (m_viewer) + { + m_viewer->update(); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimEclipseContourMapView::updateCurrentTimeStepAndRedraw() +{ + m_contourMapProjection->clearGeometry(); + RimEclipseView::updateCurrentTimeStepAndRedraw(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimEclipseContourMapView::initAfterRead() +{ + m_gridCollection->setActive(false); // This is also not added to the tree view, so cannot be enabled. + disablePerspectiveProjectionField(); + setShowGridBox(false); + meshMode.setValue(RiaDefines::NO_MESH); + surfaceMode.setValue(FAULTS); + setFaultVisParameters(); + scheduleCreateDisplayModelAndRedraw(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimEclipseContourMapView::createDisplayModel() +{ + RimEclipseView::createDisplayModel(); + + if (!this->isTimeStepDependentDataVisible()) + { + // Need to add geometry even if it hasn't happened during dynamic time step update. + updateGeometry(); + } + + if (this->viewer()->mainCamera()->viewMatrix() == sm_defaultViewMatrix) + { + this->zoomAll(); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimEclipseContourMapView::defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering) +{ + caf::PdmUiGroup* viewGroup = uiOrdering.addNewGroup("Viewer"); + viewGroup->add(this->userDescriptionField()); + viewGroup->add(this->backgroundColorField()); + viewGroup->add(&m_showAxisLines); + viewGroup->add(&m_showScaleLegend); + + caf::PdmUiGroup* nameGroup = uiOrdering.addNewGroup("Contour Map Name"); + nameConfig()->uiOrdering(uiConfigName, *nameGroup); + + uiOrdering.skipRemainingFields(true); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimEclipseContourMapView::defineUiTreeOrdering(caf::PdmUiTreeOrdering& uiTreeOrdering, QString uiConfigName /*= ""*/) +{ + uiTreeOrdering.add(m_overlayInfoConfig()); + uiTreeOrdering.add(m_contourMapProjection); + uiTreeOrdering.add(cellResult()); + cellResult()->uiCapability()->setUiReadOnly(m_contourMapProjection->isColumnResult()); + uiTreeOrdering.add(wellCollection()); + uiTreeOrdering.add(faultCollection()); + uiTreeOrdering.add(annotationCollection()); + uiTreeOrdering.add(m_rangeFilterCollection()); + uiTreeOrdering.add(nativePropertyFilterCollection()); + + uiTreeOrdering.skipRemainingChildren(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimEclipseContourMapView::updateCurrentTimeStep() +{ + static_cast(nativePropertyFilterCollection())->updateFromCurrentTimeStep(); + updateGeometry(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimEclipseContourMapView::updateGeometry() +{ + caf::ProgressInfo progress(100, "Generate Contour Map", true); + + this->updateVisibleGeometriesAndCellColors(); + + { // Step 1: generate results and some minor updates. About 30% of the time. + if (m_contourMapProjection->isChecked()) + { + m_contourMapProjection->generateResultsIfNecessary(m_currentTimeStep()); + } + progress.setProgress(30); + } + + updateLegends(); // To make sure the scalar mappers are set up correctly + appendWellsAndFracturesToModel(); + + { // Step 2: generate geometry. Takes about 60% of the time. + createContourMapGeometry(); + progress.setProgress(90); + } + + { // Step 3: generate drawables. Takes about 10% of the time. + appendContourMapProjectionToModel(); + appendContourLinesToModel(); + appendPickPointVisToModel(); + progress.setProgress(100); + } + m_overlayInfoConfig()->update3DInfo(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimEclipseContourMapView::setFaultVisParameters() +{ + faultCollection()->setShowFaultsOutsideFilter(false); + faultCollection()->showOppositeFaultFaces = true; + faultCollection()->faultResult = RimFaultInViewCollection::FAULT_NO_FACE_CULLING; + faultResultSettings()->showCustomFaultResult = true; + faultResultSettings()->customFaultResult()->setResultVariable("None"); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimEclipseContourMapView::createContourMapGeometry() +{ + if (m_viewer && m_contourMapProjection->isChecked()) + { + m_contourMapProjectionPartMgr->createProjectionGeometry(); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimEclipseContourMapView::appendContourMapProjectionToModel() +{ + if (m_viewer && m_contourMapProjection->isChecked()) + { + cvf::Scene* frameScene = m_viewer->frame(m_currentTimeStep); + if (frameScene) + { + cvf::String name = "ContourMapProjection"; + this->removeModelByName(frameScene, name); + + cvf::ref contourMapProjectionModelBasicList = new cvf::ModelBasicList; + contourMapProjectionModelBasicList->setName(name); + + cvf::ref transForm = this->displayCoordTransform(); + + m_contourMapProjectionPartMgr->appendProjectionToModel(contourMapProjectionModelBasicList.p(), transForm.p()); + contourMapProjectionModelBasicList->updateBoundingBoxesRecursive(); + frameScene->addModel(contourMapProjectionModelBasicList.p()); + } + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimEclipseContourMapView::appendContourLinesToModel() +{ + if (m_viewer && m_contourMapProjection->isChecked()) + { + cvf::Scene* frameScene = m_viewer->frame(m_currentTimeStep); + if (frameScene) + { + cvf::String name = "ContourMapLines"; + this->removeModelByName(frameScene, name); + + cvf::ref contourMapLabelModelBasicList = new cvf::ModelBasicList; + contourMapLabelModelBasicList->setName(name); + + cvf::ref transForm = this->displayCoordTransform(); + + m_contourMapProjectionPartMgr->appendContourLinesToModel(viewer()->mainCamera(), contourMapLabelModelBasicList.p(), transForm.p()); + contourMapLabelModelBasicList->updateBoundingBoxesRecursive(); + frameScene->addModel(contourMapLabelModelBasicList.p()); + } + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimEclipseContourMapView::appendPickPointVisToModel() +{ + if (m_viewer && m_contourMapProjection->isChecked()) + { + cvf::Scene* frameScene = m_viewer->frame(m_currentTimeStep); + if (frameScene) + { + cvf::String name = "ContourMapPickPoint"; + this->removeModelByName(frameScene, name); + + cvf::ref contourMapProjectionModelBasicList = new cvf::ModelBasicList; + contourMapProjectionModelBasicList->setName(name); + + cvf::ref transForm = this->displayCoordTransform(); + + m_contourMapProjectionPartMgr->appendPickPointVisToModel(contourMapProjectionModelBasicList.p(), transForm.p()); + contourMapProjectionModelBasicList->updateBoundingBoxesRecursive(); + frameScene->addModel(contourMapProjectionModelBasicList.p()); + } + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimEclipseContourMapView::updateLegends() +{ + if (m_viewer) + { + m_viewer->removeAllColorLegends(); + + if (m_contourMapProjection && m_contourMapProjection->isChecked()) + { + RimRegularLegendConfig* projectionLegend = m_contourMapProjection->legendConfig(); + if (projectionLegend) + { + m_contourMapProjection->updateLegend(); + if (projectionLegend->showLegend()) + { + m_viewer->addColorLegendToBottomLeftCorner(projectionLegend->titledOverlayFrame()); + } + } + } + + m_viewer->showScaleLegend(m_showScaleLegend()); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimEclipseContourMapView::updateViewWidgetAfterCreation() +{ + if (m_viewer) + { + m_viewer->showAxisCross(false); + m_viewer->showEdgeTickMarksXY(true, m_showAxisLines()); + m_viewer->enableNavigationRotation(false); + } + + Rim3dView::updateViewWidgetAfterCreation(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimEclipseContourMapView::updateViewFollowingRangeFilterUpdates() +{ + m_contourMapProjection->setCheckState(true); + scheduleCreateDisplayModelAndRedraw(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimEclipseContourMapView::onLoadDataAndUpdate() +{ + RimEclipseView::onLoadDataAndUpdate(); + if (m_viewer) + { + m_viewer->setView(cvf::Vec3d(0, 0, -1), cvf::Vec3d(0, 1, 0)); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimEclipseContourMapView::fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue) +{ + RimEclipseView::fieldChangedByUi(changedField, oldValue, newValue); + + if (changedField == &m_showAxisLines) + { + m_viewer->showEdgeTickMarksXY(true, m_showAxisLines()); + scheduleCreateDisplayModelAndRedraw(); + } + else if (changedField == backgroundColorField()) + { + scheduleCreateDisplayModelAndRedraw(); + } + else if (changedField == &m_showScaleLegend) + { + updateLegends(); + scheduleCreateDisplayModelAndRedraw(); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +caf::PdmFieldHandle* RimEclipseContourMapView::userDescriptionField() +{ + return nameConfig()->nameField(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::set RimEclipseContourMapView::allVisibleFaultGeometryTypes() const +{ + std::set faultGeoTypes; + // Normal eclipse views always shows faults for active and visible eclipse cells. + if (faultCollection()->showFaultCollection()) + { + faultGeoTypes = RimEclipseView::allVisibleFaultGeometryTypes(); + } + return faultGeoTypes; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QWidget* RimEclipseContourMapView::createViewWidget(QWidget* mainWindowParent) +{ + auto widget = Rim3dView::createViewWidget(mainWindowParent); + + if (viewer()) + { + viewer()->showZScaleLabel(false); + viewer()->hideZScaleCheckbox(true); + } + return widget; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimEclipseContourMapView::onViewNavigationChanged() +{ + cvf::Vec3d currentCameraPosition = viewer()->mainCamera()->position(); + if (m_cameraPositionLastUpdate.isUndefined() || zoomChangeAboveTreshold(currentCameraPosition)) + { + appendContourLinesToModel(); + m_cameraPositionLastUpdate = currentCameraPosition; + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RimEclipseContourMapView::zoomChangeAboveTreshold(const cvf::Vec3d& currentCameraPosition) const +{ + double distance = std::max(std::fabs(m_cameraPositionLastUpdate.z()), std::fabs(currentCameraPosition.z())); + const double threshold = 0.05 * distance; + return std::fabs(m_cameraPositionLastUpdate.z() - currentCameraPosition.z()) > threshold; +} diff --git a/ApplicationCode/ProjectDataModel/RimEclipseContourMapView.h b/ApplicationCode/ProjectDataModel/RimEclipseContourMapView.h new file mode 100644 index 0000000000..b33d02c4a3 --- /dev/null +++ b/ApplicationCode/ProjectDataModel/RimEclipseContourMapView.h @@ -0,0 +1,77 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2018- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "RimEclipseView.h" +#include "RimNameConfig.h" + +class RimEclipseContourMapProjection; +class RimViewNameConfig; +class RimScaleLegendConfig; +class RivContourMapProjectionPartMgr; + +class RimEclipseContourMapView : public RimEclipseView +{ + CAF_PDM_HEADER_INIT; +public: + RimEclipseContourMapView(); + RimEclipseContourMapProjection* contourMapProjection() const; + + QString createAutoName() const override; + void setDefaultCustomName(); + void updatePickPointAndRedraw(); + void updateCurrentTimeStepAndRedraw() override; + +protected: + void initAfterRead() override; + void createDisplayModel() override; + void defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering) override; + void defineUiTreeOrdering(caf::PdmUiTreeOrdering& uiTreeOrdering, QString uiConfigName = "") override; + void updateCurrentTimeStep() override; + void updateGeometry(); + void setFaultVisParameters(); + void createContourMapGeometry(); + void appendContourMapProjectionToModel(); + void appendContourLinesToModel(); + void appendPickPointVisToModel(); + void updateLegends() override; + void updateViewWidgetAfterCreation() override; + void updateViewFollowingRangeFilterUpdates() override; + void onLoadDataAndUpdate() override; + void fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue) override; + + caf::PdmFieldHandle* userDescriptionField() override; + + std::set allVisibleFaultGeometryTypes() const override; + + QWidget* createViewWidget(QWidget* mainWindowParent) override; + + void onViewNavigationChanged() override; + + bool zoomChangeAboveTreshold(const cvf::Vec3d& currentCameraPosition) const; +private: + cvf::ref m_contourMapProjectionPartMgr; + caf::PdmChildField m_contourMapProjection; + caf::PdmField m_showAxisLines; + caf::PdmField m_showScaleLegend; + cvf::Vec3d m_cameraPositionLastUpdate; + + const static cvf::Mat4d sm_defaultViewMatrix; +}; + diff --git a/ApplicationCode/ProjectDataModel/RimEclipseContourMapViewCollection.cpp b/ApplicationCode/ProjectDataModel/RimEclipseContourMapViewCollection.cpp new file mode 100644 index 0000000000..cec8ef1a63 --- /dev/null +++ b/ApplicationCode/ProjectDataModel/RimEclipseContourMapViewCollection.cpp @@ -0,0 +1,42 @@ +#include "RimEclipseContourMapViewCollection.h" + +#include "RimEclipseContourMapView.h" +#include "RimCase.h" + +CAF_PDM_SOURCE_INIT(RimEclipseContourMapViewCollection, "Eclipse2dViewCollection"); + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimEclipseContourMapViewCollection::RimEclipseContourMapViewCollection() +{ + CAF_PDM_InitObject("Contour Maps", ":/2DMaps16x16.png", "", ""); + + CAF_PDM_InitFieldNoDefault(&m_contourMapViews, "EclipseViews", "Contour Maps", ":/CrossSection16x16.png", "", ""); + m_contourMapViews.uiCapability()->setUiTreeHidden(true); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimEclipseContourMapViewCollection::~RimEclipseContourMapViewCollection() +{ + +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector RimEclipseContourMapViewCollection::views() +{ + return m_contourMapViews.childObjects(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimEclipseContourMapViewCollection::push_back(RimEclipseContourMapView* contourMap) +{ + m_contourMapViews.push_back(contourMap); +} + diff --git a/ApplicationCode/ProjectDataModel/RimEclipseContourMapViewCollection.h b/ApplicationCode/ProjectDataModel/RimEclipseContourMapViewCollection.h new file mode 100644 index 0000000000..8f176e49b8 --- /dev/null +++ b/ApplicationCode/ProjectDataModel/RimEclipseContourMapViewCollection.h @@ -0,0 +1,41 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2018- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "cafPdmObject.h" +#include "cafPdmField.h" +#include "cafPdmChildArrayField.h" + +class RimEclipseContourMapView; + +class RimEclipseContourMapViewCollection : public caf::PdmObject +{ + CAF_PDM_HEADER_INIT; +public: + RimEclipseContourMapViewCollection(); + ~RimEclipseContourMapViewCollection() override; + + std::vector views(); + void push_back(RimEclipseContourMapView* contourMap); +private: + caf::PdmChildArrayField m_contourMapViews; +}; + + + diff --git a/ApplicationCode/ProjectDataModel/RimEclipseFaultColors.cpp b/ApplicationCode/ProjectDataModel/RimEclipseFaultColors.cpp index 4810907227..e13be7458a 100644 --- a/ApplicationCode/ProjectDataModel/RimEclipseFaultColors.cpp +++ b/ApplicationCode/ProjectDataModel/RimEclipseFaultColors.cpp @@ -43,9 +43,8 @@ RimEclipseFaultColors::RimEclipseFaultColors() CAF_PDM_InitFieldNoDefault(&m_customFaultResultColors, "CustomResultSlot", "Custom Fault Result", ":/CellResult.png", "", ""); m_customFaultResultColors = new RimEclipseCellColors(); - m_customFaultResultColors.uiCapability()->setUiHidden(true); - + m_customFaultResultColors->setDiffResultOptionsEnabled(true); } //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/ProjectDataModel/RimEclipseGeometrySelectionItem.cpp b/ApplicationCode/ProjectDataModel/RimEclipseGeometrySelectionItem.cpp index 5d5701a1eb..130fb786b1 100644 --- a/ApplicationCode/ProjectDataModel/RimEclipseGeometrySelectionItem.cpp +++ b/ApplicationCode/ProjectDataModel/RimEclipseGeometrySelectionItem.cpp @@ -23,7 +23,7 @@ #include "RimEclipseCase.h" #include "RimEclipseView.h" -#include "RiuSelectionManager.h" +#include "Riu3dSelectionManager.h" CAF_PDM_SOURCE_INIT(RimEclipseGeometrySelectionItem, "EclipseGeometrySelectionItem"); diff --git a/ApplicationCode/ProjectDataModel/RimEclipseInputCase.cpp b/ApplicationCode/ProjectDataModel/RimEclipseInputCase.cpp index bf0f01b77d..a0256fa127 100644 --- a/ApplicationCode/ProjectDataModel/RimEclipseInputCase.cpp +++ b/ApplicationCode/ProjectDataModel/RimEclipseInputCase.cpp @@ -21,6 +21,7 @@ #include "RimEclipseInputCase.h" #include "RiaFieldHandleTools.h" +#include "RiaLogging.h" #include "RiaPreferences.h" #include "RifEclipseInputFileTools.h" @@ -109,14 +110,17 @@ bool RimEclipseInputCase::openDataFileSet(const QStringList& fileNames) this->setReservoirData(new RigEclipseCaseData(this)); } + bool importFaults = RiaApplication::instance()->preferences()->readerSettings()->importFaults(); + + std::vector allErrorMessages; + // First find and read the grid data if (this->eclipseCaseData()->mainGrid()->gridPointDimensions() == cvf::Vec3st(0,0,0)) { - RiaPreferences* prefs = RiaApplication::instance()->preferences(); - for (int i = 0; i < fileNames.size(); i++) { - if (RifEclipseInputFileTools::openGridFile(fileNames[i], this->eclipseCaseData(), prefs->readerSettings()->importFaults())) + QString errorMessages; + if (RifEclipseInputFileTools::openGridFile(fileNames[i], this->eclipseCaseData(), importFaults, &errorMessages)) { m_gridFileName = fileNames[i]; @@ -131,11 +135,22 @@ bool RimEclipseInputCase::openDataFileSet(const QStringList& fileNames) break; } + else + { + allErrorMessages.push_back(errorMessages); + } } } if (this->eclipseCaseData()->mainGrid()->gridPointDimensions() == cvf::Vec3st(0,0,0)) { + if (!allErrorMessages.empty()) + { + for (QString errorMessages : allErrorMessages) + { + RiaLogging::error(errorMessages); + } + } return false; // No grid present } @@ -171,6 +186,17 @@ bool RimEclipseInputCase::openDataFileSet(const QStringList& fileNames) inputProperty->resolvedState = RimEclipseInputProperty::RESOLVED; m_inputPropertyCollection->inputProperties.push_back(inputProperty); } + + if (importFaults) + { + cvf::Collection faultCollection; + RifEclipseInputFileTools::parseAndReadFaults(propertyFileName, &faultCollection); + + if (!faultCollection.empty()) + { + this->eclipseCaseData()->mainGrid()->setFaults(faultCollection); + } + } } return true; } diff --git a/ApplicationCode/ProjectDataModel/RimEclipsePropertyFilter.cpp b/ApplicationCode/ProjectDataModel/RimEclipsePropertyFilter.cpp index 3397e46477..9945b71931 100644 --- a/ApplicationCode/ProjectDataModel/RimEclipsePropertyFilter.cpp +++ b/ApplicationCode/ProjectDataModel/RimEclipsePropertyFilter.cpp @@ -3,17 +3,17 @@ // Copyright (C) 2011- Statoil ASA // Copyright (C) 2013- Ceetron Solutions AS // Copyright (C) 2011-2012 Ceetron AS -// +// // ResInsight 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 3 of the License, or // (at your option) any later version. -// +// // ResInsight 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 at +// +// See the GNU General Public License at // for more details. // ///////////////////////////////////////////////////////////////////////////////// @@ -45,23 +45,21 @@ #include // Needed for HUGE_VAL on Linux - namespace caf { // Obsolete stuff - template<> - void caf::AppEnum< RimEclipsePropertyFilter::EvaluationRegionType>::setUp() - { - addItem(RimEclipsePropertyFilter::RANGE_FILTER_REGION, "RANGE_FILTER_REGION", "Range filter cells"); - addItem(RimEclipsePropertyFilter::GLOBAL_REGION, "GLOBAL_REGION", "All cells"); - setDefault(RimEclipsePropertyFilter::RANGE_FILTER_REGION); - } +template<> +void caf::AppEnum::setUp() +{ + addItem(RimEclipsePropertyFilter::RANGE_FILTER_REGION, "RANGE_FILTER_REGION", "Range filter cells"); + addItem(RimEclipsePropertyFilter::GLOBAL_REGION, "GLOBAL_REGION", "All cells"); + setDefault(RimEclipsePropertyFilter::RANGE_FILTER_REGION); } - +} // namespace caf CAF_PDM_SOURCE_INIT(RimEclipsePropertyFilter, "CellPropertyFilter"); //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- RimEclipsePropertyFilter::RimEclipsePropertyFilter() { @@ -70,13 +68,14 @@ RimEclipsePropertyFilter::RimEclipsePropertyFilter() CAF_PDM_InitFieldNoDefault(&obsoleteField_evaluationRegion, "EvaluationRegion", "Evaluation Region", "", "", ""); RiaFieldhandleTools::disableWriteAndSetFieldHidden(&obsoleteField_evaluationRegion); - CAF_PDM_InitFieldNoDefault(&resultDefinition, "ResultDefinition", "Result Definition", "", "", ""); - resultDefinition = new RimEclipseResultDefinition(); + CAF_PDM_InitFieldNoDefault(&m_resultDefinition, "ResultDefinition", "Result Definition", "", "", ""); + m_resultDefinition = new RimEclipseResultDefinition(); + m_resultDefinition->setDiffResultOptionsEnabled(true); // Set to hidden to avoid this item to been displayed as a child item // Fields in this object are displayed using defineUiOrdering() - resultDefinition.uiCapability()->setUiHidden(true); - resultDefinition.uiCapability()->setUiTreeChildrenHidden(true); + m_resultDefinition.uiCapability()->setUiHidden(true); + m_resultDefinition.uiCapability()->setUiTreeChildrenHidden(true); CAF_PDM_InitField(&m_rangeLabelText, "Dummy_keyword", QString("Range Type"), "Range Type", "", "", ""); m_rangeLabelText.xmlCapability()->disableIO(); @@ -98,15 +97,23 @@ RimEclipsePropertyFilter::RimEclipsePropertyFilter() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- RimEclipsePropertyFilter::~RimEclipsePropertyFilter() { - delete resultDefinition; + delete m_resultDefinition; } //-------------------------------------------------------------------------------------------------- -/// +/// +//-------------------------------------------------------------------------------------------------- +RimEclipseResultDefinition* RimEclipsePropertyFilter::resultDefinition() const +{ + return m_resultDefinition; +} + +//-------------------------------------------------------------------------------------------------- +/// //-------------------------------------------------------------------------------------------------- void RimEclipsePropertyFilter::rangeValues(double* lower, double* upper) const { @@ -115,11 +122,11 @@ void RimEclipsePropertyFilter::rangeValues(double* lower, double* upper) const } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- bool RimEclipsePropertyFilter::isCategorySelectionActive() const { - if (resultDefinition->hasCategoryResult() && m_useCategorySelection) + if (m_resultDefinition->hasCategoryResult() && m_useCategorySelection) { return true; } @@ -128,10 +135,13 @@ bool RimEclipsePropertyFilter::isCategorySelectionActive() const } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- -void RimEclipsePropertyFilter::fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue) +void RimEclipsePropertyFilter::fieldChangedByUi(const caf::PdmFieldHandle* changedField, + const QVariant& oldValue, + const QVariant& newValue) { + // clang-format off if ( &m_lowerBound == changedField || &m_upperBound == changedField || &obsoleteField_evaluationRegion == changedField @@ -140,7 +150,7 @@ void RimEclipsePropertyFilter::fieldChangedByUi(const caf::PdmFieldHandle* chang || &m_selectedCategoryValues == changedField || &m_useCategorySelection == changedField) { - this->resultDefinition->loadResult(); + this->m_resultDefinition->loadResult(); this->computeResultValueRange(); updateFilterName(); this->updateIconState(); @@ -148,10 +158,11 @@ void RimEclipsePropertyFilter::fieldChangedByUi(const caf::PdmFieldHandle* chang parentContainer()->updateDisplayModelNotifyManagedViews(this); } + // clang-format on } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- RimEclipsePropertyFilterCollection* RimEclipsePropertyFilter::parentContainer() { @@ -162,7 +173,7 @@ RimEclipsePropertyFilterCollection* RimEclipsePropertyFilter::parentContainer() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RimEclipsePropertyFilter::setToDefaultValues() { @@ -174,34 +185,34 @@ void RimEclipsePropertyFilter::setToDefaultValues() m_upperBound = m_maximumResultValue; m_selectedCategoryValues = m_categoryValues; - m_useCategorySelection = true; + m_useCategorySelection = true; } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- -void RimEclipsePropertyFilter::defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering) +void RimEclipsePropertyFilter::defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering) { // Fields declared in RimCellFilter uiOrdering.add(&name); - // Fields declared in RimResultDefinition + // Fields declared in Rimm_resultDefinition caf::PdmUiGroup* group1 = uiOrdering.addNewGroup("Result"); - resultDefinition->uiOrdering(uiConfigName, *group1); - + m_resultDefinition->uiOrdering(uiConfigName, *group1); + caf::PdmUiGroup& group2 = *(uiOrdering.addNewGroup("Filter Settings")); // Fields declared in RimCellFilter group2.add(&filterMode); - + group2.add(&m_rangeLabelText); - if (resultDefinition->hasCategoryResult()) + if (m_resultDefinition->hasCategoryResult()) { group2.add(&m_useCategorySelection); } - if ( resultDefinition->hasCategoryResult() && m_useCategorySelection() ) + if (m_resultDefinition->hasCategoryResult() && m_useCategorySelection()) { group2.add(&m_selectedCategoryValues); } @@ -218,7 +229,7 @@ void RimEclipsePropertyFilter::defineUiOrdering(QString uiConfigName, caf::PdmUi } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RimEclipsePropertyFilter::defineUiTreeOrdering(caf::PdmUiTreeOrdering& uiTreeOrdering, QString uiConfigName) { @@ -228,7 +239,7 @@ void RimEclipsePropertyFilter::defineUiTreeOrdering(caf::PdmUiTreeOrdering& uiTr } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RimEclipsePropertyFilter::updateReadOnlyStateOfAllFields() { @@ -237,10 +248,10 @@ void RimEclipsePropertyFilter::updateReadOnlyStateOfAllFields() std::vector objFields; this->fields(objFields); - // Include fields declared in RimResultDefinition - objFields.push_back(&(resultDefinition->m_resultTypeUiField)); - objFields.push_back(&(resultDefinition->m_porosityModelUiField)); - objFields.push_back(&(resultDefinition->m_resultVariableUiField)); + // Include fields declared in Rimm_resultDefinition + objFields.push_back(&(m_resultDefinition->m_resultTypeUiField)); + objFields.push_back(&(m_resultDefinition->m_porosityModelUiField)); + objFields.push_back(&(m_resultDefinition->m_resultVariableUiField)); for (auto f : objFields) { @@ -251,11 +262,11 @@ void RimEclipsePropertyFilter::updateReadOnlyStateOfAllFields() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RimEclipsePropertyFilter::updateRangeLabel() { - if (resultDefinition->isFlowDiagOrInjectionFlooding()) + if (m_resultDefinition->isFlowDiagOrInjectionFlooding()) { m_rangeLabelText = "Current Timestep"; } @@ -266,7 +277,7 @@ void RimEclipsePropertyFilter::updateRangeLabel() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- bool RimEclipsePropertyFilter::isPropertyFilterControlled() { @@ -285,7 +296,7 @@ bool RimEclipsePropertyFilter::isPropertyFilterControlled() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RimEclipsePropertyFilter::setCategoriesFromTracerNames(const std::vector& tracerNames) { @@ -299,7 +310,7 @@ void RimEclipsePropertyFilter::setCategoriesFromTracerNames(const std::vector(i))); } - for (auto it : tracerNameSet) + for (const auto& it : tracerNameSet) { tracerNameValuesSorted.push_back(it); } @@ -309,7 +320,7 @@ void RimEclipsePropertyFilter::setCategoriesFromTracerNames(const std::vectorisFlowDiagOrInjectionFlooding()) + if (m_resultDefinition->isFlowDiagOrInjectionFlooding()) { Rim3dView* view; this->firstAncestorOrThisOfType(view); int timeStep = 0; if (view) timeStep = view->currentTimeStep(); - RigFlowDiagResultAddress resAddr = resultDefinition->flowDiagResAddress(); - if ( resultDefinition->flowDiagSolution() ) + RigFlowDiagResultAddress resAddr = m_resultDefinition->flowDiagResAddress(); + if (m_resultDefinition->flowDiagSolution()) { - RigFlowDiagResults* results = resultDefinition->flowDiagSolution()->flowDiagResults(); + RigFlowDiagResults* results = m_resultDefinition->flowDiagSolution()->flowDiagResults(); results->minMaxScalarValues(resAddr, timeStep, &min, &max); - if ( resultDefinition->hasCategoryResult() ) + if (m_resultDefinition->hasCategoryResult()) { - setCategoriesFromTracerNames(resultDefinition->flowDiagSolution()->tracerNames()); + setCategoriesFromTracerNames(m_resultDefinition->flowDiagSolution()->tracerNames()); } } } else { - size_t scalarIndex = resultDefinition->scalarResultIndex(); - if ( scalarIndex != cvf::UNDEFINED_SIZE_T ) + RigEclipseResultAddress scalarIndex = m_resultDefinition->eclipseResultAddress(); + if (scalarIndex.isValid()) { - RigCaseCellResultsData* results = resultDefinition->currentGridCellResults(); - if ( results ) + RigCaseCellResultsData* results = m_resultDefinition->currentGridCellResults(); + if (results) { results->minMaxCellScalarValues(scalarIndex, min, max); - if ( resultDefinition->hasCategoryResult() ) + if (m_resultDefinition->hasCategoryResult()) { - if ( resultDefinition->resultType() == RiaDefines::FORMATION_NAMES ) + if (m_resultDefinition->resultType() == RiaDefines::FORMATION_NAMES) { CVF_ASSERT(parentContainer()->reservoirView()->eclipseCase()->eclipseCaseData()); CVF_ASSERT(parentContainer()->reservoirView()->eclipseCase()->eclipseCaseData()->activeFormationNames()); - const std::vector& fnVector = parentContainer()->reservoirView()->eclipseCase()->eclipseCaseData()->activeFormationNames()->formationNames(); + const std::vector& fnVector = parentContainer() + ->reservoirView() + ->eclipseCase() + ->eclipseCaseData() + ->activeFormationNames() + ->formationNames(); setCategoryNames(fnVector); } - else if (resultDefinition->resultVariable() == RiaDefines::completionTypeResultName()) + else if (m_resultDefinition->resultVariable() == RiaDefines::completionTypeResultName()) { - std::vector componentTypes = - { - RiaDefines::WELL_PATH, RiaDefines::PERFORATION_INTERVAL, - RiaDefines::FISHBONES, RiaDefines::FRACTURE - }; + std::vector componentTypes = { + RiaDefines::WELL_PATH, RiaDefines::PERFORATION_INTERVAL, RiaDefines::FISHBONES, RiaDefines::FRACTURE}; std::vector> ctNamesAndValues; for (RiaDefines::WellPathComponentType type : componentTypes) { - ctNamesAndValues.push_back(std::make_pair(caf::AppEnum::uiText(type), type)); + ctNamesAndValues.push_back( + std::make_pair(caf::AppEnum::uiText(type), type)); } setCategoryNamesAndValues(ctNamesAndValues); } @@ -420,7 +436,7 @@ void RimEclipsePropertyFilter::computeResultValueRange() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RimEclipsePropertyFilter::updateFromCurrentTimeStep() { @@ -431,13 +447,13 @@ void RimEclipsePropertyFilter::updateFromCurrentTimeStep() // // If the user manually has set a filter value, this value is left untouched - if (!resultDefinition->isFlowDiagOrInjectionFlooding()) + if (!m_resultDefinition->isFlowDiagOrInjectionFlooding()) { return; } double threshold = 1e-6; - bool followMin = false; + bool followMin = false; if (fabs(m_lowerBound - m_minimumResultValue) < threshold || m_minimumResultValue == HUGE_VAL) { followMin = true; @@ -457,16 +473,16 @@ void RimEclipsePropertyFilter::updateFromCurrentTimeStep() Rim3dView* view = nullptr; this->firstAncestorOrThisOfTypeAsserted(view); - int timeStep = view->currentTimeStep(); - RigFlowDiagResultAddress resAddr = resultDefinition->flowDiagResAddress(); - if (resultDefinition->flowDiagSolution()) + int timeStep = view->currentTimeStep(); + RigFlowDiagResultAddress resAddr = m_resultDefinition->flowDiagResAddress(); + if (m_resultDefinition->flowDiagSolution()) { - RigFlowDiagResults* results = resultDefinition->flowDiagSolution()->flowDiagResults(); + RigFlowDiagResults* results = m_resultDefinition->flowDiagSolution()->flowDiagResults(); results->minMaxScalarValues(resAddr, timeStep, &min, &max); - if (resultDefinition->hasCategoryResult()) + if (m_resultDefinition->hasCategoryResult()) { - setCategoriesFromTracerNames(resultDefinition->flowDiagSolution()->tracerNames()); + setCategoriesFromTracerNames(m_resultDefinition->flowDiagSolution()->tracerNames()); } } @@ -502,19 +518,19 @@ void RimEclipsePropertyFilter::updateFromCurrentTimeStep() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RimEclipsePropertyFilter::updateFilterName() { - QString newFiltername = resultDefinition->resultVariableUiShortName(); + QString newFiltername = m_resultDefinition->resultVariableUiShortName(); if (isCategorySelectionActive()) { - if (m_categoryNames.size() == 0) + if (m_categoryNames.empty()) { newFiltername += " ("; - if ( m_selectedCategoryValues().size() && m_selectedCategoryValues().size() == m_categoryValues.size() ) + if (!m_selectedCategoryValues().empty() && m_selectedCategoryValues().size() == m_categoryValues.size()) { newFiltername += QString::number(m_selectedCategoryValues()[0]); newFiltername += ".."; @@ -533,10 +549,9 @@ void RimEclipsePropertyFilter::updateFilterName() } } } - + newFiltername += ")"; } - } else { @@ -547,20 +562,20 @@ void RimEclipsePropertyFilter::updateFilterName() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RimEclipsePropertyFilter::initAfterRead() { - resultDefinition->initAfterRead(); + m_resultDefinition->initAfterRead(); - resultDefinition->setEclipseCase(parentContainer()->reservoirView()->eclipseCase()); + m_resultDefinition->setEclipseCase(parentContainer()->reservoirView()->eclipseCase()); updateIconState(); } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RimEclipsePropertyFilter::updateUiFieldsFromActiveResult() { - resultDefinition->updateUiFieldsFromActiveResult(); + m_resultDefinition->updateUiFieldsFromActiveResult(); } diff --git a/ApplicationCode/ProjectDataModel/RimEclipsePropertyFilter.h b/ApplicationCode/ProjectDataModel/RimEclipsePropertyFilter.h index 333ffc8f44..56378bde96 100644 --- a/ApplicationCode/ProjectDataModel/RimEclipsePropertyFilter.h +++ b/ApplicationCode/ProjectDataModel/RimEclipsePropertyFilter.h @@ -3,17 +3,17 @@ // Copyright (C) 2011- Statoil ASA // Copyright (C) 2013- Ceetron Solutions AS // Copyright (C) 2011-2012 Ceetron AS -// +// // ResInsight 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 3 of the License, or // (at your option) any later version. -// +// // ResInsight 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 at +// +// See the GNU General Public License at // for more details. // ///////////////////////////////////////////////////////////////////////////////// @@ -28,68 +28,71 @@ class RimEclipsePropertyFilterCollection; class RimEclipseResultDefinition; //================================================================================================== -/// -/// +/// +/// //================================================================================================== class RimEclipsePropertyFilter : public RimPropertyFilter { CAF_PDM_HEADER_INIT; - + public: RimEclipsePropertyFilter(); ~RimEclipsePropertyFilter() override; - caf::PdmChildField resultDefinition; + RimEclipseResultDefinition* resultDefinition() const; - void rangeValues(double* lower, double* upper) const; - bool isCategorySelectionActive() const; + void rangeValues(double* lower, double* upper) const; + bool isCategorySelectionActive() const; - void setToDefaultValues(); - void updateFilterName(); - void computeResultValueRange(); - void updateFromCurrentTimeStep(); + void setToDefaultValues(); + void updateFilterName(); + void computeResultValueRange(); + void updateFromCurrentTimeStep(); - void fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue) override; - void initAfterRead() override; + void fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue) override; + void initAfterRead() override; - void updateUiFieldsFromActiveResult(); + void updateUiFieldsFromActiveResult(); -protected: - void defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering) override; - void defineUiTreeOrdering(caf::PdmUiTreeOrdering& uiTreeOrdering, QString uiConfigName) override; +private: + void defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering) override; + void defineUiTreeOrdering(caf::PdmUiTreeOrdering& uiTreeOrdering, QString uiConfigName) override; - void defineEditorAttribute(const caf::PdmFieldHandle* field, QString uiConfigName, caf::PdmUiEditorAttribute* attribute) override; + void defineEditorAttribute(const caf::PdmFieldHandle* field, + QString uiConfigName, + caf::PdmUiEditorAttribute* attribute) override; private: friend class RimEclipsePropertyFilterCollection; friend class RicEclipsePropertyFilterFeatureImpl; - void updateActiveState(); - void updateReadOnlyStateOfAllFields(); - void updateRangeLabel(); - bool isPropertyFilterControlled(); - void setCategoriesFromTracerNames(const std::vector& tracerNames); + void updateActiveState(); + void updateReadOnlyStateOfAllFields(); + void updateRangeLabel(); + bool isPropertyFilterControlled(); + void setCategoriesFromTracerNames(const std::vector& tracerNames); - RimEclipsePropertyFilterCollection* parentContainer(); + RimEclipsePropertyFilterCollection* parentContainer(); private: - caf::PdmField m_rangeLabelText; - caf::PdmField m_lowerBound; - caf::PdmField m_upperBound; + caf::PdmChildField m_resultDefinition; + caf::PdmField m_rangeLabelText; + caf::PdmField m_lowerBound; + caf::PdmField m_upperBound; - caf::PdmField m_useCategorySelection; + caf::PdmField m_useCategorySelection; - double m_minimumResultValue; - double m_maximumResultValue; + double m_minimumResultValue; + double m_maximumResultValue; public: - // Obsolete stuff + // Obsolete stuff enum EvaluationRegionType { RANGE_FILTER_REGION, GLOBAL_REGION }; + private: - caf::PdmField< caf::AppEnum< EvaluationRegionType > > obsoleteField_evaluationRegion; + caf::PdmField> obsoleteField_evaluationRegion; }; - diff --git a/ApplicationCode/ProjectDataModel/RimEclipsePropertyFilterCollection.cpp b/ApplicationCode/ProjectDataModel/RimEclipsePropertyFilterCollection.cpp index 58fd2c7960..754913ca0d 100644 --- a/ApplicationCode/ProjectDataModel/RimEclipsePropertyFilterCollection.cpp +++ b/ApplicationCode/ProjectDataModel/RimEclipsePropertyFilterCollection.cpp @@ -3,17 +3,17 @@ // Copyright (C) 2011- Statoil ASA // Copyright (C) 2013- Ceetron Solutions AS // Copyright (C) 2011-2012 Ceetron AS -// +// // ResInsight 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 3 of the License, or // (at your option) any later version. -// +// // ResInsight 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 at +// +// See the GNU General Public License at // for more details. // ///////////////////////////////////////////////////////////////////////////////// @@ -29,22 +29,21 @@ #include "cafPdmUiEditorHandle.h" - CAF_PDM_SOURCE_INIT(RimEclipsePropertyFilterCollection, "CellPropertyFilters"); //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- RimEclipsePropertyFilterCollection::RimEclipsePropertyFilterCollection() { CAF_PDM_InitObject("Property Filters", ":/CellFilter_Values.png", "", ""); - CAF_PDM_InitFieldNoDefault(&propertyFilters, "PropertyFilters", "Property Filters", "", "", ""); + CAF_PDM_InitFieldNoDefault(&propertyFilters, "PropertyFilters", "Property Filters", "", "", ""); propertyFilters.uiCapability()->setUiHidden(true); } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- RimEclipsePropertyFilterCollection::~RimEclipsePropertyFilterCollection() { @@ -52,7 +51,7 @@ RimEclipsePropertyFilterCollection::~RimEclipsePropertyFilterCollection() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- RimEclipseView* RimEclipsePropertyFilterCollection::reservoirView() { @@ -63,25 +62,24 @@ RimEclipseView* RimEclipsePropertyFilterCollection::reservoirView() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RimEclipsePropertyFilterCollection::loadAndInitializePropertyFilters() { - for (size_t i = 0; i < propertyFilters.size(); i++) + for (RimEclipsePropertyFilter* propertyFilter : propertyFilters) { - RimEclipsePropertyFilter* propertyFilter = propertyFilters[i]; - propertyFilter->resultDefinition->setEclipseCase(reservoirView()->eclipseCase()); + propertyFilter->resultDefinition()->setEclipseCase(reservoirView()->eclipseCase()); propertyFilter->initAfterRead(); if (isActive() && propertyFilter->isActive()) { - propertyFilter->resultDefinition->loadResult(); + propertyFilter->resultDefinition()->loadResult(); propertyFilter->computeResultValueRange(); } } } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RimEclipsePropertyFilterCollection::initAfterRead() { @@ -89,16 +87,15 @@ void RimEclipsePropertyFilterCollection::initAfterRead() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- bool RimEclipsePropertyFilterCollection::hasActiveFilters() const { if (!isActive) return false; - for (size_t i = 0; i < propertyFilters.size(); i++) + for (RimEclipsePropertyFilter* propertyFilter : propertyFilters) { - RimEclipsePropertyFilter* propertyFilter = propertyFilters[i]; - if (propertyFilter->isActive() && propertyFilter->resultDefinition->hasResult()) return true; + if (propertyFilter->isActive() && propertyFilter->resultDefinition()->hasResult()) return true; } return false; @@ -111,36 +108,33 @@ bool RimEclipsePropertyFilterCollection::hasActiveDynamicFilters() const { if (!isActive) return false; - for (size_t i = 0; i < propertyFilters.size(); i++) + for (RimEclipsePropertyFilter* propertyFilter : propertyFilters) { - RimEclipsePropertyFilter* propertyFilter = propertyFilters[i]; - if (propertyFilter->isActive() && propertyFilter->resultDefinition->hasDynamicResult()) return true; + if (propertyFilter->isActive() && propertyFilter->resultDefinition()->hasDynamicResult()) return true; } return false; } - //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- bool RimEclipsePropertyFilterCollection::isUsingFormationNames() const { - if ( !isActive ) return false; + if (!isActive) return false; - for ( size_t i = 0; i < propertyFilters.size(); i++ ) + for (RimEclipsePropertyFilter* propertyFilter : propertyFilters) { - RimEclipsePropertyFilter* propertyFilter = propertyFilters[i]; - if ( propertyFilter->isActive() - && propertyFilter->resultDefinition->resultType() == RiaDefines::FORMATION_NAMES - && propertyFilter->resultDefinition->resultVariable() != RiaDefines::undefinedResultName()) return true; + if (propertyFilter->isActive() && propertyFilter->resultDefinition()->resultType() == RiaDefines::FORMATION_NAMES && + propertyFilter->resultDefinition()->resultVariable() != RiaDefines::undefinedResultName()) + return true; } return false; } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RimEclipsePropertyFilterCollection::updateIconState() { @@ -151,8 +145,7 @@ void RimEclipsePropertyFilterCollection::updateIconState() if (view) { RimViewController* viewController = view->viewController(); - if (viewController && (viewController->isPropertyFilterOveridden() - || viewController->isVisibleCellsOveridden())) + if (viewController && (viewController->isPropertyFilterOveridden() || viewController->isVisibleCellsOveridden())) { activeIcon = false; } @@ -165,16 +158,15 @@ void RimEclipsePropertyFilterCollection::updateIconState() updateUiIconFromState(activeIcon); - for (size_t i = 0; i < propertyFilters.size(); i++) + for (RimEclipsePropertyFilter* cellFilter : propertyFilters) { - RimEclipsePropertyFilter* cellFilter = propertyFilters[i]; cellFilter->updateActiveState(); cellFilter->updateIconState(); } } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RimEclipsePropertyFilterCollection::updateFromCurrentTimeStep() { @@ -183,4 +175,3 @@ void RimEclipsePropertyFilterCollection::updateFromCurrentTimeStep() cellFilter->updateFromCurrentTimeStep(); } } - diff --git a/ApplicationCode/ProjectDataModel/RimEclipseResultCase.cpp b/ApplicationCode/ProjectDataModel/RimEclipseResultCase.cpp index 22c91a5c69..ef1a72c049 100644 --- a/ApplicationCode/ProjectDataModel/RimEclipseResultCase.cpp +++ b/ApplicationCode/ProjectDataModel/RimEclipseResultCase.cpp @@ -190,6 +190,8 @@ bool RimEclipseResultCase::importGridAndResultMetaData(bool showTimeStepFilter) progInfo.incrementProgress(); + m_flowDagSolverInterface = new RigFlowDiagSolverInterface(this); + CVF_ASSERT(this->eclipseCaseData()); CVF_ASSERT(readerInterface.notNull()); @@ -199,8 +201,6 @@ bool RimEclipseResultCase::importGridAndResultMetaData(bool showTimeStepFilter) m_gridAndWellDataIsReadFromFile = true; m_activeCellInfoIsReadFromFile = true; - m_flowDagSolverInterface = new RigFlowDiagSolverInterface(this); - QFileInfo eclipseCaseFileInfo(caseFileName()); QString rftFileName = eclipseCaseFileInfo.path() + "/" + eclipseCaseFileInfo.completeBaseName() + ".RFT"; QFileInfo rftFileInfo(rftFileName); diff --git a/ApplicationCode/ProjectDataModel/RimEclipseResultDefinition.cpp b/ApplicationCode/ProjectDataModel/RimEclipseResultDefinition.cpp index 54f7b8feeb..08cf81b8a7 100644 --- a/ApplicationCode/ProjectDataModel/RimEclipseResultDefinition.cpp +++ b/ApplicationCode/ProjectDataModel/RimEclipseResultDefinition.cpp @@ -3,23 +3,27 @@ // Copyright (C) 2011- Statoil ASA // Copyright (C) 2013- Ceetron Solutions AS // Copyright (C) 2011-2012 Ceetron AS -// +// // ResInsight 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 3 of the License, or // (at your option) any later version. -// +// // ResInsight 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 at +// +// See the GNU General Public License at // for more details. // ///////////////////////////////////////////////////////////////////////////////// #include "RimEclipseResultDefinition.h" +#include "RiaApplication.h" +#include "RiaLogging.h" +#include "RiaQDateTimeTools.h" + #include "RigActiveCellInfo.h" #include "RigCaseCellResultsData.h" #include "RigEclipseCaseData.h" @@ -29,17 +33,20 @@ #include "Rim3dView.h" #include "Rim3dWellLogCurve.h" #include "RimCellEdgeColors.h" -#include "RimContourMapProjection.h" #include "RimEclipseCase.h" #include "RimEclipseCellColors.h" +#include "RimEclipseContourMapProjection.h" #include "RimEclipseFaultColors.h" #include "RimEclipsePropertyFilter.h" #include "RimEclipseResultCase.h" #include "RimEclipseView.h" #include "RimFlowDiagSolution.h" +#include "RimGridCrossPlot.h" +#include "RimGridCrossPlotDataSet.h" #include "RimGridTimeHistoryCurve.h" #include "RimIntersectionCollection.h" #include "RimPlotCurve.h" +#include "RimProject.h" #include "RimReservoirCellResultsStorage.h" #include "RimViewLinker.h" #include "RimWellLogExtractionCurve.h" @@ -49,45 +56,54 @@ #include "cafPdmUiTreeSelectionEditor.h" #include "cafUtils.h" -#include -#include - namespace caf { - template<> - void RimEclipseResultDefinition::FlowTracerSelectionEnum::setUp() - { - addItem(RimEclipseResultDefinition::FLOW_TR_INJ_AND_PROD, "FLOW_TR_INJ_AND_PROD", "All Injectors and Producers"); - addItem(RimEclipseResultDefinition::FLOW_TR_PRODUCERS, "FLOW_TR_PRODUCERS", "All Producers"); - addItem(RimEclipseResultDefinition::FLOW_TR_INJECTORS, "FLOW_TR_INJECTORS", "All Injectors"); - addItem(RimEclipseResultDefinition::FLOW_TR_BY_SELECTION, "FLOW_TR_BY_SELECTION", "By Selection"); +template<> +void RimEclipseResultDefinition::FlowTracerSelectionEnum::setUp() +{ + addItem(RimEclipseResultDefinition::FLOW_TR_INJ_AND_PROD, "FLOW_TR_INJ_AND_PROD", "All Injectors and Producers"); + addItem(RimEclipseResultDefinition::FLOW_TR_PRODUCERS, "FLOW_TR_PRODUCERS", "All Producers"); + addItem(RimEclipseResultDefinition::FLOW_TR_INJECTORS, "FLOW_TR_INJECTORS", "All Injectors"); + addItem(RimEclipseResultDefinition::FLOW_TR_BY_SELECTION, "FLOW_TR_BY_SELECTION", "By Selection"); - setDefault(RimEclipseResultDefinition::FLOW_TR_INJ_AND_PROD); - } + setDefault(RimEclipseResultDefinition::FLOW_TR_INJ_AND_PROD); } - +} // namespace caf CAF_PDM_SOURCE_INIT(RimEclipseResultDefinition, "ResultDefinition"); //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- -RimEclipseResultDefinition::RimEclipseResultDefinition() +RimEclipseResultDefinition::RimEclipseResultDefinition(caf::PdmUiItemInfo::LabelPosType labelPosition) + : m_diffResultOptionsEnabled(false) + , m_labelPosition(labelPosition) + , m_ternaryEnabled(true) { CAF_PDM_InitObject("Result Definition", "", "", ""); - CAF_PDM_InitFieldNoDefault(&m_resultType, "ResultType", "Type", "", "", ""); + CAF_PDM_InitFieldNoDefault(&m_resultType, "ResultType", "Type", "", "", ""); m_resultType.uiCapability()->setUiHidden(true); - CAF_PDM_InitFieldNoDefault(&m_porosityModel, "PorosityModelType", "Porosity", "", "", ""); + CAF_PDM_InitFieldNoDefault(&m_porosityModel, "PorosityModelType", "Porosity", "", "", ""); m_porosityModel.uiCapability()->setUiHidden(true); - CAF_PDM_InitField(&m_resultVariable, "ResultVariable", RiaDefines::undefinedResultName(), "Variable", "", "", "" ); + CAF_PDM_InitField(&m_resultVariable, "ResultVariable", RiaDefines::undefinedResultName(), "Variable", "", "", ""); m_resultVariable.uiCapability()->setUiHidden(true); CAF_PDM_InitFieldNoDefault(&m_flowSolution, "FlowDiagSolution", "Solution", "", "", ""); m_flowSolution.uiCapability()->setUiHidden(true); + CAF_PDM_InitField(&m_timeLapseBaseTimestep, + "TimeLapseBaseTimeStep", + RigEclipseResultAddress::noTimeLapseValue(), + "Base Time Step", + "", + "", + ""); + + CAF_PDM_InitFieldNoDefault(&m_differenceCase, "DifferenceCase", "Difference Case", "", "", ""); + // One single tracer list has been split into injectors and producers. // The old list is defined as injectors and we'll have to move any producers in old projects. CAF_PDM_InitFieldNoDefault(&m_selectedTracers_OBSOLETE, "SelectedTracers", "Tracers", "", "", ""); @@ -99,37 +115,38 @@ RimEclipseResultDefinition::RimEclipseResultDefinition() CAF_PDM_InitFieldNoDefault(&m_selectedProducerTracers, "SelectedProducerTracers", "Producer Tracers", "", "", ""); m_selectedProducerTracers.uiCapability()->setUiHidden(true); - CAF_PDM_InitFieldNoDefault(&m_selectedSouringTracers, "SelectedSouringTracers", "Tracers", "", "", ""); m_selectedSouringTracers.uiCapability()->setUiHidden(true); CAF_PDM_InitFieldNoDefault(&m_flowTracerSelectionMode, "FlowTracerSelectionMode", "Tracers", "", "", ""); CAF_PDM_InitFieldNoDefault(&m_phaseSelection, "PhaseSelection", "Phases", "", "", ""); - + m_phaseSelection.uiCapability()->setUiLabelPosition(m_labelPosition); // Ui only fields - CAF_PDM_InitFieldNoDefault(&m_resultTypeUiField, "MResultType", "Type", "", "", ""); + CAF_PDM_InitFieldNoDefault(&m_resultTypeUiField, "MResultType", "Type", "", "", ""); m_resultTypeUiField.xmlCapability()->disableIO(); + m_resultTypeUiField.uiCapability()->setUiLabelPosition(m_labelPosition); - CAF_PDM_InitFieldNoDefault(&m_porosityModelUiField, "MPorosityModelType", "Porosity", "", "", ""); + CAF_PDM_InitFieldNoDefault(&m_porosityModelUiField, "MPorosityModelType", "Porosity", "", "", ""); m_porosityModelUiField.xmlCapability()->disableIO(); + m_porosityModelUiField.uiCapability()->setUiLabelPosition(m_labelPosition); - CAF_PDM_InitField(&m_resultVariableUiField, "MResultVariable", RiaDefines::undefinedResultName(), "Result Property", "", "", "" ); + CAF_PDM_InitField( + &m_resultVariableUiField, "MResultVariable", RiaDefines::undefinedResultName(), "Result Property", "", "", ""); m_resultVariableUiField.xmlCapability()->disableIO(); m_resultVariableUiField.uiCapability()->setUiEditorTypeName(caf::PdmUiListEditor::uiEditorTypeName()); - + m_resultVariableUiField.uiCapability()->setUiLabelPosition(m_labelPosition); CAF_PDM_InitFieldNoDefault(&m_flowSolutionUiField, "MFlowDiagSolution", "Solution", "", "", ""); m_flowSolutionUiField.xmlCapability()->disableIO(); m_flowSolutionUiField.uiCapability()->setUiHidden(true); // For now since there are only one to choose from - + CAF_PDM_InitField(&m_syncInjectorToProducerSelection, "MSyncSelectedInjProd", false, "Add Communicators ->", "", "", ""); m_syncInjectorToProducerSelection.uiCapability()->setUiEditorTypeName(caf::PdmUiToolButtonEditor::uiEditorTypeName()); CAF_PDM_InitField(&m_syncProducerToInjectorSelection, "MSyncSelectedProdInj", false, "<- Add Communicators", "", "", ""); m_syncProducerToInjectorSelection.uiCapability()->setUiEditorTypeName(caf::PdmUiToolButtonEditor::uiEditorTypeName()); - CAF_PDM_InitFieldNoDefault(&m_selectedInjectorTracersUiField, "MSelectedInjectorTracers", "Injector Tracers", "", "", ""); m_selectedInjectorTracersUiField.xmlCapability()->disableIO(); m_selectedInjectorTracersUiField.uiCapability()->setUiEditorTypeName(caf::PdmUiTreeSelectionEditor::uiEditorTypeName()); @@ -143,18 +160,16 @@ RimEclipseResultDefinition::RimEclipseResultDefinition() CAF_PDM_InitFieldNoDefault(&m_selectedSouringTracersUiField, "MSelectedSouringTracers", "Tracers", "", "", ""); m_selectedSouringTracersUiField.xmlCapability()->disableIO(); m_selectedSouringTracersUiField.uiCapability()->setUiEditorTypeName(caf::PdmUiListEditor::uiEditorTypeName()); + m_selectedSouringTracersUiField.uiCapability()->setUiLabelPosition(m_labelPosition); } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- -RimEclipseResultDefinition::~RimEclipseResultDefinition() -{ -} - +RimEclipseResultDefinition::~RimEclipseResultDefinition() {} //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RimEclipseResultDefinition::simpleCopy(const RimEclipseResultDefinition* other) { @@ -166,50 +181,58 @@ void RimEclipseResultDefinition::simpleCopy(const RimEclipseResultDefinition* ot this->setSelectedProducerTracers(other->m_selectedProducerTracers()); this->setSelectedSouringTracers(other->m_selectedSouringTracers()); m_flowTracerSelectionMode = other->m_flowTracerSelectionMode(); - m_phaseSelection = other->m_phaseSelection; + m_phaseSelection = other->m_phaseSelection; + + m_differenceCase = other->m_differenceCase(); + m_timeLapseBaseTimestep = other->m_timeLapseBaseTimestep(); } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RimEclipseResultDefinition::setEclipseCase(RimEclipseCase* eclipseCase) { - m_eclipseCase = eclipseCase; - - assignFlowSolutionFromCase(); + m_eclipseCase = eclipseCase; + + assignFlowSolutionFromCase(); } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimEclipseCase* RimEclipseResultDefinition::eclipseCase() +{ + return m_eclipseCase; +} //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- RigCaseCellResultsData* RimEclipseResultDefinition::currentGridCellResults() const { - if (!m_eclipseCase ) return nullptr; + if (!m_eclipseCase) return nullptr; return m_eclipseCase->results(m_porosityModel()); } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- -void RimEclipseResultDefinition::fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue) +void RimEclipseResultDefinition::fieldChangedByUi(const caf::PdmFieldHandle* changedField, + const QVariant& oldValue, + const QVariant& newValue) { - if ( &m_flowSolutionUiField == changedField - || &m_resultTypeUiField == changedField - || &m_porosityModelUiField == changedField ) + if (&m_flowSolutionUiField == changedField || &m_resultTypeUiField == changedField || &m_porosityModelUiField == changedField) { - // If the user are seeing the list with the actually selected result, + // If the user are seeing the list with the actually selected result, // select that result in the list. Otherwise select nothing. - QStringList varList = getResultNamesForCurrentUiResultType(); + QStringList varList = getResultNamesForResultType(m_resultTypeUiField(), this->currentGridCellResults()); bool isFlowDiagFieldsRelevant = (m_resultType() == RiaDefines::FLOW_DIAGNOSTICS); - - if ( ( m_flowSolutionUiField() == m_flowSolution() || !isFlowDiagFieldsRelevant) - && m_resultTypeUiField() == m_resultType() - && m_porosityModelUiField() == m_porosityModel() ) + if ((m_flowSolutionUiField() == m_flowSolution() || !isFlowDiagFieldsRelevant) && + m_resultTypeUiField() == m_resultType() && m_porosityModelUiField() == m_porosityModel()) { if (varList.contains(resultVariable())) { @@ -229,7 +252,7 @@ void RimEclipseResultDefinition::fieldChangedByUi(const caf::PdmFieldHandle* cha } else { - m_resultVariableUiField = ""; + m_resultVariableUiField = ""; m_selectedInjectorTracersUiField = std::vector(); m_selectedProducerTracersUiField = std::vector(); } @@ -240,10 +263,10 @@ void RimEclipseResultDefinition::fieldChangedByUi(const caf::PdmFieldHandle* cha m_porosityModel = m_porosityModelUiField; m_resultType = m_resultTypeUiField; m_resultVariable = m_resultVariableUiField; - + if (m_resultTypeUiField() == RiaDefines::FLOW_DIAGNOSTICS) { - m_flowSolution = m_flowSolutionUiField(); + m_flowSolution = m_flowSolutionUiField(); m_selectedInjectorTracers = m_selectedInjectorTracersUiField(); m_selectedProducerTracers = m_selectedProducerTracersUiField(); } @@ -254,13 +277,23 @@ void RimEclipseResultDefinition::fieldChangedByUi(const caf::PdmFieldHandle* cha loadDataAndUpdate(); } - if (&m_flowTracerSelectionMode == changedField) + if (&m_differenceCase == changedField) + { + m_timeLapseBaseTimestep = RigEclipseResultAddress::noTimeLapseValue(); + loadDataAndUpdate(); + } + + if (&m_timeLapseBaseTimestep == changedField) { loadDataAndUpdate(); } + if (&m_flowTracerSelectionMode == changedField) + { + loadDataAndUpdate(); + } - if (&m_selectedInjectorTracersUiField == changedField ) + if (&m_selectedInjectorTracersUiField == changedField) { changedTracerSelectionField(true); } @@ -272,7 +305,7 @@ void RimEclipseResultDefinition::fieldChangedByUi(const caf::PdmFieldHandle* cha if (&m_syncInjectorToProducerSelection == changedField) { - syncInjectorToProducerSelection(); + syncInjectorToProducerSelection(); m_syncInjectorToProducerSelection = false; } @@ -282,7 +315,6 @@ void RimEclipseResultDefinition::fieldChangedByUi(const caf::PdmFieldHandle* cha m_syncProducerToInjectorSelection = false; } - if (&m_selectedSouringTracersUiField == changedField) { if (!m_resultVariable().isEmpty()) @@ -296,8 +328,8 @@ void RimEclipseResultDefinition::fieldChangedByUi(const caf::PdmFieldHandle* cha { if (m_phaseSelection() != RigFlowDiagResultAddress::PHASE_ALL) { - m_resultType = m_resultTypeUiField; - m_resultVariable = RIG_FLD_TOF_RESNAME; + m_resultType = m_resultTypeUiField; + m_resultVariable = RIG_FLD_TOF_RESNAME; m_resultVariableUiField = RIG_FLD_TOF_RESNAME; } loadDataAndUpdate(); @@ -313,10 +345,9 @@ void RimEclipseResultDefinition::changedTracerSelectionField(bool injector) { m_flowSolution = m_flowSolutionUiField(); - std::vector& selectedTracers = injector ? m_selectedInjectorTracers.v() - : m_selectedProducerTracers.v(); - std::vector& selectedTracersUi = injector ? m_selectedInjectorTracersUiField.v() - : m_selectedProducerTracersUiField.v(); + std::vector& selectedTracers = injector ? m_selectedInjectorTracers.v() : m_selectedProducerTracers.v(); + std::vector& selectedTracersUi = + injector ? m_selectedInjectorTracersUiField.v() : m_selectedProducerTracersUiField.v(); selectedTracers = selectedTracersUi; @@ -324,7 +355,7 @@ void RimEclipseResultDefinition::changedTracerSelectionField(bool injector) } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RimEclipseResultDefinition::updateAnyFieldHasChanged() { @@ -334,7 +365,7 @@ void RimEclipseResultDefinition::updateAnyFieldHasChanged() { propFilter->updateConnectedEditors(); } - + RimEclipseFaultColors* faultColors = nullptr; this->firstAncestorOrThisOfType(faultColors); if (faultColors) @@ -356,6 +387,13 @@ void RimEclipseResultDefinition::updateAnyFieldHasChanged() cellColors->updateConnectedEditors(); } + RimGridCrossPlotDataSet* crossPlotCurveSet = nullptr; + this->firstAncestorOrThisOfType(crossPlotCurveSet); + if (crossPlotCurveSet) + { + crossPlotCurveSet->updateConnectedEditors(); + } + RimPlotCurve* curve = nullptr; this->firstAncestorOrThisOfType(curve); if (curve) @@ -370,7 +408,7 @@ void RimEclipseResultDefinition::updateAnyFieldHasChanged() rim3dWellLogCurve->resetMinMaxValuesAndUpdateUI(); } - RimContourMapProjection* contourMap = nullptr; + RimEclipseContourMapProjection* contourMap = nullptr; this->firstAncestorOrThisOfType(contourMap); if (contourMap) { @@ -379,7 +417,7 @@ void RimEclipseResultDefinition::updateAnyFieldHasChanged() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RimEclipseResultDefinition::setTofAndSelectTracer(const QString& tracerName) { @@ -398,11 +436,12 @@ void RimEclipseResultDefinition::setTofAndSelectTracer(const QString& tracerName std::vector tracers; tracers.push_back(tracerName); - if (tracerStatus == RimFlowDiagSolution::INJECTOR) + if ((tracerStatus == RimFlowDiagSolution::INJECTOR) || (tracerStatus == RimFlowDiagSolution::VARYING)) { setSelectedInjectorTracers(tracers); } - else if (tracerStatus == RimFlowDiagSolution::PRODUCER) + + if ((tracerStatus == RimFlowDiagSolution::PRODUCER) || (tracerStatus == RimFlowDiagSolution::VARYING)) { setSelectedProducerTracers(tracers); } @@ -410,7 +449,7 @@ void RimEclipseResultDefinition::setTofAndSelectTracer(const QString& tracerName } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RimEclipseResultDefinition::loadDataAndUpdate() { @@ -464,6 +503,14 @@ void RimEclipseResultDefinition::loadDataAndUpdate() } } + RimGridCrossPlotDataSet* crossPlotCurveSet = nullptr; + this->firstAncestorOrThisOfType(crossPlotCurveSet); + if (crossPlotCurveSet) + { + crossPlotCurveSet->destroyCurves(); + crossPlotCurveSet->loadDataAndUpdate(true); + } + RimPlotCurve* curve = nullptr; this->firstAncestorOrThisOfType(curve); if (curve) @@ -480,17 +527,18 @@ void RimEclipseResultDefinition::loadDataAndUpdate() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- -QList RimEclipseResultDefinition::calculateValueOptions(const caf::PdmFieldHandle* fieldNeedingOptions, bool* useOptionsOnly) +QList RimEclipseResultDefinition::calculateValueOptions(const caf::PdmFieldHandle* fieldNeedingOptions, + bool* useOptionsOnly) { QList options; - if ( fieldNeedingOptions == &m_resultTypeUiField ) + if (fieldNeedingOptions == &m_resultTypeUiField) { - bool hasSourSimRLFile = false; - RimEclipseResultCase* eclResCase = dynamic_cast(m_eclipseCase.p()); - if ( eclResCase && eclResCase->eclipseCaseData() ) + bool hasSourSimRLFile = false; + RimEclipseResultCase* eclResCase = dynamic_cast(m_eclipseCase.p()); + if (eclResCase && eclResCase->eclipseCaseData()) { hasSourSimRLFile = eclResCase->hasSourSimFile(); } @@ -515,26 +563,23 @@ QList RimEclipseResultDefinition::calculateValueOptions( } #endif /* ENABLE_SOURING */ - RimGridTimeHistoryCurve* timeHistoryCurve; this->firstAncestorOrThisOfType(timeHistoryCurve); // Do not include flow diagnostics results if it is a time history curve // Do not include SourSimRL if no SourSim file is loaded - if ( timeHistoryCurve != nullptr || !hasSourSimRLFile || !enableSouring ) + if (timeHistoryCurve != nullptr || !hasSourSimRLFile || !enableSouring) { - using ResCatEnum = caf::AppEnum< RiaDefines::ResultCatType >; - for ( size_t i = 0; i < ResCatEnum::size(); ++i ) + using ResCatEnum = caf::AppEnum; + for (size_t i = 0; i < ResCatEnum::size(); ++i) { RiaDefines::ResultCatType resType = ResCatEnum::fromIndex(i); - if ( resType == RiaDefines::FLOW_DIAGNOSTICS - && (timeHistoryCurve) ) + if (resType == RiaDefines::FLOW_DIAGNOSTICS && (timeHistoryCurve)) { - continue; + continue; } - if ( resType == RiaDefines::SOURSIMRL - && (!hasSourSimRLFile ) ) + if (resType == RiaDefines::SOURSIMRL && (!hasSourSimRLFile)) { continue; } @@ -550,9 +595,9 @@ QList RimEclipseResultDefinition::calculateValueOptions( } } - if ( m_resultTypeUiField() == RiaDefines::FLOW_DIAGNOSTICS ) + if (m_resultTypeUiField() == RiaDefines::FLOW_DIAGNOSTICS) { - if ( fieldNeedingOptions == &m_resultVariableUiField ) + if (fieldNeedingOptions == &m_resultVariableUiField) { options.push_back(caf::PdmOptionItemInfo(timeOfFlightString(false), RIG_FLD_TOF_RESNAME)); if (m_phaseSelection() == RigFlowDiagResultAddress::PHASE_ALL) @@ -572,7 +617,7 @@ QList RimEclipseResultDefinition::calculateValueOptions( { options.push_back(caf::PdmOptionItemInfo(flowSol->userDescription(), flowSol)); } - } + } } else if (fieldNeedingOptions == &m_selectedInjectorTracersUiField) { @@ -594,8 +639,7 @@ QList RimEclipseResultDefinition::calculateValueOptions( for (const QString& resultName : dynamicResultNames) { - if (!resultName.endsWith("F") || - resultName == RiaDefines::completionTypeResultName()) + if (!resultName.endsWith("F") || resultName == RiaDefines::completionTypeResultName()) { continue; } @@ -610,38 +654,125 @@ QList RimEclipseResultDefinition::calculateValueOptions( } else { - if ( fieldNeedingOptions == &m_resultVariableUiField ) + if (fieldNeedingOptions == &m_resultVariableUiField) { - options = calcOptionsForVariableUiFieldStandard(); + options = calcOptionsForVariableUiFieldStandard(m_resultTypeUiField(), + this->currentGridCellResults(), + showDerivedResultsFirstInVariableUiField(), + addPerCellFaceOptionsForVariableUiField(), + m_ternaryEnabled); } - } + else if (fieldNeedingOptions == &m_differenceCase) + { + options.push_back(caf::PdmOptionItemInfo("None", nullptr)); + + RimEclipseCase* eclipseCase = nullptr; + this->firstAncestorOrThisOfTypeAsserted(eclipseCase); + if (eclipseCase && eclipseCase->eclipseCaseData() && eclipseCase->eclipseCaseData()->mainGrid()) + { + RimProject* proj = nullptr; + eclipseCase->firstAncestorOrThisOfTypeAsserted(proj); + + std::vector allCases = proj->eclipseCases(); + for (RimEclipseCase* otherCase : allCases) + { + if (otherCase == eclipseCase) continue; + + if (otherCase->eclipseCaseData() && otherCase->eclipseCaseData()->mainGrid()) + { + options.push_back(caf::PdmOptionItemInfo( + QString("%1 (#%2)").arg(otherCase->caseUserDescription()).arg(otherCase->caseId()), + otherCase, + false, + otherCase->uiIcon())); + } + } + } + } + else if (fieldNeedingOptions == &m_timeLapseBaseTimestep) + { + RimEclipseCase* currentCase = nullptr; + this->firstAncestorOrThisOfTypeAsserted(currentCase); + RimEclipseCase* baseCase = currentCase; + if (m_differenceCase) + { + baseCase = m_differenceCase; + } + + options.push_back(caf::PdmOptionItemInfo("Disabled", RigEclipseResultAddress::noTimeLapseValue())); + + std::vector stepDates = baseCase->timeStepDates(); + for (size_t stepIdx = 0; stepIdx < stepDates.size(); ++stepIdx) + { + QString displayString = stepDates[stepIdx].toString(RiaQDateTimeTools::dateFormatString()); + displayString += QString(" (#%1)").arg(stepIdx); + + options.push_back(caf::PdmOptionItemInfo(displayString, static_cast(stepIdx))); + } + } + } (*useOptionsOnly) = true; - + return options; } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- -size_t RimEclipseResultDefinition::scalarResultIndex() const +RigEclipseResultAddress RimEclipseResultDefinition::eclipseResultAddress() const { - size_t gridScalarResultIndex = cvf::UNDEFINED_SIZE_T; - - if (isFlowDiagOrInjectionFlooding()) return cvf::UNDEFINED_SIZE_T; + if (isFlowDiagOrInjectionFlooding()) return RigEclipseResultAddress(); const RigCaseCellResultsData* gridCellResults = this->currentGridCellResults(); - if (gridCellResults ) + if (gridCellResults) + { + int timelapseTimeStep = RigEclipseResultAddress::noTimeLapseValue(); + int diffCaseId = RigEclipseResultAddress::noCaseDiffValue(); + + if (isTimeDiffResult()) + { + timelapseTimeStep = m_timeLapseBaseTimestep(); + } + + if (isCaseDiffResult()) + { + diffCaseId = m_differenceCase->caseId(); + } + + return RigEclipseResultAddress(m_resultType(), m_resultVariable(), timelapseTimeStep, diffCaseId); + } + else { - gridScalarResultIndex = gridCellResults->findScalarResultIndex(m_resultType(), m_resultVariable()); + return RigEclipseResultAddress(); } +} - return gridScalarResultIndex; +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimEclipseResultDefinition::setFromEclipseResultAddress(const RigEclipseResultAddress& address) +{ + m_resultType = address.m_resultCatType; + m_resultVariable = address.m_resultName; + m_timeLapseBaseTimestep = address.m_timeLapseBaseFrameIdx; + + if (address.hasDifferenceCase()) + { + auto eclipseCases = RiaApplication::instance()->project()->eclipseCases(); + for (RimEclipseCase* c : eclipseCases) + { + if (c && c->caseId() == address.m_differenceCaseId) + { + m_differenceCase = c; + } + } + } } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- RigFlowDiagResultAddress RimEclipseResultDefinition::flowDiagResAddress() const { @@ -664,7 +795,7 @@ RigFlowDiagResultAddress RimEclipseResultDefinition::flowDiagResAddress() const timeStep = static_cast(wellLogExtractionCurve->currentTimeStep()); } - // Time history curves are not supported, since it requires the time + // Time history curves are not supported, since it requires the time // step to access to be supplied. RimGridTimeHistoryCurve* timeHistoryCurve = nullptr; this->firstAncestorOrThisOfType(timeHistoryCurve); @@ -729,15 +860,15 @@ RigFlowDiagResultAddress RimEclipseResultDefinition::flowDiagResAddress() const } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RimEclipseResultDefinition::setFlowDiagTracerSelectionType(FlowTracerSelectionType selectionType) -{ +{ m_flowTracerSelectionMode = selectionType; } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- QString RimEclipseResultDefinition::resultVariableUiName() const { @@ -750,7 +881,7 @@ QString RimEclipseResultDefinition::resultVariableUiName() const } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- QString RimEclipseResultDefinition::resultVariableUiShortName() const { @@ -763,32 +894,122 @@ QString RimEclipseResultDefinition::resultVariableUiShortName() const } //-------------------------------------------------------------------------------------------------- -/// +/// +//-------------------------------------------------------------------------------------------------- +QString RimEclipseResultDefinition::diffResultUiName() const +{ + QStringList diffResult; + if (isTimeDiffResult()) + { + std::vector stepDates; + const RigCaseCellResultsData* gridCellResults = this->currentGridCellResults(); + if (gridCellResults) + { + stepDates = gridCellResults->timeStepDates(); + diffResult += QString("Base Time Step: %1") + .arg(stepDates[m_timeLapseBaseTimestep()].toString(RiaQDateTimeTools::dateFormatString())); + } + } + if (isCaseDiffResult()) + { + diffResult += QString("Base Case: %1").arg(m_differenceCase()->caseUserDescription()); + } + return diffResult.join("\n"); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RimEclipseResultDefinition::diffResultUiShortName() const +{ + QStringList diffResult; + if (isTimeDiffResult() || isCaseDiffResult()) + { + diffResult += QString("Diff. Options:"); + } + if (isCaseDiffResult()) + { + diffResult += QString("Base Case: #%1").arg(m_differenceCase()->caseId()); + } + if (isTimeDiffResult()) + { + diffResult += QString("Base Time: #%1").arg(m_timeLapseBaseTimestep()); + } + return diffResult.join("\n"); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RimEclipseResultDefinition::diffResultUiShortNameHTML() const +{ + QStringList diffResult; + if (isTimeDiffResult() || isCaseDiffResult()) + { + diffResult += QString("Diff. Options:"); + } + if (isCaseDiffResult()) + { + diffResult += QString("Base Case: #%1").arg(m_differenceCase()->caseId()); + } + if (isTimeDiffResult()) + { + diffResult += QString("Base Time: #%1").arg(m_timeLapseBaseTimestep()); + } + return diffResult.join("
"); +} + +//-------------------------------------------------------------------------------------------------- +/// //-------------------------------------------------------------------------------------------------- void RimEclipseResultDefinition::loadResult() { + ensureProcessingOfObsoleteFields(); + if (isFlowDiagOrInjectionFlooding()) return; // Will load automatically on access + if (m_eclipseCase) + { + if (!m_eclipseCase->ensureReservoirCaseIsOpen()) + { + RiaLogging::error("Could not open the Eclipse Grid file: " + m_eclipseCase->gridFileName()); + return; + } + } + + if (m_differenceCase) + { + if (!m_differenceCase->ensureReservoirCaseIsOpen()) + { + RiaLogging::error("Could not open the Eclipse Grid file: " + m_eclipseCase->gridFileName()); + return; + } + } + RigCaseCellResultsData* gridCellResults = this->currentGridCellResults(); if (gridCellResults) { - gridCellResults->findOrLoadScalarResult(m_resultType(), m_resultVariable); - } + if (isTimeDiffResult() || isCaseDiffResult()) + { + gridCellResults->createResultEntry(this->eclipseResultAddress(), false); + } + gridCellResults->ensureKnownResultLoaded(this->eclipseResultAddress()); + } } //-------------------------------------------------------------------------------------------------- -/// Returns whether the result requested by the definition is a single frame result +/// Returns whether the result requested by the definition is a single frame result /// The result needs to be loaded before asking //-------------------------------------------------------------------------------------------------- bool RimEclipseResultDefinition::hasStaticResult() const { if (isFlowDiagOrInjectionFlooding()) return false; - const RigCaseCellResultsData* gridCellResults = this->currentGridCellResults(); - size_t gridScalarResultIndex = this->scalarResultIndex(); + const RigCaseCellResultsData* gridCellResults = this->currentGridCellResults(); + RigEclipseResultAddress gridScalarResultIndex = this->eclipseResultAddress(); - if (hasResult() && gridCellResults->timeStepCount(gridScalarResultIndex) == 1 ) + if (hasResult() && gridCellResults->timeStepCount(gridScalarResultIndex) == 1) { return true; } @@ -807,18 +1028,18 @@ bool RimEclipseResultDefinition::hasResult() const { if (m_flowSolution() && !m_resultVariable().isEmpty()) return true; } - else if (this->currentGridCellResults() ) + else if (this->currentGridCellResults()) { const RigCaseCellResultsData* gridCellResults = this->currentGridCellResults(); - size_t gridScalarResultIndex = gridCellResults->findScalarResultIndex(m_resultType(), m_resultVariable()); - return gridScalarResultIndex != cvf::UNDEFINED_SIZE_T; + + return gridCellResults->hasResultEntry(this->eclipseResultAddress()); } return false; } //-------------------------------------------------------------------------------------------------- -/// Returns whether the result requested by the definition is a multi frame result +/// Returns whether the result requested by the definition is a multi frame result /// The result needs to be loaded before asking //-------------------------------------------------------------------------------------------------- bool RimEclipseResultDefinition::hasDynamicResult() const @@ -844,9 +1065,9 @@ bool RimEclipseResultDefinition::hasDynamicResult() const if (this->currentGridCellResults()) { - const RigCaseCellResultsData* gridCellResults = this->currentGridCellResults(); - size_t gridScalarResultIndex = this->scalarResultIndex(); - if (gridCellResults->timeStepCount(gridScalarResultIndex) > 1 ) + const RigCaseCellResultsData* gridCellResults = this->currentGridCellResults(); + RigEclipseResultAddress gridScalarResultIndex = this->eclipseResultAddress(); + if (gridCellResults->timeStepCount(gridScalarResultIndex) > 1) { return true; } @@ -856,9 +1077,8 @@ bool RimEclipseResultDefinition::hasDynamicResult() const return false; } - //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RimEclipseResultDefinition::initAfterRead() { @@ -867,45 +1087,45 @@ void RimEclipseResultDefinition::initAfterRead() assignFlowSolutionFromCase(); } - m_porosityModelUiField = m_porosityModel; - m_resultTypeUiField = m_resultType; + m_porosityModelUiField = m_porosityModel; + m_resultTypeUiField = m_resultType; m_resultVariableUiField = m_resultVariable; - m_flowSolutionUiField = m_flowSolution(); + m_flowSolutionUiField = m_flowSolution(); m_selectedInjectorTracersUiField = m_selectedInjectorTracers; this->updateUiIconFromToggleField(); } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RimEclipseResultDefinition::setResultType(RiaDefines::ResultCatType val) { - m_resultType = val; + m_resultType = val; m_resultTypeUiField = val; } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RimEclipseResultDefinition::setPorosityModel(RiaDefines::PorosityModelType val) { - m_porosityModel = val; + m_porosityModel = val; m_porosityModelUiField = val; } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RimEclipseResultDefinition::setResultVariable(const QString& val) { - m_resultVariable = val; + m_resultVariable = val; m_resultVariableUiField = val; } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- RimFlowDiagSolution* RimEclipseResultDefinition::flowDiagSolution() { @@ -913,11 +1133,11 @@ RimFlowDiagSolution* RimEclipseResultDefinition::flowDiagSolution() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RimEclipseResultDefinition::setFlowSolution(RimFlowDiagSolution* flowSol) { - this->m_flowSolution = flowSol; + this->m_flowSolution = flowSol; this->m_flowSolutionUiField = flowSol; } @@ -957,11 +1177,11 @@ void RimEclipseResultDefinition::setSelectedTracers(const std::vector& } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RimEclipseResultDefinition::setSelectedInjectorTracers(const std::vector& selectedTracers) { - this->m_selectedInjectorTracers = selectedTracers; + this->m_selectedInjectorTracers = selectedTracers; this->m_selectedInjectorTracersUiField = selectedTracers; } @@ -970,41 +1190,49 @@ void RimEclipseResultDefinition::setSelectedInjectorTracers(const std::vector& selectedTracers) { - this->m_selectedProducerTracers = selectedTracers; + this->m_selectedProducerTracers = selectedTracers; this->m_selectedProducerTracersUiField = selectedTracers; } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RimEclipseResultDefinition::setSelectedSouringTracers(const std::vector& selectedTracers) { - this->m_selectedSouringTracers = selectedTracers; + this->m_selectedSouringTracers = selectedTracers; this->m_selectedSouringTracersUiField = selectedTracers; } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RimEclipseResultDefinition::updateUiFieldsFromActiveResult() { - m_resultTypeUiField = m_resultType; + m_resultTypeUiField = m_resultType; m_resultVariableUiField = resultVariable(); } //-------------------------------------------------------------------------------------------------- -/// +/// +//-------------------------------------------------------------------------------------------------- +void RimEclipseResultDefinition::setDiffResultOptionsEnabled(bool enabled) +{ + m_diffResultOptionsEnabled = true; +} + +//-------------------------------------------------------------------------------------------------- +/// //-------------------------------------------------------------------------------------------------- bool RimEclipseResultDefinition::isTernarySaturationSelected() const { - bool isTernary = (m_resultType() == RiaDefines::DYNAMIC_NATIVE) && - (m_resultVariable().compare(RiaDefines::ternarySaturationResultName(), Qt::CaseInsensitive) == 0); + bool isTernary = (m_resultType() == RiaDefines::DYNAMIC_NATIVE) && + (m_resultVariable().compare(RiaDefines::ternarySaturationResultName(), Qt::CaseInsensitive) == 0); return isTernary; } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- bool RimEclipseResultDefinition::isCompletionTypeSelected() const { @@ -1012,28 +1240,27 @@ bool RimEclipseResultDefinition::isCompletionTypeSelected() const } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- bool RimEclipseResultDefinition::hasCategoryResult() const { - if (this->m_resultType() == RiaDefines::FORMATION_NAMES - && m_eclipseCase - && m_eclipseCase->eclipseCaseData() - && m_eclipseCase->eclipseCaseData()->activeFormationNames() ) return true; + if (this->m_resultType() == RiaDefines::FORMATION_NAMES && m_eclipseCase && m_eclipseCase->eclipseCaseData() && + m_eclipseCase->eclipseCaseData()->activeFormationNames()) + return true; - if (this->m_resultType() == RiaDefines::DYNAMIC_NATIVE - && this->resultVariable() == RiaDefines::completionTypeResultName()) return true; + if (this->m_resultType() == RiaDefines::DYNAMIC_NATIVE && this->resultVariable() == RiaDefines::completionTypeResultName()) + return true; - if (this->m_resultType() == RiaDefines::FLOW_DIAGNOSTICS - && m_resultVariable() == RIG_FLD_MAX_FRACTION_TRACER_RESNAME) return true; + if (this->m_resultType() == RiaDefines::FLOW_DIAGNOSTICS && m_resultVariable() == RIG_FLD_MAX_FRACTION_TRACER_RESNAME) + return true; if (!this->hasStaticResult()) return false; - return this->resultVariable().contains("NUM", Qt::CaseInsensitive); + return RiaDefines::isNativeCategoryResult(this->resultVariable()); } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- bool RimEclipseResultDefinition::isFlowDiagOrInjectionFlooding() const { @@ -1046,23 +1273,23 @@ bool RimEclipseResultDefinition::isFlowDiagOrInjectionFlooding() const } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RimEclipseResultDefinition::defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering) { uiOrdering.add(&m_resultTypeUiField); - if (hasDualPorFractureResult()) + if (hasDualPorFractureResult()) { uiOrdering.add(&m_porosityModelUiField); } - if ( m_resultTypeUiField() == RiaDefines::FLOW_DIAGNOSTICS ) - { + if (m_resultTypeUiField() == RiaDefines::FLOW_DIAGNOSTICS) + { uiOrdering.add(&m_flowSolutionUiField); uiOrdering.add(&m_flowTracerSelectionMode); - + if (m_flowTracerSelectionMode == FLOW_TR_BY_SELECTION) { caf::PdmUiGroup* selectionGroup = uiOrdering.addNewGroup("Tracer Selection"); @@ -1079,7 +1306,7 @@ void RimEclipseResultDefinition::defineUiOrdering(QString uiConfigName, caf::Pdm uiOrdering.add(&m_phaseSelection); - if ( m_flowSolution() == nullptr ) + if (m_flowSolution() == nullptr) { assignFlowSolutionFromCase(); } @@ -1099,13 +1326,34 @@ void RimEclipseResultDefinition::defineUiOrdering(QString uiConfigName, caf::Pdm uiOrdering.add(&m_resultVariableUiField); } + if (isCaseDiffResultAvailable() || isTimeDiffResultAvailable()) + { + caf::PdmUiGroup* differenceGroup = uiOrdering.addNewGroup("Difference Options"); + differenceGroup->setUiReadOnly(!(isTimeDiffResultAvailable() || isCaseDiffResultAvailable())); + + m_differenceCase.uiCapability()->setUiReadOnly(!isCaseDiffResultAvailable()); + m_timeLapseBaseTimestep.uiCapability()->setUiReadOnly(!isTimeDiffResultAvailable()); + + if (isCaseDiffResultAvailable()) differenceGroup->add(&m_differenceCase); + if (isTimeDiffResultAvailable()) differenceGroup->add(&m_timeLapseBaseTimestep); + + QString resultPropertyLabel = "Result Property"; + if (isTimeDiffResult() || isCaseDiffResult()) + { + resultPropertyLabel += QString("\n%1").arg(diffResultUiShortName()); + } + m_resultVariableUiField.uiCapability()->setUiName(resultPropertyLabel); + } + uiOrdering.skipRemainingFields(true); } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- -void RimEclipseResultDefinition::defineEditorAttribute(const caf::PdmFieldHandle* field, QString uiConfigName, caf::PdmUiEditorAttribute* attribute) +void RimEclipseResultDefinition::defineEditorAttribute(const caf::PdmFieldHandle* field, + QString uiConfigName, + caf::PdmUiEditorAttribute* attribute) { if (m_resultTypeUiField() == RiaDefines::FLOW_DIAGNOSTICS) { @@ -1117,8 +1365,7 @@ void RimEclipseResultDefinition::defineEditorAttribute(const caf::PdmFieldHandle listEditAttr->m_heightHint = 50; } } - else if (field == &m_syncInjectorToProducerSelection || - field == &m_syncProducerToInjectorSelection) + else if (field == &m_syncInjectorToProducerSelection || field == &m_syncProducerToInjectorSelection) { caf::PdmUiToolButtonEditorAttribute* toolButtonAttr = dynamic_cast(attribute); if (toolButtonAttr) @@ -1127,6 +1374,14 @@ void RimEclipseResultDefinition::defineEditorAttribute(const caf::PdmFieldHandle } } } + if (field == &m_resultVariableUiField) + { + caf::PdmUiListEditorAttribute* listEditAttr = dynamic_cast(attribute); + if (listEditAttr) + { + listEditAttr->m_allowHorizontalScrollBar = false; + } + } } //-------------------------------------------------------------------------------------------------- @@ -1134,36 +1389,7 @@ void RimEclipseResultDefinition::defineEditorAttribute(const caf::PdmFieldHandle //-------------------------------------------------------------------------------------------------- void RimEclipseResultDefinition::onEditorWidgetsCreated() { - if (m_flowSolution() && !m_selectedTracers_OBSOLETE().empty()) - { - std::vector selectedTracers; - selectedTracers.swap(m_selectedTracers_OBSOLETE.v()); - - std::set allInjectorTracers = setOfTracersOfType(true); - std::set allProducerTracers = setOfTracersOfType(false); - - std::vector selectedInjectorTracers; - std::vector selectedProducerTracers; - for (const QString& tracerName : selectedTracers) - { - if (allInjectorTracers.count(tracerName)) - { - selectedInjectorTracers.push_back(tracerName); - } - if (allProducerTracers.count(tracerName)) - { - selectedProducerTracers.push_back(tracerName); - } - } - if (!selectedInjectorTracers.empty()) - { - setSelectedInjectorTracers(selectedInjectorTracers); - } - if (!selectedProducerTracers.empty()) - { - setSelectedProducerTracers(selectedProducerTracers); - } - } + ensureProcessingOfObsoleteFields(); } //-------------------------------------------------------------------------------------------------- @@ -1186,7 +1412,7 @@ bool RimEclipseResultDefinition::TracerComp::operator()(const QString& lhs, cons } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RimEclipseResultDefinition::assignFlowSolutionFromCase() { @@ -1202,12 +1428,11 @@ void RimEclipseResultDefinition::assignFlowSolutionFromCase() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- bool RimEclipseResultDefinition::hasDualPorFractureResult() { - if (m_eclipseCase - && m_eclipseCase->eclipseCaseData()) + if (m_eclipseCase && m_eclipseCase->eclipseCaseData()) { return m_eclipseCase->eclipseCaseData()->hasFractureResults(); } @@ -1234,7 +1459,7 @@ QString RimEclipseResultDefinition::flowDiagResUiText(bool shortLabel, int maxTr if (!tracersString.isEmpty()) { - const QString postfix = "..."; + const QString postfix = "..."; if (tracersString.size() > maxTracerStringLength + postfix.size()) { @@ -1247,23 +1472,30 @@ QString RimEclipseResultDefinition::flowDiagResUiText(bool shortLabel, int maxTr } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- -QList RimEclipseResultDefinition::calcOptionsForVariableUiFieldStandard() +QList + RimEclipseResultDefinition::calcOptionsForVariableUiFieldStandard(RiaDefines::ResultCatType resultCatType, + const RigCaseCellResultsData* results, + bool showDerivedResultsFirst, + bool addPerCellFaceOptionItems, + bool ternaryEnabled) { - CVF_ASSERT(m_resultTypeUiField() != RiaDefines::FLOW_DIAGNOSTICS && m_resultTypeUiField() != RiaDefines::INJECTION_FLOODING); + CVF_ASSERT(resultCatType != RiaDefines::FLOW_DIAGNOSTICS && resultCatType != RiaDefines::INJECTION_FLOODING); - if (this->currentGridCellResults()) + if (results) { QList optionList; QStringList cellCenterResultNames; QStringList cellFaceResultNames; - RigCaseCellResultsData* results = this->currentGridCellResults(); - foreach(QString s, getResultNamesForCurrentUiResultType()) + for (const QString& s : getResultNamesForResultType(resultCatType, results)) { - if (s == RiaDefines::completionTypeResultName() && results->timeStepDates().empty()) continue; + if (s == RiaDefines::completionTypeResultName()) + { + if (results->timeStepDates().empty()) continue; + } if (RiaDefines::isPerCellFaceResult(s)) { @@ -1279,68 +1511,59 @@ QList RimEclipseResultDefinition::calcOptionsForVariable cellFaceResultNames.sort(); // Cell Center result names - foreach(QString s, cellCenterResultNames) + for (const QString& s : cellCenterResultNames) { optionList.push_back(caf::PdmOptionItemInfo(s, s)); } // Ternary Result - bool hasAtLeastOneTernaryComponent = false; - if (cellCenterResultNames.contains("SOIL")) hasAtLeastOneTernaryComponent = true; - else if (cellCenterResultNames.contains("SGAS")) hasAtLeastOneTernaryComponent = true; - else if (cellCenterResultNames.contains("SWAT")) hasAtLeastOneTernaryComponent = true; - - if (m_resultTypeUiField == RiaDefines::DYNAMIC_NATIVE && hasAtLeastOneTernaryComponent) - { - optionList.push_front(caf::PdmOptionItemInfo(RiaDefines::ternarySaturationResultName(), RiaDefines::ternarySaturationResultName())); - } - - // Cell Face result names - bool showDerivedResultsFirstInList = false; - { - RimEclipseFaultColors* rimEclipseFaultColors = nullptr; - this->firstAncestorOrThisOfType(rimEclipseFaultColors); - - if ( rimEclipseFaultColors ) showDerivedResultsFirstInList = true; - } - - foreach(QString s, cellFaceResultNames) + if (ternaryEnabled) { - if (showDerivedResultsFirstInList) - { - optionList.push_front(caf::PdmOptionItemInfo(s, s)); - } - else + bool hasAtLeastOneTernaryComponent = false; + if (cellCenterResultNames.contains("SOIL")) + hasAtLeastOneTernaryComponent = true; + else if (cellCenterResultNames.contains("SGAS")) + hasAtLeastOneTernaryComponent = true; + else if (cellCenterResultNames.contains("SWAT")) + hasAtLeastOneTernaryComponent = true; + + if (resultCatType == RiaDefines::DYNAMIC_NATIVE && hasAtLeastOneTernaryComponent) { - optionList.push_back(caf::PdmOptionItemInfo(s, s)); + optionList.push_front( + caf::PdmOptionItemInfo(RiaDefines::ternarySaturationResultName(), RiaDefines::ternarySaturationResultName())); } } - - optionList.push_front(caf::PdmOptionItemInfo(RiaDefines::undefinedResultName(), RiaDefines::undefinedResultName())); - - // Remove Per Cell Face options + if (addPerCellFaceOptionItems) { - RimPlotCurve* curve = nullptr; - this->firstAncestorOrThisOfType(curve); - - RimEclipsePropertyFilter* propFilter = nullptr; - this->firstAncestorOrThisOfType(propFilter); - - RimCellEdgeColors* cellEdge = nullptr; - this->firstAncestorOrThisOfType(cellEdge); - - if ( propFilter || curve || cellEdge ) + for (const QString& s : cellFaceResultNames) { - removePerCellFaceOptionItems(optionList); + if (showDerivedResultsFirst) + { + optionList.push_front(caf::PdmOptionItemInfo(s, s)); + } + else + { + optionList.push_back(caf::PdmOptionItemInfo(s, s)); + } } } + optionList.push_front(caf::PdmOptionItemInfo(RiaDefines::undefinedResultName(), RiaDefines::undefinedResultName())); + return optionList; } return QList(); } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimEclipseResultDefinition::setTernaryEnabled(bool enabled) +{ + m_ternaryEnabled = enabled; +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -1355,7 +1578,7 @@ QList RimEclipseResultDefinition::calcOptionsForSelected for (const QString& tracerName : sortedTracers) { - QString postfix; + QString postfix; RimFlowDiagSolution::TracerStatusType status = flowSol->tracerStatusOverall(tracerName); if (status == RimFlowDiagSolution::VARYING) { @@ -1377,32 +1600,36 @@ QList RimEclipseResultDefinition::calcOptionsForSelected QString RimEclipseResultDefinition::timeOfFlightString(bool shorter) const { QString tofString; - bool multipleSelected = false; + bool multipleSelected = false; if (injectorSelectionState() != NONE_SELECTED && producerSelectionState() != NONE_SELECTED) { - tofString = shorter ? "Res.Time" : "Residence Time"; + tofString = shorter ? "Res.Time" : "Residence Time"; multipleSelected = true; } else if (injectorSelectionState() != NONE_SELECTED) { - tofString = shorter ? "Fwd.TOF" : "Forward Time Of Flight"; + tofString = shorter ? "Fwd.TOF" : "Forward Time of Flight"; } else if (producerSelectionState() != NONE_SELECTED) { - tofString = shorter ? "Rev.TOF" : "Reverse Time Of Flight"; + tofString = shorter ? "Rev.TOF" : "Reverse Time of Flight"; } else { - tofString = shorter ? "TOF" : "Time Of Flight"; + tofString = shorter ? "TOF" : "Time of Flight"; } - multipleSelected = multipleSelected || - injectorSelectionState() >= MULTIPLE_SELECTED || producerSelectionState() >= MULTIPLE_SELECTED; + multipleSelected = + multipleSelected || injectorSelectionState() >= MULTIPLE_SELECTED || producerSelectionState() >= MULTIPLE_SELECTED; if (multipleSelected && !shorter) { tofString += " (Average)"; } + + tofString += " [days]"; + // Conversion from seconds in flow module to days is done in RigFlowDiagTimeStepResult::setTracerTOF() + return tofString; } @@ -1415,14 +1642,12 @@ QString RimEclipseResultDefinition::maxFractionTracerString(bool shorter) const if (injectorSelectionState() >= ONE_SELECTED && producerSelectionState() == NONE_SELECTED) { mfString = shorter ? "FloodReg" : "Flooding Region"; - if (injectorSelectionState() >= MULTIPLE_SELECTED) - mfString += "s"; + if (injectorSelectionState() >= MULTIPLE_SELECTED) mfString += "s"; } else if (injectorSelectionState() == NONE_SELECTED && producerSelectionState() >= ONE_SELECTED) { mfString = shorter ? "DrainReg" : "Drainage Region"; - if (producerSelectionState() >= MULTIPLE_SELECTED) - mfString += "s"; + if (producerSelectionState() >= MULTIPLE_SELECTED) mfString += "s"; } else { @@ -1443,7 +1668,7 @@ QString RimEclipseResultDefinition::selectedTracersString() const if (injectorState == ALL_SELECTED && producerState == ALL_SELECTED) { - fullTracersList += caf::AppEnum::uiText(FLOW_TR_INJ_AND_PROD); + fullTracersList += caf::AppEnum::uiText(FLOW_TR_INJ_AND_PROD); } else { @@ -1493,17 +1718,16 @@ QString RimEclipseResultDefinition::selectedTracersString() const } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- -QStringList RimEclipseResultDefinition::getResultNamesForCurrentUiResultType() +QStringList RimEclipseResultDefinition::getResultNamesForResultType(RiaDefines::ResultCatType resultCatType, + const RigCaseCellResultsData* results) { - if (m_resultTypeUiField() != RiaDefines::FLOW_DIAGNOSTICS) + if (resultCatType != RiaDefines::FLOW_DIAGNOSTICS) { - RigCaseCellResultsData* cellResultsStorage = currentGridCellResults(); + if (!results) return QStringList(); - if (!cellResultsStorage) return QStringList(); - - return cellResultsStorage->resultNames(m_resultTypeUiField()); + return results->resultNames(resultCatType); } else { @@ -1517,32 +1741,7 @@ QStringList RimEclipseResultDefinition::getResultNamesForCurrentUiResultType() } //-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RimEclipseResultDefinition::removePerCellFaceOptionItems(QList& optionItems) -{ - std::vector indicesToRemove; - for (int i = 0; i < optionItems.size(); i++) - { - QString text = optionItems[i].optionUiText(); - - if (RiaDefines::isPerCellFaceResult(text)) - { - indicesToRemove.push_back(i); - } - } - - std::sort(indicesToRemove.begin(), indicesToRemove.end()); - - std::vector::reverse_iterator rit; - for (rit = indicesToRemove.rbegin(); rit != indicesToRemove.rend(); ++rit) - { - optionItems.takeAt(*rit); - } -} - -//-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- std::vector RimEclipseResultDefinition::allTracerNames() const { @@ -1551,7 +1750,7 @@ std::vector RimEclipseResultDefinition::allTracerNames() const RimFlowDiagSolution* flowSol = m_flowSolutionUiField(); if (flowSol) { - tracerNames = flowSol->tracerNames(); + tracerNames = flowSol->tracerNames(); } return tracerNames; @@ -1576,7 +1775,7 @@ std::set RimEclipseResultDefini includeTracer |= !injector && status == RimFlowDiagSolution::PRODUCER; if (includeTracer) - { + { sortedTracers.insert(tracerName); } } @@ -1599,11 +1798,11 @@ RimEclipseResultDefinition::FlowTracerSelectionState RimEclipseResultDefinition: { return ALL_SELECTED; } - else if (m_selectedInjectorTracers().size() == (size_t) 1) + else if (m_selectedInjectorTracers().size() == (size_t)1) { return ONE_SELECTED; } - else if (m_selectedInjectorTracers().size() > (size_t) 1) + else if (m_selectedInjectorTracers().size() > (size_t)1) { return MULTIPLE_SELECTED; } @@ -1626,17 +1825,16 @@ RimEclipseResultDefinition::FlowTracerSelectionState RimEclipseResultDefinition: { return ALL_SELECTED; } - else if (m_selectedProducerTracers().size() == (size_t) 1) + else if (m_selectedProducerTracers().size() == (size_t)1) { return ONE_SELECTED; } - else if (m_selectedProducerTracers().size() > (size_t) 1) + else if (m_selectedProducerTracers().size() > (size_t)1) { return MULTIPLE_SELECTED; } } return NONE_SELECTED; - } //-------------------------------------------------------------------------------------------------- @@ -1659,7 +1857,7 @@ void RimEclipseResultDefinition::syncInjectorToProducerSelection() if (flowSol && m_flowTracerSelectionMode == FLOW_TR_BY_SELECTION) { std::set producers = setOfTracersOfType(false); - + std::set newProducerSelection; for (const QString& selectedInjector : m_selectedInjectorTracers()) { @@ -1680,7 +1878,7 @@ void RimEclipseResultDefinition::syncInjectorToProducerSelection() } std::vector newProducerVector(newProducerSelection.begin(), newProducerSelection.end()); setSelectedProducerTracers(newProducerVector); - } + } } //-------------------------------------------------------------------------------------------------- @@ -1726,3 +1924,119 @@ void RimEclipseResultDefinition::syncProducerToInjectorSelection() setSelectedInjectorTracers(newInjectorVector); } } + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RimEclipseResultDefinition::enableDiffResultOptions() const +{ + return m_diffResultOptionsEnabled; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RimEclipseResultDefinition::isTimeDiffResultAvailable() const +{ + return enableDiffResultOptions() && m_resultTypeUiField() == RiaDefines::DYNAMIC_NATIVE && !isTernarySaturationSelected(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RimEclipseResultDefinition::isTimeDiffResult() const +{ + return isTimeDiffResultAvailable() && m_timeLapseBaseTimestep() >= 0; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RimEclipseResultDefinition::isCaseDiffResultAvailable() const +{ + return enableDiffResultOptions() && !isTernarySaturationSelected() && + (m_resultTypeUiField() == RiaDefines::DYNAMIC_NATIVE || m_resultTypeUiField() == RiaDefines::STATIC_NATIVE || + m_resultTypeUiField() == RiaDefines::GENERATED); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RimEclipseResultDefinition::isCaseDiffResult() const +{ + return isCaseDiffResultAvailable() && m_differenceCase() != nullptr; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RimEclipseResultDefinition::showDerivedResultsFirstInVariableUiField() const +{ + // Cell Face result names + bool showDerivedResultsFirstInList = false; + RimEclipseFaultColors* rimEclipseFaultColors = nullptr; + this->firstAncestorOrThisOfType(rimEclipseFaultColors); + + if (rimEclipseFaultColors) showDerivedResultsFirstInList = true; + + return showDerivedResultsFirstInList; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RimEclipseResultDefinition::addPerCellFaceOptionsForVariableUiField() const +{ + RimPlotCurve* curve = nullptr; + this->firstAncestorOrThisOfType(curve); + + RimEclipsePropertyFilter* propFilter = nullptr; + this->firstAncestorOrThisOfType(propFilter); + + RimCellEdgeColors* cellEdge = nullptr; + this->firstAncestorOrThisOfType(cellEdge); + + if (propFilter || curve || cellEdge) + { + return false; + } + + return true; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimEclipseResultDefinition::ensureProcessingOfObsoleteFields() +{ + if (m_flowSolution() && !m_selectedTracers_OBSOLETE().empty()) + { + std::vector selectedTracers; + selectedTracers.swap(m_selectedTracers_OBSOLETE.v()); + + std::set allInjectorTracers = setOfTracersOfType(true); + std::set allProducerTracers = setOfTracersOfType(false); + + std::vector selectedInjectorTracers; + std::vector selectedProducerTracers; + for (const QString& tracerName : selectedTracers) + { + if (allInjectorTracers.count(tracerName)) + { + selectedInjectorTracers.push_back(tracerName); + } + if (allProducerTracers.count(tracerName)) + { + selectedProducerTracers.push_back(tracerName); + } + } + if (!selectedInjectorTracers.empty()) + { + setSelectedInjectorTracers(selectedInjectorTracers); + } + if (!selectedProducerTracers.empty()) + { + setSelectedProducerTracers(selectedProducerTracers); + } + } +} diff --git a/ApplicationCode/ProjectDataModel/RimEclipseResultDefinition.h b/ApplicationCode/ProjectDataModel/RimEclipseResultDefinition.h index b84c8c371d..c44f741fb2 100644 --- a/ApplicationCode/ProjectDataModel/RimEclipseResultDefinition.h +++ b/ApplicationCode/ProjectDataModel/RimEclipseResultDefinition.h @@ -35,6 +35,8 @@ #include +#include "RigCaseCellResultsData.h" + class RigCaseCellResultsData; class RimEclipseCase; class RimEclipseView; @@ -68,12 +70,13 @@ class RimEclipseResultDefinition : public caf::PdmObject }; public: - RimEclipseResultDefinition(); + RimEclipseResultDefinition(caf::PdmUiItemInfo::LabelPosType labelPosition = caf::PdmUiItemInfo::LEFT); ~RimEclipseResultDefinition() override; void simpleCopy(const RimEclipseResultDefinition* other); void setEclipseCase(RimEclipseCase* eclipseCase); + RimEclipseCase* eclipseCase(); RiaDefines::ResultCatType resultType() const { return m_resultType(); } void setResultType(RiaDefines::ResultCatType val); @@ -91,8 +94,13 @@ class RimEclipseResultDefinition : public caf::PdmObject QString resultVariableUiName() const; QString resultVariableUiShortName() const; + QString diffResultUiName() const; + QString diffResultUiShortName() const; + QString diffResultUiShortNameHTML() const; + void loadResult(); - size_t scalarResultIndex() const; + RigEclipseResultAddress eclipseResultAddress() const; + void setFromEclipseResultAddress(const RigEclipseResultAddress& resultAddress); bool hasStaticResult() const; bool hasDynamicResult() const; bool hasResult() const; @@ -114,6 +122,17 @@ class RimEclipseResultDefinition : public caf::PdmObject void updateUiFieldsFromActiveResult(); + void setDiffResultOptionsEnabled(bool enabled); + + bool hasDualPorFractureResult(); + + static QList calcOptionsForVariableUiFieldStandard(RiaDefines::ResultCatType resultCatType, + const RigCaseCellResultsData* results, + bool showDerivedResultsFirst = false, + bool addPerCellFaceOptionItems = false, + bool enableTernary = false); + + void setTernaryEnabled(bool enabled); protected: virtual void updateLegendCategorySettings() {}; @@ -129,6 +148,9 @@ class RimEclipseResultDefinition : public caf::PdmObject caf::PdmField< caf::AppEnum< RiaDefines::ResultCatType > > m_resultType; caf::PdmField< caf::AppEnum< RiaDefines::PorosityModelType > > m_porosityModel; caf::PdmField m_resultVariable; + caf::PdmField m_timeLapseBaseTimestep; + + caf::PdmPtrField m_differenceCase; caf::PdmPtrField m_flowSolution; caf::PdmField > m_selectedInjectorTracers; @@ -169,11 +191,8 @@ class RimEclipseResultDefinition : public caf::PdmObject private: void assignFlowSolutionFromCase(); - bool hasDualPorFractureResult(); - QString flowDiagResUiText(bool shortLabel, int maxTracerStringLength = std::numeric_limits::max()) const; - QList calcOptionsForVariableUiFieldStandard(); QList calcOptionsForSelectedTracerField(bool injector); QString timeOfFlightString(bool shorter) const; @@ -182,8 +201,7 @@ class RimEclipseResultDefinition : public caf::PdmObject QString selectedTracersString() const; void changedTracerSelectionField(bool injector); - QStringList getResultNamesForCurrentUiResultType(); - static void removePerCellFaceOptionItems(QList& optionItems); + static QStringList getResultNamesForResultType(RiaDefines::ResultCatType resultCatType, const RigCaseCellResultsData* results); std::vector allTracerNames() const; std::set setOfTracersOfType(bool injector) const; @@ -193,5 +211,22 @@ class RimEclipseResultDefinition : public caf::PdmObject void syncInjectorToProducerSelection(); void syncProducerToInjectorSelection(); + + bool enableDiffResultOptions() const; + bool isTimeDiffResultAvailable() const; + bool isTimeDiffResult() const; + bool isCaseDiffResultAvailable() const; + bool isCaseDiffResult() const; + + bool showDerivedResultsFirstInVariableUiField() const; + bool addPerCellFaceOptionsForVariableUiField() const; + + void ensureProcessingOfObsoleteFields(); + bool isTernaryEnabled() const; + +private: + bool m_diffResultOptionsEnabled; + caf::PdmUiItemInfo::LabelPosType m_labelPosition; + bool m_ternaryEnabled; }; diff --git a/ApplicationCode/ProjectDataModel/RimEclipseStatisticsCase.cpp b/ApplicationCode/ProjectDataModel/RimEclipseStatisticsCase.cpp index 619c2cde4f..26d320dd5e 100644 --- a/ApplicationCode/ProjectDataModel/RimEclipseStatisticsCase.cpp +++ b/ApplicationCode/ProjectDataModel/RimEclipseStatisticsCase.cpp @@ -665,8 +665,8 @@ void RimEclipseStatisticsCase::updatePercentileUiVisibility() bool RimEclipseStatisticsCase::hasComputedStatistics() const { if ( eclipseCaseData() - && ( eclipseCaseData()->results(RiaDefines::MATRIX_MODEL)->resultCount() - || eclipseCaseData()->results(RiaDefines::FRACTURE_MODEL)->resultCount())) + && ( eclipseCaseData()->results(RiaDefines::MATRIX_MODEL)->existingResults().size() + || eclipseCaseData()->results(RiaDefines::FRACTURE_MODEL)->existingResults().size())) { return true; } diff --git a/ApplicationCode/ProjectDataModel/RimEclipseStatisticsCaseEvaluator.cpp b/ApplicationCode/ProjectDataModel/RimEclipseStatisticsCaseEvaluator.cpp index 434fc62491..57e5caeaa1 100644 --- a/ApplicationCode/ProjectDataModel/RimEclipseStatisticsCaseEvaluator.cpp +++ b/ApplicationCode/ProjectDataModel/RimEclipseStatisticsCaseEvaluator.cpp @@ -39,18 +39,22 @@ //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RimEclipseStatisticsCaseEvaluator::addNamedResult(RigCaseCellResultsData* destinationCellResults, RiaDefines::ResultCatType resultType, const QString& resultName, size_t activeUnionCellCount) +void RimEclipseStatisticsCaseEvaluator::addNamedResult(RigCaseCellResultsData* destinationCellResults, + RiaDefines::ResultCatType resultType, + const QString& resultName, + size_t activeUnionCellCount) { // Use time step dates from first result in first source case CVF_ASSERT(m_sourceCases.size() > 0); - std::vector sourceTimeStepInfos = m_sourceCases[0]->results(RiaDefines::MATRIX_MODEL)->timeStepInfos(0); + std::vector resAddresses = m_sourceCases[0]->results(RiaDefines::MATRIX_MODEL)->existingResults(); + std::vector sourceTimeStepInfos = m_sourceCases[0]->results(RiaDefines::MATRIX_MODEL)->timeStepInfos(resAddresses[0]); - size_t destinationScalarResultIndex = destinationCellResults->findOrCreateScalarResultIndex(resultType, resultName, true); - CVF_ASSERT(destinationScalarResultIndex != cvf::UNDEFINED_SIZE_T); + RigEclipseResultAddress resAddr(resultType, resultName); + destinationCellResults->createResultEntry(resAddr, true); - destinationCellResults->setTimeStepInfos(destinationScalarResultIndex, sourceTimeStepInfos); - std::vector< std::vector >& dataValues = destinationCellResults->cellScalarResults(destinationScalarResultIndex); + destinationCellResults->setTimeStepInfos(resAddr, sourceTimeStepInfos); + std::vector< std::vector >& dataValues = destinationCellResults->modifiableCellScalarResultTimesteps(resAddr); dataValues.resize(sourceTimeStepInfos.size()); @@ -141,8 +145,6 @@ void RimEclipseStatisticsCaseEvaluator::evaluateForResults(const QList& if (activeCellCount == 0) continue; - RigCaseCellResultsData* destCellResultsData = m_destinationCase->results(poroModel); - size_t dataAccessTimeStepIndex = timeStepIdx; // Always evaluate statistics once, and always use time step index zero @@ -161,9 +163,14 @@ void RimEclipseStatisticsCaseEvaluator::evaluateForResults(const QList& RimEclipseCase* sourceCase = m_sourceCases.at(caseIdx); // Trigger loading of dataset - sourceCase->results(poroModel)->findOrLoadScalarResultForTimeStep(resultType, resultName, dataAccessTimeStepIndex); - - cvf::ref resultAccessor = RigResultAccessorFactory::createFromNameAndType(sourceCase->eclipseCaseData(), gridIdx, poroModel, dataAccessTimeStepIndex, resultName, resultType); + sourceCase->results(poroModel)->ensureKnownResultLoadedForTimeStep(RigEclipseResultAddress(resultType, resultName), + dataAccessTimeStepIndex); + + cvf::ref resultAccessor = RigResultAccessorFactory::createFromResultAddress(sourceCase->eclipseCaseData(), + gridIdx, + poroModel, + dataAccessTimeStepIndex, + RigEclipseResultAddress( resultType, resultName)); if (resultAccessor.notNull()) { sourceDataAccessList.push_back(resultAccessor.p()); @@ -188,9 +195,11 @@ void RimEclipseStatisticsCaseEvaluator::evaluateForResults(const QList& for (size_t stIdx = 0; stIdx < statisticalResultNames.size(); ++stIdx) { - size_t scalarResultIndex = destCellResultsData->findScalarResultIndex(resultType, statisticalResultNames[stIdx]); - - cvf::ref resultModifier = RigResultModifierFactory::createResultModifier(m_destinationCase, grid->gridIndex(), poroModel, dataAccessTimeStepIndex, scalarResultIndex); + cvf::ref resultModifier = RigResultModifierFactory::createResultModifier(m_destinationCase, + grid->gridIndex(), + poroModel, + dataAccessTimeStepIndex, + RigEclipseResultAddress(resultType, statisticalResultNames[stIdx])); destinationDataAccessList.push_back(resultModifier.p()); } diff --git a/ApplicationCode/ProjectDataModel/RimEclipseStatisticsCaseEvaluator.h b/ApplicationCode/ProjectDataModel/RimEclipseStatisticsCaseEvaluator.h index 5241c33898..8e3c117df1 100644 --- a/ApplicationCode/ProjectDataModel/RimEclipseStatisticsCaseEvaluator.h +++ b/ApplicationCode/ProjectDataModel/RimEclipseStatisticsCaseEvaluator.h @@ -24,7 +24,7 @@ #include "RimEclipseStatisticsCase.h" #include -#include +#include class RimEclipseCase; diff --git a/ApplicationCode/ProjectDataModel/RimEclipseView.cpp b/ApplicationCode/ProjectDataModel/RimEclipseView.cpp index abaec62c4f..f595da6449 100644 --- a/ApplicationCode/ProjectDataModel/RimEclipseView.cpp +++ b/ApplicationCode/ProjectDataModel/RimEclipseView.cpp @@ -3,17 +3,17 @@ // Copyright (C) 2011- Statoil ASA // Copyright (C) 2013- Ceetron Solutions AS // Copyright (C) 2011-2012 Ceetron AS -// +// // ResInsight 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 3 of the License, or // (at your option) any later version. -// +// // ResInsight 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 at +// +// See the GNU General Public License at // for more details. // ///////////////////////////////////////////////////////////////////////////////// @@ -25,6 +25,8 @@ #include "RiaFieldHandleTools.h" #include "RiaPreferences.h" +#include "HoloLensCommands/RicExportToSharingServerScheduler.h" + #include "RigActiveCellInfo.h" #include "RigCaseCellResultsData.h" #include "RigEclipseCaseData.h" @@ -38,6 +40,8 @@ #include "Rim2dIntersectionView.h" #include "Rim3dOverlayInfoConfig.h" +#include "RimAnnotationCollection.h" +#include "RimAnnotationInViewCollection.h" #include "RimCellEdgeColors.h" #include "RimCellRangeFilterCollection.h" #include "RimEclipseCase.h" @@ -49,82 +53,81 @@ #include "RimFaultInViewCollection.h" #include "RimFlowCharacteristicsPlot.h" #include "RimFlowDiagSolution.h" +#include "RimFracture.h" +#include "RimFractureTemplateCollection.h" #include "RimGridCollection.h" +#include "RimGridCrossPlotDataSet.h" #include "RimIntersection.h" #include "RimIntersectionCollection.h" #include "RimOilField.h" #include "RimProject.h" #include "RimRegularLegendConfig.h" #include "RimReservoirCellResultsStorage.h" +#include "RimSimWellFracture.h" #include "RimSimWellInView.h" #include "RimSimWellInViewCollection.h" #include "RimStimPlanColors.h" #include "RimTernaryLegendConfig.h" #include "RimViewController.h" #include "RimViewLinker.h" +#include "RimViewNameConfig.h" #include "RimVirtualPerforationResults.h" #include "RimWellPathCollection.h" +#include "Riu3dSelectionManager.h" #include "RiuMainWindow.h" -#include "RiuSelectionManager.h" #include "RiuViewer.h" #include "RivReservoirSimWellsPartMgr.h" #include "RivReservoirViewPartMgr.h" #include "RivSingleCellPartGenerator.h" #include "RivTernarySaturationOverlayItem.h" -#include "RivWellPathsPartMgr.h" - -#include "RimFracture.h" -#include "RimFractureTemplateCollection.h" -#include "RimSimWellFracture.h" #include "RivWellFracturePartMgr.h" - +#include "RivWellPathsPartMgr.h" #include "cafCadNavigation.h" #include "cafCeetronPlusNavigation.h" #include "cafDisplayCoordTransform.h" #include "cafFrameAnimationControl.h" -#include "cafPdmUiTreeOrdering.h" #include "cafOverlayScalarMapperLegend.h" +#include "cafPdmUiTreeOrdering.h" #include "cvfDrawable.h" #include "cvfModelBasicList.h" #include "cvfPart.h" #include "cvfScene.h" -#include "cvfViewport.h" +#include "cvfViewport.h" #include "cvfqtUtils.h" #include -#include - - +#include CAF_PDM_SOURCE_INIT(RimEclipseView, "ReservoirView"); //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- RimEclipseView::RimEclipseView() { - RiaApplication* app = RiaApplication::instance(); + RiaApplication* app = RiaApplication::instance(); RiaPreferences* preferences = app->preferences(); CVF_ASSERT(preferences); CAF_PDM_InitObject("Reservoir View", ":/3DView16x16.png", "", ""); - - CAF_PDM_InitFieldNoDefault(&m_cellResult, "GridCellResult", "Cell Result", ":/CellResult.png", "", ""); + + CAF_PDM_InitFieldNoDefault(&m_cellResult, "GridCellResult", "Cell Result", ":/CellResult.png", "", ""); m_cellResult = new RimEclipseCellColors(); m_cellResult.uiCapability()->setUiHidden(true); + m_cellResult->setDiffResultOptionsEnabled(true); - CAF_PDM_InitFieldNoDefault(&m_cellEdgeResult, "GridCellEdgeResult", "Cell Edge Result", ":/EdgeResult_1.png", "", ""); + CAF_PDM_InitFieldNoDefault(&m_cellEdgeResult, "GridCellEdgeResult", "Cell Edge Result", ":/EdgeResult_1.png", "", ""); m_cellEdgeResult = new RimCellEdgeColors(); m_cellEdgeResult.uiCapability()->setUiHidden(true); - CAF_PDM_InitFieldNoDefault(&m_faultResultSettings, "FaultResultSettings", "Separate Fault Result", "", "", ""); + CAF_PDM_InitFieldNoDefault(&m_faultResultSettings, "FaultResultSettings", "Separate Fault Result", "", "", ""); m_faultResultSettings = new RimEclipseFaultColors(); m_faultResultSettings.uiCapability()->setUiHidden(true); - + CAF_PDM_InitFieldNoDefault(&m_fractureColors, "StimPlanColors", "Fracture", "", "", ""); m_fractureColors = new RimStimPlanColors(); m_fractureColors.uiCapability()->setUiHidden(true); @@ -141,17 +144,21 @@ RimEclipseView::RimEclipseView() m_faultCollection = new RimFaultInViewCollection; m_faultCollection.uiCapability()->setUiHidden(true); + CAF_PDM_InitFieldNoDefault(&m_annotationCollection, "AnnotationCollection", "Annotations", "", "", ""); + m_annotationCollection = new RimAnnotationInViewCollection; + m_annotationCollection.uiCapability()->setUiHidden(true); + CAF_PDM_InitFieldNoDefault(&m_propertyFilterCollection, "PropertyFilters", "Property Filters", "", "", ""); m_propertyFilterCollection = new RimEclipsePropertyFilterCollection(); m_propertyFilterCollection.uiCapability()->setUiHidden(true); // Visualization fields - CAF_PDM_InitField(&m_showMainGrid_OBSOLETE, "ShowMainGrid", true, "Show Main Grid", "", "", ""); + CAF_PDM_InitField(&m_showMainGrid_OBSOLETE, "ShowMainGrid", true, "Show Main Grid", "", "", ""); RiaFieldhandleTools::disableWriteAndSetFieldHidden(&m_showMainGrid_OBSOLETE); - CAF_PDM_InitField(&m_showInactiveCells, "ShowInactiveCells", false, "Show Inactive Cells", "", "", ""); - CAF_PDM_InitField(&m_showInvalidCells, "ShowInvalidCells", false, "Show Invalid Cells", "", "", ""); - + CAF_PDM_InitField(&m_showInactiveCells, "ShowInactiveCells", false, "Show Inactive Cells", "", "", ""); + CAF_PDM_InitField(&m_showInvalidCells, "ShowInvalidCells", false, "Show Invalid Cells", "", "", ""); + this->cellResult()->setReservoirView(this); this->cellEdgeResult()->setReservoirView(this); @@ -160,12 +167,18 @@ RimEclipseView::RimEclipseView() this->faultResultSettings()->setReservoirView(this); m_reservoirGridPartManager = new RivReservoirViewPartMgr(this); - m_simWellsPartManager = new RivReservoirSimWellsPartMgr(this); - m_eclipseCase = nullptr; + m_simWellsPartManager = new RivReservoirSimWellsPartMgr(this); + m_eclipseCase = nullptr; + + nameConfig()->setCustomName("3D View"); + nameConfig()->hideCaseNameField(false); + nameConfig()->hideAggregationTypeField(true); + nameConfig()->hidePropertyField(false); + nameConfig()->hideSampleSpacingField(true); } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- RimEclipseView::~RimEclipseView() { @@ -176,15 +189,15 @@ RimEclipseView::~RimEclipseView() delete m_propertyFilterCollection; delete wellCollection(); delete faultCollection(); + delete annotationCollection(); m_reservoirGridPartManager->clearGeometryCache(); m_eclipseCase = nullptr; } - //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- RimEclipseCellColors* RimEclipseView::cellResult() const { @@ -192,7 +205,7 @@ RimEclipseCellColors* RimEclipseView::cellResult() const } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- RimCellEdgeColors* RimEclipseView::cellEdgeResult() const { @@ -200,7 +213,7 @@ RimCellEdgeColors* RimEclipseView::cellEdgeResult() const } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- RimEclipseFaultColors* RimEclipseView::faultResultSettings() const { @@ -208,7 +221,7 @@ RimEclipseFaultColors* RimEclipseView::faultResultSettings() const } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- RimStimPlanColors* RimEclipseView::fractureColors() const { @@ -216,7 +229,7 @@ RimStimPlanColors* RimEclipseView::fractureColors() const } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- RimSimWellInViewCollection* RimEclipseView::wellCollection() const { @@ -224,7 +237,7 @@ RimSimWellInViewCollection* RimEclipseView::wellCollection() const } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- RimFaultInViewCollection* RimEclipseView::faultCollection() const { @@ -232,7 +245,7 @@ RimFaultInViewCollection* RimEclipseView::faultCollection() const } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- RimVirtualPerforationResults* RimEclipseView::virtualPerforationResult() const { @@ -244,19 +257,19 @@ RimVirtualPerforationResults* RimEclipseView::virtualPerforationResult() const //-------------------------------------------------------------------------------------------------- void RimEclipseView::clampCurrentTimestep() { - if (this->currentGridCellResults()) + if (this->currentGridCellResults()) { if (m_currentTimeStep() >= static_cast(this->currentGridCellResults()->maxTimeStepCount())) { - m_currentTimeStep = static_cast(this->currentGridCellResults()->maxTimeStepCount()) -1; + m_currentTimeStep = static_cast(this->currentGridCellResults()->maxTimeStepCount()) - 1; } } - if (m_currentTimeStep < 0 ) m_currentTimeStep = 0; + if (m_currentTimeStep < 0) m_currentTimeStep = 0; } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RimEclipseView::setVisibleGridParts(const std::vector& cellSets) { @@ -264,18 +277,18 @@ void RimEclipseView::setVisibleGridParts(const std::vector& cell } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RimEclipseView::setVisibleGridPartsWatertight() { - for (RivCellSetEnum cellSetType : m_visibleGridParts) - { - m_reservoirGridPartManager->forceWatertightGeometryOnForType(cellSetType); - } + for (RivCellSetEnum cellSetType : m_visibleGridParts) + { + m_reservoirGridPartManager->forceWatertightGeometryOnForType(cellSetType); + } } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RimEclipseView::fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue) { @@ -291,7 +304,7 @@ void RimEclipseView::fieldChangedByUi(const caf::PdmFieldHandle* changedField, c else if (changedField == &m_showInactiveCells) { this->updateGridBoxData(); - + this->scheduleGeometryRegen(INACTIVE); this->scheduleGeometryRegen(RANGE_FILTERED_INACTIVE); @@ -309,16 +322,16 @@ void RimEclipseView::fieldChangedByUi(const caf::PdmFieldHandle* changedField, c this->scheduleGeometryRegen(PROPERTY_FILTERED); scheduleCreateDisplayModelAndRedraw(); - } + } } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RimEclipseView::updateScaleTransform() { cvf::Mat4d scale = cvf::Mat4d::IDENTITY; - scale(2, 2) = scaleZ(); + scale(2, 2) = scaleZ(); this->scaleTransform()->setLocalTransform(scale); m_simWellsPartManager->setScaleTransform(this->scaleTransform()); @@ -352,7 +365,7 @@ void RimEclipseView::createDisplayModel() // Find the number of time frames the animation needs to show the requested data. - if (isTimeStepDependentDataVisible()) + if (isTimeStepDependentDataVisible() && currentGridCellResults()->maxTimeStepCount() > 0) { CVF_ASSERT(currentGridCellResults()); @@ -361,25 +374,22 @@ void RimEclipseView::createDisplayModel() { timeStepIndices.push_back(i); } - } - else if (this->cellResult()->hasStaticResult() - || this->cellEdgeResult()->hasResult() - || this->eclipsePropertyFilterCollection()->hasActiveFilters()) + } + else if (this->cellResult()->hasStaticResult() || this->cellEdgeResult()->hasResult() || + this->eclipsePropertyFilterCollection()->hasActiveFilters()) { // The one and only result entry timeStepIndices.push_back(0); } - - cvf::Collection frameModels; - size_t timeIdx; + size_t timeIdx; for (timeIdx = 0; timeIdx < timeStepIndices.size(); timeIdx++) { frameModels.push_back(new cvf::ModelBasicList); } - // Remove all existing animation frames from the viewer. + // Remove all existing animation frames from the viewer. // The parts are still cached in the RivReservoir geometry and friends m_viewer->removeAllFrames(); @@ -389,15 +399,13 @@ void RimEclipseView::createDisplayModel() std::vector gridIndices = this->indicesToVisibleGrids(); /// - // Get or create the parts for "static" type geometry. The same geometry is used + // Get or create the parts for "static" type geometry. The same geometry is used // for the different frames. updateCurrentTimeStep updates the colors etc. - // For property filtered geometry : just set all the models as empty scenes + // For property filtered geometry : just set all the models as empty scenes // updateCurrentTimeStep requests the actual parts - - if (!this->eclipsePropertyFilterCollection()->hasActiveFilters() - || ( this->viewController() - && this->viewController()->isVisibleCellsOveridden()) ) + if (!this->eclipsePropertyFilterCollection()->hasActiveFilters() || + (this->viewController() && this->viewController()->isVisibleCellsOveridden())) { std::vector geometryTypesToAdd; @@ -441,7 +449,7 @@ void RimEclipseView::createDisplayModel() } } - // NOTE: This assignment must be done here, as m_visibleGridParts is used in code triggered by + // NOTE: This assignment must be done here, as m_visibleGridParts is used in code triggered by // m_reservoirGridPartManager->appendStaticGeometryPartsToModel() setVisibleGridParts(geometryTypesToAdd); @@ -450,20 +458,21 @@ void RimEclipseView::createDisplayModel() { for (size_t gtIdx = 0; gtIdx < geometryTypesToAdd.size(); ++gtIdx) { - if ( isGridVisualizationMode() ) + if (isGridVisualizationMode()) { - m_reservoirGridPartManager->appendStaticGeometryPartsToModel(frameModels[frameIdx].p(), geometryTypesToAdd[gtIdx], gridIndices); + m_reservoirGridPartManager->appendStaticGeometryPartsToModel( + frameModels[frameIdx].p(), geometryTypesToAdd[gtIdx], gridIndices); } else { - m_reservoirGridPartManager->ensureStaticGeometryPartsCreated( geometryTypesToAdd[gtIdx]); + m_reservoirGridPartManager->ensureStaticGeometryPartsCreated(geometryTypesToAdd[gtIdx]); } } } - // Set static colors + // Set static colors this->updateStaticCellColors(); } - else + else { std::vector empty; setVisibleGridParts(empty); @@ -471,20 +480,20 @@ void RimEclipseView::createDisplayModel() m_reservoirGridPartManager->clearWatertightGeometryFlags(); - if ( faultCollection()->showFaultCollection() - || !this->eclipsePropertyFilterCollection()->hasActiveFilters() ) + if (faultCollection()->showFaultCollection() || !this->eclipsePropertyFilterCollection()->hasActiveFilters()) { setVisibleGridPartsWatertight(); std::set faultGeometryTypesToAppend = allVisibleFaultGeometryTypes(); - RivCellSetEnum faultLabelType = m_reservoirGridPartManager->geometryTypeForFaultLabels(faultGeometryTypesToAppend, faultCollection()->isShowingFaultsAndFaultsOutsideFilters()); + RivCellSetEnum faultLabelType = m_reservoirGridPartManager->geometryTypeForFaultLabels( + faultGeometryTypesToAppend, faultCollection()->isShowingFaultsAndFaultsOutsideFilters()); for (size_t frameIdx = 0; frameIdx < frameModels.size(); ++frameIdx) { for (RivCellSetEnum geometryType : faultGeometryTypesToAppend) { if (geometryType == PROPERTY_FILTERED || geometryType == PROPERTY_FILTERED_WELL_CELLS) continue; - + m_reservoirGridPartManager->appendFaultsStaticGeometryPartsToModel(frameModels[frameIdx].p(), geometryType); } @@ -492,7 +501,6 @@ void RimEclipseView::createDisplayModel() } } - // Cross sections m_crossSectionVizModel->removeAllParts(); @@ -510,14 +518,14 @@ void RimEclipseView::createDisplayModel() addWellPathsToModel(m_wellPathPipeVizModel.p(), currentActiveCellInfo()->geometryBoundingBox()); - m_wellPathsPartManager->appendStaticFracturePartsToModel(m_wellPathPipeVizModel.p(), currentActiveCellInfo()->geometryBoundingBox()); + m_wellPathsPartManager->appendStaticFracturePartsToModel(m_wellPathPipeVizModel.p(), + currentActiveCellInfo()->geometryBoundingBox()); m_wellPathPipeVizModel->updateBoundingBoxesRecursive(); m_viewer->addStaticModelOnce(m_wellPathPipeVizModel.p()); // Create Scenes from the frameModels // Animation frames for results display, starts from frame 1 - size_t frameIndex; for (frameIndex = 0; frameIndex < frameModels.size(); frameIndex++) { @@ -545,19 +553,31 @@ void RimEclipseView::createDisplayModel() updateLegends(); } - std::vector objects; - this->objectsWithReferringPtrFieldsOfType(objects); - for (auto plot : objects) + std::vector characteristicsPlots; + this->objectsWithReferringPtrFieldsOfType(characteristicsPlots); + for (auto plot : characteristicsPlots) { if (plot != nullptr) { plot->viewGeometryUpdated(); } } + + std::vector curveSets; + this->objectsWithReferringPtrFieldsOfType(curveSets); + for (auto curveSet : curveSets) + { + if (curveSet != nullptr) + { + curveSet->cellFilterViewUpdated(); + } + } + + RicExportToSharingServerScheduler::instance()->scheduleUpdateSession(); } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RimEclipseView::updateCurrentTimeStep() { @@ -568,12 +588,14 @@ void RimEclipseView::updateCurrentTimeStep() updateVisibleGeometriesAndCellColors(); appendWellsAndFracturesToModel(); - + m_overlayInfoConfig()->update3DInfo(); // Invisible Wells are marked as read only when "show wells intersecting visible cells" is enabled // Visibility of wells differ betweeen time steps, so trigger a rebuild of tree state items wellCollection()->updateConnectedEditors(); + + RicExportToSharingServerScheduler::instance()->scheduleUpdateSession(); } //-------------------------------------------------------------------------------------------------- @@ -599,8 +621,10 @@ void RimEclipseView::updateVisibleGeometriesAndCellColors() if (isGridVisualizationMode()) { - m_reservoirGridPartManager->appendDynamicGeometryPartsToModel(frameParts.p(), PROPERTY_FILTERED, m_currentTimeStep, gridIndices); - m_reservoirGridPartManager->appendDynamicGeometryPartsToModel(frameParts.p(), PROPERTY_FILTERED_WELL_CELLS, m_currentTimeStep, gridIndices); + m_reservoirGridPartManager->appendDynamicGeometryPartsToModel( + frameParts.p(), PROPERTY_FILTERED, m_currentTimeStep, gridIndices); + m_reservoirGridPartManager->appendDynamicGeometryPartsToModel( + frameParts.p(), PROPERTY_FILTERED_WELL_CELLS, m_currentTimeStep, gridIndices); } else { @@ -616,7 +640,8 @@ void RimEclipseView::updateVisibleGeometriesAndCellColors() { if (geometryType == PROPERTY_FILTERED || geometryType == PROPERTY_FILTERED_WELL_CELLS) { - m_reservoirGridPartManager->appendFaultsDynamicGeometryPartsToModel(frameParts.p(), geometryType, m_currentTimeStep); + m_reservoirGridPartManager->appendFaultsDynamicGeometryPartsToModel( + frameParts.p(), geometryType, m_currentTimeStep); } else { @@ -624,10 +649,12 @@ void RimEclipseView::updateVisibleGeometriesAndCellColors() } } - RivCellSetEnum faultLabelType = m_reservoirGridPartManager->geometryTypeForFaultLabels(faultGeometryTypesToAppend, faultCollection()->isShowingFaultsAndFaultsOutsideFilters()); + RivCellSetEnum faultLabelType = m_reservoirGridPartManager->geometryTypeForFaultLabels( + faultGeometryTypesToAppend, faultCollection()->isShowingFaultsAndFaultsOutsideFilters()); if (faultLabelType == PROPERTY_FILTERED) { - m_reservoirGridPartManager->appendFaultLabelsDynamicGeometryPartsToModel(frameParts.p(), faultLabelType, m_currentTimeStep); + m_reservoirGridPartManager->appendFaultLabelsDynamicGeometryPartsToModel( + frameParts.p(), faultLabelType, m_currentTimeStep); } else { @@ -635,15 +662,17 @@ void RimEclipseView::updateVisibleGeometriesAndCellColors() } // Set the transparency on all the Wellcell parts before setting the result color - float opacity = static_cast (1 - cvf::Math::clamp(this->wellCollection()->wellCellTransparencyLevel(), 0.0, 1.0)); - m_reservoirGridPartManager->updateCellColor(PROPERTY_FILTERED_WELL_CELLS, m_currentTimeStep, cvf::Color4f(cvf::Color3f(cvf::Color3::WHITE), opacity)); - + float opacity = static_cast(1 - cvf::Math::clamp(this->wellCollection()->wellCellTransparencyLevel(), 0.0, 1.0)); + m_reservoirGridPartManager->updateCellColor( + PROPERTY_FILTERED_WELL_CELLS, m_currentTimeStep, cvf::Color4f(cvf::Color3f(cvf::Color3::WHITE), opacity)); if (this->showInactiveCells()) { - if (this->rangeFilterCollection()->hasActiveFilters()) // Wells not considered, because we do not have a INACTIVE_WELL_CELLS group yet. + if (this->rangeFilterCollection() + ->hasActiveFilters()) // Wells not considered, because we do not have a INACTIVE_WELL_CELLS group yet. { - m_reservoirGridPartManager->appendStaticGeometryPartsToModel(frameParts.p(), RANGE_FILTERED_INACTIVE, gridIndices); + m_reservoirGridPartManager->appendStaticGeometryPartsToModel( + frameParts.p(), RANGE_FILTERED_INACTIVE, gridIndices); if (!faultCollection()->isShowingFaultsAndFaultsOutsideFilters()) { @@ -699,9 +728,11 @@ void RimEclipseView::updateVisibleGeometriesAndCellColors() { if (this->hasUserRequestedAnimation() && this->cellEdgeResult()->hasResult()) { - m_reservoirGridPartManager->updateCellEdgeResultColor(geometriesToRecolor[i], m_currentTimeStep, this->cellResult(), this->cellEdgeResult()); + m_reservoirGridPartManager->updateCellEdgeResultColor( + geometriesToRecolor[i], m_currentTimeStep, this->cellResult(), this->cellEdgeResult()); } - else if ((this->hasUserRequestedAnimation() && this->cellResult()->hasResult()) || this->cellResult()->isTernarySaturationSelected()) + else if ((this->hasUserRequestedAnimation() && this->cellResult()->hasResult()) || + this->cellResult()->isTernarySaturationSelected()) { m_reservoirGridPartManager->updateCellResultColor(geometriesToRecolor[i], m_currentTimeStep, this->cellResult()); } @@ -713,12 +744,12 @@ void RimEclipseView::updateVisibleGeometriesAndCellColors() this->updateFaultColors(); - - if ((this->hasUserRequestedAnimation() && this->cellResult()->hasResult()) || this->cellResult()->isTernarySaturationSelected()) + if ((this->hasUserRequestedAnimation() && this->cellResult()->hasResult()) || + this->cellResult()->isTernarySaturationSelected()) { m_crossSectionCollection->updateCellResultColor(m_currentTimeStep, - this->cellResult()->legendConfig()->scalarMapper(), - this->cellResult()->ternaryLegendConfig()->scalarMapper()); + this->cellResult()->legendConfig()->scalarMapper(), + this->cellResult()->ternaryLegendConfig()->scalarMapper()); } else { @@ -784,7 +815,8 @@ void RimEclipseView::appendWellsAndFracturesToModel() f->firstAncestorOrThisOfType(simWell); if (simWell) { - bool isAnyGeometryPresent = simWell->isWellPipeVisible(m_currentTimeStep) || simWell->isWellSpheresVisible(m_currentTimeStep); + bool isAnyGeometryPresent = + simWell->isWellPipeVisible(m_currentTimeStep) || simWell->isWellSpheresVisible(m_currentTimeStep); if (!isAnyGeometryPresent) { continue; @@ -802,7 +834,7 @@ void RimEclipseView::appendWellsAndFracturesToModel() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RimEclipseView::onLoadDataAndUpdate() { @@ -812,10 +844,10 @@ void RimEclipseView::onLoadDataAndUpdate() { if (!m_eclipseCase->openReserviorCase()) { - QMessageBox::warning(RiuMainWindow::instance(), - "Error when opening project file", - "Could not open the Eclipse Grid file: \n"+ m_eclipseCase->gridFileName()); - this->setEclipseCase( nullptr); + QMessageBox::warning(RiuMainWindow::instance(), + "Error when opening project file", + "Could not open the Eclipse Grid file: \n" + m_eclipseCase->gridFileName()); + this->setEclipseCase(nullptr); return; } } @@ -839,10 +871,12 @@ void RimEclipseView::onLoadDataAndUpdate() m_simWellsPartManager->clearGeometryCache(); syncronizeWellsWithResults(); - + + syncronizeLocalAnnotationsFromGlobal(); + { // Update simulation well fractures after well cell results are imported - + std::vector simFractures; this->descendantsIncludingThisOfType(simFractures); for (auto fracture : simFractures) @@ -859,10 +893,16 @@ void RimEclipseView::onLoadDataAndUpdate() this->scheduleCreateDisplayModelAndRedraw(); } - +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +caf::PdmFieldHandle* RimEclipseView::userDescriptionField() +{ + return nameConfig()->nameField(); +} //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RimEclipseView::initAfterRead() { @@ -880,27 +920,26 @@ void RimEclipseView::initAfterRead() this->updateUiIconFromToggleField(); } - //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RimEclipseView::updateStaticCellColors() { - updateStaticCellColors( OVERRIDDEN_CELL_VISIBILITY); - updateStaticCellColors( ACTIVE); - updateStaticCellColors( ALL_WELL_CELLS); - updateStaticCellColors( VISIBLE_WELL_CELLS); - updateStaticCellColors( VISIBLE_WELL_FENCE_CELLS); - updateStaticCellColors( VISIBLE_WELL_CELLS_OUTSIDE_RANGE_FILTER); - updateStaticCellColors( VISIBLE_WELL_FENCE_CELLS_OUTSIDE_RANGE_FILTER); - updateStaticCellColors( INACTIVE); - updateStaticCellColors( RANGE_FILTERED); - updateStaticCellColors( RANGE_FILTERED_WELL_CELLS); - updateStaticCellColors( RANGE_FILTERED_INACTIVE); + updateStaticCellColors(OVERRIDDEN_CELL_VISIBILITY); + updateStaticCellColors(ACTIVE); + updateStaticCellColors(ALL_WELL_CELLS); + updateStaticCellColors(VISIBLE_WELL_CELLS); + updateStaticCellColors(VISIBLE_WELL_FENCE_CELLS); + updateStaticCellColors(VISIBLE_WELL_CELLS_OUTSIDE_RANGE_FILTER); + updateStaticCellColors(VISIBLE_WELL_FENCE_CELLS_OUTSIDE_RANGE_FILTER); + updateStaticCellColors(INACTIVE); + updateStaticCellColors(RANGE_FILTERED); + updateStaticCellColors(RANGE_FILTERED_WELL_CELLS); + updateStaticCellColors(RANGE_FILTERED_INACTIVE); } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RimEclipseView::updateStaticCellColors(RivCellSetEnum geometryType) { @@ -919,34 +958,86 @@ void RimEclipseView::updateStaticCellColors(RivCellSetEnum geometryType) } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- cvf::Color4f RimEclipseView::colorFromCellCategory(RivCellSetEnum geometryType) const { - float opacity = static_cast (1 - cvf::Math::clamp(this->wellCollection()->wellCellTransparencyLevel(), 0.0, 1.0)); + float opacity = static_cast(1 - cvf::Math::clamp(this->wellCollection()->wellCellTransparencyLevel(), 0.0, 1.0)); cvf::Color4f color(cvf::Color3::ORANGE); switch (geometryType) { - case ACTIVE: color = cvf::Color4f(cvf::Color3::ORANGE); break; - case ALL_WELL_CELLS: color = cvf::Color4f(cvf::Color3f(cvf::Color3::BROWN), opacity); break; - case VISIBLE_WELL_CELLS: color = cvf::Color4f(cvf::Color3f(cvf::Color3::BROWN), opacity); break; - case VISIBLE_WELL_FENCE_CELLS: color = cvf::Color4f(cvf::Color3::ORANGE); break; - case VISIBLE_WELL_CELLS_OUTSIDE_RANGE_FILTER: - color = cvf::Color4f(cvf::Color3f(cvf::Color3::BROWN), opacity); break; - case VISIBLE_WELL_FENCE_CELLS_OUTSIDE_RANGE_FILTER: - color = cvf::Color4f(cvf::Color3::ORANGE); break; - case INACTIVE: color = cvf::Color4f(RiaColorTables::undefinedCellColor()); break; - case RANGE_FILTERED: color = cvf::Color4f(cvf::Color3::ORANGE); break; - case RANGE_FILTERED_WELL_CELLS: color = cvf::Color4f(cvf::Color3f(cvf::Color3::BROWN), opacity); break; - case RANGE_FILTERED_INACTIVE: color = cvf::Color4f(RiaColorTables::undefinedCellColor()); break; + case ACTIVE: + color = cvf::Color4f(cvf::Color3::ORANGE); + break; + case ALL_WELL_CELLS: + color = cvf::Color4f(cvf::Color3f(cvf::Color3::BROWN), opacity); + break; + case VISIBLE_WELL_CELLS: + color = cvf::Color4f(cvf::Color3f(cvf::Color3::BROWN), opacity); + break; + case VISIBLE_WELL_FENCE_CELLS: + color = cvf::Color4f(cvf::Color3::ORANGE); + break; + case VISIBLE_WELL_CELLS_OUTSIDE_RANGE_FILTER: + color = cvf::Color4f(cvf::Color3f(cvf::Color3::BROWN), opacity); + break; + case VISIBLE_WELL_FENCE_CELLS_OUTSIDE_RANGE_FILTER: + color = cvf::Color4f(cvf::Color3::ORANGE); + break; + case INACTIVE: + color = cvf::Color4f(RiaColorTables::undefinedCellColor()); + break; + case RANGE_FILTERED: + color = cvf::Color4f(cvf::Color3::ORANGE); + break; + case RANGE_FILTERED_WELL_CELLS: + color = cvf::Color4f(cvf::Color3f(cvf::Color3::BROWN), opacity); + break; + case RANGE_FILTERED_INACTIVE: + color = cvf::Color4f(RiaColorTables::undefinedCellColor()); + break; } return color; } //-------------------------------------------------------------------------------------------------- -/// +/// +//-------------------------------------------------------------------------------------------------- +QString RimEclipseView::createAutoName() const +{ + QStringList autoName; + + if (!nameConfig()->customName().isEmpty()) + { + autoName.push_back(nameConfig()->customName()); + } + + QStringList generatedAutoTags; + + RimCase* ownerCase = nullptr; + this->firstAncestorOrThisOfTypeAsserted(ownerCase); + + if (nameConfig()->addCaseName()) + { + generatedAutoTags.push_back(ownerCase->caseUserDescription()); + } + + if (nameConfig()->addProperty()) + { + generatedAutoTags.push_back(cellResult()->resultVariable()); + } + + if (!generatedAutoTags.empty()) + { + autoName.push_back(generatedAutoTags.join(", ")); + } + return autoName.join(": "); +} + +//-------------------------------------------------------------------------------------------------- +/// //-------------------------------------------------------------------------------------------------- void RimEclipseView::updateDisplayModelVisibility() { @@ -976,13 +1067,11 @@ RigCaseCellResultsData* RimEclipseView::currentGridCellResults() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- const RigActiveCellInfo* RimEclipseView::currentActiveCellInfo() const { - if (m_eclipseCase && - m_eclipseCase->eclipseCaseData() - ) + if (m_eclipseCase && m_eclipseCase->eclipseCaseData()) { return m_eclipseCase->eclipseCaseData()->activeCellInfo(cellResult()->porosityModel()); } @@ -990,9 +1079,8 @@ const RigActiveCellInfo* RimEclipseView::currentActiveCellInfo() const return nullptr; } - //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RimEclipseView::scheduleGeometryRegen(RivCellSetEnum geometryType) { @@ -1011,7 +1099,7 @@ void RimEclipseView::scheduleGeometryRegen(RivCellSetEnum geometryType) } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RimEclipseView::scheduleReservoirGridGeometryRegen() { @@ -1027,9 +1115,8 @@ void RimEclipseView::scheduleSimWellGeometryRegen() m_simWellsPartManager->scheduleGeometryRegen(); } - //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- std::vector RimEclipseView::indicesToVisibleGrids() const { @@ -1039,7 +1126,7 @@ std::vector RimEclipseView::indicesToVisibleGrids() const } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RimEclipseView::updateLegends() { @@ -1048,7 +1135,7 @@ void RimEclipseView::updateLegends() m_viewer->removeAllColorLegends(); } - if (!m_eclipseCase || !m_viewer || !m_eclipseCase->eclipseCaseData() ) + if (!m_eclipseCase || !m_viewer || !m_eclipseCase->eclipseCaseData()) { return; } @@ -1072,7 +1159,7 @@ void RimEclipseView::updateLegends() { if (this->cellEdgeResult()->isUsingSingleVariable()) { - this->cellEdgeResult()->singleVarEdgeResultColors()->updateLegendData(m_currentTimeStep); + this->cellEdgeResult()->singleVarEdgeResultColors()->updateLegendData(m_eclipseCase, m_currentTimeStep); } else { @@ -1081,14 +1168,16 @@ void RimEclipseView::updateLegends() this->cellEdgeResult()->minMaxCellEdgeValues(globalMin, globalMax); this->cellEdgeResult()->posNegClosestToZero(globalPosClosestToZero, globalNegClosestToZero); - this->cellEdgeResult()->legendConfig()->setClosestToZeroValues(globalPosClosestToZero, globalNegClosestToZero, globalPosClosestToZero, globalNegClosestToZero); + this->cellEdgeResult()->legendConfig()->setClosestToZeroValues( + globalPosClosestToZero, globalNegClosestToZero, globalPosClosestToZero, globalNegClosestToZero); this->cellEdgeResult()->legendConfig()->setAutomaticRanges(globalMin, globalMax, globalMin, globalMax); if (this->cellEdgeResult()->hasCategoryResult()) { if (cellEdgeResult()->singleVarEdgeResultColors()->resultType() != RiaDefines::FORMATION_NAMES) { - cellEdgeResult()->legendConfig()->setIntegerCategories(results->uniqueCellScalarValues(cellEdgeResult()->singleVarEdgeResultColors()->scalarResultIndex())); + cellEdgeResult()->legendConfig()->setIntegerCategories(results->uniqueCellScalarValues( + cellEdgeResult()->singleVarEdgeResultColors()->eclipseResultAddress())); } else { @@ -1098,27 +1187,45 @@ void RimEclipseView::updateLegends() } } - this->cellEdgeResult()->legendConfig()->setTitle(QString("Edge Results: \n") + this->cellEdgeResult()->resultVariableUiShortName()); + this->cellEdgeResult()->legendConfig()->setTitle(QString("Edge Results: \n") + + this->cellEdgeResult()->resultVariableUiShortName()); m_viewer->addColorLegendToBottomLeftCorner(this->cellEdgeResult()->legendConfig()->titledOverlayFrame()); } else { this->cellEdgeResult()->legendConfig()->setClosestToZeroValues(0, 0, 0, 0); - this->cellEdgeResult()->legendConfig()->setAutomaticRanges(cvf::UNDEFINED_DOUBLE, cvf::UNDEFINED_DOUBLE, cvf::UNDEFINED_DOUBLE, cvf::UNDEFINED_DOUBLE); + this->cellEdgeResult()->legendConfig()->setAutomaticRanges( + cvf::UNDEFINED_DOUBLE, cvf::UNDEFINED_DOUBLE, cvf::UNDEFINED_DOUBLE, cvf::UNDEFINED_DOUBLE); } } - RimRegularLegendConfig* stimPlanLegend = fractureColors()->activeLegend(); - if (stimPlanLegend && stimPlanLegend->showLegend()) { - fractureColors()->updateLegendData(); - - if (fractureColors()->isChecked() && stimPlanLegend->titledOverlayFrame()) + bool hasAnyVisibleFractures = false; { - m_viewer->addColorLegendToBottomLeftCorner(stimPlanLegend->titledOverlayFrame()); + std::vector fractures; + RiaApplication::instance()->project()->activeOilField()->descendantsIncludingThisOfType(fractures); + + for (const auto& f : fractures) + { + if (f->isEnabled()) hasAnyVisibleFractures = true; + } + } + + if (hasAnyVisibleFractures) + { + RimRegularLegendConfig* stimPlanLegend = fractureColors()->activeLegend(); + if (stimPlanLegend && stimPlanLegend->showLegend()) + { + fractureColors()->updateLegendData(); + + if (fractureColors()->isChecked() && stimPlanLegend->titledOverlayFrame()) + { + m_viewer->addColorLegendToBottomLeftCorner(stimPlanLegend->titledOverlayFrame()); + } + } } } - + if (m_virtualPerforationResult->showConnectionFactors() && m_virtualPerforationResult->legendConfig()->showLegend()) { updateVirtualConnectionLegendRanges(); @@ -1129,17 +1236,30 @@ void RimEclipseView::updateLegends() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- -void RimEclipseView::updateMinMaxValuesAndAddLegendToView(QString legendLabel, - RimEclipseCellColors* resultColors, +void RimEclipseView::updateMinMaxValuesAndAddLegendToView(QString legendLabel, + RimEclipseCellColors* resultColors, RigCaseCellResultsData* cellResultsData) { - resultColors->updateLegendData(m_currentTimeStep); + resultColors->updateLegendData(m_eclipseCase, m_currentTimeStep); if (resultColors->hasResult() && resultColors->legendConfig()->showLegend()) { - resultColors->legendConfig()->setTitle(legendLabel + resultColors->resultVariableUiName()); + QString title = legendLabel + resultColors->resultVariableUiName(); + if (!resultColors->diffResultUiShortName().isEmpty()) + { + title += QString("\n%1").arg(resultColors->diffResultUiShortName()); + } + + if (resultColors->hasDualPorFractureResult()) + { + QString porosityModelText = caf::AppEnum::uiText(resultColors->porosityModel()); + + title += QString("\nDual Por : %1").arg(porosityModelText); + } + + resultColors->legendConfig()->setTitle(title); m_viewer->addColorLegendToBottomLeftCorner(resultColors->legendConfig()->titledOverlayFrame()); } @@ -1155,19 +1275,19 @@ void RimEclipseView::updateMinMaxValuesAndAddLegendToView(QString legendLabel, } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RimEclipseView::setEclipseCase(RimEclipseCase* reservoir) { m_eclipseCase = reservoir; cellResult()->setEclipseCase(reservoir); faultResultSettings()->customFaultResult()->setEclipseCase(reservoir); - + cellEdgeResult()->setEclipseCase(reservoir); } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- RimEclipseCase* RimEclipseView::eclipseCase() const { @@ -1178,9 +1298,9 @@ RimEclipseCase* RimEclipseView::eclipseCase() const // /* wells vs wellres - For all wellres + For all wellres find well - if no well, create new + if no well, create new connect well and wellres for all wells not connected Delete ? @@ -1189,12 +1309,11 @@ RimEclipseCase* RimEclipseView::eclipseCase() const //-------------------------------------------------------------------------------------------------- void RimEclipseView::syncronizeWellsWithResults() { - if (!(m_eclipseCase && m_eclipseCase->eclipseCaseData()) ) return; + if (!(m_eclipseCase && m_eclipseCase->eclipseCaseData())) return; cvf::Collection wellResults = m_eclipseCase->eclipseCaseData()->wellResults(); - - std::vector > newWells; + std::vector> newWells; // Clear the possible well results data present for (size_t wIdx = 0; wIdx < this->wellCollection()->wells().size(); ++wIdx) @@ -1213,7 +1332,7 @@ void RimEclipseView::syncronizeWellsWithResults() if (!well) { - well = new RimSimWellInView; + well = new RimSimWellInView; well->name = wellResults[wIdx]->m_wellName; isAnyWellCreated = true; @@ -1227,8 +1346,8 @@ void RimEclipseView::syncronizeWellsWithResults() for (size_t wIdx = 0; wIdx < this->wellCollection()->wells().size(); ++wIdx) { - RimSimWellInView* well = this->wellCollection()->wells()[wIdx]; - RigSimWellData* simWellData = well->simWellData(); + RimSimWellInView* well = this->wellCollection()->wells()[wIdx]; + RigSimWellData* simWellData = well->simWellData(); if (simWellData == nullptr) { delete well; @@ -1252,7 +1371,23 @@ void RimEclipseView::syncronizeWellsWithResults() } //-------------------------------------------------------------------------------------------------- -/// +/// +//-------------------------------------------------------------------------------------------------- +void RimEclipseView::syncronizeLocalAnnotationsFromGlobal() +{ + RimProject* proj = RiaApplication::instance()->project(); + if (proj && proj->activeOilField()) + { + RimAnnotationCollection* annotColl = proj->activeOilField()->annotationCollection(); + if (annotColl && annotationCollection()) + { + annotationCollection()->onGlobalCollectionChanged(annotColl); + } + } +} + +//-------------------------------------------------------------------------------------------------- +/// //-------------------------------------------------------------------------------------------------- const RivReservoirViewPartMgr* RimEclipseView::reservoirGridPartManager() const { @@ -1260,17 +1395,17 @@ const RivReservoirViewPartMgr* RimEclipseView::reservoirGridPartManager() const } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- -RivReservoirViewPartMgr * RimEclipseView::reservoirGridPartManager() +RivReservoirViewPartMgr* RimEclipseView::reservoirGridPartManager() { return m_reservoirGridPartManager.p(); } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- -void RimEclipseView::calculateVisibleWellCellsIncFence(cvf::UByteArray* visibleCells, RigGridBase * grid) +void RimEclipseView::calculateVisibleWellCellsIncFence(cvf::UByteArray* visibleCells, RigGridBase* grid) { CVF_ASSERT(visibleCells != nullptr); @@ -1288,13 +1423,13 @@ void RimEclipseView::calculateVisibleWellCellsIncFence(cvf::UByteArray* visibleC // Loop over the wells and find their contribution for (size_t wIdx = 0; wIdx < this->wellCollection()->wells().size(); ++wIdx) { - RimSimWellInView* well = this->wellCollection()->wells()[wIdx]; + RimSimWellInView* well = this->wellCollection()->wells()[wIdx]; if (well->isWellCellsVisible()) { RigSimWellData* simWellData = well->simWellData(); if (!simWellData) continue; - const std::vector< RigWellResultFrame >& wellResFrames = simWellData->m_wellCellsTimeSteps; + const std::vector& wellResFrames = simWellData->m_wellCellsTimeSteps; for (size_t wfIdx = 0; wfIdx < wellResFrames.size(); ++wfIdx) { // Add all the cells from the branches @@ -1303,7 +1438,7 @@ void RimEclipseView::calculateVisibleWellCellsIncFence(cvf::UByteArray* visibleC for (size_t wsIdx = 0; wsIdx < wellResSegments.size(); ++wsIdx) { const std::vector& wsResCells = wellResSegments[wsIdx].m_branchResultPoints; - for (size_t cIdx = 0; cIdx < wsResCells.size(); ++ cIdx) + for (size_t cIdx = 0; cIdx < wsResCells.size(); ++cIdx) { if (wsResCells[cIdx].m_gridIndex == grid->gridIndex()) { @@ -1312,7 +1447,7 @@ void RimEclipseView::calculateVisibleWellCellsIncFence(cvf::UByteArray* visibleC continue; } - size_t gridCellIndex = wsResCells[cIdx].m_gridCellIndex; + size_t gridCellIndex = wsResCells[cIdx].m_gridCellIndex; (*visibleCells)[gridCellIndex] = true; // Calculate well fence cells @@ -1321,31 +1456,31 @@ void RimEclipseView::calculateVisibleWellCellsIncFence(cvf::UByteArray* visibleC size_t i, j, k; grid->ijkFromCellIndex(gridCellIndex, &i, &j, &k); - size_t* pI = &i; - size_t *pJ = &j; - size_t *pK = &k; - size_t cellCountFenceDirection = 0; - size_t fIdx = 0; + size_t* pI = &i; + size_t* pJ = &j; + size_t* pK = &k; + size_t cellCountFenceDirection = 0; + size_t fIdx = 0; if (this->wellCollection()->wellCellFenceType == RimSimWellInViewCollection::K_DIRECTION) { cellCountFenceDirection = grid->cellCountK(); - pK = &fIdx; + pK = &fIdx; } else if (this->wellCollection()->wellCellFenceType == RimSimWellInViewCollection::J_DIRECTION) { cellCountFenceDirection = grid->cellCountJ(); - pJ = &fIdx; + pJ = &fIdx; } else if (this->wellCollection()->wellCellFenceType == RimSimWellInViewCollection::I_DIRECTION) { cellCountFenceDirection = grid->cellCountI(); - pI = &fIdx; + pI = &fIdx; } - for ( fIdx = 0; fIdx < cellCountFenceDirection; ++fIdx) + for (fIdx = 0; fIdx < cellCountFenceDirection; ++fIdx) { - size_t fenceCellIndex = grid->cellIndexFromIJK(*pI,*pJ,*pK); + size_t fenceCellIndex = grid->cellIndexFromIJK(*pI, *pJ, *pK); size_t reservoirCellIndex = grid->reservoirCellIndex(fenceCellIndex); if (activeCellInfo && activeCellInfo->isActive(reservoirCellIndex)) @@ -1363,7 +1498,7 @@ void RimEclipseView::calculateVisibleWellCellsIncFence(cvf::UByteArray* visibleC } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RimEclipseView::updateDisplayModelForWellResults() { @@ -1380,13 +1515,11 @@ void RimEclipseView::updateDisplayModelForWellResults() m_viewer->animationControl()->setCurrentFrame(m_currentTimeStep); } - RiuMainWindow::instance()->refreshAnimationActions(); - + RiuMainWindow::instance()->refreshAnimationActions(); } - //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RimEclipseView::calculateCompletionTypeAndRedrawIfRequired() { @@ -1417,7 +1550,7 @@ void RimEclipseView::calculateCompletionTypeAndRedrawIfRequired() for (const auto& propFilter : m_propertyFilterCollection()->propertyFilters) { - if (propFilter->isActive() && propFilter->resultDefinition->resultVariable() == RiaDefines::completionTypeResultName()) + if (propFilter->isActive() && propFilter->resultDefinition()->resultVariable() == RiaDefines::completionTypeResultName()) { isDependingOnCompletionType = true; } @@ -1430,7 +1563,7 @@ void RimEclipseView::calculateCompletionTypeAndRedrawIfRequired() std::vector intersections = m_crossSectionCollection->intersections(); for (auto intersection : intersections) { - if ( intersection && intersection->correspondingIntersectionView() ) + if (intersection && intersection->correspondingIntersectionView()) { intersection->correspondingIntersectionView()->scheduleCreateDisplayModelAndRedraw(); } @@ -1439,7 +1572,7 @@ void RimEclipseView::calculateCompletionTypeAndRedrawIfRequired() for (const auto& propFilter : m_propertyFilterCollection()->propertyFilters) { - if (propFilter->isActive() && propFilter->resultDefinition->resultVariable() == RiaDefines::completionTypeResultName()) + if (propFilter->isActive() && propFilter->resultDefinition()->resultVariable() == RiaDefines::completionTypeResultName()) { propFilter->updateConnectedEditors(); } @@ -1447,7 +1580,7 @@ void RimEclipseView::calculateCompletionTypeAndRedrawIfRequired() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- bool RimEclipseView::isVirtualConnectionFactorGeometryVisible() const { @@ -1461,12 +1594,13 @@ bool RimEclipseView::isVirtualConnectionFactorGeometryVisible() const } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- bool RimEclipseView::isMainGridVisible() const { auto indicesToVisibleGrids = m_gridCollection->indicesToVisibleGrids(); - bool isMainGridVisible = std::find(indicesToVisibleGrids.begin(), indicesToVisibleGrids.end(), 0) != indicesToVisibleGrids.end(); + bool isMainGridVisible = + std::find(indicesToVisibleGrids.begin(), indicesToVisibleGrids.end(), 0) != indicesToVisibleGrids.end(); if (!isMainGridVisible) return false; @@ -1474,7 +1608,7 @@ bool RimEclipseView::isMainGridVisible() const } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- const std::vector& RimEclipseView::visibleGridParts() const { @@ -1482,7 +1616,7 @@ const std::vector& RimEclipseView::visibleGridParts() const } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RimEclipseView::defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering) { @@ -1491,10 +1625,15 @@ void RimEclipseView::defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& caf::PdmUiGroup* cellGroup = uiOrdering.addNewGroup("Cell Visibility"); cellGroup->add(&m_showInactiveCells); cellGroup->add(&m_showInvalidCells); + + caf::PdmUiGroup* nameGroup = uiOrdering.addNewGroup("View Name"); + nameConfig()->uiOrdering(uiConfigName, *nameGroup); + + uiOrdering.skipRemainingFields(true); } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RimEclipseView::defineUiTreeOrdering(caf::PdmUiTreeOrdering& uiTreeOrdering, QString uiConfigName /*= ""*/) { @@ -1509,8 +1648,8 @@ void RimEclipseView::defineUiTreeOrdering(caf::PdmUiTreeOrdering& uiTreeOrdering RimProject* project = RiaApplication::instance()->project(); CVF_ASSERT(project); RimOilField* oilfield = project->activeOilField(); - - if (oilfield && oilfield->fractureDefinitionCollection().notNull()) + + if (oilfield && oilfield->fractureDefinitionCollection()) { if (!oilfield->fractureDefinitionCollection()->fractureTemplates().empty()) { @@ -1521,15 +1660,16 @@ void RimEclipseView::defineUiTreeOrdering(caf::PdmUiTreeOrdering& uiTreeOrdering uiTreeOrdering.add(m_virtualPerforationResult); uiTreeOrdering.add(faultCollection()); + uiTreeOrdering.add(annotationCollection()); uiTreeOrdering.add(crossSectionCollection()); - + uiTreeOrdering.add(m_rangeFilterCollection()); uiTreeOrdering.add(m_propertyFilterCollection()); uiTreeOrdering.skipRemainingChildren(true); } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- std::set RimEclipseView::allVisibleFaultGeometryTypes() const { @@ -1551,7 +1691,7 @@ std::set RimEclipseView::allVisibleFaultGeometryTypes() const } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RimEclipseView::updateFaultColors() { @@ -1563,7 +1703,8 @@ void RimEclipseView::updateFaultColors() { if (this->hasUserRequestedAnimation() && this->cellEdgeResult()->hasResult()) { - m_reservoirGridPartManager->updateFaultCellEdgeResultColor(cellSetType, m_currentTimeStep, faultResultColors, this->cellEdgeResult()); + m_reservoirGridPartManager->updateFaultCellEdgeResultColor( + cellSetType, m_currentTimeStep, faultResultColors, this->cellEdgeResult()); } else { @@ -1572,20 +1713,19 @@ void RimEclipseView::updateFaultColors() } } - //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- bool RimEclipseView::isTimeStepDependentDataVisible() const { if (this->cellResult()->hasDynamicResult()) return true; if (this->eclipsePropertyFilterCollection()->hasActiveDynamicFilters()) return true; - + if (this->wellCollection()->hasVisibleWellPipes()) return true; if (this->cellResult()->isTernarySaturationSelected()) return true; - + if (this->faultResultSettings()->showCustomFaultResult()) { if (this->faultResultSettings()->customFaultResult()->hasDynamicResult()) return true; @@ -1593,16 +1733,15 @@ bool RimEclipseView::isTimeStepDependentDataVisible() const if (this->faultResultSettings()->customFaultResult()->isTernarySaturationSelected()) return true; } - if (this->wellPathCollection()->anyWellsContainingPerforationIntervals()) return true; + if (this->wellPathCollection() && this->wellPathCollection()->anyWellsContainingPerforationIntervals()) return true; if (this->hasVisibleTimeStepDependent3dWellLogCurves()) return true; return false; } - //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- RimEclipseCellColors* RimEclipseView::currentFaultResultColors() { @@ -1617,7 +1756,7 @@ RimEclipseCellColors* RimEclipseView::currentFaultResultColors() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RimEclipseView::resetLegendsInViewer() { @@ -1628,7 +1767,7 @@ void RimEclipseView::resetLegendsInViewer() this->cellEdgeResult()->legendConfig()->recreateLegend(); m_viewer->removeAllColorLegends(); - + if (cellResultNormalLegendConfig) { m_viewer->addColorLegendToBottomLeftCorner(cellResultNormalLegendConfig->titledOverlayFrame()); @@ -1638,17 +1777,18 @@ void RimEclipseView::resetLegendsInViewer() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RimEclipseView::updateVirtualConnectionLegendRanges() { if (!eclipseCase()) return; - const RigVirtualPerforationTransmissibilities* virtualTransmissibilities = eclipseCase()->computeAndGetVirtualPerforationTransmissibilities(); + const RigVirtualPerforationTransmissibilities* virtualTransmissibilities = + eclipseCase()->computeAndGetVirtualPerforationTransmissibilities(); if (virtualTransmissibilities) { - double minValue = HUGE_VAL; - double maxValue = -HUGE_VAL; + double minValue = HUGE_VAL; + double maxValue = -HUGE_VAL; double posClosestToZero = HUGE_VAL; double negClosestToZero = -HUGE_VAL; @@ -1665,7 +1805,7 @@ void RimEclipseView::updateVirtualConnectionLegendRanges() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- cvf::Transform* RimEclipseView::scaleTransform() { @@ -1673,7 +1813,7 @@ cvf::Transform* RimEclipseView::scaleTransform() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- RimCase* RimEclipseView::ownerCase() const { @@ -1681,7 +1821,7 @@ RimCase* RimEclipseView::ownerCase() const } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- RigMainGrid* RimEclipseView::mainGrid() const { @@ -1694,7 +1834,7 @@ RigMainGrid* RimEclipseView::mainGrid() const } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- RimEclipsePropertyFilterCollection* RimEclipseView::eclipsePropertyFilterCollection() { @@ -1709,7 +1849,7 @@ RimEclipsePropertyFilterCollection* RimEclipseView::eclipsePropertyFilterCollect } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- const RimEclipsePropertyFilterCollection* RimEclipseView::eclipsePropertyFilterCollection() const { @@ -1724,7 +1864,7 @@ const RimEclipsePropertyFilterCollection* RimEclipseView::eclipsePropertyFilterC } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RimEclipseView::setOverridePropertyFilterCollection(RimEclipsePropertyFilterCollection* pfc) { @@ -1739,7 +1879,7 @@ void RimEclipseView::setOverridePropertyFilterCollection(RimEclipsePropertyFilte } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RimEclipseView::calculateCurrentTotalCellVisibility(cvf::UByteArray* totalVisibility, int timeStep) { @@ -1751,14 +1891,15 @@ void RimEclipseView::calculateCurrentTotalCellVisibility(cvf::UByteArray* totalV for (size_t gridIdx = 0; gridIdx < gridCount; ++gridIdx) { - RigGridBase * grid = this->eclipseCase()->eclipseCaseData()->grid(gridIdx); - int gridCellCount = static_cast(grid->cellCount()); + RigGridBase* grid = this->eclipseCase()->eclipseCaseData()->grid(gridIdx); + int gridCellCount = static_cast(grid->cellCount()); for (size_t gpIdx = 0; gpIdx < m_visibleGridParts.size(); ++gpIdx) { - const cvf::UByteArray* visibility = m_reservoirGridPartManager->cellVisibility(m_visibleGridParts[gpIdx], gridIdx, timeStep); + const cvf::UByteArray* visibility = + m_reservoirGridPartManager->cellVisibility(m_visibleGridParts[gpIdx], gridIdx, timeStep); - for (int lcIdx = 0; lcIdx < gridCellCount; ++ lcIdx) + for (int lcIdx = 0; lcIdx < gridCellCount; ++lcIdx) { (*totalVisibility)[grid->reservoirCellIndex(lcIdx)] |= (*visibility)[lcIdx]; } @@ -1767,7 +1908,7 @@ void RimEclipseView::calculateCurrentTotalCellVisibility(cvf::UByteArray* totalV } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- std::vector RimEclipseView::legendConfigs() const { @@ -1785,7 +1926,7 @@ std::vector RimEclipseView::legendConfigs() const } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- bool RimEclipseView::showActiveCellsOnly() { @@ -1793,11 +1934,11 @@ bool RimEclipseView::showActiveCellsOnly() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RimEclipseView::createPartCollectionFromSelection(cvf::Collection* parts) { - RiuSelectionManager* riuSelManager = RiuSelectionManager::instance(); + Riu3dSelectionManager* riuSelManager = Riu3dSelectionManager::instance(); std::vector items; riuSelManager->selectedItems(items); @@ -1811,7 +1952,9 @@ void RimEclipseView::createPartCollectionFromSelection(cvf::Collectionm_view->eclipseCase()); CVF_ASSERT(eclipseSelItem->m_view->eclipseCase()->eclipseCaseData()); - RivSingleCellPartGenerator partGen(eclipseSelItem->m_view->eclipseCase()->eclipseCaseData(), eclipseSelItem->m_gridIndex, eclipseSelItem->m_gridLocalCellIndex); + RivSingleCellPartGenerator partGen(eclipseSelItem->m_view->eclipseCase()->eclipseCaseData(), + eclipseSelItem->m_gridIndex, + eclipseSelItem->m_gridLocalCellIndex); cvf::ref part = partGen.createPart(eclipseSelItem->m_color); part->setTransform(this->scaleTransform()); @@ -1823,7 +1966,7 @@ void RimEclipseView::createPartCollectionFromSelection(cvf::CollectionresultType() == RiaDefines::FORMATION_NAMES)) return true; - + return eclipsePropertyFilterCollection()->isUsingFormationNames(); } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- bool RimEclipseView::showInvalidCells() const { @@ -1866,7 +2009,7 @@ bool RimEclipseView::showInvalidCells() const } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- bool RimEclipseView::showInactiveCells() const { @@ -1874,7 +2017,7 @@ bool RimEclipseView::showInactiveCells() const } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- const RimPropertyFilterCollection* RimEclipseView::propertyFilterCollection() const { diff --git a/ApplicationCode/ProjectDataModel/RimEclipseView.h b/ApplicationCode/ProjectDataModel/RimEclipseView.h index 8d5ff87b29..57a590ab62 100644 --- a/ApplicationCode/ProjectDataModel/RimEclipseView.h +++ b/ApplicationCode/ProjectDataModel/RimEclipseView.h @@ -137,28 +137,33 @@ class RimEclipseView : public RimGridView bool isUsingFormationNames() const override; - virtual void calculateCurrentTotalCellVisibility(cvf::UByteArray* totalVisibility, int timeStep) override; + void calculateCurrentTotalCellVisibility(cvf::UByteArray* totalVisibility, int timeStep) override; - virtual std::vector legendConfigs() const override; + std::vector legendConfigs() const override; cvf::Color4f colorFromCellCategory(RivCellSetEnum geometryType) const; + void syncronizeLocalAnnotationsFromGlobal(); + protected: void initAfterRead() override; - virtual void defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering ) override; - virtual void defineUiTreeOrdering(caf::PdmUiTreeOrdering& uiTreeOrdering, QString uiConfigName = "") override; - virtual void onLoadDataAndUpdate() override; + void defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering ) override; + void defineUiTreeOrdering(caf::PdmUiTreeOrdering& uiTreeOrdering, QString uiConfigName = "") override; + void onLoadDataAndUpdate() override; + caf::PdmFieldHandle* userDescriptionField() override; void createPartCollectionFromSelection(cvf::Collection* parts) override; bool showActiveCellsOnly() override; - virtual void updateCurrentTimeStep() override; + void updateCurrentTimeStep() override; void updateVisibleGeometriesAndCellColors(); void appendWellsAndFracturesToModel(); - virtual void createDisplayModel() override; + void createDisplayModel() override; RimPropertyFilterCollection* nativePropertyFilterCollection(); virtual std::set allVisibleFaultGeometryTypes() const; private: + QString createAutoName() const override; + void updateDisplayModelVisibility() override; std::vector indicesToVisibleGrids() const; @@ -168,7 +173,7 @@ class RimEclipseView : public RimGridView void updateStaticCellColors() override; void updateStaticCellColors(RivCellSetEnum geometryType); - virtual void updateLegends() override; + void updateLegends() override; void updateMinMaxValuesAndAddLegendToView(QString legendLabel, RimEclipseCellColors* resultColors, RigCaseCellResultsData* cellResultsData); void resetLegendsInViewer() override; void updateVirtualConnectionLegendRanges(); diff --git a/ApplicationCode/ProjectDataModel/RimGeoMechCase.cpp b/ApplicationCode/ProjectDataModel/RimGeoMechCase.cpp index 494d284f8b..1ee043ed2a 100644 --- a/ApplicationCode/ProjectDataModel/RimGeoMechCase.cpp +++ b/ApplicationCode/ProjectDataModel/RimGeoMechCase.cpp @@ -33,6 +33,8 @@ #include "Rim2dIntersectionViewCollection.h" #include "RimFormationNames.h" #include "RimGeoMechCellColors.h" +#include "RimGeoMechContourMapView.h" +#include "RimGeoMechContourMapViewCollection.h" #include "RimGeoMechPropertyFilter.h" #include "RimGeoMechPropertyFilterCollection.h" #include "RimGeoMechResultDefinition.h" @@ -79,6 +81,10 @@ RimGeoMechCase::RimGeoMechCase(void) CAF_PDM_InitField(&m_reloadElementPropertyFileCommand, "reloadElementPropertyFileCommand", false, "", "", "", ""); caf::PdmUiPushButtonEditor::configureEditorForField(&m_reloadElementPropertyFileCommand); + + CAF_PDM_InitFieldNoDefault(&m_contourMapCollection, "ContourMaps", "2d Contour Maps", "", "", ""); + m_contourMapCollection = new RimGeoMechContourMapViewCollection; + m_contourMapCollection.uiCapability()->setUiTreeHidden(true); } //-------------------------------------------------------------------------------------------------- @@ -158,6 +164,14 @@ void RimGeoMechCase::reloadDataAndUpdate() v->loadDataAndUpdate(); v->setCurrentTimeStep(v->currentTimeStep()); } + + for (RimGeoMechContourMapView* contourMap : m_contourMapCollection->views()) + { + CVF_ASSERT(contourMap); + contourMap->loadDataAndUpdate(); + contourMap->updateGridBoxData(); + contourMap->updateAnnotationItems(); + } } } @@ -167,8 +181,6 @@ void RimGeoMechCase::reloadDataAndUpdate() RimGeoMechView* RimGeoMechCase::createAndAddReservoirView() { RimGeoMechView* gmv = new RimGeoMechView(); - size_t i = geoMechViews().size(); - gmv->setName(QString("View %1").arg(i + 1)); gmv->setGeoMechCase(this); @@ -276,6 +288,12 @@ std::vector RimGeoMechCase::allSpecialViews() const { views.push_back(geoMechViews[vIdx]); } + + for (RimGeoMechContourMapView* view : m_contourMapCollection->views()) + { + views.push_back(view); + } + return views; } @@ -294,9 +312,22 @@ void RimGeoMechCase::defineUiTreeOrdering(caf::PdmUiTreeOrdering& uiTreeOrdering uiTreeOrdering.add(&m_2dIntersectionViewCollection); } + if (!m_contourMapCollection->views().empty()) + { + uiTreeOrdering.add(&m_contourMapCollection); + } + uiTreeOrdering.skipRemainingChildren(true); } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimGeoMechContourMapViewCollection* RimGeoMechCase::contourMapCollection() +{ + return m_contourMapCollection; +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -321,6 +352,10 @@ void RimGeoMechCase::initAfterRead() riv->setGeoMechCase(this); } + for (RimGeoMechContourMapView* contourMap : m_contourMapCollection->views()) + { + contourMap->setGeoMechCase(this); + } } //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/ProjectDataModel/RimGeoMechCase.h b/ApplicationCode/ProjectDataModel/RimGeoMechCase.h index d2ea9003aa..e7fa9b3ae1 100644 --- a/ApplicationCode/ProjectDataModel/RimGeoMechCase.h +++ b/ApplicationCode/ProjectDataModel/RimGeoMechCase.h @@ -34,6 +34,8 @@ class RimGeoMechView; class RigGeoMechCaseData; class RifGeoMechReaderInterface; +class RimGeoMechContourMapView; +class RimGeoMechContourMapViewCollection; //================================================================================================== /// @@ -60,6 +62,8 @@ class RimGeoMechCase : public RimCase RigGeoMechCaseData* geoMechData(); const RigGeoMechCaseData* geoMechData() const; + RimGeoMechContourMapViewCollection* contourMapCollection(); + void reloadDataAndUpdate(); RimGeoMechView* createAndAddReservoirView(); @@ -115,5 +119,8 @@ class RimGeoMechCase : public RimCase caf::PdmField > m_elementPropertyFileNameIndexUiSelection; caf::PdmField m_closeElementPropertyFileCommand; caf::PdmField m_reloadElementPropertyFileCommand; + + caf::PdmChildField m_contourMapCollection; + bool m_applyTimeFilter; }; diff --git a/ApplicationCode/ProjectDataModel/RimGeoMechCellColors.cpp b/ApplicationCode/ProjectDataModel/RimGeoMechCellColors.cpp index 98c9bdf542..8dc3a364fb 100644 --- a/ApplicationCode/ProjectDataModel/RimGeoMechCellColors.cpp +++ b/ApplicationCode/ProjectDataModel/RimGeoMechCellColors.cpp @@ -33,7 +33,7 @@ CAF_PDM_SOURCE_INIT(RimGeoMechCellColors, "GeoMechResultSlot"); //-------------------------------------------------------------------------------------------------- RimGeoMechCellColors::RimGeoMechCellColors(void) { - CAF_PDM_InitFieldNoDefault(&legendConfig, "LegendDefinition", "Legend Definition", "", "", ""); + CAF_PDM_InitFieldNoDefault(&legendConfig, "LegendDefinition", "Color Legend", "", "", ""); this->legendConfig = new RimRegularLegendConfig(); legendConfig.uiCapability()->setUiHidden(true); } diff --git a/ApplicationCode/ProjectDataModel/RimGeoMechContourMapProjection.cpp b/ApplicationCode/ProjectDataModel/RimGeoMechContourMapProjection.cpp new file mode 100644 index 0000000000..75f558b2b6 --- /dev/null +++ b/ApplicationCode/ProjectDataModel/RimGeoMechContourMapProjection.cpp @@ -0,0 +1,617 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2018- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// +#include "RimGeoMechContourMapProjection.h" + +#include "RiaImageTools.h" +#include "RiaWeightedGeometricMeanCalculator.h" +#include "RiaWeightedHarmonicMeanCalculator.h" +#include "RiaWeightedMeanCalculator.h" + +#include "RigCellGeometryTools.h" +#include "RigGeoMechCaseData.h" +#include "RigFemPart.h" +#include "RigFemPartGrid.h" +#include "RigFemPartCollection.h" +#include "RigFemPartResultsCollection.h" +#include "RigHexIntersectionTools.h" + +#include "RimCellRangeFilterCollection.h" +#include "RimGeoMechContourMapView.h" +#include "RimGeoMechCellColors.h" +#include "RimGeoMechPropertyFilterCollection.h" + +#include "RivFemElmVisibilityCalculator.h" + +#include "cafPdmUiDoubleSliderEditor.h" + +#include "cvfArray.h" +#include "cvfCellRange.h" +#include "cvfGeometryTools.h" +#include "cvfGeometryUtils.h" +#include "cvfScalarMapper.h" +#include "cvfStructGridGeometryGenerator.h" +#include "cvfVector3.h" + +#include +#include +#include +#include + +CAF_PDM_SOURCE_INIT(RimGeoMechContourMapProjection, "RimGeoMechContourMapProjection"); + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimGeoMechContourMapProjection::RimGeoMechContourMapProjection() +{ + CAF_PDM_InitObject("RimContourMapProjection", ":/2DMapProjection16x16.png", "", ""); + CAF_PDM_InitField(&m_limitToPorePressureRegions, "LimitToPorRegion", true, "Limit to Pore Pressure regions", "", "", ""); + CAF_PDM_InitField(&m_applyPPRegionLimitVertically, "VerticalLimit", false, "Apply Limit Vertically", "", "", ""); + CAF_PDM_InitField(&m_paddingAroundPorePressureRegion, "PaddingAroundPorRegion", 0.0, "Horizontal Padding around PP regions", "", "", ""); + m_paddingAroundPorePressureRegion.uiCapability()->setUiEditorTypeName(caf::PdmUiDoubleSliderEditor::uiEditorTypeName()); + setName("Map Projection"); + nameField()->uiCapability()->setUiReadOnly(true); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimGeoMechContourMapProjection::~RimGeoMechContourMapProjection() {} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RimGeoMechContourMapProjection::resultDescriptionText() const +{ + QString resultText = QString("%1, %2").arg(resultAggregationText()).arg(view()->cellResult()->resultFieldUiName()); + return resultText; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimRegularLegendConfig* RimGeoMechContourMapProjection::legendConfig() const +{ + return view()->cellResult()->legendConfig(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimGeoMechContourMapProjection::updateLegend() +{ + RimGeoMechCellColors* cellColors = view()->cellResult(); + + double minVal = minValue(m_aggregatedResults); + double maxVal = maxValue(m_aggregatedResults); + + std::pair minmaxValAllTimeSteps = minmaxValuesAllTimeSteps(); + + legendConfig()->setAutomaticRanges(minmaxValAllTimeSteps.first, minmaxValAllTimeSteps.second, minVal, maxVal); + + QString projectionLegendText = QString("Map Projection\n%1").arg(m_resultAggregation().uiText()); + if (cellColors->resultAddress().isValid()) + { + projectionLegendText += QString("\nResult: %1").arg(cellColors->resultFieldUiName()); + if (!cellColors->resultComponentUiName().isEmpty()) + { + projectionLegendText += QString(", %1").arg(cellColors->resultComponentUiName()); + } + } + else + { + projectionLegendText += QString("\nNo Result Selected"); + } + + legendConfig()->setTitle(projectionLegendText); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +cvf::ref RimGeoMechContourMapProjection::getCellVisibility() const +{ + cvf::ref cellGridIdxVisibility = new cvf::UByteArray(m_femPart->elementCount()); + RivFemElmVisibilityCalculator::computeAllVisible(cellGridIdxVisibility.p(), m_femPart.p()); + + if (view()->rangeFilterCollection()->isActive()) + { + cvf::CellRangeFilter cellRangeFilter; + view()->rangeFilterCollection()->compoundCellRangeFilter(&cellRangeFilter, 0); + RivFemElmVisibilityCalculator::computeRangeVisibility(cellGridIdxVisibility.p(), m_femPart.p(), cellRangeFilter); + } + if (view()->propertyFilterCollection()->isActive()) + { + RivFemElmVisibilityCalculator::computePropertyVisibility(cellGridIdxVisibility.p(), m_femPart.p(), view()->currentTimeStep(), cellGridIdxVisibility.p(), view()->geoMechPropertyFilterCollection()); + } + + return cellGridIdxVisibility; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +cvf::BoundingBox RimGeoMechContourMapProjection::calculateExpandedPorBarBBox(int timeStep) const +{ + RigFemResultAddress porBarAddr( + RigFemResultPosEnum::RIG_ELEMENT_NODAL, "POR-Bar", view()->cellResult()->resultComponentName().toStdString()); + RigGeoMechCaseData* caseData = geoMechCase()->geoMechData(); + RigFemPartResultsCollection* resultCollection = caseData->femPartResults(); + + const std::vector& resultValues = resultCollection->resultValues(porBarAddr, 0, timeStep); + + cvf::BoundingBox boundingBox; + for (int i = 0; i < m_femPart->elementCount(); ++i) + { + size_t resValueIdx = m_femPart->elementNodeResultIdx((int)i, 0); + CVF_ASSERT(resValueIdx < resultValues.size()); + double scalarValue = resultValues[resValueIdx]; + bool validPorValue = scalarValue != std::numeric_limits::infinity(); + + if (validPorValue) + { + std::array hexCorners; + m_femPartGrid->cellCornerVertices(i, hexCorners.data()); + for (size_t c = 0; c < 8; ++c) + { + boundingBox.add(hexCorners[c]); + } + } + } + cvf::Vec3d boxMin = boundingBox.min(); + cvf::Vec3d boxMax = boundingBox.max(); + cvf::Vec3d boxExtent = boundingBox.extent(); + boxMin.x() -= boxExtent.x() * 0.5 * m_paddingAroundPorePressureRegion(); + boxMin.y() -= boxExtent.y() * 0.5 * m_paddingAroundPorePressureRegion(); + boxMax.x() += boxExtent.x() * 0.5 * m_paddingAroundPorePressureRegion(); + boxMax.y() += boxExtent.y() * 0.5 * m_paddingAroundPorePressureRegion(); + return cvf::BoundingBox(boxMin, boxMax); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimGeoMechContourMapProjection::updateGridInformation() +{ + RimGeoMechCase* geoMechCase = this->geoMechCase(); + m_femPart = geoMechCase->geoMechData()->femParts()->part(0); + m_femPartGrid = m_femPart->getOrCreateStructGrid(); + m_sampleSpacing = m_relativeSampleSpacing * geoMechCase->characteristicCellSize(); + m_femPart->ensureIntersectionSearchTreeIsBuilt(); + + m_gridBoundingBox = geoMechCase->activeCellsBoundingBox(); + + if (m_limitToPorePressureRegions) + { + m_expandedBoundingBox = calculateExpandedPorBarBBox(view()->currentTimeStep()); + } + else + { + m_expandedBoundingBox = m_gridBoundingBox; + } + cvf::Vec3d minExpandedPoint = m_expandedBoundingBox.min() - cvf::Vec3d(gridEdgeOffset(), gridEdgeOffset(), 0.0); + cvf::Vec3d maxExpandedPoint = m_expandedBoundingBox.max() + cvf::Vec3d(gridEdgeOffset(), gridEdgeOffset(), 0.0); + if (m_limitToPorePressureRegions && !m_applyPPRegionLimitVertically) + { + minExpandedPoint.z() = m_gridBoundingBox.min().z(); + maxExpandedPoint.z() = m_gridBoundingBox.max().z(); + } + m_expandedBoundingBox = cvf::BoundingBox(minExpandedPoint, maxExpandedPoint); + + m_mapSize = calculateMapSize(); + + // Re-jig max point to be an exact multiple of cell size + cvf::Vec3d minPoint = m_expandedBoundingBox.min(); + cvf::Vec3d maxPoint = m_expandedBoundingBox.max(); + maxPoint.x() = minPoint.x() + m_mapSize.x() * m_sampleSpacing; + maxPoint.y() = minPoint.y() + m_mapSize.y() * m_sampleSpacing; + m_expandedBoundingBox = cvf::BoundingBox(minPoint, maxPoint); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector RimGeoMechContourMapProjection::getMapCellVisibility() +{ + cvf::Vec2ui nCellsIJ = numberOfElementsIJ(); + std::vector> distanceImage (nCellsIJ.x(), std::vector(nCellsIJ.y(), 0u)); + + std::vector mapCellVisibility; + RigFemResultAddress resAddr = view()->cellResult()->resultAddress(); + + if (m_limitToPorePressureRegions) + { + resAddr = RigFemResultAddress(RigFemResultPosEnum::RIG_ELEMENT_NODAL, "POR-Bar", ""); + } + + std::vector cellResults = generateResultsFromAddress(resAddr, mapCellVisibility, view()->currentTimeStep()); + + mapCellVisibility.resize(numberOfCells(), true); + CVF_ASSERT(mapCellVisibility.size() == cellResults.size()); + + { + cvf::BoundingBox validResBoundingBox; + for (size_t cellIndex = 0; cellIndex < cellResults.size(); ++cellIndex) + { + cvf::Vec2ui ij = ijFromCellIndex(cellIndex); + if (cellResults[cellIndex] != std::numeric_limits::infinity()) + { + distanceImage[ij.x()][ij.y()] = 1u; + validResBoundingBox.add(cvf::Vec3d(cellCenterPosition(ij.x(), ij.y()), 0.0)); + } + else + { + mapCellVisibility[cellIndex] = false; + } + } + + if (m_limitToPorePressureRegions && m_paddingAroundPorePressureRegion > 0.0) + { + RiaImageTools::distanceTransform2d(distanceImage); + + cvf::Vec3d porExtent = validResBoundingBox.extent(); + double radius = std::max(porExtent.x(), porExtent.y()) * 0.25; + double expansion = m_paddingAroundPorePressureRegion * radius; + size_t cellPadding = std::ceil(expansion / m_sampleSpacing); + for (size_t cellIndex = 0; cellIndex < cellResults.size(); ++cellIndex) + { + if (!mapCellVisibility[cellIndex]) + { + cvf::Vec2ui ij = ijFromCellIndex(cellIndex); + if (distanceImage[ij.x()][ij.y()] < cellPadding * cellPadding) + { + mapCellVisibility[cellIndex] = true; + } + } + } + } + } + return mapCellVisibility; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector RimGeoMechContourMapProjection::retrieveParameterWeights() +{ + return std::vector(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector RimGeoMechContourMapProjection::generateResults(int timeStep) +{ + RimGeoMechCellColors* cellColors = view()->cellResult(); + RigFemResultAddress resultAddress = cellColors->resultAddress(); + + std::vector aggregatedResults = generateResultsFromAddress(resultAddress, m_mapCellVisibility, timeStep); + + return aggregatedResults; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector RimGeoMechContourMapProjection::generateResultsFromAddress(RigFemResultAddress resultAddress, const std::vector& mapCellVisibility, int timeStep) +{ + RigGeoMechCaseData* caseData = geoMechCase()->geoMechData(); + RigFemPartResultsCollection* resultCollection = caseData->femPartResults(); + size_t nCells = numberOfCells(); + std::vector aggregatedResults = std::vector(nCells, std::numeric_limits::infinity()); + + bool wasInvalid = false; + if (!resultAddress.isValid()) + { + wasInvalid = true; + resultAddress = RigFemResultAddress(RigFemResultPosEnum::RIG_ELEMENT_NODAL, "POR-Bar", ""); + } + + if (resultAddress.fieldName == "PP") + { + resultAddress.fieldName = "POR-Bar"; // More likely to be in memory than POR + } + if (resultAddress.fieldName == "POR-Bar") + { + resultAddress.resultPosType = RIG_ELEMENT_NODAL; + } + else if (resultAddress.resultPosType == RIG_FORMATION_NAMES) + { + resultAddress.resultPosType = RIG_ELEMENT_NODAL; // formation indices are stored per element node result. + } + + std::vector resultValuesF = resultCollection->resultValues(resultAddress, 0, timeStep); + std::vector resultValues = gridCellValues(resultAddress, resultValuesF); + + if (wasInvalid) + { + // For invalid result addresses we just use the POR-Bar result to get the reservoir region + // And display a dummy 0-result in the region. + for (double& value : resultValues) + { + if (value != std::numeric_limits::infinity()) + { + value = 0.0; + } + } + } + +#pragma omp parallel for + for (int index = 0; index < static_cast(nCells); ++index) + { + if (mapCellVisibility.empty() || mapCellVisibility[index]) + { + cvf::Vec2ui ij = ijFromCellIndex(index); + aggregatedResults[index] = calculateValueInMapCell(ij.x(), ij.y(), resultValues); + } + } + + return aggregatedResults; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RimGeoMechContourMapProjection::resultVariableChanged() const +{ + RimGeoMechCellColors* cellColors = view()->cellResult(); + RigFemResultAddress resAddr = cellColors->resultAddress(); + + if (resAddr.fieldName == "PP") + { + resAddr.fieldName = "POR-Bar"; // More likely to be in memory than POR + } + if (resAddr.fieldName == "POR-Bar") resAddr.resultPosType = RIG_ELEMENT_NODAL; + + return !(m_currentResultAddr == resAddr); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimGeoMechContourMapProjection::clearResultVariable() +{ + m_currentResultAddr = RigFemResultAddress(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimGridView* RimGeoMechContourMapProjection::baseView() const +{ + return view(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector RimGeoMechContourMapProjection::findIntersectingCells(const cvf::BoundingBox& bbox) const +{ + std::vector allCellIndices; + m_femPart->findIntersectingCellsWithExistingSearchTree(bbox, &allCellIndices); + return allCellIndices; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +size_t RimGeoMechContourMapProjection::kLayer(size_t globalCellIdx) const +{ + size_t i, j, k; + m_femPartGrid->ijkFromCellIndex(globalCellIdx, &i, &j, &k); + return k; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +double RimGeoMechContourMapProjection::calculateOverlapVolume(size_t globalCellIdx, + const cvf::BoundingBox& bbox) const +{ + std::array hexCorners; + m_femPartGrid->cellCornerVertices(globalCellIdx, hexCorners.data()); + + cvf::BoundingBox overlapBBox; + std::array overlapCorners; + if (RigCellGeometryTools::estimateHexOverlapWithBoundingBox(hexCorners, bbox, &overlapCorners, &overlapBBox)) + { + double overlapVolume = RigCellGeometryTools::calculateCellVolume(overlapCorners); + return overlapVolume; + } + return 0.0; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +double RimGeoMechContourMapProjection::calculateRayLengthInCell(size_t globalCellIdx, + const cvf::Vec3d& highestPoint, + const cvf::Vec3d& lowestPoint) const +{ + std::array hexCorners; + + const std::vector& nodeCoords = m_femPart->nodes().coordinates; + const int* cornerIndices = m_femPart->connectivities(globalCellIdx); + + hexCorners[0] = cvf::Vec3d(nodeCoords[cornerIndices[0]]); + hexCorners[1] = cvf::Vec3d(nodeCoords[cornerIndices[1]]); + hexCorners[2] = cvf::Vec3d(nodeCoords[cornerIndices[2]]); + hexCorners[3] = cvf::Vec3d(nodeCoords[cornerIndices[3]]); + hexCorners[4] = cvf::Vec3d(nodeCoords[cornerIndices[4]]); + hexCorners[5] = cvf::Vec3d(nodeCoords[cornerIndices[5]]); + hexCorners[6] = cvf::Vec3d(nodeCoords[cornerIndices[6]]); + hexCorners[7] = cvf::Vec3d(nodeCoords[cornerIndices[7]]); + + std::vector intersections; + + if (RigHexIntersectionTools::lineHexCellIntersection(highestPoint, lowestPoint, hexCorners.data(), 0, &intersections)) + { + double lengthInCell = (intersections.back().m_intersectionPoint - intersections.front().m_intersectionPoint).length(); + return lengthInCell; + } + return 0.0; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +double RimGeoMechContourMapProjection::getParameterWeightForCell(size_t globalCellIdx, + const std::vector& parameterWeights) const +{ + if (parameterWeights.empty()) return 1.0; + + return parameterWeights[globalCellIdx]; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector RimGeoMechContourMapProjection::gridCellValues(RigFemResultAddress resAddr, std::vector& resultValues) const +{ + std::vector gridCellValues(m_femPart->elementCount(), std::numeric_limits::infinity()); + for (size_t globalCellIdx = 0; globalCellIdx < static_cast(m_femPart->elementCount()); ++globalCellIdx) + { + RigElementType elmType = m_femPart->elementType(globalCellIdx); + if (!(elmType == HEX8 || elmType == HEX8P)) continue; + + if (resAddr.resultPosType == RIG_ELEMENT) + { + gridCellValues[globalCellIdx] = static_cast(resultValues[globalCellIdx]); + } + else if (resAddr.resultPosType == RIG_ELEMENT_NODAL) + { + RiaWeightedMeanCalculator cellAverage; + for (int i = 0; i < 8; ++i) + { + size_t gridResultValueIdx = + m_femPart->resultValueIdxFromResultPosType(resAddr.resultPosType, static_cast(globalCellIdx), i); + cellAverage.addValueAndWeight(resultValues[gridResultValueIdx], 1.0); + } + + gridCellValues[globalCellIdx] = static_cast(cellAverage.weightedMean()); + } + else + { + RiaWeightedMeanCalculator cellAverage; + const int* elmNodeIndices = m_femPart->connectivities(globalCellIdx); + for (int i = 0; i < 8; ++i) + { + cellAverage.addValueAndWeight(resultValues[elmNodeIndices[i]], 1.0); + } + gridCellValues[globalCellIdx] = static_cast(cellAverage.weightedMean()); + } + } + return gridCellValues; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimGeoMechCase* RimGeoMechContourMapProjection::geoMechCase() const +{ + RimGeoMechCase* geoMechCase = nullptr; + firstAncestorOrThisOfType(geoMechCase); + return geoMechCase; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimGeoMechContourMapView* RimGeoMechContourMapProjection::view() const +{ + RimGeoMechContourMapView* view = nullptr; + firstAncestorOrThisOfTypeAsserted(view); + return view; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimGeoMechContourMapProjection::fieldChangedByUi(const caf::PdmFieldHandle* changedField, + const QVariant& oldValue, + const QVariant& newValue) +{ + RimContourMapProjection::fieldChangedByUi(changedField, oldValue, newValue); + if (changedField == &m_limitToPorePressureRegions || changedField == &m_applyPPRegionLimitVertically || + changedField == &m_paddingAroundPorePressureRegion) + { + clearGridMapping(); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QList + RimGeoMechContourMapProjection::calculateValueOptions(const caf::PdmFieldHandle* fieldNeedingOptions, bool* useOptionsOnly) +{ + QList options; + + if (fieldNeedingOptions == &m_resultAggregation) + { + std::vector validOptions = {RESULTS_TOP_VALUE, + RESULTS_MEAN_VALUE, + RESULTS_GEOM_VALUE, + RESULTS_HARM_VALUE, + RESULTS_MIN_VALUE, + RESULTS_MAX_VALUE, + RESULTS_SUM}; + + for (ResultAggregationEnum option : validOptions) + { + options.push_back(caf::PdmOptionItemInfo(ResultAggregation::uiText(option), option)); + } + } + return options; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimGeoMechContourMapProjection::defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering) +{ + RimContourMapProjection::defineUiOrdering(uiConfigName, uiOrdering); + caf::PdmUiGroup* group = uiOrdering.addNewGroup("Map Boundaries"); + group->add(&m_limitToPorePressureRegions); + group->add(&m_applyPPRegionLimitVertically); + group->add(&m_paddingAroundPorePressureRegion); + m_applyPPRegionLimitVertically.uiCapability()->setUiReadOnly(!m_limitToPorePressureRegions()); + m_paddingAroundPorePressureRegion.uiCapability()->setUiReadOnly(!m_limitToPorePressureRegions()); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimGeoMechContourMapProjection::defineEditorAttribute(const caf::PdmFieldHandle* field, + QString uiConfigName, + caf::PdmUiEditorAttribute* attribute) +{ + RimContourMapProjection::defineEditorAttribute(field, uiConfigName, attribute); + if (field == &m_paddingAroundPorePressureRegion) + { + caf::PdmUiDoubleSliderEditorAttribute* myAttr = dynamic_cast(attribute); + if (myAttr) + { + myAttr->m_minimum = 0.0; + myAttr->m_maximum = 2.0; + myAttr->m_sliderTickCount = 4; + myAttr->m_delaySliderUpdateUntilRelease = true; + } + } +} + diff --git a/ApplicationCode/ProjectDataModel/RimGeoMechContourMapProjection.h b/ApplicationCode/ProjectDataModel/RimGeoMechContourMapProjection.h new file mode 100644 index 0000000000..258650c312 --- /dev/null +++ b/ApplicationCode/ProjectDataModel/RimGeoMechContourMapProjection.h @@ -0,0 +1,101 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2018- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "RigFemPart.h" +#include "RigFemResultAddress.h" + +#include "RimCheckableNamedObject.h" +#include "RimContourMapProjection.h" +#include "RimGeoMechCase.h" +#include "RimRegularLegendConfig.h" + +#include "cafDisplayCoordTransform.h" +#include "cafPdmChildField.h" +#include "cafPdmField.h" +#include "cafPdmObject.h" + +#include "cvfArray.h" +#include "cvfBoundingBox.h" +#include "cvfGeometryBuilderFaceList.h" +#include "cvfString.h" +#include "cvfVector2.h" + +class RimGeoMechContourMapView; + +//================================================================================================== +/// +/// +//================================================================================================== +class RimGeoMechContourMapProjection : public RimContourMapProjection +{ + CAF_PDM_HEADER_INIT; +public: + + RimGeoMechContourMapProjection(); + ~RimGeoMechContourMapProjection() override; + + // GeoMech case overrides for contour map methods + QString resultDescriptionText() const override; + RimRegularLegendConfig* legendConfig() const override; + void updateLegend() override; + +protected: + typedef RimContourMapProjection::CellIndexAndResult CellIndexAndResult; + + // GeoMech implementation specific data generation methods + cvf::ref getCellVisibility() const override; + cvf::BoundingBox calculateExpandedPorBarBBox(int timeStep) const; + void updateGridInformation() override; + std::vector getMapCellVisibility() override; + std::vector retrieveParameterWeights() override; + std::vector generateResults(int timeStep) override; + std::vector generateResultsFromAddress(RigFemResultAddress resultAddress, const std::vector& mapCellVisibility, int timeStep); + bool resultVariableChanged() const override; + void clearResultVariable() override; + RimGridView* baseView() const override; + std::vector findIntersectingCells(const cvf::BoundingBox& bbox) const override; + size_t kLayer(size_t globalCellIdx) const override; + double calculateOverlapVolume(size_t globalCellIdx, const cvf::BoundingBox& bbox) const override; + double calculateRayLengthInCell(size_t globalCellIdx, const cvf::Vec3d& highestPoint, const cvf::Vec3d& lowestPoint) const override; + double getParameterWeightForCell(size_t globalCellIdx, const std::vector& parameterWeights) const override; + std::vector gridCellValues(RigFemResultAddress resAddr, std::vector& resultValues) const; + RimGeoMechCase* geoMechCase() const; + RimGeoMechContourMapView* view() const; + +protected: + // Framework overrides + void fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue) override; + QList calculateValueOptions(const caf::PdmFieldHandle* fieldNeedingOptions, + bool* useOptionsOnly) override; + void defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering) override; + void defineEditorAttribute(const caf::PdmFieldHandle* field, + QString uiConfigName, + caf::PdmUiEditorAttribute* attribute) override; + +protected: + caf::PdmField m_limitToPorePressureRegions; + caf::PdmField m_applyPPRegionLimitVertically; + caf::PdmField m_paddingAroundPorePressureRegion; + cvf::ref m_femPart; + cvf::cref m_femPartGrid; + RigFemResultAddress m_currentResultAddr; +}; + + diff --git a/ApplicationCode/ProjectDataModel/RimGeoMechContourMapView.cpp b/ApplicationCode/ProjectDataModel/RimGeoMechContourMapView.cpp new file mode 100644 index 0000000000..394de6d0f0 --- /dev/null +++ b/ApplicationCode/ProjectDataModel/RimGeoMechContourMapView.cpp @@ -0,0 +1,496 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2018- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// +#include "RimGeoMechContourMapView.h" +#include "RivContourMapProjectionPartMgr.h" +#include "RiuViewer.h" + +#include "Rim3dOverlayInfoConfig.h" +#include "RimCase.h" +#include "RimCellRangeFilterCollection.h" +#include "RimGeoMechCellColors.h" +#include "RimGeoMechContourMapProjection.h" +#include "RimGeoMechPropertyFilterCollection.h" +#include "RimGridCollection.h" +#include "RimScaleLegendConfig.h" +#include "RimSimWellInViewCollection.h" +#include "RimViewNameConfig.h" + +#include "cafPdmUiTreeOrdering.h" +#include "cafProgressInfo.h" + +#include "cvfCamera.h" +#include "cvfModelBasicList.h" +#include "cvfPart.h" +#include "cvfScene.h" + +CAF_PDM_SOURCE_INIT(RimGeoMechContourMapView, "RimGeoMechContourMapView"); + + +const cvf::Mat4d RimGeoMechContourMapView::sm_defaultViewMatrix = cvf::Mat4d(1, 0, 0, 0, + 0, 1, 0, 0, + 0, 0, 1, 1000, + 0, 0, 0, 1); + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimGeoMechContourMapView::RimGeoMechContourMapView() + : m_cameraPositionLastUpdate(cvf::Vec3d::UNDEFINED) +{ + CAF_PDM_InitObject("GeoMech Contour Map View", ":/2DMap16x16.png", "", ""); + + CAF_PDM_InitFieldNoDefault(&m_contourMapProjection, "ContourMapProjection", "Contour Map Projection", "", "", ""); + m_contourMapProjection = new RimGeoMechContourMapProjection(); + + CAF_PDM_InitField(&m_showAxisLines, "ShowAxisLines", true, "Show Axis Lines", "", "", ""); + CAF_PDM_InitField(&m_showScaleLegend, "ShowScaleLegend", true, "Show Scale Legend", "", "", ""); + + m_gridCollection->setActive(false); // This is also not added to the tree view, so cannot be enabled. + + setDefaultCustomName(); + + m_contourMapProjectionPartMgr = new RivContourMapProjectionPartMgr(contourMapProjection(), this); + + ((RiuViewerToViewInterface*)this)->setCameraPosition(sm_defaultViewMatrix); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimGeoMechContourMapProjection* RimGeoMechContourMapView::contourMapProjection() const +{ + return m_contourMapProjection().p(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RimGeoMechContourMapView::createAutoName() const +{ + QStringList autoName; + + if (!nameConfig()->customName().isEmpty()) + { + autoName.push_back(nameConfig()->customName()); + } + + QStringList generatedAutoTags; + + RimCase* ownerCase = nullptr; + this->firstAncestorOrThisOfTypeAsserted(ownerCase); + + if (nameConfig()->addCaseName()) + { + generatedAutoTags.push_back(ownerCase->caseUserDescription()); + } + + if (nameConfig()->addAggregationType()) + { + generatedAutoTags.push_back(contourMapProjection()->resultAggregationText()); + } + + if (nameConfig()->addProperty() && !contourMapProjection()->isColumnResult()) + { + generatedAutoTags.push_back(cellResult()->resultFieldUiName()); + } + + if (nameConfig()->addSampleSpacing()) + { + generatedAutoTags.push_back(QString("%1").arg(contourMapProjection()->sampleSpacingFactor(), 3, 'f', 2)); + } + + if (!generatedAutoTags.empty()) + { + autoName.push_back(generatedAutoTags.join(", ")); + } + return autoName.join(": "); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimGeoMechContourMapView::setDefaultCustomName() +{ + nameConfig()->setCustomName("Contour Map"); + nameConfig()->hideCaseNameField(false); + nameConfig()->hideAggregationTypeField(false); + nameConfig()->hidePropertyField(false); + nameConfig()->hideSampleSpacingField(false); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimGeoMechContourMapView::updatePickPointAndRedraw() +{ + appendPickPointVisToModel(); + if (m_viewer) + { + m_viewer->update(); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimGeoMechContourMapView::updateCurrentTimeStepAndRedraw() +{ + m_contourMapProjection->clearGeometry(); + RimGeoMechView::updateCurrentTimeStepAndRedraw(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RimGeoMechContourMapView::isGridVisualizationMode() const +{ + return m_contourMapProjection->isChecked(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RimGeoMechContourMapView::isTimeStepDependentDataVisible() const +{ + return true; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimGeoMechContourMapView::initAfterRead() +{ + m_gridCollection->setActive(false); // This is also not added to the tree view, so cannot be enabled. + disablePerspectiveProjectionField(); + setShowGridBox(false); + meshMode.setValue(RiaDefines::NO_MESH); + surfaceMode.setValue(FAULTS); + scheduleCreateDisplayModelAndRedraw(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimGeoMechContourMapView::createDisplayModel() +{ + RimGeoMechView::createDisplayModel(); + + if (!this->isTimeStepDependentDataVisible()) + { + // Need to add geometry even if it hasn't happened during dynamic time step update. + updateGeometry(); + } + + if (this->viewer()->mainCamera()->viewMatrix() == sm_defaultViewMatrix) + { + this->zoomAll(); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimGeoMechContourMapView::defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering) +{ + caf::PdmUiGroup* viewGroup = uiOrdering.addNewGroup("Viewer"); + viewGroup->add(this->userDescriptionField()); + viewGroup->add(this->backgroundColorField()); + viewGroup->add(&m_showAxisLines); + viewGroup->add(&m_showScaleLegend); + + caf::PdmUiGroup* nameGroup = uiOrdering.addNewGroup("Contour Map Name"); + nameConfig()->uiOrdering(uiConfigName, *nameGroup); + + uiOrdering.skipRemainingFields(true); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimGeoMechContourMapView::defineUiTreeOrdering(caf::PdmUiTreeOrdering& uiTreeOrdering, QString uiConfigName /*= ""*/) +{ + uiTreeOrdering.add(m_overlayInfoConfig()); + uiTreeOrdering.add(m_contourMapProjection); + uiTreeOrdering.add(cellResult()); + cellResult()->uiCapability()->setUiReadOnly(m_contourMapProjection->isColumnResult()); + uiTreeOrdering.add(m_rangeFilterCollection()); + uiTreeOrdering.add(nativePropertyFilterCollection()); + + uiTreeOrdering.skipRemainingChildren(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimGeoMechContourMapView::updateCurrentTimeStep() +{ + updateGeometry(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimGeoMechContourMapView::updateGeometry() +{ + caf::ProgressInfo progress(100, "Generate Contour Map", true); + + { // Step 1: generate results. About 30% of the time. + if (m_contourMapProjection->isChecked()) + { + m_contourMapProjection->generateResultsIfNecessary(m_currentTimeStep()); + } + updateLegends(); + + progress.setProgress(30); + } + + { // Step 2: generate geometry. Takes about 60% of the time. + createContourMapGeometry(); + progress.setProgress(90); + } + + { // Step 3: generate drawables. About 10% of the time. + appendContourMapProjectionToModel(); + appendContourLinesToModel(); + appendPickPointVisToModel(); + progress.setProgress(100); + } + m_overlayInfoConfig->update3DInfo(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimGeoMechContourMapView::createContourMapGeometry() +{ + if (m_viewer && m_contourMapProjection->isChecked()) + { + m_contourMapProjectionPartMgr->createProjectionGeometry(); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimGeoMechContourMapView::appendContourMapProjectionToModel() +{ + if (m_viewer && m_contourMapProjection->isChecked()) + { + cvf::Scene* frameScene = m_viewer->frame(m_currentTimeStep); + if (frameScene) + { + cvf::String name = "ContourMapProjection"; + this->removeModelByName(frameScene, name); + + cvf::ref contourMapProjectionModelBasicList = new cvf::ModelBasicList; + contourMapProjectionModelBasicList->setName(name); + + cvf::ref transForm = this->displayCoordTransform(); + + m_contourMapProjectionPartMgr->appendProjectionToModel(contourMapProjectionModelBasicList.p(), transForm.p()); + contourMapProjectionModelBasicList->updateBoundingBoxesRecursive(); + frameScene->addModel(contourMapProjectionModelBasicList.p()); + } + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimGeoMechContourMapView::appendContourLinesToModel() +{ + if (m_viewer && m_contourMapProjection->isChecked()) + { + cvf::Scene* frameScene = m_viewer->frame(m_currentTimeStep); + if (frameScene) + { + cvf::String name = "ContourMapLines"; + this->removeModelByName(frameScene, name); + + cvf::ref contourMapLabelModelBasicList = new cvf::ModelBasicList; + contourMapLabelModelBasicList->setName(name); + + cvf::ref transForm = this->displayCoordTransform(); + + m_contourMapProjectionPartMgr->appendContourLinesToModel( + viewer()->mainCamera(), contourMapLabelModelBasicList.p(), transForm.p()); + contourMapLabelModelBasicList->updateBoundingBoxesRecursive(); + frameScene->addModel(contourMapLabelModelBasicList.p()); + } + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimGeoMechContourMapView::appendPickPointVisToModel() +{ + if (m_viewer && m_contourMapProjection->isChecked()) + { + cvf::Scene* frameScene = m_viewer->frame(m_currentTimeStep); + if (frameScene) + { + cvf::String name = "ContourMapPickPoint"; + this->removeModelByName(frameScene, name); + + cvf::ref contourMapProjectionModelBasicList = new cvf::ModelBasicList; + contourMapProjectionModelBasicList->setName(name); + + cvf::ref transForm = this->displayCoordTransform(); + + m_contourMapProjectionPartMgr->appendPickPointVisToModel(contourMapProjectionModelBasicList.p(), transForm.p()); + contourMapProjectionModelBasicList->updateBoundingBoxesRecursive(); + frameScene->addModel(contourMapProjectionModelBasicList.p()); + } + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimGeoMechContourMapView::updateLegends() +{ + if (m_viewer) + { + m_viewer->removeAllColorLegends(); + + if (m_contourMapProjection && m_contourMapProjection->isChecked()) + { + RimRegularLegendConfig* projectionLegend = m_contourMapProjection->legendConfig(); + if (projectionLegend) + { + m_contourMapProjection->updateLegend(); + if (projectionLegend->showLegend()) + { + m_viewer->addColorLegendToBottomLeftCorner(projectionLegend->titledOverlayFrame()); + } + } + } + + m_viewer->showScaleLegend(m_showScaleLegend()); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimGeoMechContourMapView::updateViewWidgetAfterCreation() +{ + if (m_viewer) + { + m_viewer->showAxisCross(false); + m_viewer->showEdgeTickMarksXY(true, m_showAxisLines()); + m_viewer->enableNavigationRotation(false); + } + + Rim3dView::updateViewWidgetAfterCreation(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimGeoMechContourMapView::updateViewFollowingRangeFilterUpdates() +{ + m_contourMapProjection->setCheckState(true); + scheduleCreateDisplayModelAndRedraw(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimGeoMechContourMapView::onLoadDataAndUpdate() +{ + RimGeoMechView::onLoadDataAndUpdate(); + if (m_viewer) + { + m_viewer->setView(cvf::Vec3d(0, 0, -1), cvf::Vec3d(0, 1, 0)); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimGeoMechContourMapView::fieldChangedByUi(const caf::PdmFieldHandle* changedField, + const QVariant& oldValue, + const QVariant& newValue) +{ + RimGeoMechView::fieldChangedByUi(changedField, oldValue, newValue); + + if (changedField == &m_showAxisLines) + { + m_viewer->showEdgeTickMarksXY(true, m_showAxisLines()); + scheduleCreateDisplayModelAndRedraw(); + } + else if (changedField == backgroundColorField()) + { + scheduleCreateDisplayModelAndRedraw(); + } + else if (changedField == &m_showScaleLegend) + { + updateLegends(); + scheduleCreateDisplayModelAndRedraw(); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +caf::PdmFieldHandle* RimGeoMechContourMapView::userDescriptionField() +{ + return nameConfig()->nameField(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QWidget* RimGeoMechContourMapView::createViewWidget(QWidget* mainWindowParent) +{ + auto widget = Rim3dView::createViewWidget(mainWindowParent); + + if (viewer()) + { + viewer()->showZScaleLabel(false); + viewer()->hideZScaleCheckbox(true); + } + return widget; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimGeoMechContourMapView::onViewNavigationChanged() +{ + cvf::Vec3d currentCameraPosition = viewer()->mainCamera()->position(); + if (m_cameraPositionLastUpdate.isUndefined() || zoomChangeAboveTreshold(currentCameraPosition)) + { + appendContourLinesToModel(); + m_cameraPositionLastUpdate = currentCameraPosition; + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RimGeoMechContourMapView::zoomChangeAboveTreshold(const cvf::Vec3d& currentCameraPosition) const +{ + double distance = std::max(std::fabs(m_cameraPositionLastUpdate.z()), std::fabs(currentCameraPosition.z())); + const double threshold = 0.05 * distance; + return std::fabs(m_cameraPositionLastUpdate.z() - currentCameraPosition.z()) > threshold; +} + + diff --git a/ApplicationCode/ProjectDataModel/RimGeoMechContourMapView.h b/ApplicationCode/ProjectDataModel/RimGeoMechContourMapView.h new file mode 100644 index 0000000000..208aaa9ef0 --- /dev/null +++ b/ApplicationCode/ProjectDataModel/RimGeoMechContourMapView.h @@ -0,0 +1,79 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2018- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "RimGeoMechView.h" +#include "RimNameConfig.h" + +class RimGeoMechContourMapProjection; +class RimViewNameConfig; +class RimScaleLegendConfig; +class RivContourMapProjectionPartMgr; + +class RimGeoMechContourMapView : public RimGeoMechView +{ + CAF_PDM_HEADER_INIT; + +public: + RimGeoMechContourMapView(); + RimGeoMechContourMapProjection* contourMapProjection() const; + + QString createAutoName() const override; + void setDefaultCustomName(); + void updatePickPointAndRedraw(); + void updateCurrentTimeStepAndRedraw() override; + bool isGridVisualizationMode() const override; + + bool isTimeStepDependentDataVisible() const override; + +protected: + void initAfterRead() override; + void createDisplayModel() override; + void defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering) override; + void defineUiTreeOrdering(caf::PdmUiTreeOrdering& uiTreeOrdering, QString uiConfigName = "") override; + void updateCurrentTimeStep() override; + void updateGeometry(); + void createContourMapGeometry(); + void appendContourMapProjectionToModel(); + void appendContourLinesToModel(); + void appendPickPointVisToModel(); + void updateLegends() override; + void updateViewWidgetAfterCreation() override; + void updateViewFollowingRangeFilterUpdates() override; + void onLoadDataAndUpdate() override; + void fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue) override; + + caf::PdmFieldHandle* userDescriptionField() override; + + QWidget* createViewWidget(QWidget* mainWindowParent) override; + + void onViewNavigationChanged() override; + + bool zoomChangeAboveTreshold(const cvf::Vec3d& currentCameraPosition) const; + +private: + cvf::ref m_contourMapProjectionPartMgr; + caf::PdmChildField m_contourMapProjection; + caf::PdmField m_showAxisLines; + caf::PdmField m_showScaleLegend; + cvf::Vec3d m_cameraPositionLastUpdate; + + const static cvf::Mat4d sm_defaultViewMatrix; +}; + diff --git a/ApplicationCode/ProjectDataModel/RimGeoMechContourMapViewCollection.cpp b/ApplicationCode/ProjectDataModel/RimGeoMechContourMapViewCollection.cpp new file mode 100644 index 0000000000..69e3846559 --- /dev/null +++ b/ApplicationCode/ProjectDataModel/RimGeoMechContourMapViewCollection.cpp @@ -0,0 +1,38 @@ +#include "RimGeoMechContourMapViewCollection.h" + +#include "RimCase.h" +#include "RimGeoMechContourMapView.h" + +CAF_PDM_SOURCE_INIT(RimGeoMechContourMapViewCollection, "GeoMech2dViewCollection"); + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimGeoMechContourMapViewCollection::RimGeoMechContourMapViewCollection() +{ + CAF_PDM_InitObject("GeoMech Contour Maps", ":/2DMaps16x16.png", "", ""); + + CAF_PDM_InitFieldNoDefault(&m_contourMapViews, "GeoMechViews", "Contour Maps", ":/CrossSection16x16.png", "", ""); + m_contourMapViews.uiCapability()->setUiTreeHidden(true); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimGeoMechContourMapViewCollection::~RimGeoMechContourMapViewCollection() {} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector RimGeoMechContourMapViewCollection::views() +{ + return m_contourMapViews.childObjects(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimGeoMechContourMapViewCollection::push_back(RimGeoMechContourMapView* contourMap) +{ + m_contourMapViews.push_back(contourMap); +} diff --git a/ApplicationCode/ProjectDataModel/RimGeoMechContourMapViewCollection.h b/ApplicationCode/ProjectDataModel/RimGeoMechContourMapViewCollection.h new file mode 100644 index 0000000000..1212a60060 --- /dev/null +++ b/ApplicationCode/ProjectDataModel/RimGeoMechContourMapViewCollection.h @@ -0,0 +1,45 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2019- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "cafPdmChildArrayField.h" +#include "cafPdmField.h" +#include "cafPdmObject.h" + +class RimGeoMechContourMapView; + +class RimGeoMechContourMapViewCollection : public caf::PdmObject +{ + CAF_PDM_HEADER_INIT; + +public: + RimGeoMechContourMapViewCollection(); + ~RimGeoMechContourMapViewCollection() override; + + std::vector views(); + void push_back(RimGeoMechContourMapView* contourMap); + +private: + caf::PdmChildArrayField m_contourMapViews; +}; + + + + + diff --git a/ApplicationCode/ProjectDataModel/RimGeoMechPropertyFilter.cpp b/ApplicationCode/ProjectDataModel/RimGeoMechPropertyFilter.cpp index f15f5c1438..5b67a624c7 100644 --- a/ApplicationCode/ProjectDataModel/RimGeoMechPropertyFilter.cpp +++ b/ApplicationCode/ProjectDataModel/RimGeoMechPropertyFilter.cpp @@ -177,8 +177,7 @@ void RimGeoMechPropertyFilter::updateReadOnlyStateOfAllFields() // Include fields declared in RimResultDefinition objFields.push_back(&(resultDefinition->m_resultPositionTypeUiField)); objFields.push_back(&(resultDefinition->m_resultVariableUiField)); - objFields.push_back(&(resultDefinition->m_isTimeLapseResultUiField)); - objFields.push_back(&(resultDefinition->m_timeLapseBaseTimestepUiField)); + objFields.push_back(&(resultDefinition->m_timeLapseBaseTimestep)); for (size_t i = 0; i < objFields.size(); i++) { diff --git a/ApplicationCode/ProjectDataModel/RimGeoMechResultDefinition.cpp b/ApplicationCode/ProjectDataModel/RimGeoMechResultDefinition.cpp index a90c1d050b..98f5c66a15 100644 --- a/ApplicationCode/ProjectDataModel/RimGeoMechResultDefinition.cpp +++ b/ApplicationCode/ProjectDataModel/RimGeoMechResultDefinition.cpp @@ -1,6 +1,7 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2015- Statoil ASA +// Copyright (C) 2018- Equinor ASA +// Copyright (C) 2015-2018 Statoil ASA // Copyright (C) 2015- Ceetron Solutions AS // // ResInsight is free software: you can redistribute it and/or modify @@ -76,11 +77,7 @@ RimGeoMechResultDefinition::RimGeoMechResultDefinition(void) CAF_PDM_InitField(&m_resultComponentName, "ResultComponentName", QString(""), "Component", "", "", ""); m_resultComponentName.uiCapability()->setUiHidden(true); - CAF_PDM_InitField(&m_isTimeLapseResult, "IsTimeLapseResult", false, "TimeLapseResult", "", "", ""); - m_isTimeLapseResult.uiCapability()->setUiHidden(true); - - CAF_PDM_InitField(&m_timeLapseBaseTimestep, "TimeLapseBaseTimeStep", 0, "Base Time Step", "", "", ""); - m_timeLapseBaseTimestep.uiCapability()->setUiHidden(true); + CAF_PDM_InitField(&m_timeLapseBaseTimestep, "TimeLapseBaseTimeStep", RigFemResultAddress::noTimeLapseValue(), "Base Time Step", "", "", ""); CAF_PDM_InitField(&m_compactionRefLayer, "CompactionRefLayer", 0, "Compaction Ref Layer", "", "", ""); m_compactionRefLayer.uiCapability()->setUiHidden(true); @@ -91,18 +88,17 @@ RimGeoMechResultDefinition::RimGeoMechResultDefinition(void) CAF_PDM_InitField(&m_resultVariableUiField, "ResultVariableUI", QString(""), "Value", "", "", ""); m_resultVariableUiField.xmlCapability()->disableIO(); - CAF_PDM_InitField(&m_isTimeLapseResultUiField, "IsTimeLapseResultUI", false, "Enable Relative Result", "", "Use the difference with respect to a specific time step as the result variable to plot", ""); - m_isTimeLapseResultUiField.xmlCapability()->disableIO(); - - CAF_PDM_InitField(&m_timeLapseBaseTimestepUiField, "TimeLapseBaseTimeStepUI", 0, "Base Time Step", "", "", ""); - m_timeLapseBaseTimestepUiField.xmlCapability()->disableIO(); - m_resultVariableUiField.uiCapability()->setUiEditorTypeName(caf::PdmUiListEditor::uiEditorTypeName()); m_resultVariableUiField.uiCapability()->setUiLabelPosition(caf::PdmUiItemInfo::TOP); - CAF_PDM_InitField(&m_compactionRefLayerUiField, "CompactionRefLayerUi", (int)RigFemResultAddress::NO_COMPACTION, "Compaction Ref Layer", "", "The compaction is calculated with reference to this layer. Default layer is the topmost layer with POR", ""); + CAF_PDM_InitField(&m_compactionRefLayerUiField, "CompactionRefLayerUi", RigFemResultAddress::noCompactionValue(), "Compaction Ref Layer", "", "The compaction is calculated with reference to this layer. Default layer is the topmost layer with POR", ""); m_compactionRefLayerUiField.xmlCapability()->disableIO(); + // OBSOLETE FIELDS + CAF_PDM_InitField(&m_isTimeLapseResult_OBSOLETE, "IsTimeLapseResult", true, "TimeLapseResult", "", "", ""); + m_isTimeLapseResult_OBSOLETE.xmlCapability()->setIOWritable(false); + m_isTimeLapseResult_OBSOLETE.uiCapability()->setUiHidden(true); + m_isChangedByField = false; m_addWellPathDerivedResults = false; } @@ -123,12 +119,17 @@ void RimGeoMechResultDefinition::defineUiOrdering(QString uiConfigName, caf::Pdm uiOrdering.add(&m_resultPositionTypeUiField); uiOrdering.add(&m_resultVariableUiField); + QString valueLabel = "Value"; + if (m_timeLapseBaseTimestep != RigFemResultAddress::noTimeLapseValue()) + { + valueLabel += QString(" (%1)").arg(diffResultUiName()); + } + m_resultVariableUiField.uiCapability()->setUiName(valueLabel); + if ( m_resultPositionTypeUiField() != RIG_FORMATION_NAMES ) { - caf::PdmUiGroup * timeLapseGr = uiOrdering.addNewGroup("Relative Result Options"); - timeLapseGr->add(&m_isTimeLapseResultUiField); - if ( m_isTimeLapseResultUiField() ) - timeLapseGr->add(&m_timeLapseBaseTimestepUiField); + caf::PdmUiGroup * timeLapseGr = uiOrdering.addNewGroup("Difference Options"); + timeLapseGr->add(&m_timeLapseBaseTimestep); } if (m_resultPositionTypeUiField() == RIG_NODAL) @@ -136,7 +137,7 @@ void RimGeoMechResultDefinition::defineUiOrdering(QString uiConfigName, caf::Pdm caf::PdmUiGroup * compactionGroup = uiOrdering.addNewGroup("Compaction Options"); compactionGroup->add(&m_compactionRefLayerUiField); - if (m_compactionRefLayerUiField == (int)RigFemResultAddress::NO_COMPACTION) + if (m_compactionRefLayerUiField == RigFemResultAddress::noCompactionValue()) { if (m_geomCase && m_geomCase->geoMechData() ) { @@ -184,21 +185,15 @@ QList RimGeoMechResultDefinition::calculateValueOptions( QStringList uiVarNames; QStringList varNames; - bool isNeedingTimeLapseStrings = m_isTimeLapseResultUiField() && (m_resultPositionTypeUiField() != RIG_FORMATION_NAMES); - getUiAndResultVariableStringList(&uiVarNames, &varNames, fieldCompNames, isNeedingTimeLapseStrings, m_timeLapseBaseTimestepUiField); + getUiAndResultVariableStringList(&uiVarNames, &varNames, fieldCompNames); for (int oIdx = 0; oIdx < uiVarNames.size(); ++oIdx) { options.push_back(caf::PdmOptionItemInfo(uiVarNames[oIdx], varNames[oIdx])); } } - else if (&m_isTimeLapseResultUiField == fieldNeedingOptions) - { - //options.push_back(caf::PdmOptionItemInfo("Absolute", false)); - //options.push_back(caf::PdmOptionItemInfo("Time Lapse", true)); - } - else if (&m_timeLapseBaseTimestepUiField == fieldNeedingOptions) + else if (&m_timeLapseBaseTimestep == fieldNeedingOptions) { std::vector stepNames; if(m_geomCase->geoMechData()) @@ -206,9 +201,10 @@ QList RimGeoMechResultDefinition::calculateValueOptions( stepNames = m_geomCase->geoMechData()->femPartResults()->filteredStepNames(); } + options.push_back(caf::PdmOptionItemInfo(QString("Disabled"), RigFemResultAddress::noTimeLapseValue())); for (size_t stepIdx = 0; stepIdx < stepNames.size(); ++stepIdx) { - options.push_back(caf::PdmOptionItemInfo(QString::fromStdString(stepNames[stepIdx]), static_cast(stepIdx))); + options.push_back(caf::PdmOptionItemInfo(QString("%1 (#%2)").arg(QString::fromStdString(stepNames[stepIdx])).arg(stepIdx), static_cast(stepIdx))); } } else if (&m_compactionRefLayerUiField == fieldNeedingOptions) @@ -246,45 +242,27 @@ void RimGeoMechResultDefinition::fieldChangedByUi(const caf::PdmFieldHandle* cha if (&m_resultPositionTypeUiField == changedField) { - if (m_resultPositionTypeUiField() == RIG_WELLPATH_DERIVED) + if (m_resultPositionTypeUiField() == RIG_WELLPATH_DERIVED || m_resultPositionType() == RIG_FORMATION_NAMES) { - m_isTimeLapseResultUiField = false; - m_isTimeLapseResultUiField.uiCapability()->setUiReadOnly(true); - m_timeLapseBaseTimestepUiField.uiCapability()->setUiReadOnly(true); + m_timeLapseBaseTimestep = RigFemResultAddress::noTimeLapseValue(); + m_timeLapseBaseTimestep.uiCapability()->setUiReadOnly(true); } else - { - m_isTimeLapseResultUiField.uiCapability()->setUiReadOnly(false); - m_timeLapseBaseTimestepUiField.uiCapability()->setUiReadOnly(false); - } - } - - if (&m_isTimeLapseResultUiField == changedField) - { - m_isTimeLapseResult = m_isTimeLapseResultUiField; - if (m_isTimeLapseResult()) - { - if (m_timeLapseBaseTimestep() == RigFemResultAddress::NO_TIME_LAPSE) - { - m_timeLapseBaseTimestep = 0; - m_timeLapseBaseTimestepUiField = 0; - } + { + m_timeLapseBaseTimestep.uiCapability()->setUiReadOnly(false); } } if( &m_resultPositionTypeUiField == changedField - || &m_isTimeLapseResultUiField == changedField - || &m_timeLapseBaseTimestepUiField == changedField) + || &m_timeLapseBaseTimestep == changedField) { std::map > fieldCompNames = getResultMetaDataForUIFieldSetting(); QStringList uiVarNames; QStringList varNames; - bool isNeedingTimeLapseStrings = m_isTimeLapseResultUiField() && (m_resultPositionTypeUiField() != RIG_FORMATION_NAMES); - getUiAndResultVariableStringList(&uiVarNames, &varNames, fieldCompNames, isNeedingTimeLapseStrings, m_timeLapseBaseTimestepUiField); + + getUiAndResultVariableStringList(&uiVarNames, &varNames, fieldCompNames); if (m_resultPositionTypeUiField() == m_resultPositionType() - && m_isTimeLapseResultUiField() == m_isTimeLapseResult() - && m_timeLapseBaseTimestepUiField() == m_timeLapseBaseTimestep() && varNames.contains(composeFieldCompString(m_resultFieldName(), m_resultComponentName()))) { m_resultVariableUiField = composeFieldCompString(m_resultFieldName(), m_resultComponentName()); @@ -305,7 +283,7 @@ void RimGeoMechResultDefinition::fieldChangedByUi(const caf::PdmFieldHandle* cha this->firstAncestorOrThisOfType(rim3dWellLogCurve); - if (&m_resultVariableUiField == changedField || &m_compactionRefLayerUiField == changedField) + if (&m_resultVariableUiField == changedField || &m_compactionRefLayerUiField == changedField || &m_timeLapseBaseTimestep == changedField) { QStringList fieldComponentNames = m_resultVariableUiField().split(QRegExp("\\s+")); if (fieldComponentNames.size() > 0) @@ -316,8 +294,6 @@ void RimGeoMechResultDefinition::fieldChangedByUi(const caf::PdmFieldHandle* cha // Complete string of selected formation is stored in m_resultFieldName m_resultFieldName = m_resultVariableUiField(); m_resultComponentName = ""; - m_isTimeLapseResult = false; - m_timeLapseBaseTimestep = 0; } else { @@ -331,8 +307,6 @@ void RimGeoMechResultDefinition::fieldChangedByUi(const caf::PdmFieldHandle* cha m_resultComponentName = ""; } - m_isTimeLapseResult = m_isTimeLapseResultUiField(); - m_timeLapseBaseTimestep = m_timeLapseBaseTimestepUiField(); m_compactionRefLayer = m_compactionRefLayerUiField(); } @@ -416,9 +390,7 @@ std::map > RimGeoMechResultDefinition::get //-------------------------------------------------------------------------------------------------- void RimGeoMechResultDefinition::getUiAndResultVariableStringList(QStringList* uiNames, QStringList* variableNames, - const std::map >& fieldCompNames, - bool isTimeLapseResultList, - int baseFrameIdx) + const std::map >& fieldCompNames) { CVF_ASSERT(uiNames && variableNames); @@ -429,7 +401,7 @@ void RimGeoMechResultDefinition::getUiAndResultVariableStringList(QStringList* u if (resultFieldName == "E" || resultFieldName == "S" || resultFieldName == "POR") continue; // We will not show the native POR, Stress and Strain - QString resultFieldUiName = convertToUiResultFieldName(resultFieldName, isTimeLapseResultList, baseFrameIdx); + QString resultFieldUiName = convertToUiResultFieldName(resultFieldName); uiNames->push_back(resultFieldUiName); variableNames->push_back(resultFieldName); @@ -438,7 +410,7 @@ void RimGeoMechResultDefinition::getUiAndResultVariableStringList(QStringList* u for (compIt = fieldIt->second.begin(); compIt != fieldIt->second.end(); ++compIt) { QString resultCompName = QString::fromStdString(*compIt); - uiNames->push_back(" " + convertToUIComponentName(resultCompName, isTimeLapseResultList, baseFrameIdx)); + uiNames->push_back(" " + resultCompName); variableNames->push_back(composeFieldCompString(resultFieldName, resultCompName)); } } @@ -461,13 +433,17 @@ QString RimGeoMechResultDefinition::composeFieldCompString(const QString& result //-------------------------------------------------------------------------------------------------- void RimGeoMechResultDefinition::initAfterRead() { + if (!m_isTimeLapseResult_OBSOLETE()) + { + m_timeLapseBaseTimestep = RigFemResultAddress::noTimeLapseValue(); + } + m_resultPositionTypeUiField = m_resultPositionType; - m_resultVariableUiField = composeFieldCompString(m_resultFieldName(), m_resultComponentName()); - m_isTimeLapseResultUiField = m_isTimeLapseResult; - m_timeLapseBaseTimestepUiField = m_timeLapseBaseTimestep; - m_isTimeLapseResultUiField.uiCapability()->setUiReadOnly(resultPositionType() == RIG_WELLPATH_DERIVED); - m_timeLapseBaseTimestepUiField.uiCapability()->setUiReadOnly(resultPositionType() == RIG_WELLPATH_DERIVED); + m_resultVariableUiField = composeFieldCompString(m_resultFieldName(), m_resultComponentName()); m_compactionRefLayerUiField = m_compactionRefLayer; + + m_timeLapseBaseTimestep.uiCapability()->setUiReadOnly(resultPositionType() == RIG_WELLPATH_DERIVED); + } @@ -509,8 +485,8 @@ RigFemResultAddress RimGeoMechResultDefinition::resultAddress() const return RigFemResultAddress(resultPositionType(), resultFieldName().toStdString(), resultComponentName().toStdString(), - m_isTimeLapseResult() ? m_timeLapseBaseTimestep() : RigFemResultAddress::NO_TIME_LAPSE, - resultFieldName().toStdString() == RigFemPartResultsCollection::FIELD_NAME_COMPACTION ? m_compactionRefLayer() : RigFemResultAddress::NO_COMPACTION); + m_timeLapseBaseTimestep(), + resultFieldName().toStdString() == RigFemPartResultsCollection::FIELD_NAME_COMPACTION ? m_compactionRefLayer() : RigFemResultAddress::noCompactionValue()); } //-------------------------------------------------------------------------------------------------- @@ -545,6 +521,40 @@ QString RimGeoMechResultDefinition::resultComponentName() const return m_resultComponentName(); } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RimGeoMechResultDefinition::diffResultUiName() const +{ + QString diffResultString; + if (m_timeLapseBaseTimestep != RigFemResultAddress::noTimeLapseValue()) + { + if (m_geomCase->geoMechData()) + { + std::vector stepNames = m_geomCase->geoMechData()->femPartResults()->filteredStepNames(); + QString timeStepString = QString::fromStdString(stepNames[m_timeLapseBaseTimestep()]); + diffResultString += QString("Base Time Step: %1").arg(timeStepString); + } + } + return diffResultString; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RimGeoMechResultDefinition::diffResultUiShortName() const +{ + QString diffResultString; + if (m_timeLapseBaseTimestep != RigFemResultAddress::noTimeLapseValue()) + { + if (m_geomCase->geoMechData()) + { + diffResultString += QString("Base Time: #%1").arg(m_timeLapseBaseTimestep()); + } + } + return diffResultString; +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -576,7 +586,7 @@ bool RimGeoMechResultDefinition::hasResult() //-------------------------------------------------------------------------------------------------- QString RimGeoMechResultDefinition::resultFieldUiName() { - return convertToUiResultFieldName(m_resultFieldName(), m_isTimeLapseResult, m_timeLapseBaseTimestep); + return convertToUiResultFieldName(m_resultFieldName()); } //-------------------------------------------------------------------------------------------------- @@ -584,15 +594,13 @@ QString RimGeoMechResultDefinition::resultFieldUiName() //-------------------------------------------------------------------------------------------------- QString RimGeoMechResultDefinition::resultComponentUiName() { - return convertToUIComponentName(m_resultComponentName(), m_isTimeLapseResult, m_timeLapseBaseTimestep); + return m_resultComponentName(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -QString RimGeoMechResultDefinition::convertToUiResultFieldName(QString resultFieldName, - bool isTimeLapseResultList, - int baseFrameIdx) +QString RimGeoMechResultDefinition::convertToUiResultFieldName(QString resultFieldName) { QString newName (resultFieldName); @@ -603,23 +611,9 @@ QString RimGeoMechResultDefinition::convertToUiResultFieldName(QString resultFie if (resultFieldName == "MODULUS") newName = "Young's Modulus"; if (resultFieldName == "RATIO") newName = "Poisson's Ratio"; - if (isTimeLapseResultList) newName += "_D" + QString::number(baseFrameIdx); - return newName; } -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -QString RimGeoMechResultDefinition::convertToUIComponentName(QString resultComponentName, - bool isTimeLapseResultList, - int baseFrameIdx) -{ - if(isTimeLapseResultList) resultComponentName += "_D" + QString::number(baseFrameIdx); - - return resultComponentName; -} - //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -628,18 +622,10 @@ void RimGeoMechResultDefinition::setResultAddress( const RigFemResultAddress& re m_resultPositionType = resultAddress.resultPosType; m_resultFieldName = QString::fromStdString(resultAddress.fieldName); m_resultComponentName = QString::fromStdString(resultAddress.componentName); - m_resultPositionTypeUiField = m_resultPositionType; - m_resultVariableUiField = composeFieldCompString(m_resultFieldName(), m_resultComponentName()); + m_timeLapseBaseTimestep = resultAddress.timeLapseBaseFrameIdx; + m_compactionRefLayer = resultAddress.refKLayerIndex; - m_isTimeLapseResult = resultAddress.isTimeLapse(); - m_isTimeLapseResultUiField = m_isTimeLapseResult; - - if (m_isTimeLapseResult) - { - m_timeLapseBaseTimestep = resultAddress.timeLapseBaseFrameIdx; - } - m_timeLapseBaseTimestepUiField = m_timeLapseBaseTimestep; - - m_compactionRefLayer = resultAddress.refKLayerIndex; + m_resultPositionTypeUiField = m_resultPositionType; + m_resultVariableUiField = composeFieldCompString(m_resultFieldName(), m_resultComponentName()); m_compactionRefLayerUiField = m_compactionRefLayer; } diff --git a/ApplicationCode/ProjectDataModel/RimGeoMechResultDefinition.h b/ApplicationCode/ProjectDataModel/RimGeoMechResultDefinition.h index 5784cff651..419c50329f 100644 --- a/ApplicationCode/ProjectDataModel/RimGeoMechResultDefinition.h +++ b/ApplicationCode/ProjectDataModel/RimGeoMechResultDefinition.h @@ -1,6 +1,7 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2015- Statoil ASA +// Copyright (C) 2018- Equinor ASA +// Copyright (C) 2015-2018 Statoil ASA // Copyright (C) 2015- Ceetron Solutions AS // // ResInsight is free software: you can redistribute it and/or modify @@ -24,7 +25,6 @@ #include "cafPdmPointer.h" #include "cafAppEnum.h" #include "RigFemResultPosEnum.h" -#include "RigFemResultAddress.h" #include "RimFemResultObserver.h" class RimGeoMechView; @@ -44,28 +44,30 @@ class RimGeoMechResultDefinition : public RimFemResultObserver RimGeoMechResultDefinition(void); ~RimGeoMechResultDefinition(void) override; - void setGeoMechCase(RimGeoMechCase* geomCase); + void setGeoMechCase(RimGeoMechCase* geomCase); - RigGeoMechCaseData* ownerCaseData(); - bool hasResult(); - void loadResult(); - void setAddWellPathDerivedResults(bool addWellPathDerivedResults); + RigGeoMechCaseData* ownerCaseData(); + bool hasResult(); + void loadResult(); + void setAddWellPathDerivedResults(bool addWellPathDerivedResults); - RigFemResultAddress resultAddress() const; + RigFemResultAddress resultAddress() const; std::vector observedResults() const override; - RigFemResultPosEnum resultPositionType() const; - QString resultFieldName() const; - QString resultComponentName() const; - void setResultAddress(const RigFemResultAddress& resultAddress); + RigFemResultPosEnum resultPositionType() const; + QString resultFieldName() const; + QString resultComponentName() const; + QString diffResultUiName() const; + QString diffResultUiShortName() const; + void setResultAddress(const RigFemResultAddress& resultAddress); - QString resultFieldUiName(); - QString resultComponentUiName(); + QString resultFieldUiName(); + QString resultComponentUiName(); - bool hasCategoryResult() { return m_resultPositionType() == RIG_FORMATION_NAMES; } + bool hasCategoryResult() { return m_resultPositionType() == RIG_FORMATION_NAMES; } protected: - virtual void updateLegendCategorySettings() {}; + virtual void updateLegendCategorySettings() {}; void defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering) override; private: @@ -84,41 +86,33 @@ class RimGeoMechResultDefinition : public RimFemResultObserver std::map > getResultMetaDataForUIFieldSetting(); static void getUiAndResultVariableStringList(QStringList* uiNames, QStringList* variableNames, - const std::map >& fieldCompNames, - bool isTimeLapseResultList, - int baseFrameIdx); + const std::map >& fieldCompNames); static QString composeFieldCompString(const QString& resultFieldName, const QString& resultComponentName); - static QString convertToUiResultFieldName(QString resultFieldName, - bool isTimeLapseResultList, - int baseFrameIdx); - static QString convertToUIComponentName(QString resultComponentName, - bool isTimeLapseResultList, - int baseFrameIdx); + static QString convertToUiResultFieldName(QString resultFieldName); // Data Fields caf::PdmField > m_resultPositionType; caf::PdmField m_resultFieldName; caf::PdmField m_resultComponentName; - caf::PdmField m_isTimeLapseResult; caf::PdmField m_timeLapseBaseTimestep; caf::PdmField m_compactionRefLayer; // UI Fields only - friend class RimGeoMechPropertyFilter; // Property filter needs the ui fields friend class RimWellLogExtractionCurve; // Curve needs the ui fields friend class RimGeoMechCellColors; // Needs the ui fields caf::PdmField > m_resultPositionTypeUiField; caf::PdmField m_resultVariableUiField; - caf::PdmField m_isTimeLapseResultUiField; - caf::PdmField m_timeLapseBaseTimestepUiField; caf::PdmField m_compactionRefLayerUiField; caf::PdmPointer m_geomCase; + // Obsolete Data Fields + caf::PdmField m_isTimeLapseResult_OBSOLETE; + bool m_isChangedByField; bool m_addWellPathDerivedResults; }; diff --git a/ApplicationCode/ProjectDataModel/RimGeoMechView.cpp b/ApplicationCode/ProjectDataModel/RimGeoMechView.cpp index 7307e3d7c4..abccbc2345 100644 --- a/ApplicationCode/ProjectDataModel/RimGeoMechView.cpp +++ b/ApplicationCode/ProjectDataModel/RimGeoMechView.cpp @@ -40,9 +40,10 @@ #include "RimRegularLegendConfig.h" #include "RimTensorResults.h" #include "RimViewLinker.h" +#include "RimViewNameConfig.h" #include "Riu3DMainWindowTools.h" -#include "RiuSelectionManager.h" +#include "Riu3dSelectionManager.h" #include "RiuViewer.h" #include "RivGeoMechPartMgr.h" @@ -97,6 +98,12 @@ RimGeoMechView::RimGeoMechView(void) m_scaleTransform = new cvf::Transform(); m_vizLogic = new RivGeoMechVizLogic(this); m_tensorPartMgr = new RivTensorResultPartMgr(this); + + nameConfig()->setCustomName("GeoMech View"); + nameConfig()->hideCaseNameField(false); + nameConfig()->hideAggregationTypeField(true); + nameConfig()->hidePropertyField(false); + nameConfig()->hideSampleSpacingField(true); } //-------------------------------------------------------------------------------------------------- @@ -181,6 +188,42 @@ void RimGeoMechView::updateScaleTransform() if (m_viewer) m_viewer->updateCachedValuesInScene(); } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RimGeoMechView::createAutoName() const +{ + QStringList autoName; + + if (!nameConfig()->customName().isEmpty()) + { + autoName.push_back(nameConfig()->customName()); + } + + QStringList generatedAutoTags; + + RimCase* ownerCase = nullptr; + this->firstAncestorOrThisOfTypeAsserted(ownerCase); + + if (nameConfig()->addCaseName()) + { + generatedAutoTags.push_back(ownerCase->caseUserDescription()); + } + + if (nameConfig()->addProperty()) + { + auto resultName = cellResultResultDefinition()->resultFieldName(); + if(!resultName.isEmpty()) + generatedAutoTags.push_back(resultName); + } + + if (!generatedAutoTags.empty()) + { + autoName.push_back(generatedAutoTags.join(", ")); + } + return autoName.join(": "); +} + //-------------------------------------------------------------------------------------------------- /// Create display model, /// or at least empty scenes as frames that is delivered to the viewer @@ -262,6 +305,14 @@ void RimGeoMechView::createDisplayModel() } } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimPropertyFilterCollection* RimGeoMechView::nativePropertyFilterCollection() +{ + return m_propertyFilterCollection(); +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -503,6 +554,11 @@ void RimGeoMechView::updateLegendTextAndRanges(RimRegularLegendConfig* legendCon legendTitle += " [GPa]"; } + if (!cellResult->diffResultUiShortName().isEmpty()) + { + legendTitle += QString("\nTime Diff:\n%1").arg(cellResult->diffResultUiShortName()); + } + legendConfig->setTitle(legendTitle); } @@ -769,7 +825,7 @@ void RimGeoMechView::calculateCurrentTotalCellVisibility(cvf::UByteArray* totalV //-------------------------------------------------------------------------------------------------- void RimGeoMechView::createPartCollectionFromSelection(cvf::Collection* parts) { - RiuSelectionManager* riuSelManager = RiuSelectionManager::instance(); + Riu3dSelectionManager* riuSelManager = Riu3dSelectionManager::instance(); std::vector items; riuSelManager->selectedItems(items); for (size_t i = 0; i < items.size(); i++) @@ -826,6 +882,17 @@ bool RimGeoMechView::isUsingFormationNames() const return geoMechPropertyFilterCollection()->isUsingFormationNames(); } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimGeoMechView::defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering) +{ + RimGridView::defineUiOrdering(uiConfigName, uiOrdering); + + caf::PdmUiGroup* nameGroup = uiOrdering.addNewGroup("View Name"); + nameConfig()->uiOrdering(uiConfigName, *nameGroup); +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -848,7 +915,7 @@ void RimGeoMechView::defineUiTreeOrdering(caf::PdmUiTreeOrdering& uiTreeOrdering //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -RimGeoMechResultDefinition* RimGeoMechView::cellResultResultDefinition() +RimGeoMechResultDefinition* RimGeoMechView::cellResultResultDefinition() const { return cellResult(); } diff --git a/ApplicationCode/ProjectDataModel/RimGeoMechView.h b/ApplicationCode/ProjectDataModel/RimGeoMechView.h index e2eb099c49..1701031518 100644 --- a/ApplicationCode/ProjectDataModel/RimGeoMechView.h +++ b/ApplicationCode/ProjectDataModel/RimGeoMechView.h @@ -68,7 +68,7 @@ class RimGeoMechView : public RimGridView RimCase* ownerCase() const override; caf::PdmChildField cellResult; - RimGeoMechResultDefinition* cellResultResultDefinition(); + RimGeoMechResultDefinition* cellResultResultDefinition() const; const RimPropertyFilterCollection* propertyFilterCollection() const override; @@ -102,13 +102,17 @@ class RimGeoMechView : public RimGridView void convertCameraPositionFromOldProjectFiles(); protected: + void defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering) override; void defineUiTreeOrdering(caf::PdmUiTreeOrdering& uiTreeOrdering, QString uiConfigName = "") override; void onLoadDataAndUpdate() override; + void fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue) override; void createPartCollectionFromSelection(cvf::Collection* parts) override; - -private: void createDisplayModel() override; + RimPropertyFilterCollection* nativePropertyFilterCollection(); +private: + QString createAutoName() const override; + void updateScaleTransform() override; void clampCurrentTimestep() override; @@ -122,7 +126,6 @@ class RimGeoMechView : public RimGridView void updateTensorLegendTextAndRanges(RimRegularLegendConfig* legendConfig, int timeStepIndex); - void fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue) override; void initAfterRead() override; diff --git a/ApplicationCode/ProjectDataModel/RimGridCollection.h b/ApplicationCode/ProjectDataModel/RimGridCollection.h index 273832d2f1..b109ede592 100644 --- a/ApplicationCode/ProjectDataModel/RimGridCollection.h +++ b/ApplicationCode/ProjectDataModel/RimGridCollection.h @@ -37,7 +37,7 @@ class RimGridInfo : public caf::PdmObject public: RimGridInfo(); - ~RimGridInfo() {} + ~RimGridInfo() override {} void setName(const QString& name); void setEclipseGridIndex(int index); @@ -68,7 +68,7 @@ class RimGridInfoCollection : public caf::PdmObject public: RimGridInfoCollection(); - ~RimGridInfoCollection() {} + ~RimGridInfoCollection() override {} bool isActive() const; void addGridInfo(RimGridInfo * gridInfo); diff --git a/ApplicationCode/ProjectDataModel/RimGridTimeHistoryCurve.cpp b/ApplicationCode/ProjectDataModel/RimGridTimeHistoryCurve.cpp index c78a2f7422..c0575d2616 100644 --- a/ApplicationCode/ProjectDataModel/RimGridTimeHistoryCurve.cpp +++ b/ApplicationCode/ProjectDataModel/RimGridTimeHistoryCurve.cpp @@ -24,6 +24,7 @@ #include "RigEclipseCaseData.h" #include "RigMainGrid.h" #include "RigTimeHistoryResultAccessor.h" +#include "RigFemResultAddress.h" #include "RimEclipseCase.h" #include "RimEclipseCellColors.h" @@ -41,7 +42,7 @@ #include "RiuFemTimeHistoryResultAccessor.h" #include "RiuQwtPlotCurve.h" -#include "RiuSelectionManager.h" +#include "Riu3dSelectionManager.h" #include "qwt_plot.h" diff --git a/ApplicationCode/ProjectDataModel/RimGridView.cpp b/ApplicationCode/ProjectDataModel/RimGridView.cpp index 8c301725e2..8d860691f1 100644 --- a/ApplicationCode/ProjectDataModel/RimGridView.cpp +++ b/ApplicationCode/ProjectDataModel/RimGridView.cpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018- Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -21,20 +21,25 @@ #include "RiaApplication.h" #include "Rim3dOverlayInfoConfig.h" +#include "RimAnnotationInViewCollection.h" #include "RimCellRangeFilterCollection.h" #include "RimGridCollection.h" #include "RimIntersectionCollection.h" #include "RimProject.h" #include "RimPropertyFilterCollection.h" +#include "RimTextAnnotation.h" #include "RimViewController.h" #include "RimViewLinker.h" #include "RimViewLinkerCollection.h" +#include "RimViewNameConfig.h" #include "Riu3DMainWindowTools.h" +#include "RiuMainWindow.h" #include "cvfModel.h" #include "cvfScene.h" -#include "RiuMainWindow.h" + +#include CAF_PDM_XML_ABSTRACT_SOURCE_INIT(RimGridView, "GenericGridView"); // Do not use. Abstract class @@ -67,7 +72,6 @@ RimGridView::RimGridView() m_overlayInfoConfig = new Rim3dOverlayInfoConfig(); m_overlayInfoConfig->setReservoirView(this); m_overlayInfoConfig.uiCapability()->setUiHidden(true); - } //-------------------------------------------------------------------------------------------------- @@ -179,6 +183,14 @@ const RimCellRangeFilterCollection* RimGridView::rangeFilterCollection() const } } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimAnnotationInViewCollection* RimGridView::annotationCollection() const +{ + return m_annotationCollection; +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -275,6 +287,52 @@ bool RimGridView::isGridVisualizationMode() const return this->m_gridCollection->isActive(); } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RimGridView::hasCustomFontSizes(RiaDefines::FontSettingType fontSettingType, int defaultFontSize) const +{ + bool hasCustomFonts = Rim3dView::hasCustomFontSizes(fontSettingType, defaultFontSize); + if (fontSettingType == RiaDefines::ANNOTATION_FONT) + { + auto annotations = annotationCollection(); + if (annotations) + { + RiaFontCache::FontSize defaultFontSizeEnum = RiaFontCache::fontSizeEnumFromPointSize(defaultFontSize); + hasCustomFonts = annotations->hasTextAnnotationsWithCustomFontSize(defaultFontSizeEnum) || hasCustomFonts; + } + } + return hasCustomFonts; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RimGridView::applyFontSize(RiaDefines::FontSettingType fontSettingType, + int oldFontSize, + int fontSize, + bool forceChange /*= false*/) +{ + bool anyChange = Rim3dView::applyFontSize(fontSettingType, oldFontSize, fontSize, forceChange); + if (fontSettingType == RiaDefines::ANNOTATION_FONT) + { + auto annotations = annotationCollection(); + if (annotations) + { + RiaFontCache::FontSize oldFontSizeEnum = RiaFontCache::fontSizeEnumFromPointSize(oldFontSize); + RiaFontCache::FontSize newFontSizeEnum = RiaFontCache::fontSizeEnumFromPointSize(fontSize); + bool applyFontSizes = forceChange || !annotations->hasTextAnnotationsWithCustomFontSize(oldFontSizeEnum); + + if (applyFontSizes) + { + anyChange = + annotations->applyFontSizeToAllTextAnnotations(oldFontSizeEnum, newFontSizeEnum, forceChange) || anyChange; + } + } + } + return anyChange; +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -296,7 +354,7 @@ void RimGridView::updateViewFollowingRangeFilterUpdates() //-------------------------------------------------------------------------------------------------- void RimGridView::initAfterRead() { - RimViewWindow::initAfterRead(); + Rim3dView::initAfterRead(); RimProject* proj = nullptr; firstAncestorOrThisOfType(proj); @@ -306,7 +364,7 @@ void RimGridView::initAfterRead() // Current : Grid visualization mode is directly defined by m_gridCollection->isActive // This change was introduced in https://github.com/OPM/ResInsight/commit/f7bfe8d0 - bool isGridVisualizationModeBefore_2018_1_1 = ((surfaceMode() == RimGridView::SURFACE) || (meshMode() == RimGridView::FULL_MESH)); + bool isGridVisualizationModeBefore_2018_1_1 = ((surfaceMode() == RimGridView::SURFACE) || (meshMode() == RiaDefines::FULL_MESH)); m_gridCollection->setActive(isGridVisualizationModeBefore_2018_1_1); if (!isGridVisualizationModeBefore_2018_1_1) @@ -315,7 +373,7 @@ void RimGridView::initAfterRead() // If was showing with mesh and/or surfaces, turn to full mesh/surf mode to show the mesh, // and to avoid a strange setup when dropping out into grid mode again if (surfaceMode() != RimGridView::NO_SURFACE) surfaceMode = RimGridView::SURFACE; - if (meshMode() != RimGridView::NO_MESH) meshMode = RimGridView::FULL_MESH; + if (meshMode() != RiaDefines::NO_MESH) meshMode = RiaDefines::FULL_MESH; } } } diff --git a/ApplicationCode/ProjectDataModel/RimGridView.h b/ApplicationCode/ProjectDataModel/RimGridView.h index 2befa053d0..3da53aef10 100644 --- a/ApplicationCode/ProjectDataModel/RimGridView.h +++ b/ApplicationCode/ProjectDataModel/RimGridView.h @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018- Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -23,7 +23,8 @@ #include "cvfBase.h" #include "cvfArray.h" -class RimContourMapProjection; +class RimAnnotationInViewCollection; +class RimEclipseContourMapProjection; class Rim3dOverlayInfoConfig; class RimIntersectionCollection; class RimPropertyFilterCollection; @@ -50,7 +51,9 @@ class RimGridView : public Rim3dView void rangeFiltersUpdated(); RimCellRangeFilterCollection* rangeFilterCollection(); const RimCellRangeFilterCollection* rangeFilterCollection() const; - + + RimAnnotationInViewCollection* annotationCollection() const; + bool hasOverridenRangeFilterCollection(); void setOverrideRangeFilterCollection(RimCellRangeFilterCollection* rfc); void replaceRangeFilterCollectionWithOverride(); @@ -61,6 +64,10 @@ class RimGridView : public Rim3dView bool isGridVisualizationMode() const override; + + bool hasCustomFontSizes(RiaDefines::FontSettingType fontSettingType, int defaultFontSize) const override; + bool applyFontSize(RiaDefines::FontSettingType fontSettingType, int oldFontSize, int fontSize, bool forceChange = false) override; + protected: virtual void updateViewFollowingRangeFilterUpdates(); void initAfterRead() override; @@ -78,6 +85,8 @@ class RimGridView : public Rim3dView caf::PdmChildField m_rangeFilterCollection; caf::PdmChildField m_overrideRangeFilterCollection; caf::PdmChildField m_gridCollection; + caf::PdmChildField m_annotationCollection; + protected: cvf::ref m_currentReservoirCellVisibility; diff --git a/ApplicationCode/ProjectDataModel/RimIdenticalGridCaseGroup.cpp b/ApplicationCode/ProjectDataModel/RimIdenticalGridCaseGroup.cpp index df58cd91ac..2686fcca33 100644 --- a/ApplicationCode/ProjectDataModel/RimIdenticalGridCaseGroup.cpp +++ b/ApplicationCode/ProjectDataModel/RimIdenticalGridCaseGroup.cpp @@ -230,47 +230,11 @@ void RimIdenticalGridCaseGroup::loadMainCaseAndActiveCellInfo() computeUnionOfActiveCells(); } - // Action B : Copy result meta data from main case to all other cases in grid case group - // This code was originally part of RimStatisticsCaseEvaluator, but moved here to be a general solution - // for all cases + RigCaseCellResultsData::copyResultsMetaDataFromMainCase(rigCaseData, + poroModel, + caseCollection->reservoirs.childObjects()); - { - std::vector timeStepInfos = rigCaseData->results(poroModel)->timeStepInfos(0); - - const std::vector resultInfos = rigCaseData->results(poroModel)->infoForEachResultIndex(); - - for (size_t i = 1; i < caseCollection()->reservoirs.size(); i++) - { - RimEclipseResultCase* rimReservoir = dynamic_cast(caseCollection()->reservoirs[i]); - if (!rimReservoir) continue; // Input reservoir - - RigCaseCellResultsData* cellResultsStorage = rimReservoir->results(poroModel); - - for (size_t resIdx = 0; resIdx < resultInfos.size(); resIdx++) - { - RiaDefines::ResultCatType resultType = resultInfos[resIdx].resultType(); - QString resultName = resultInfos[resIdx].resultName(); - bool needsToBeStored = resultInfos[resIdx].needsToBeStored(); - bool mustBeCalculated = resultInfos[resIdx].mustBeCalculated(); - - size_t scalarResultIndex = cellResultsStorage->findScalarResultIndex(resultType, resultName); - if (scalarResultIndex == cvf::UNDEFINED_SIZE_T) - { - scalarResultIndex = cellResultsStorage->findOrCreateScalarResultIndex(resultType, resultName, needsToBeStored); - - if (mustBeCalculated) cellResultsStorage->setMustBeCalculated(scalarResultIndex); - - cellResultsStorage->setTimeStepInfos(scalarResultIndex, timeStepInfos); - - std::vector< std::vector >& dataValues = cellResultsStorage->cellScalarResults(scalarResultIndex); - dataValues.resize(timeStepInfos.size()); - } - } - - cellResultsStorage->createPlaceholderResultEntries(); - } - } // "Load" the statistical cases diff --git a/ApplicationCode/ProjectDataModel/RimIntersection.cpp b/ApplicationCode/ProjectDataModel/RimIntersection.cpp index 053adf58b9..71b23f6ce3 100644 --- a/ApplicationCode/ProjectDataModel/RimIntersection.cpp +++ b/ApplicationCode/ProjectDataModel/RimIntersection.cpp @@ -100,7 +100,7 @@ RimIntersection::RimIntersection() m_dipAngle.uiCapability()->setUiEditorTypeName(caf::PdmUiDoubleSliderEditor::uiEditorTypeName()); CAF_PDM_InitFieldNoDefault(&m_customExtrusionPoints, "CustomExtrusionPoints", "", "", "", ""); - CAF_PDM_InitFieldNoDefault(&m_twoAzimuthPoints, "TwoAzimuthPoints", "Points", "", "Use Ctrl-C for copy and Ctrl-V for paste", ""); + CAF_PDM_InitFieldNoDefault(&m_twoAzimuthPoints, "TwoAzimuthPoints", "Points", "", "Pick two points to define a line.\nUse Ctrl-C for copy and Ctrl-V for paste", ""); CAF_PDM_InitField (&m_branchIndex, "Branch", -1, "Branch", "", "", ""); CAF_PDM_InitField (&m_extentLength, "ExtentLength", 200.0, "Extent Length", "", "", ""); diff --git a/ApplicationCode/ProjectDataModel/RimLegendConfig.cpp b/ApplicationCode/ProjectDataModel/RimLegendConfig.cpp index c95c9ab734..7be30c8ae8 100644 --- a/ApplicationCode/ProjectDataModel/RimLegendConfig.cpp +++ b/ApplicationCode/ProjectDataModel/RimLegendConfig.cpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018 Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by diff --git a/ApplicationCode/ProjectDataModel/RimLegendConfig.h b/ApplicationCode/ProjectDataModel/RimLegendConfig.h index 50b6616ac2..efe036b770 100644 --- a/ApplicationCode/ProjectDataModel/RimLegendConfig.h +++ b/ApplicationCode/ProjectDataModel/RimLegendConfig.h @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018 Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by diff --git a/ApplicationCode/ProjectDataModel/RimMainPlotCollection.cpp b/ApplicationCode/ProjectDataModel/RimMainPlotCollection.cpp index 8baf71ea6f..9133220a8d 100644 --- a/ApplicationCode/ProjectDataModel/RimMainPlotCollection.cpp +++ b/ApplicationCode/ProjectDataModel/RimMainPlotCollection.cpp @@ -21,9 +21,12 @@ #include "RimFlowCharacteristicsPlot.h" #include "RimFlowPlotCollection.h" +#include "RimGridCrossPlot.h" +#include "RimGridCrossPlotCollection.h" #include "RimPltPlotCollection.h" #include "RimProject.h" #include "RimRftPlotCollection.h" +#include "RimSaturationPressurePlotCollection.h" #include "RimSummaryCrossPlotCollection.h" #include "RimSummaryPlotCollection.h" #include "RimViewWindow.h" @@ -65,13 +68,20 @@ RimMainPlotCollection::RimMainPlotCollection() CAF_PDM_InitFieldNoDefault(&m_flowPlotCollection, "FlowPlotCollection", "Flow Diagnostics Plots", "", "", ""); m_flowPlotCollection.uiCapability()->setUiHidden(true); + CAF_PDM_InitFieldNoDefault(&m_gridCrossPlotCollection, "Rim3dCrossPlotCollection", "3d Cross Plots", "", "", ""); + m_gridCrossPlotCollection.uiCapability()->setUiHidden(true); + + CAF_PDM_InitFieldNoDefault(&m_saturationPressurePlotCollection, "RimSaturationPressurePlotCollection", "Saturation Pressure Plots", "", "", ""); + m_saturationPressurePlotCollection.uiCapability()->setUiHidden(true); + m_wellLogPlotCollection = new RimWellLogPlotCollection(); m_rftPlotCollection = new RimRftPlotCollection(); m_pltPlotCollection = new RimPltPlotCollection(); m_summaryPlotCollection = new RimSummaryPlotCollection(); m_summaryCrossPlotCollection = new RimSummaryCrossPlotCollection(); m_flowPlotCollection = new RimFlowPlotCollection(); - + m_gridCrossPlotCollection = new RimGridCrossPlotCollection; + m_saturationPressurePlotCollection = new RimSaturationPressurePlotCollection; } //-------------------------------------------------------------------------------------------------- @@ -79,13 +89,6 @@ RimMainPlotCollection::RimMainPlotCollection() //-------------------------------------------------------------------------------------------------- RimMainPlotCollection::~RimMainPlotCollection() { - if (m_wellLogPlotCollection()) delete m_wellLogPlotCollection(); - if (m_rftPlotCollection()) delete m_rftPlotCollection(); - if (m_pltPlotCollection()) delete m_pltPlotCollection(); - if (m_summaryPlotCollection()) delete m_summaryPlotCollection(); - if (m_summaryCrossPlotCollection()) delete m_summaryCrossPlotCollection(); - if (m_flowPlotCollection()) delete m_flowPlotCollection(); - } //-------------------------------------------------------------------------------------------------- @@ -152,6 +155,22 @@ RimFlowPlotCollection* RimMainPlotCollection::flowPlotCollection() return m_flowPlotCollection(); } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimGridCrossPlotCollection* RimMainPlotCollection::gridCrossPlotCollection() +{ + return m_gridCrossPlotCollection(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimSaturationPressurePlotCollection* RimMainPlotCollection::saturationPressurePlotCollection() +{ + return m_saturationPressurePlotCollection(); +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -162,8 +181,9 @@ void RimMainPlotCollection::deleteAllContainedObjects() m_pltPlotCollection()->deleteAllPlots(); m_summaryPlotCollection()->summaryPlots.deleteAllChildObjects(); m_summaryCrossPlotCollection()->deleteAllChildObjects(); - + m_gridCrossPlotCollection->deleteAllChildObjects(); m_flowPlotCollection()->closeDefaultPlotWindowAndDeletePlots(); + m_saturationPressurePlotCollection()->deleteAllChildObjects(); } @@ -208,6 +228,14 @@ void RimMainPlotCollection::updatePlotsWithFormations() { m_flowPlotCollection->loadDataAndUpdate(); } + + if (m_gridCrossPlotCollection) + { + for (RimGridCrossPlot* crossPlot : m_gridCrossPlotCollection->gridCrossPlots()) + { + crossPlot->loadDataAndUpdate(); + } + } } //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/ProjectDataModel/RimMainPlotCollection.h b/ApplicationCode/ProjectDataModel/RimMainPlotCollection.h index 95cdc674d1..86576ff944 100644 --- a/ApplicationCode/ProjectDataModel/RimMainPlotCollection.h +++ b/ApplicationCode/ProjectDataModel/RimMainPlotCollection.h @@ -2,78 +2,83 @@ // // Copyright (C) 2015- Statoil ASA // Copyright (C) 2015- Ceetron Solutions AS -// +// // ResInsight 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 3 of the License, or // (at your option) any later version. -// +// // ResInsight 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 at +// +// See the GNU General Public License at // for more details. // ///////////////////////////////////////////////////////////////////////////////// #pragma once -#include "cafPdmObject.h" -#include "cafPdmField.h" #include "cafPdmChildField.h" +#include "cafPdmField.h" +#include "cafPdmObject.h" -#include #include - +#include class RimWellLogPlotCollection; class RimRftPlotCollection; class RimPltPlotCollection; +class RimGridCrossPlotCollection; class RimSummaryPlotCollection; class RimSummaryCrossPlotCollection; class RimSummaryPlot; class RifReaderEclipseSummary; class RimEclipseResultCase; class RimFlowPlotCollection; - +class RimSaturationPressurePlotCollection; //================================================================================================== -/// -/// +/// +/// //================================================================================================== class RimMainPlotCollection : public caf::PdmObject { CAF_PDM_HEADER_INIT; + public: RimMainPlotCollection(); ~RimMainPlotCollection() override; - RimWellLogPlotCollection* wellLogPlotCollection(); - RimRftPlotCollection* rftPlotCollection(); - RimPltPlotCollection* pltPlotCollection(); - RimSummaryPlotCollection* summaryPlotCollection(); - RimSummaryCrossPlotCollection* summaryCrossPlotCollection(); - RimFlowPlotCollection* flowPlotCollection(); + RimWellLogPlotCollection* wellLogPlotCollection(); + RimRftPlotCollection* rftPlotCollection(); + RimPltPlotCollection* pltPlotCollection(); + RimSummaryPlotCollection* summaryPlotCollection(); + RimSummaryCrossPlotCollection* summaryCrossPlotCollection(); + RimFlowPlotCollection* flowPlotCollection(); + RimGridCrossPlotCollection* gridCrossPlotCollection(); + RimSaturationPressurePlotCollection* saturationPressurePlotCollection(); - void deleteAllContainedObjects(); - void updateCurrentTimeStepInPlots(); - void updatePlotsWithFormations(); - void updatePlotsWithCompletions(); - void deleteAllCachedData(); -private: + void deleteAllContainedObjects(); + void updateCurrentTimeStepInPlots(); + void updatePlotsWithFormations(); + void updatePlotsWithCompletions(); + void deleteAllCachedData(); +private: // Overridden PDM methods caf::PdmFieldHandle* objectToggleField() override; - void fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue) override; + void fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue) override; private: - caf::PdmChildField m_wellLogPlotCollection; - caf::PdmChildField m_rftPlotCollection; - caf::PdmChildField m_pltPlotCollection; - caf::PdmChildField m_summaryPlotCollection; - caf::PdmChildField m_summaryCrossPlotCollection; - caf::PdmChildField m_flowPlotCollection; + caf::PdmChildField m_wellLogPlotCollection; + caf::PdmChildField m_rftPlotCollection; + caf::PdmChildField m_pltPlotCollection; + caf::PdmChildField m_summaryPlotCollection; + caf::PdmChildField m_summaryCrossPlotCollection; + caf::PdmChildField m_flowPlotCollection; + caf::PdmChildField m_gridCrossPlotCollection; + caf::PdmChildField m_saturationPressurePlotCollection; caf::PdmField m_show; }; diff --git a/ApplicationCode/ProjectDataModel/RimMdiWindowController.cpp b/ApplicationCode/ProjectDataModel/RimMdiWindowController.cpp index 689dcb5ca5..84f9fb340a 100644 --- a/ApplicationCode/ProjectDataModel/RimMdiWindowController.cpp +++ b/ApplicationCode/ProjectDataModel/RimMdiWindowController.cpp @@ -19,6 +19,7 @@ #include "RimMdiWindowController.h" #include "RiaApplication.h" +#include "RimProject.h" #include "RimViewWindow.h" #include "RiuMainWindowBase.h" @@ -81,8 +82,11 @@ RimMdiWindowGeometry RimMdiWindowController::mdiWindowGeometry() void RimMdiWindowController::handleViewerDeletion() { viewPdmObject()->m_showWindow = false; - + viewPdmObject()->updateConnectedEditors(); + viewPdmObject()->updateUiIconFromToggleField(); uiCapability()->updateUiIconFromToggleField(); + removeWindowFromMDI(); + updateConnectedEditors(); } diff --git a/ApplicationCode/ProjectDataModel/RimMdiWindowController.h b/ApplicationCode/ProjectDataModel/RimMdiWindowController.h index 47d3a5ea9f..cbd1602391 100644 --- a/ApplicationCode/ProjectDataModel/RimMdiWindowController.h +++ b/ApplicationCode/ProjectDataModel/RimMdiWindowController.h @@ -23,8 +23,9 @@ #include "cafPdmField.h" -class RimViewWindow; class RiuMainWindowBase; +class RiuMdiSubWindow; +class RimViewWindow; struct RimMdiWindowGeometry; //================================================================================================== @@ -50,6 +51,7 @@ class RimMdiWindowController : public caf::PdmObject RimViewWindow* viewPdmObject(); QWidget* viewWidget(); + RiuMdiSubWindow* viewSubWindow(); RiuMainWindowBase* getMainWindow(); // Overridden PDM methods diff --git a/ApplicationCode/ProjectDataModel/RimModeledWellPath.cpp b/ApplicationCode/ProjectDataModel/RimModeledWellPath.cpp index 4096a1b59e..616ba9a17c 100644 --- a/ApplicationCode/ProjectDataModel/RimModeledWellPath.cpp +++ b/ApplicationCode/ProjectDataModel/RimModeledWellPath.cpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018 - Equinor ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -127,6 +127,7 @@ QString RimModeledWellPath::wellPlanText() QTextStream qtxtStream(&planText); RifEclipseDataTableFormatter formatter(qtxtStream); + formatter.setUnlimitedDataRowWidth(); formatter.setTableRowPrependText(""); formatter.setTableRowLineAppendText(""); diff --git a/ApplicationCode/ProjectDataModel/RimModeledWellPath.h b/ApplicationCode/ProjectDataModel/RimModeledWellPath.h index 3cb1172579..4afa5f6ce7 100644 --- a/ApplicationCode/ProjectDataModel/RimModeledWellPath.h +++ b/ApplicationCode/ProjectDataModel/RimModeledWellPath.h @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018 - Equinor ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by diff --git a/ApplicationCode/ProjectDataModel/RimMultiSnapshotDefinition.cpp b/ApplicationCode/ProjectDataModel/RimMultiSnapshotDefinition.cpp deleted file mode 100644 index 309b17fb3d..0000000000 --- a/ApplicationCode/ProjectDataModel/RimMultiSnapshotDefinition.cpp +++ /dev/null @@ -1,304 +0,0 @@ -///////////////////////////////////////////////////////////////////////////////// -// -// Copyright (C) 2016- Statoil ASA -// -// ResInsight 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 3 of the License, or -// (at your option) any later version. -// -// ResInsight 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 at -// for more details. -// -///////////////////////////////////////////////////////////////////////////////// - -#include "RimMultiSnapshotDefinition.h" - -#include "RiaApplication.h" -#include "RiaOptionItemFactory.h" - -#include "RigActiveCellInfo.h" -#include "RigCaseCellResultsData.h" -#include "RigReservoirGridTools.h" - -#include "Rim3dView.h" -#include "RimCase.h" -#include "RimEclipseView.h" -#include "RimProject.h" -#include "RimReservoirCellResultsStorage.h" -#include "RimTools.h" - -#include "cafPdmPointer.h" - -// clang-format off - -namespace caf -{ - template<> - void caf::AppEnum< RimMultiSnapshotDefinition::SnapShotDirectionEnum >::setUp() - { - addItem(RimMultiSnapshotDefinition::NO_RANGEFILTER, "None", "None"); - addItem(RimMultiSnapshotDefinition::RANGEFILTER_I, "I", "I"); - addItem(RimMultiSnapshotDefinition::RANGEFILTER_J, "J", "J"); - addItem(RimMultiSnapshotDefinition::RANGEFILTER_K, "K", "K"); - - setDefault(RimMultiSnapshotDefinition::RANGEFILTER_K); - } -} - -CAF_PDM_SOURCE_INIT(RimMultiSnapshotDefinition, "MultiSnapshotDefinition"); - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -RimMultiSnapshotDefinition::RimMultiSnapshotDefinition() -{ - //CAF_PDM_InitObject("MultiSnapshotDefinition", ":/Well.png", "", ""); - CAF_PDM_InitObject("MultiSnapshotDefinition", "", "", ""); - - CAF_PDM_InitField(&isActive, "IsActive", true, "Active", "", "", ""); - - CAF_PDM_InitFieldNoDefault(&view, "View", "View", "", "", ""); - - CAF_PDM_InitFieldNoDefault(&eclipseResultType, "EclipseResultType", "Result Type", "", "", ""); - CAF_PDM_InitFieldNoDefault(&selectedEclipseResults, "SelectedEclipseResults", "Properties", "", "", ""); - - CAF_PDM_InitField(&timeStepStart, "TimeStepStart", 0, "Start Time", "", "", ""); - CAF_PDM_InitField(&timeStepEnd, "TimeStepEnd", 0, "End Time", "", "", ""); - - CAF_PDM_InitField(&sliceDirection, "SnapShotDirection", caf::AppEnum(NO_RANGEFILTER), "Range Filter Slice", "", "", ""); - CAF_PDM_InitField(&startSliceIndex, "RangeFilterStart", 1, "Range Start", "", "", ""); - CAF_PDM_InitField(&endSliceIndex, "RangeFilterEnd", 1, "Range End", "", "", ""); - - CAF_PDM_InitFieldNoDefault(&additionalCases, "AdditionalCases", "Cases", "", "", ""); -} - -// clang-format on - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -RimMultiSnapshotDefinition::~RimMultiSnapshotDefinition() {} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -QList RimMultiSnapshotDefinition::calculateValueOptions(const caf::PdmFieldHandle* fieldNeedingOptions, - bool* useOptionsOnly) -{ - QList options; - - if (fieldNeedingOptions == &view) - { - options.push_back(caf::PdmOptionItemInfo("None", nullptr)); - - std::vector views; - - RimProject* proj = RiaApplication::instance()->project(); - std::vector cases; - proj->allCases(cases); - - for (RimCase* rimCase : cases) - { - for (Rim3dView* rimView : rimCase->views()) - { - views.push_back(rimView); - } - } - - for (Rim3dView* rim3dView : views) - { - RiaOptionItemFactory::appendOptionItemFromViewNameAndCaseName(rim3dView, &options); - } - } - else if (fieldNeedingOptions == &eclipseResultType) - { - options.push_back(caf::PdmOptionItemInfo(caf::AppEnum(RiaDefines::DYNAMIC_NATIVE).uiText(), - RiaDefines::DYNAMIC_NATIVE)); - options.push_back(caf::PdmOptionItemInfo(caf::AppEnum(RiaDefines::STATIC_NATIVE).uiText(), - RiaDefines::STATIC_NATIVE)); - } - else if (fieldNeedingOptions == &selectedEclipseResults) - { - RimEclipseView* rimEclipseView = dynamic_cast(view()); - if (rimEclipseView) - { - QStringList varList; - varList = rimEclipseView->currentGridCellResults()->resultNames(eclipseResultType()); - - options = toOptionList(varList); - } - } - else if (fieldNeedingOptions == &timeStepEnd) - { - getTimeStepStrings(options); - } - else if (fieldNeedingOptions == &timeStepStart) - { - getTimeStepStrings(options); - } - else if (fieldNeedingOptions == &additionalCases) - { - RimTools::caseOptionItems(&options); - } - - if (useOptionsOnly) *useOptionsOnly = true; - - return options; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RimMultiSnapshotDefinition::getTimeStepStrings(QList& options) -{ - if (!view()) return; - - QStringList timeSteps; - - timeSteps = view->ownerCase()->timeStepStrings(); - - for (int i = 0; i < timeSteps.size(); i++) - { - options.push_back(caf::PdmOptionItemInfo(timeSteps[i], i)); - } -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RimMultiSnapshotDefinition::fieldChangedByUi(const caf::PdmFieldHandle* changedField, - const QVariant& oldValue, - const QVariant& newValue) -{ - if (changedField == &eclipseResultType) - { - selectedEclipseResults.v().clear(); - } - else if (changedField == &sliceDirection) - { - const cvf::StructGridInterface* mainGrid = nullptr; - const RigActiveCellInfo* actCellInfo = nullptr; - - if (view()) - { - actCellInfo = RigReservoirGridTools::activeCellInfo(view()); - - RimCase* rimCase = nullptr; - view()->firstAncestorOrThisOfTypeAsserted(rimCase); - - mainGrid = RigReservoirGridTools::mainGrid(rimCase); - } - - if (mainGrid && actCellInfo) - { - cvf::Vec3st min, max; - actCellInfo->IJKBoundingBox(min, max); - - // Adjust to Eclipse indexing - min.x() = min.x() + 1; - min.y() = min.y() + 1; - min.z() = min.z() + 1; - - max.x() = max.x() + 1; - max.y() = max.y() + 1; - max.z() = max.z() + 1; - - int maxInt = 0; - int minInt = 0; - - if (newValue == RimMultiSnapshotDefinition::RANGEFILTER_I) - { - maxInt = static_cast(max.x()); - minInt = static_cast(min.x()); - } - else if (newValue == RimMultiSnapshotDefinition::RANGEFILTER_J) - { - maxInt = static_cast(max.y()); - minInt = static_cast(min.y()); - } - else if (newValue == RimMultiSnapshotDefinition::RANGEFILTER_K) - { - maxInt = static_cast(max.z()); - minInt = static_cast(min.z()); - } - - startSliceIndex = minInt; - endSliceIndex = maxInt; - } - - startSliceIndex.uiCapability()->updateConnectedEditors(); - } -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -QList RimMultiSnapshotDefinition::toOptionList(const QStringList& varList) -{ - QList optionList; - int i; - for (i = 0; i < varList.size(); ++i) - { - optionList.push_back(caf::PdmOptionItemInfo(varList[i], varList[i])); - } - return optionList; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RimMultiSnapshotDefinition::defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering) -{ - if (!isActive()) - { - view.uiCapability()->setUiReadOnly(true); - eclipseResultType.uiCapability()->setUiReadOnly(true); - selectedEclipseResults.uiCapability()->setUiReadOnly(true); - timeStepStart.uiCapability()->setUiReadOnly(true); - timeStepEnd.uiCapability()->setUiReadOnly(true); - sliceDirection.uiCapability()->setUiReadOnly(true); - startSliceIndex.uiCapability()->setUiReadOnly(true); - endSliceIndex.uiCapability()->setUiReadOnly(true); - additionalCases.uiCapability()->setUiReadOnly(true); - } - else - { - view.uiCapability()->setUiReadOnly(false); - - if (!view()) - { - eclipseResultType.uiCapability()->setUiReadOnly(true); - selectedEclipseResults.uiCapability()->setUiReadOnly(true); - timeStepStart.uiCapability()->setUiReadOnly(true); - timeStepEnd.uiCapability()->setUiReadOnly(true); - sliceDirection.uiCapability()->setUiReadOnly(true); - startSliceIndex.uiCapability()->setUiReadOnly(true); - endSliceIndex.uiCapability()->setUiReadOnly(true); - additionalCases.uiCapability()->setUiReadOnly(true); - } - else - { - eclipseResultType.uiCapability()->setUiReadOnly(false); - selectedEclipseResults.uiCapability()->setUiReadOnly(false); - timeStepStart.uiCapability()->setUiReadOnly(false); - timeStepEnd.uiCapability()->setUiReadOnly(false); - sliceDirection.uiCapability()->setUiReadOnly(false); - - additionalCases.uiCapability()->setUiReadOnly(false); - - bool rangeReadOnly = false; - if (sliceDirection() == NO_RANGEFILTER) - { - rangeReadOnly = true; - } - - startSliceIndex.uiCapability()->setUiReadOnly(rangeReadOnly); - endSliceIndex.uiCapability()->setUiReadOnly(rangeReadOnly); - } - } -} diff --git a/ApplicationCode/ProjectDataModel/RimMultiSnapshotDefinition.h b/ApplicationCode/ProjectDataModel/RimMultiSnapshotDefinition.h deleted file mode 100644 index 0e68a7eba2..0000000000 --- a/ApplicationCode/ProjectDataModel/RimMultiSnapshotDefinition.h +++ /dev/null @@ -1,78 +0,0 @@ -///////////////////////////////////////////////////////////////////////////////// -// -// Copyright (C) 2016- Statoil ASA -// -// ResInsight 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 3 of the License, or -// (at your option) any later version. -// -// ResInsight 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 at -// for more details. -// -///////////////////////////////////////////////////////////////////////////////// - -#pragma once - -#include "RiaDefines.h" - -#include "cafAppEnum.h" -#include "cafPdmField.h" -#include "cafPdmObject.h" -#include "cafPdmPtrField.h" -#include "cafPdmPtrArrayField.h" - -class RimCase; -class Rim3dView; - -//================================================================================================== -/// -/// -//================================================================================================== -class RimMultiSnapshotDefinition : public caf::PdmObject -{ - CAF_PDM_HEADER_INIT; -public: - RimMultiSnapshotDefinition(); - ~RimMultiSnapshotDefinition() override; - - caf::PdmField isActive; - - caf::PdmPtrField view; - - caf::PdmField< caf::AppEnum< RiaDefines::ResultCatType > > eclipseResultType; - caf::PdmField< std::vector > selectedEclipseResults; - - caf::PdmField timeStepStart; - caf::PdmField timeStepEnd; - - enum SnapShotDirectionEnum - { - RANGEFILTER_I, - RANGEFILTER_J, - RANGEFILTER_K, - NO_RANGEFILTER - }; - - caf::PdmField< caf::AppEnum< SnapShotDirectionEnum > > sliceDirection; - caf::PdmField startSliceIndex; - caf::PdmField endSliceIndex; - - caf::PdmPtrArrayField additionalCases; - -protected: - void defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering) override; - -private: - QList calculateValueOptions(const caf::PdmFieldHandle* fieldNeedingOptions, bool * useOptionsOnly) override; - - void getTimeStepStrings(QList &options); - - void fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue) override; - - QList toOptionList(const QStringList& varList); -}; diff --git a/ApplicationCode/ProjectDataModel/RimNameConfig.cpp b/ApplicationCode/ProjectDataModel/RimNameConfig.cpp index 8c018a7c99..421898af2e 100644 --- a/ApplicationCode/ProjectDataModel/RimNameConfig.cpp +++ b/ApplicationCode/ProjectDataModel/RimNameConfig.cpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018- Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -38,7 +38,7 @@ RimNameConfig::RimNameConfig(const RimNameConfigHolderInterface* configHolder /* CAF_PDM_InitField(&m_isUsingAutoName_OBSOLETE, "IsUsingAutoName", true, "Add Automatic Name Tags", "", "", ""); CAF_PDM_InitFieldNoDefault(&m_customName, "CustomCurveName", "Custom Name Part", "", "", ""); - CAF_PDM_InitFieldNoDefault(&m_autoName, "AutoCurveName", "Full Curve Name", "", "", ""); + CAF_PDM_InitFieldNoDefault(&m_autoName, "AutoCurveName", "Full Name", "", "", ""); m_isUsingAutoName_OBSOLETE.xmlCapability()->setIOWritable(false); m_autoName.registerGetMethod(this, &RimNameConfig::autoName); m_autoName.xmlCapability()->disableIO(); @@ -145,6 +145,4 @@ void RimNameConfig::initAfterRead() { enableAllAutoNameTags(false); } - - updateAllSettings(); } diff --git a/ApplicationCode/ProjectDataModel/RimNameConfig.h b/ApplicationCode/ProjectDataModel/RimNameConfig.h index 3ffc8fb8f7..2b3eb91dab 100644 --- a/ApplicationCode/ProjectDataModel/RimNameConfig.h +++ b/ApplicationCode/ProjectDataModel/RimNameConfig.h @@ -30,10 +30,9 @@ class RimNameConfigHolderInterface { public: virtual QString createAutoName() const = 0; - void updateHolder() { performHolderUpdate(); } - + void updateHolder() { performAutoNameUpdate(); } protected: - virtual void performHolderUpdate() {} + virtual void performAutoNameUpdate() {} }; //================================================================================================== @@ -56,7 +55,7 @@ class RimNameConfig : public caf::PdmObject void uiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering); protected: - virtual void defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering) override; + void defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering) override; void fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue) override; QString autoName() const; virtual void updateAllSettings(); diff --git a/ApplicationCode/ProjectDataModel/RimOilField.cpp b/ApplicationCode/ProjectDataModel/RimOilField.cpp index 47bdd2770d..75e35f18ab 100644 --- a/ApplicationCode/ProjectDataModel/RimOilField.cpp +++ b/ApplicationCode/ProjectDataModel/RimOilField.cpp @@ -20,16 +20,19 @@ #include "RimOilField.h" +#include "RimAnnotationCollection.h" +#include "RimCompletionTemplateCollection.h" #include "RimEclipseCaseCollection.h" #include "RimFormationNamesCollection.h" #include "RimFractureTemplateCollection.h" +#include "RimValveTemplateCollection.h" #include "RimGeoMechModels.h" #include "RimObservedData.h" #include "RimObservedDataCollection.h" #include "RimSummaryCase.h" #include "RimSummaryCaseMainCollection.h" #include "RimWellPathCollection.h" - +#include "RimMeasurement.h" CAF_PDM_SOURCE_INIT(RimOilField, "ResInsightOilField"); //-------------------------------------------------------------------------------------------------- @@ -43,18 +46,32 @@ RimOilField::RimOilField(void) CAF_PDM_InitFieldNoDefault(&geoMechModels, "GeoMechModels", "Geo Mech Models", ":/GridModels.png", "", ""); CAF_PDM_InitFieldNoDefault(&wellPathCollection, "WellPathCollection", "Well Paths", ":/WellCollection.png", "", ""); - CAF_PDM_InitFieldNoDefault(&fractureDefinitionCollection, "FractureDefinitionCollection", "Defenition of Fractures", "", "", ""); + CAF_PDM_InitFieldNoDefault(&completionTemplateCollection, "CompletionTemplateCollection", "", "", "", ""); CAF_PDM_InitFieldNoDefault(&summaryCaseMainCollection,"SummaryCaseCollection","Summary Cases",":/GridModels.png","",""); CAF_PDM_InitFieldNoDefault(&formationNamesCollection,"FormationNamesCollection","Formations","","",""); CAF_PDM_InitFieldNoDefault(&observedDataCollection, "ObservedDataCollection", "Observed Data", ":/Cases16x16.png", "", ""); - fractureDefinitionCollection = new RimFractureTemplateCollection(); + CAF_PDM_InitFieldNoDefault(&annotationCollection, "AnnotationCollection", "Annotations", "", "", ""); + + CAF_PDM_InitFieldNoDefault( + &m_fractureTemplateCollection_OBSOLETE, "FractureDefinitionCollection", "Defenition of Fractures", "", "", ""); + + completionTemplateCollection = new RimCompletionTemplateCollection; + + CAF_PDM_InitFieldNoDefault(&measurement, "Measurement", "Measurement", "", "", ""); + measurement = new RimMeasurement(); + measurement.xmlCapability()->disableIO(); + analysisModels = new RimEclipseCaseCollection(); wellPathCollection = new RimWellPathCollection(); summaryCaseMainCollection = new RimSummaryCaseMainCollection(); observedDataCollection = new RimObservedDataCollection(); formationNamesCollection = new RimFormationNamesCollection(); + annotationCollection = new RimAnnotationCollection(); + + m_fractureTemplateCollection_OBSOLETE = new RimFractureTemplateCollection; + m_fractureTemplateCollection_OBSOLETE.xmlCapability()->setIOWritable(false); } //-------------------------------------------------------------------------------------------------- @@ -62,14 +79,38 @@ RimOilField::RimOilField(void) //-------------------------------------------------------------------------------------------------- RimOilField::~RimOilField(void) { - if (wellPathCollection()) delete wellPathCollection(); - - if (fractureDefinitionCollection()) delete fractureDefinitionCollection(); - if (geoMechModels()) delete geoMechModels(); - if (analysisModels()) delete analysisModels(); - if (summaryCaseMainCollection()) delete summaryCaseMainCollection(); - if (formationNamesCollection()) delete formationNamesCollection(); - if (observedDataCollection()) delete observedDataCollection(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimFractureTemplateCollection* RimOilField::fractureDefinitionCollection() +{ + return completionTemplateCollection()->fractureTemplateCollection(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +const RimFractureTemplateCollection* RimOilField::fractureDefinitionCollection() const +{ + return completionTemplateCollection()->fractureTemplateCollection(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimValveTemplateCollection* RimOilField::valveTemplateCollection() +{ + return completionTemplateCollection()->valveTemplateCollection(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +const RimValveTemplateCollection* RimOilField::valveTemplateCollection() const +{ + return completionTemplateCollection()->valveTemplateCollection(); } //-------------------------------------------------------------------------------------------------- @@ -80,11 +121,11 @@ QString RimOilField::uniqueShortNameForCase(RimSummaryCase* summaryCase) std::set allAutoShortNames; std::vector allCases = summaryCaseMainCollection->allSummaryCases(); - std::vector observedDataCases = observedDataCollection->allObservedData(); + std::vector observedDataCases = observedDataCollection->allObservedData(); for (auto observedData : observedDataCases) { - allCases.push_back(dynamic_cast(observedData)); + allCases.push_back(observedData); } for (RimSummaryCase* sumCase : allCases) @@ -140,3 +181,16 @@ QString RimOilField::uniqueShortNameForCase(RimSummaryCase* summaryCase) return shortName; } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimOilField::initAfterRead() +{ + RimFractureTemplateCollection* fractureTemplateCollection = m_fractureTemplateCollection_OBSOLETE.value(); + if (!fractureTemplateCollection->fractureTemplates().empty()) + { + m_fractureTemplateCollection_OBSOLETE.removeChildObject(fractureTemplateCollection); + completionTemplateCollection->setFractureTemplateCollection(fractureTemplateCollection); + } +} + diff --git a/ApplicationCode/ProjectDataModel/RimOilField.h b/ApplicationCode/ProjectDataModel/RimOilField.h index 2e180c5848..7f07818bf3 100644 --- a/ApplicationCode/ProjectDataModel/RimOilField.h +++ b/ApplicationCode/ProjectDataModel/RimOilField.h @@ -28,11 +28,15 @@ class RimEclipseCaseCollection; class RimFormationNamesCollection; class RimFractureTemplateCollection; +class RimCompletionTemplateCollection; +class RimValveTemplateCollection; class RimGeoMechModels; class RimObservedDataCollection; class RimSummaryCase; class RimSummaryCaseMainCollection; class RimWellPathCollection; +class RimAnnotationCollection; +class RimMeasurement; //================================================================================================== /// @@ -46,14 +50,27 @@ class RimOilField : public caf::PdmObject RimOilField(void); ~RimOilField(void) override; + RimFractureTemplateCollection* fractureDefinitionCollection(); + const RimFractureTemplateCollection* fractureDefinitionCollection() const; + + RimValveTemplateCollection* valveTemplateCollection(); + const RimValveTemplateCollection* valveTemplateCollection() const; + QString uniqueShortNameForCase(RimSummaryCase* summaryCase); caf::PdmChildField analysisModels; caf::PdmChildField geoMechModels; caf::PdmChildField wellPathCollection; - caf::PdmChildField fractureDefinitionCollection; + caf::PdmChildField completionTemplateCollection; caf::PdmChildField summaryCaseMainCollection; caf::PdmChildField observedDataCollection; caf::PdmChildField formationNamesCollection; + caf::PdmChildField annotationCollection; + caf::PdmChildField measurement; + +protected: + void initAfterRead() override; +private: + caf::PdmChildField m_fractureTemplateCollection_OBSOLETE; }; diff --git a/ApplicationCode/ProjectDataModel/RimPlotAxisAnnotation.cpp b/ApplicationCode/ProjectDataModel/RimPlotAxisAnnotation.cpp new file mode 100644 index 0000000000..20661ee764 --- /dev/null +++ b/ApplicationCode/ProjectDataModel/RimPlotAxisAnnotation.cpp @@ -0,0 +1,269 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2019- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "RimPlotAxisAnnotation.h" + +#include "RigEclipseCaseData.h" +#include "RigEquil.h" + +#include "RimEclipseCase.h" +#include "RimRiuQwtPlotOwnerInterface.h" +#include "RimTools.h" +#include "RimViewWindow.h" + +#include + +namespace caf +{ +template<> +void RimPlotAxisAnnotation::ExportKeywordEnum::setUp() +{ + addItem(RimPlotAxisAnnotation::PL_USER_DEFINED, "User Defined", "User Defined"); + addItem(RimPlotAxisAnnotation::PL_EQUIL_WATER_OIL_CONTACT, "PL_EQUIL_WATER_OIL_CONTACT", "PL_EQUIL_WATER_OIL_CONTACT"); + addItem(RimPlotAxisAnnotation::PL_EQUIL_GAS_OIL_CONTACT, "PL_EQUIL_GAS_OIL_CONTACT", "PL_EQUIL_GAS_OIL_CONTACT"); + setDefault(RimPlotAxisAnnotation::PL_USER_DEFINED); +} +} // namespace caf + +CAF_PDM_SOURCE_INIT(RimPlotAxisAnnotation, "RimPlotAxisAnnotation"); + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimPlotAxisAnnotation::RimPlotAxisAnnotation() +{ + CAF_PDM_InitObject("Plot Axis Annotation", ":/LeftAxis16x16.png", "", ""); + + CAF_PDM_InitField(&m_isActive, "Active", true, "Active", "", "", ""); + m_isActive.uiCapability()->setUiHidden(true); + + CAF_PDM_InitFieldNoDefault(&m_name, "Name", "Name", "", "", ""); + CAF_PDM_InitFieldNoDefault(&m_value, "Value", "Value", "", "", ""); + + CAF_PDM_InitFieldNoDefault(&m_annotationType, "AnnotationType", "AnnotationType", "", "", ""); + + CAF_PDM_InitFieldNoDefault(&m_sourceCase, "Associated3DCase", "Eclipse Case", "", "", ""); + CAF_PDM_InitFieldNoDefault(&m_equilNum, "m_equilNum", "equil Num", "", "", ""); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimPlotAxisAnnotation::setName(const QString& name) +{ + m_name = name; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimPlotAxisAnnotation::setValue(double value) +{ + m_value = value; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimPlotAxisAnnotation::setEquilibriumData(RimEclipseCase* eclipseCase, + int zeroBasedEquilRegionIndex, + PlotAxisAnnotationType annotationType) +{ + m_sourceCase = eclipseCase; + m_equilNum = zeroBasedEquilRegionIndex + 1; + m_annotationType = annotationType; + + updateName(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RimPlotAxisAnnotation::name() const +{ + return m_name(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +double RimPlotAxisAnnotation::value() const +{ + if (m_annotationType() == PL_EQUIL_WATER_OIL_CONTACT) + { + return selectedItem().waterOilContactDepth(); + } + else if (m_annotationType() == PL_EQUIL_GAS_OIL_CONTACT) + { + return selectedItem().gasOilContactDepth(); + } + + return m_value(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QColor RimPlotAxisAnnotation::color() const +{ + if (m_annotationType() == PL_EQUIL_WATER_OIL_CONTACT) + { + return QColor(0, 0, 0); + } + else if (m_annotationType() == PL_EQUIL_GAS_OIL_CONTACT) + { + return QColor(220, 0, 0); + } + + return QColor(0, 0, 100); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +caf::PdmFieldHandle* RimPlotAxisAnnotation::userDescriptionField() +{ + return &m_name; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +caf::PdmFieldHandle* RimPlotAxisAnnotation::objectToggleField() +{ + return &m_isActive; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimPlotAxisAnnotation::fieldChangedByUi(const caf::PdmFieldHandle* changedField, + const QVariant& oldValue, + const QVariant& newValue) +{ + RimRiuQwtPlotOwnerInterface* parentPlot = nullptr; + this->firstAncestorOrThisOfType(parentPlot); + if (parentPlot) + { + parentPlot->updateAxisDisplay(); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QList RimPlotAxisAnnotation::calculateValueOptions(const caf::PdmFieldHandle* fieldNeedingOptions, + bool* useOptionsOnly) +{ + QList options; + + if (fieldNeedingOptions == &m_sourceCase) + { + RimTools::caseOptionItems(&options); + } + else if (fieldNeedingOptions == &m_equilNum) + { + for (int i = 0; i < static_cast(equilItems().size()); i++) + { + QString uiText = QString("%1").arg(i + 1); + options.push_back(caf::PdmOptionItemInfo(uiText, i)); + } + } + + return options; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimPlotAxisAnnotation::defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering) +{ + uiOrdering.add(&m_annotationType); + + if (m_annotationType() == PL_USER_DEFINED) + { + uiOrdering.add(&m_name); + uiOrdering.add(&m_value); + } + else + { + uiOrdering.add(&m_sourceCase); + uiOrdering.add(&m_equilNum); + } + + uiOrdering.skipRemainingFields(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RigEquil RimPlotAxisAnnotation::selectedItem() const +{ + int index = m_equilNum() - 1; + + if (index < static_cast(equilItems().size())) + { + return equilItems()[index]; + } + + return RigEquil::defaultObject(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector RimPlotAxisAnnotation::equilItems() const +{ + if (m_sourceCase && m_sourceCase->eclipseCaseData()) + { + m_sourceCase->ensureDeckIsParsedForEquilData(); + + return m_sourceCase->eclipseCaseData()->equilData(); + } + + return std::vector(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimPlotAxisAnnotation::updateName() +{ + QString text; + + if (m_annotationType() == PL_EQUIL_WATER_OIL_CONTACT || m_annotationType() == PL_EQUIL_GAS_OIL_CONTACT) + { + double diffBetweenTwoContactDepths = + std::fabs(selectedItem().gasOilContactDepth() - selectedItem().waterOilContactDepth()); + + if (diffBetweenTwoContactDepths < 0.1) + { + text = QString("GWC %1").arg(selectedItem().gasOilContactDepth()); + } + else if (m_annotationType() == PL_EQUIL_WATER_OIL_CONTACT) + { + text = QString("WOC %1").arg(value()); + } + else if (m_annotationType() == PL_EQUIL_GAS_OIL_CONTACT) + { + text = QString("GOC %1").arg(value()); + } + + m_name = text; + } +} diff --git a/ApplicationCode/ProjectDataModel/RimPlotAxisAnnotation.h b/ApplicationCode/ProjectDataModel/RimPlotAxisAnnotation.h new file mode 100644 index 0000000000..fb81cef6f3 --- /dev/null +++ b/ApplicationCode/ProjectDataModel/RimPlotAxisAnnotation.h @@ -0,0 +1,84 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2019- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "cafAppEnum.h" +#include "cafPdmField.h" +#include "cafPdmObject.h" +#include "cafPdmPtrField.h" + +#include + +class RimEclipseCase; +class RigEquil; + +//================================================================================================== +/// +/// +//================================================================================================== +class RimPlotAxisAnnotation : public caf::PdmObject +{ + CAF_PDM_HEADER_INIT; + +public: + enum PlotAxisAnnotationType + { + PL_USER_DEFINED, + PL_EQUIL_WATER_OIL_CONTACT, + PL_EQUIL_GAS_OIL_CONTACT + }; + typedef caf::AppEnum ExportKeywordEnum; + + RimPlotAxisAnnotation(); + + void setName(const QString& name); + void setValue(double value); + + void setEquilibriumData(RimEclipseCase* eclipseCase, int zeroBasedEquilRegionIndex, PlotAxisAnnotationType annotationType); + + QString name() const; + double value() const; + QColor color() const; + + caf::PdmFieldHandle* userDescriptionField() override; + caf::PdmFieldHandle* objectToggleField() override; + + void fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue) override; + + QList calculateValueOptions(const caf::PdmFieldHandle* fieldNeedingOptions, + bool* useOptionsOnly) override; + +protected: + virtual void defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering) override; + +private: + RigEquil selectedItem() const; + std::vector equilItems() const; + void updateName(); + +private: + caf::PdmField m_annotationType; + + caf::PdmField m_isActive; + caf::PdmField m_name; + caf::PdmField m_value; + + caf::PdmPtrField m_sourceCase; + caf::PdmField m_equilNum; +}; diff --git a/ApplicationCode/ProjectDataModel/RimPlotAxisProperties.cpp b/ApplicationCode/ProjectDataModel/RimPlotAxisProperties.cpp new file mode 100644 index 0000000000..a0bedafe20 --- /dev/null +++ b/ApplicationCode/ProjectDataModel/RimPlotAxisProperties.cpp @@ -0,0 +1,545 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2016-2018 Statoil ASA +// Copyright (C) 2019- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "RimPlotAxisProperties.h" + +#include "RiaApplication.h" +#include "RiaDefines.h" +#include "RiaPreferences.h" +#include "RiaFontCache.h" +#include "RigStatisticsCalculator.h" + +#include "RimRiuQwtPlotOwnerInterface.h" +#include "RimPlotAxisAnnotation.h" + +#include "cafPdmUiSliderEditor.h" + +#include "cvfVector2.h" + +#include + +#include + +// clang-format off +namespace caf +{ +template<> +void caf::AppEnum::setUp() +{ + addItem(RimPlotAxisProperties::NUMBER_FORMAT_AUTO, "NUMBER_FORMAT_AUTO", "Auto"); + addItem(RimPlotAxisProperties::NUMBER_FORMAT_DECIMAL, "NUMBER_FORMAT_DECIMAL", "Decimal"); + addItem(RimPlotAxisProperties::NUMBER_FORMAT_SCIENTIFIC, "NUMBER_FORMAT_SCIENTIFIC", "Scientific"); + + setDefault(RimPlotAxisProperties::NUMBER_FORMAT_AUTO); +} +} // namespace caf + +CAF_PDM_SOURCE_INIT(RimPlotAxisProperties, "SummaryYAxisProperties"); + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimPlotAxisProperties::RimPlotAxisProperties() + : m_enableTitleTextSettings(true) +{ + CAF_PDM_InitObject("Axis Properties", ":/LeftAxis16x16.png", "", ""); + + CAF_PDM_InitField(&m_isActive, "Active", true, "Active", "", "", ""); + m_isActive.uiCapability()->setUiHidden(true); + + CAF_PDM_InitFieldNoDefault(&m_name, "Name", "Name", "", "", ""); + m_name.uiCapability()->setUiHidden(true); + + CAF_PDM_InitField(&isAutoTitle, "AutoTitle", true, "Auto Title", "", "", ""); + + CAF_PDM_InitField(&m_displayLongName, "DisplayLongName", true, " Names", "", "", ""); + CAF_PDM_InitField(&m_displayShortName, "DisplayShortName", false, " Acronyms", "", "", ""); + CAF_PDM_InitField(&m_displayUnitText, "DisplayUnitText", true, " Units", "", "", ""); + + CAF_PDM_InitFieldNoDefault(&customTitle, "CustomTitle", "Title", "", "", ""); + + CAF_PDM_InitField(&visibleRangeMax, "VisibleRangeMax", RiaDefines::maximumDefaultValuePlot(), "Max", "", "", ""); + CAF_PDM_InitField(&visibleRangeMin, "VisibleRangeMin", RiaDefines::minimumDefaultValuePlot(), "Min", "", "", ""); + + CAF_PDM_InitFieldNoDefault(&numberFormat, "NumberFormat", "Number Format", "", "", ""); + CAF_PDM_InitField(&numberOfDecimals, "Decimals", 2, "Number of Decimals", "", "", ""); + CAF_PDM_InitField(&scaleFactor, "ScaleFactor", 1.0, "Scale Factor", "", "", ""); + + numberOfDecimals.uiCapability()->setUiEditorTypeName(caf::PdmUiSliderEditor::uiEditorTypeName()); + + CAF_PDM_InitField(&m_isAutoZoom, "AutoZoom", true, "Set Range Automatically", "", "", ""); + CAF_PDM_InitField(&isLogarithmicScaleEnabled, "LogarithmicScale", false, "Logarithmic Scale", "", "", ""); + CAF_PDM_InitField(&m_isAxisInverted, "AxisInverted", false, "Invert Axis", "", "", ""); + + CAF_PDM_InitFieldNoDefault(&m_titlePositionEnum, "TitlePosition", "Title Position", "", "", ""); + CAF_PDM_InitField(&m_titleFontSize, "FontSize", 10, "Font Size", "", "", ""); + m_titleFontSize = RiaFontCache::pointSizeFromFontSizeEnum(RiaApplication::instance()->preferences()->defaultPlotFontSize()); + CAF_PDM_InitField(&m_valuesFontSize, "ValuesFontSize", 10, "Font Size", "", "", ""); + m_valuesFontSize = RiaFontCache::pointSizeFromFontSizeEnum(RiaApplication::instance()->preferences()->defaultPlotFontSize()); + + CAF_PDM_InitFieldNoDefault(&m_annotations, "Annotations", "", "", "", ""); + + m_annotations.uiCapability()->setUiHidden(true); +// m_annotations.uiCapability()->setUiTreeChildrenHidden(true); + + updateOptionSensitivity(); +} +// clang-format on + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimPlotAxisProperties::setEnableTitleTextSettings(bool enable) +{ + m_enableTitleTextSettings = enable; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +caf::PdmFieldHandle* RimPlotAxisProperties::userDescriptionField() +{ + return &m_name; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QList RimPlotAxisProperties::calculateValueOptions(const caf::PdmFieldHandle* fieldNeedingOptions, + bool* useOptionsOnly) +{ + QList options; + *useOptionsOnly = true; + + if (&m_titleFontSize == fieldNeedingOptions || &m_valuesFontSize == fieldNeedingOptions) + { + std::vector fontSizes; + fontSizes.push_back(8); + fontSizes.push_back(9); + fontSizes.push_back(10); + fontSizes.push_back(11); + fontSizes.push_back(12); + fontSizes.push_back(14); + fontSizes.push_back(16); + fontSizes.push_back(18); + fontSizes.push_back(24); + + for (int value : fontSizes) + { + QString text = QString("%1").arg(value); + options.push_back(caf::PdmOptionItemInfo(text, value)); + } + } + else if (fieldNeedingOptions == &scaleFactor) + { + for (int exp = -12; exp <= 12; exp += 3) + { + QString uiText = exp == 0 ? "1" : QString("10 ^ %1").arg(exp); + double value = std::pow(10, exp); + + options.push_back(caf::PdmOptionItemInfo(uiText, value)); + } + } + + return options; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimPlotAxisProperties::defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering) +{ + if (m_enableTitleTextSettings) + { + caf::PdmUiGroup* titleTextGroup = uiOrdering.addNewGroup("Title Text"); + + titleTextGroup->add(&isAutoTitle); + + if (isAutoTitle()) + { + titleTextGroup->add(&m_displayLongName); + titleTextGroup->add(&m_displayShortName); + titleTextGroup->add(&m_displayUnitText); + + customTitle.uiCapability()->setUiReadOnly(true); + } + else + { + titleTextGroup->add(&customTitle); + customTitle.uiCapability()->setUiReadOnly(false); + } + } + + { + caf::PdmUiGroup* titleGroup = uiOrdering.addNewGroup("Title Layout"); + titleGroup->add(&m_titlePositionEnum); + titleGroup->add(&m_titleFontSize); + } + + caf::PdmUiGroup& scaleGroup = *(uiOrdering.addNewGroup("Axis Values")); + scaleGroup.add(&isLogarithmicScaleEnabled); + scaleGroup.add(&m_isAxisInverted); + scaleGroup.add(&numberFormat); + + if (numberFormat() != NUMBER_FORMAT_AUTO) + { + scaleGroup.add(&numberOfDecimals); + scaleGroup.add(&scaleFactor); + } + + scaleGroup.add(&visibleRangeMin); + scaleGroup.add(&visibleRangeMax); + scaleGroup.add(&m_valuesFontSize); + + uiOrdering.skipRemainingFields(true); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimPlotAxisProperties::setNameAndAxis(const QString& name, QwtPlot::Axis axis) +{ + m_name = name; + m_axis = axis; + + if (axis == QwtPlot::yRight) this->setUiIcon(QIcon(":/RightAxis16x16.png")); + if (axis == QwtPlot::xBottom) this->setUiIcon(QIcon(":/BottomAxis16x16.png")); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimPlotAxisPropertiesInterface::AxisTitlePositionType RimPlotAxisProperties::titlePosition() const +{ + return m_titlePositionEnum(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +int RimPlotAxisProperties::titleFontSize() const +{ + return m_titleFontSize; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimPlotAxisProperties::setTitleFontSize(int fontSize) +{ + m_titleFontSize = fontSize; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +int RimPlotAxisProperties::valuesFontSize() const +{ + return m_valuesFontSize; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimPlotAxisProperties::setValuesFontSize(int fontSize) +{ + m_valuesFontSize = fontSize; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QwtPlot::Axis RimPlotAxisProperties::qwtPlotAxisType() const +{ + return m_axis; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RimPlotAxisProperties::name() const +{ + return m_name; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RiaDefines::PlotAxis RimPlotAxisProperties::plotAxisType() const +{ + if (m_axis == QwtPlot::yRight) return RiaDefines::PLOT_AXIS_RIGHT; + if (m_axis == QwtPlot::xBottom) return RiaDefines::PLOT_AXIS_BOTTOM; + + return RiaDefines::PLOT_AXIS_LEFT; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RimPlotAxisProperties::useAutoTitle() const +{ + return isAutoTitle(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RimPlotAxisProperties::showDescription() const +{ + return m_displayLongName(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RimPlotAxisProperties::showAcronym() const +{ + return m_displayShortName(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RimPlotAxisProperties::showUnitText() const +{ + return m_displayUnitText(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RimPlotAxisProperties::isAutoZoom() const +{ + return m_isAutoZoom(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimPlotAxisProperties::setAutoZoom(bool enableAutoZoom) +{ + m_isAutoZoom = enableAutoZoom; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RimPlotAxisProperties::isAxisInverted() const +{ + return m_isAxisInverted(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector RimPlotAxisProperties::annotations() const +{ + return m_annotations.childObjects(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimPlotAxisProperties::appendAnnotation(RimPlotAxisAnnotation* annotation) +{ + m_annotations.push_back(annotation); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimPlotAxisProperties::setAxisInverted(bool inverted) +{ + m_isAxisInverted = inverted; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RimPlotAxisProperties::isActive() const +{ + return m_isActive; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimPlotAxisProperties::setInvertedAxis(bool enable) +{ + m_isAxisInverted = enable; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimPlotAxisProperties::showAnnotationObjectsInProjectTree() +{ + m_annotations.uiCapability()->setUiTreeChildrenHidden(false); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimPlotAxisProperties::fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, + const QVariant& newValue) +{ + if (changedField == &isAutoTitle) + { + updateOptionSensitivity(); + } + else if (changedField == &visibleRangeMax) + { + if (visibleRangeMin > visibleRangeMax) visibleRangeMax = oldValue.toDouble(); + + m_isAutoZoom = false; + } + else if (changedField == &visibleRangeMin) + { + if (visibleRangeMin > visibleRangeMax) visibleRangeMin = oldValue.toDouble(); + + m_isAutoZoom = false; + } + + RimRiuQwtPlotOwnerInterface* parentPlot = nullptr; + this->firstAncestorOrThisOfType(parentPlot); + if (parentPlot) + { + if (changedField == &isLogarithmicScaleEnabled) + { + parentPlot->updateAxisScaling(); + } + else + { + parentPlot->updateAxisDisplay(); + } + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimPlotAxisProperties::updateOptionSensitivity() +{ + customTitle.uiCapability()->setUiReadOnly(isAutoTitle); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimPlotAxisProperties::initAfterRead() +{ + updateOptionSensitivity(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +caf::PdmFieldHandle* RimPlotAxisProperties::objectToggleField() +{ + return &m_isActive; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimPlotAxisLogRangeCalculator::RimPlotAxisLogRangeCalculator(QwtPlot::Axis axis, + const std::vector& qwtCurves) + : m_axis(axis) + , m_curves(qwtCurves) +{ +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimPlotAxisLogRangeCalculator::computeAxisRange(double* minPositive, double* max) const +{ + double minPosValue = HUGE_VAL; + double maxValue = -HUGE_VAL; + + for (const QwtPlotCurve* curve : m_curves) + { + double minPosCurveValue = HUGE_VAL; + double maxCurveValue = -HUGE_VAL; + + if (curveValueRange(curve, &minPosCurveValue, &maxCurveValue)) + { + if (minPosCurveValue < minPosValue) + { + CVF_ASSERT(minPosCurveValue > 0.0); + minPosValue = minPosCurveValue; + } + + if (maxCurveValue > maxValue) + { + maxValue = maxCurveValue; + } + } + } + + if (minPosValue == HUGE_VAL) + { + minPosValue = RiaDefines::minimumDefaultLogValuePlot(); + maxValue = RiaDefines::maximumDefaultValuePlot(); + } + + *minPositive = minPosValue; + *max = maxValue; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RimPlotAxisLogRangeCalculator::curveValueRange(const QwtPlotCurve* qwtCurve, double* minPositive, double* max) const +{ + if (!qwtCurve) return false; + + if (qwtCurve->data()->size() < 1) + { + return false; + } + + float minPosF = std::numeric_limits::infinity(); + float maxF = -std::numeric_limits::infinity(); + + int axisValueIndex = 0; + if (m_axis == QwtPlot::yLeft || m_axis == QwtPlot::yRight) + { + axisValueIndex = 1; + } + + for (size_t i = 0; i < qwtCurve->dataSize(); ++i) + { + QPointF sample = qwtCurve->sample((int) i); + cvf::Vec2f vec(sample.x(), sample.y()); + float value = vec[axisValueIndex]; + if (value == HUGE_VALF) continue; + + maxF = std::max(maxF, value); + if (value > 0.0f && value < minPosF) + { + minPosF = value; + } + } + + *minPositive = minPosF; + *max = maxF; + + return true; +} diff --git a/ApplicationCode/ProjectDataModel/RimPlotAxisProperties.h b/ApplicationCode/ProjectDataModel/RimPlotAxisProperties.h new file mode 100644 index 0000000000..b44250c420 --- /dev/null +++ b/ApplicationCode/ProjectDataModel/RimPlotAxisProperties.h @@ -0,0 +1,148 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2016-2018 Statoil ASA +// Copyright (C) 2019- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "RiaDefines.h" +#include "RimPlotAxisPropertiesInterface.h" + +#include "cafAppEnum.h" +#include "cafPdmChildArrayField.h" +#include "cafPdmField.h" +#include "cafPdmObject.h" + +#include "qwt_plot.h" + +#include + +class RimPlotAxisAnnotation; + +//================================================================================================== +/// +/// +//================================================================================================== +class RimPlotAxisProperties : public caf::PdmObject, public RimPlotAxisPropertiesInterface +{ + CAF_PDM_HEADER_INIT; + +public: + enum NumberFormatType + { + NUMBER_FORMAT_AUTO, + NUMBER_FORMAT_DECIMAL, + NUMBER_FORMAT_SCIENTIFIC + }; + +public: + RimPlotAxisProperties(); + + void setEnableTitleTextSettings(bool enable); + void setNameAndAxis(const QString& name, QwtPlot::Axis axis); + AxisTitlePositionType titlePosition() const override; + int titleFontSize() const override; + void setTitleFontSize(int fontSize) override; + int valuesFontSize() const override; + void setValuesFontSize(int fontSize) override; + + QwtPlot::Axis qwtPlotAxisType() const; + QString name() const; + RiaDefines::PlotAxis plotAxisType() const; + bool useAutoTitle() const; + bool showDescription() const; + bool showAcronym() const; + bool showUnitText() const; + bool isAutoZoom() const; + void setAutoZoom(bool enableAutoZoom); + bool isAxisInverted() const; + void setAxisInverted(bool inverted); + + std::vector annotations() const; + void appendAnnotation(RimPlotAxisAnnotation* annotation); + + caf::PdmField customTitle; + + caf::PdmField visibleRangeMin; + caf::PdmField visibleRangeMax; + + caf::PdmField> numberFormat; + caf::PdmField numberOfDecimals; + caf::PdmField scaleFactor; + caf::PdmField isLogarithmicScaleEnabled; + + bool isActive() const; + + void setInvertedAxis(bool enable); + void showAnnotationObjectsInProjectTree(); + +protected: + void initAfterRead() override; + caf::PdmFieldHandle* userDescriptionField() override; + caf::PdmFieldHandle* objectToggleField() override; + void fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, + const QVariant& newValue) override; + void defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering) override; + + QList calculateValueOptions(const caf::PdmFieldHandle* fieldNeedingOptions, + bool* useOptionsOnly) override; + +private: + void updateOptionSensitivity(); + +private: + caf::PdmField m_isActive; + + caf::PdmField isAutoTitle; + caf::PdmField m_displayShortName; + caf::PdmField m_displayLongName; + caf::PdmField m_displayUnitText; + caf::PdmField m_isAutoZoom; + caf::PdmField m_isAxisInverted; + + caf::PdmField m_name; + QwtPlot::Axis m_axis; + + bool m_enableTitleTextSettings; + + caf::PdmField m_titleFontSize; + caf::PdmField> m_titlePositionEnum; + caf::PdmField m_valuesFontSize; + caf::PdmChildArrayField m_annotations; +}; + +class QwtPlotCurve; + +//================================================================================================== +/// +/// +//================================================================================================== +class RimPlotAxisLogRangeCalculator +{ +public: + RimPlotAxisLogRangeCalculator(QwtPlot::Axis axis, + const std::vector& qwtCurves); + + void computeAxisRange(double* minPositive, double* max) const; + +private: + bool curveValueRange(const QwtPlotCurve* qwtCurve, double* minPositive, double* max) const; + +private: + QwtPlot::Axis m_axis; + const std::vector m_curves; +}; diff --git a/ApplicationCode/ProjectDataModel/RimPlotAxisPropertiesInterface.cpp b/ApplicationCode/ProjectDataModel/RimPlotAxisPropertiesInterface.cpp new file mode 100644 index 0000000000..4ea07e82c6 --- /dev/null +++ b/ApplicationCode/ProjectDataModel/RimPlotAxisPropertiesInterface.cpp @@ -0,0 +1,35 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2019- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// +#include "RimPlotAxisPropertiesInterface.h" + +#include "cafAppEnum.h" + +// clang-format off +namespace caf +{ +template<> +void caf::AppEnum::setUp() +{ + addItem(RimPlotAxisPropertiesInterface::AXIS_TITLE_CENTER, "AXIS_TITLE_CENTER", "Center"); + addItem(RimPlotAxisPropertiesInterface::AXIS_TITLE_END, "AXIS_TITLE_END", "At End"); + + setDefault(RimPlotAxisPropertiesInterface::AXIS_TITLE_CENTER); +} +} // namespace caf + + diff --git a/ApplicationCode/ProjectDataModel/RimPlotAxisPropertiesInterface.h b/ApplicationCode/ProjectDataModel/RimPlotAxisPropertiesInterface.h new file mode 100644 index 0000000000..a12c3d87ef --- /dev/null +++ b/ApplicationCode/ProjectDataModel/RimPlotAxisPropertiesInterface.h @@ -0,0 +1,37 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2019- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// +#pragma once + +class RimPlotAxisPropertiesInterface +{ +public: + enum AxisTitlePositionType + { + AXIS_TITLE_CENTER, + AXIS_TITLE_END + }; + +public: + virtual AxisTitlePositionType titlePosition() const = 0; + virtual int titleFontSize() const = 0; + virtual void setTitleFontSize(int fontSize) = 0; + virtual int valuesFontSize() const = 0; + virtual void setValuesFontSize(int fontSize) = 0; + +}; + diff --git a/ApplicationCode/ProjectDataModel/RimPlotCurve.cpp b/ApplicationCode/ProjectDataModel/RimPlotCurve.cpp index 5feb88ef8a..321bb7022e 100644 --- a/ApplicationCode/ProjectDataModel/RimPlotCurve.cpp +++ b/ApplicationCode/ProjectDataModel/RimPlotCurve.cpp @@ -96,6 +96,9 @@ RimPlotCurve::RimPlotCurve() CAF_PDM_InitFieldNoDefault(&m_customCurveName, "CurveDescription", "Custom Name", "", "", ""); m_customCurveName.uiCapability()->setUiHidden(true); + CAF_PDM_InitFieldNoDefault(&m_legendEntryText, "LegendDescription", "Legend Name", "", "", ""); + m_legendEntryText.uiCapability()->setUiHidden(true); + CAF_PDM_InitField(&m_isUsingAutoName, "AutoName", true, "Auto Name", "", "", ""); CAF_PDM_InitField(&m_curveColor, "Color", cvf::Color3f(cvf::Color3::BLACK), "Color", "", "", ""); @@ -106,6 +109,7 @@ RimPlotCurve::RimPlotCurve() CAF_PDM_InitFieldNoDefault(&m_curveInterpolation, "CurveInterpolation", "Interpolation", "", "", ""); CAF_PDM_InitFieldNoDefault(&m_lineStyle, "LineStyle", "Line Style", "", "", ""); CAF_PDM_InitFieldNoDefault(&m_pointSymbol, "PointSymbol", "Symbol", "", "", ""); + CAF_PDM_InitField(&m_symbolEdgeColor, "SymbolEdgeColor", cvf::Color3f(cvf::Color3::BLACK), "Symbol Edge Color", "", "", ""); CAF_PDM_InitField(&m_symbolSkipPixelDistance, "SymbolSkipPxDist", 0.0f, "Symbol Skip Distance", "", "Minimum pixel distance between symbols", ""); @@ -159,7 +163,8 @@ void RimPlotCurve::fieldChangedByUi(const caf::PdmFieldHandle* changedField, con || &m_lineStyle == changedField || &m_symbolSkipPixelDistance == changedField || &m_curveInterpolation == changedField - || &m_symbolSize == changedField) + || &m_symbolSize == changedField + || &m_symbolEdgeColor == changedField) { updateCurveAppearance(); @@ -213,6 +218,26 @@ void RimPlotCurve::setCustomName(const QString& customName) m_customCurveName = customName; } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RimPlotCurve::legendEntryText() const +{ + if (!m_legendEntryText().isEmpty()) + { + return m_legendEntryText; + } + return m_customCurveName; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimPlotCurve::setLegendEntryText(const QString& legendEntryText) +{ + m_legendEntryText = legendEntryText; +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -287,6 +312,10 @@ void RimPlotCurve::setParentQwtPlotNoReplot(QwtPlot* plot) { m_qwtPlotCurve->attach(m_parentQwtPlot); } + else + { + m_qwtPlotCurve->detach(); + } } //-------------------------------------------------------------------------------------------------- @@ -350,9 +379,9 @@ void RimPlotCurve::setCurveVisiblity(bool visible) } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- -void RimPlotCurve::updateCurveNameAndUpdatePlotLegendAndTitle() +void RimPlotCurve::updateCurveName() { if (m_isUsingAutoName) { @@ -363,25 +392,32 @@ void RimPlotCurve::updateCurveNameAndUpdatePlotLegendAndTitle() m_curveName = m_customCurveName; } - m_qwtPlotCurve->setTitle(m_curveName); - updateLegendEntryVisibilityAndPlotLegend(); + if (!m_legendEntryText().isEmpty()) + { + m_qwtPlotCurve->setTitle(m_legendEntryText); + } + else + { + m_qwtPlotCurve->setTitle(m_curveName); + } + } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RimPlotCurve::updateCurveNameNoLegendUpdate() +void RimPlotCurve::updateCurveNameAndUpdatePlotLegendAndTitle() { - if (m_isUsingAutoName) - { - m_curveName = this->createCurveAutoName(); - } - else - { - m_curveName = m_customCurveName; - } + updateCurveName(); + updateLegendEntryVisibilityAndPlotLegend(); +} - m_qwtPlotCurve->setTitle(m_curveName); +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimPlotCurve::updateCurveNameNoLegendUpdate() +{ + updateCurveName(); updateLegendEntryVisibilityNoPlotUpdate(); } @@ -418,6 +454,14 @@ void RimPlotCurve::updateLegendsInPlot() } } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimPlotCurve::defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering) +{ + throw std::logic_error("The method or operation is not implemented."); +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -425,6 +469,7 @@ void RimPlotCurve::appearanceUiOrdering(caf::PdmUiOrdering& uiOrdering) { uiOrdering.add(&m_curveColor); uiOrdering.add(&m_pointSymbol); + uiOrdering.add(&m_symbolEdgeColor); uiOrdering.add(&m_symbolSize); uiOrdering.add(&m_symbolSkipPixelDistance); uiOrdering.add(&m_lineStyle); @@ -442,6 +487,22 @@ void RimPlotCurve::curveNameUiOrdering(caf::PdmUiOrdering& uiOrdering) uiOrdering.add(&m_curveName); } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimPlotCurve::updateUiIconFromPlotSymbol() +{ + if (m_pointSymbol() != RiuQwtSymbol::NoSymbol) + { + QColor curveColor(m_curveColor.value().rByte(), m_curveColor.value().gByte(), m_curveColor.value().bByte()); + + QSizeF iconSize(24, 24); + QwtGraphic graphic = m_qwtPlotCurve->legendIcon(0, iconSize); + QPixmap pixmap = graphic.toPixmap(); + setUiIcon(QIcon(pixmap)); + } +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -479,8 +540,7 @@ void RimPlotCurve::updateCurveAppearance() { CVF_ASSERT(m_qwtPlotCurve); - QColor curveColor(m_curveColor.value().rByte(), m_curveColor.value().gByte(), m_curveColor.value().bByte()); - + QColor curveColor(m_curveColor.value().rByte(), m_curveColor.value().gByte(), m_curveColor.value().bByte()); QwtSymbol* symbol = nullptr; if (m_pointSymbol() != RiuQwtSymbol::SYMBOL_NONE) @@ -489,6 +549,10 @@ void RimPlotCurve::updateCurveAppearance() symbol = new RiuQwtSymbol(m_pointSymbol(), m_symbolLabel, m_symbolLabelPosition); symbol->setSize(m_symbolSize, m_symbolSize); symbol->setColor(curveColor); + + QColor symbolEdgeColor(m_symbolEdgeColor.value().rByte(), m_symbolEdgeColor.value().gByte(), m_symbolEdgeColor.value().bByte()); + + symbol->setPen(symbolEdgeColor); } m_qwtPlotCurve->setAppearance(m_lineStyle(), m_curveInterpolation(), m_curveThickness(), curveColor); @@ -500,18 +564,21 @@ void RimPlotCurve::updateCurveAppearance() // Make sure the legend lines are long enough to distinguish between line types. // Standard width in Qwt is 8 which is too short. // Use 10 and scale this by curve thickness + add space for displaying symbol. - QSize legendIconSize = m_qwtPlotCurve->legendIconSize(); - - int symbolWidth = 0; - if (symbol) + if (m_lineStyle() != RiuQwtPlotCurve::STYLE_NONE) { - symbolWidth = symbol->boundingRect().size().width() + 2; - } + QSize legendIconSize = m_qwtPlotCurve->legendIconSize(); - int width = std::max(10 * m_curveThickness, (symbolWidth * 3) / 2); - - legendIconSize.setWidth(width); - m_qwtPlotCurve->setLegendIconSize(legendIconSize); + int symbolWidth = 0; + if (symbol) + { + symbolWidth = symbol->boundingRect().size().width() + 2; + } + + int width = std::max(10 * m_curveThickness, (symbolWidth * 3) / 2); + + legendIconSize.setWidth(width); + m_qwtPlotCurve->setLegendIconSize(legendIconSize); + } } //-------------------------------------------------------------------------------------------------- @@ -614,6 +681,22 @@ RiuQwtSymbol::PointSymbolEnum RimPlotCurve::symbol() return m_pointSymbol(); } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +cvf::Color3f RimPlotCurve::symbolEdgeColor() const +{ + return m_symbolEdgeColor; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimPlotCurve::setSymbolEdgeColor(const cvf::Color3f& edgeColor) +{ + m_symbolEdgeColor = edgeColor; +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -652,6 +735,7 @@ void RimPlotCurve::setLineThickness(int thickness) void RimPlotCurve::resetAppearance() { setColor(cvf::Color3f(cvf::Color3::BLACK)); + setSymbolEdgeColor(cvf::Color3f(cvf::Color3::BLACK)); setLineThickness(2); setLineStyle(RiuQwtPlotCurve::STYLE_SOLID); setSymbol(RiuQwtSymbol::SYMBOL_NONE); diff --git a/ApplicationCode/ProjectDataModel/RimPlotCurve.h b/ApplicationCode/ProjectDataModel/RimPlotCurve.h index 51bf266ada..0a2ee328e8 100644 --- a/ApplicationCode/ProjectDataModel/RimPlotCurve.h +++ b/ApplicationCode/ProjectDataModel/RimPlotCurve.h @@ -62,6 +62,8 @@ class RimPlotCurve : public caf::PdmObject void setLineStyle(RiuQwtPlotCurve::LineStyleEnum lineStyle); void setSymbol(RiuQwtSymbol::PointSymbolEnum symbolStyle); RiuQwtSymbol::PointSymbolEnum symbol(); + cvf::Color3f symbolEdgeColor() const; + void setSymbolEdgeColor(const cvf::Color3f& edgeColor); void setSymbolSkipDistance(float distance); void setSymbolLabel(const QString& label); void setSymbolSize(int sizeInPixels); @@ -71,12 +73,16 @@ class RimPlotCurve : public caf::PdmObject bool isCurveVisible() const; void setCurveVisiblity(bool visible); + void updateCurveName(); void updateCurveNameAndUpdatePlotLegendAndTitle(); void updateCurveNameNoLegendUpdate(); QString curveName() const { return m_curveName; } virtual QString curveExportDescription(const RifEclipseSummaryAddress& address = RifEclipseSummaryAddress()) const { return m_curveName; } void setCustomName(const QString& customName); + QString legendEntryText() const; + void setLegendEntryText(const QString& legendEntryText); + void updateCurveVisibility(bool updateParentPlot); void updateLegendEntryVisibilityAndPlotLegend(); void updateLegendEntryVisibilityNoPlotUpdate(); @@ -87,18 +93,21 @@ class RimPlotCurve : public caf::PdmObject virtual void updateCurveAppearance(); bool isCrossPlotCurve() const; + void updateUiIconFromPlotSymbol(); protected: virtual QString createCurveAutoName() = 0; virtual void updateZoomInParentPlot() = 0; virtual void onLoadDataAndUpdate(bool updateParentPlot) = 0; - void initAfterRead() override; + void initAfterRead() override; void updateCurvePresentation(bool updatePlotLegendAndTitle); void updateOptionSensitivity(); void updatePlotTitle(); virtual void updateLegendsInPlot(); + void defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering) override; + protected: // Overridden PDM methods @@ -108,7 +117,6 @@ class RimPlotCurve : public caf::PdmObject QList calculateValueOptions(const caf::PdmFieldHandle* fieldNeedingOptions, bool* useOptionsOnly) override; void appearanceUiOrdering(caf::PdmUiOrdering& uiOrdering); void curveNameUiOrdering(caf::PdmUiOrdering& uiOrdering); - private: bool canCurveBeAttached() const; @@ -122,7 +130,8 @@ class RimPlotCurve : public caf::PdmObject caf::PdmField m_showLegend; QString m_symbolLabel; caf::PdmField m_symbolSize; - + caf::PdmField m_legendEntryText; + caf::PdmField m_isUsingAutoName; caf::PdmField m_curveColor; caf::PdmField m_curveThickness; @@ -133,6 +142,7 @@ class RimPlotCurve : public caf::PdmObject caf::PdmField m_lineStyle; caf::PdmField m_curveInterpolation; RiuQwtSymbol::LabelPosition m_symbolLabelPosition; + caf::PdmField m_symbolEdgeColor; }; diff --git a/ApplicationCode/ProjectDataModel/RimProject.cpp b/ApplicationCode/ProjectDataModel/RimProject.cpp index f4b1981081..7cf0922fd1 100644 --- a/ApplicationCode/ProjectDataModel/RimProject.cpp +++ b/ApplicationCode/ProjectDataModel/RimProject.cpp @@ -30,10 +30,14 @@ #include "RigEclipseCaseData.h" #include "RigGridBase.h" +#include "RimAdvancedSnapshotExportDefinition.h" +#include "RimAnnotationCollection.h" +#include "RimAnnotationInViewCollection.h" #include "RimCalcScript.h" #include "RimCase.h" #include "RimCaseCollection.h" #include "RimCommandObject.h" +#include "RimCompletionTemplateCollection.h" #include "RimContextCommandBuilder.h" #include "RimDialogData.h" #include "RimEclipseCase.h" @@ -44,21 +48,28 @@ #include "RimFractureTemplateCollection.h" #include "RimGeoMechCase.h" #include "RimGeoMechModels.h" +#include "RimGridCrossPlotCollection.h" #include "RimGridSummaryCase.h" #include "RimGridView.h" #include "RimIdenticalGridCaseGroup.h" #include "RimMainPlotCollection.h" -#include "RimMultiSnapshotDefinition.h" +#include "RimMeasurement.h" +#include "RimObservedData.h" #include "RimObservedDataCollection.h" #include "RimOilField.h" #include "RimPltPlotCollection.h" +#include "RimPolylinesFromFileAnnotation.h" #include "RimRftPlotCollection.h" +#include "RimSaturationPressurePlotCollection.h" #include "RimScriptCollection.h" #include "RimSummaryCalculationCollection.h" #include "RimSummaryCaseMainCollection.h" #include "RimSummaryCrossPlotCollection.h" #include "RimSummaryPlotCollection.h" #include "RimTools.h" +#include "RimUserDefinedPolylinesAnnotation.h" +#include "RimValveTemplate.h" +#include "RimValveTemplateCollection.h" #include "RimViewLinker.h" #include "RimViewLinkerCollection.h" #include "RimWellLogFile.h" @@ -139,6 +150,12 @@ RimProject::RimProject(void) CAF_PDM_InitField(&m_showPlotWindow, "showPlotWindow", false, "Show Plot Window", "", "", ""); m_showPlotWindow.uiCapability()->setUiHidden(true); + CAF_PDM_InitField(&m_subWindowsTiled3DWindow, "tiled3DWindow", false, "Tile 3D Window", "", "", ""); + m_subWindowsTiled3DWindow.uiCapability()->setUiHidden(true); + + CAF_PDM_InitField(&m_subWindowsTiledPlotWindow, "tiledPlotWindow", false, "Tile Plot Window", "", "", ""); + m_subWindowsTiledPlotWindow.uiCapability()->setUiHidden(true); + CAF_PDM_InitFieldNoDefault(&m_dialogData, "DialogData", "DialogData", "", "", ""); m_dialogData = new RimDialogData(); m_dialogData.uiCapability()->setUiHidden(true); @@ -442,7 +459,7 @@ void RimProject::setProjectFileNameAndUpdateDependencies(const QString& projectF QString oldProjectPath = fileInfoOld.path(); std::vector filePaths; - fieldsByType(this, filePaths); + fieldContentsByType(this, filePaths); for (caf::FilePath* filePath : filePaths) { @@ -680,7 +697,7 @@ void RimProject::allNotLinkedViews(std::vector& views) //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RimProject::allVisibleViews(std::vector& views) +void RimProject::allVisibleViews(std::vector& views) const { std::vector cases; allCases(cases); @@ -704,10 +721,10 @@ void RimProject::allVisibleViews(std::vector& views) //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RimProject::allVisibleGridViews(std::vector& views) +void RimProject::allVisibleGridViews(std::vector& views) const { std::vector visibleViews; - this->allVisibleViews(visibleViews); + this->allVisibleViews(visibleViews); for ( Rim3dView* view : visibleViews ) { RimGridView* gridView = dynamic_cast(view); @@ -841,6 +858,38 @@ bool RimProject::showPlotWindow() const return m_showPlotWindow; } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RimProject::subWindowsTiled3DWindow() const +{ + return m_subWindowsTiled3DWindow; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RimProject::subWindowsTiledPlotWindow() const +{ + return m_subWindowsTiledPlotWindow; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimProject::setSubWindowsTiledIn3DWindow(bool tiled) +{ + m_subWindowsTiled3DWindow = tiled; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimProject::setSubWindowsTiledInPlotWindow(bool tiled) +{ + m_subWindowsTiledPlotWindow = tiled; +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -916,7 +965,6 @@ std::vector RimProject::simulationWellNames() const //-------------------------------------------------------------------------------------------------- RimWellPath* RimProject::wellPathFromSimWellName(const QString& simWellName, int branchIndex) { - std::vector paths; for (RimWellPath* const path : allWellPaths()) { if (QString::compare(path->associatedSimulationWellName(), simWellName) == 0 && @@ -957,6 +1005,83 @@ std::vector RimProject::allWellPaths() const return paths; } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector RimProject::textAnnotations() const +{ + std::vector annotations; + + // 'Global' text annotations + for (const auto& oilField : oilFields()) + { + auto annotationColl = oilField->annotationCollection(); + for (const auto& annotation : annotationColl->textAnnotations()) + { + annotations.push_back(annotation); + } + } + + // 'Local' text annotations + std::vector visibleViews; + allVisibleGridViews(visibleViews); + for (const auto& view : visibleViews) + { + std::vector annotationColls; + view->descendantsIncludingThisOfType(annotationColls); + + if (annotationColls.size() == 1) + { + for (const auto& annotation : annotationColls.front()->textAnnotations()) + { + annotations.push_back(annotation); + } + } + } + + return annotations; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector RimProject::reachCircleAnnotations() const +{ + std::vector annotations; + for (const auto& oilField : oilFields()) + { + auto annotationColl = oilField->annotationCollection(); + for (const auto& annotation : annotationColl->reachCircleAnnotations()) + { + annotations.push_back(annotation); + } + } + return annotations; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector RimProject::polylineAnnotations() const +{ + std::vector annotations; + for (const auto& oilField : oilFields()) + { + auto annotationColl = oilField->annotationCollection(); + for (const auto& annotation : annotationColl->userDefinedPolylineAnnotations()) + { + annotations.push_back(annotation); + } + + for (const auto& annotation : annotationColl->polylinesFromFileAnnotations()) + { + annotations.push_back(annotation); + } + + } + return annotations; +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -1014,6 +1139,38 @@ std::vector RimProject::allFractureTemplates() const return templates; } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector RimProject::allValveTemplateCollections() const +{ + std::vector templColls; + std::vector rimOilFields; + + allOilFields(rimOilFields); + for (RimOilField* oilField : rimOilFields) + { + templColls.push_back(oilField->valveTemplateCollection()); + } + return templColls; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector RimProject::allValveTemplates() const +{ + std::vector templates; + for (RimValveTemplateCollection* templColl : allValveTemplateCollections()) + { + for (RimValveTemplate* templ : templColl->valveTemplates()) + { + templates.push_back(templ); + } + } + return templates; +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -1044,6 +1201,14 @@ RiaEclipseUnitTools::UnitSystemType RimProject::commonUnitSystemForAllCases() co return commonUnitSystem; } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimMeasurement* RimProject::measurement() const +{ + return activeOilField()->measurement; +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -1067,7 +1232,7 @@ void RimProject::defineUiTreeOrdering(caf::PdmUiTreeOrdering& uiTreeOrdering, QS if (uiConfigName == "PlotWindow") { { - auto itemCollection = uiTreeOrdering.add("Cases", ":/Folder.png"); + auto itemCollection = uiTreeOrdering.add("Cases and Data", ":/Folder.png"); RimOilField* oilField = activeOilField(); if (oilField) @@ -1115,6 +1280,16 @@ void RimProject::defineUiTreeOrdering(caf::PdmUiTreeOrdering& uiTreeOrdering, QS { itemCollection->add(mainPlotCollection->flowPlotCollection()); } + + if (mainPlotCollection->gridCrossPlotCollection()) + { + itemCollection->add(mainPlotCollection->gridCrossPlotCollection()); + } + + if (mainPlotCollection->saturationPressurePlotCollection()) + { + itemCollection->add(mainPlotCollection->saturationPressurePlotCollection()); + } } } else @@ -1132,7 +1307,8 @@ void RimProject::defineUiTreeOrdering(caf::PdmUiTreeOrdering& uiTreeOrdering, QS if (oilField->geoMechModels()) uiTreeOrdering.add(oilField->geoMechModels()); if (oilField->wellPathCollection()) uiTreeOrdering.add(oilField->wellPathCollection()); if (oilField->formationNamesCollection()) uiTreeOrdering.add(oilField->formationNamesCollection()); - if (oilField->fractureDefinitionCollection()) uiTreeOrdering.add(oilField->fractureDefinitionCollection()); + if (oilField->completionTemplateCollection()) uiTreeOrdering.add(oilField->completionTemplateCollection()); + if (oilField->annotationCollection()) uiTreeOrdering.add(oilField->annotationCollection()); } uiTreeOrdering.add(scriptCollection()); diff --git a/ApplicationCode/ProjectDataModel/RimProject.h b/ApplicationCode/ProjectDataModel/RimProject.h index 7f349e0734..244185af1c 100644 --- a/ApplicationCode/ProjectDataModel/RimProject.h +++ b/ApplicationCode/ProjectDataModel/RimProject.h @@ -35,15 +35,20 @@ class RigGridManager; class RigMainGrid; class RigWellPath; +class RimTextAnnotation; +class RimReachCircleAnnotation; +class RimPolylinesAnnotation; class RimSummaryCalculationCollection; class RimCase; class RimCommandObject; +class RimCommandObject; class RimDialogData; class RimEclipseCase; class RimGeoMechCase; class RimIdenticalGridCaseGroup; class RimMainPlotCollection; -class RimMultiSnapshotDefinition; +class RimMeasurement; +class RimAdvancedSnapshotExportDefinition; class RimObservedData; class RimOilField; class RimScriptCollection; @@ -58,6 +63,9 @@ class RimWellPath; class RimWellPathImport; class RimFractureTemplateCollection; class RimFractureTemplate; +class RimValveTemplateCollection; +class RimValveTemplate; +class RimCompletionTemplateCollection; namespace caf { @@ -88,7 +96,7 @@ class RimProject : public caf::PdmDocument caf::PdmChildField calculationCollection; caf::PdmChildArrayField commandObjects; - caf::PdmChildArrayField multiSnapshotDefinitions; + caf::PdmChildArrayField multiSnapshotDefinitions; caf::PdmField mainWindowTreeViewState; caf::PdmField mainWindowCurrentModelIndexPath; @@ -112,8 +120,8 @@ class RimProject : public caf::PdmDocument std::vector summaryGroups() const; RimSummaryCaseMainCollection* firstSummaryCaseMainCollection() const; - void allVisibleViews(std::vector& views); - void allVisibleGridViews(std::vector& views); + void allVisibleViews(std::vector& views) const; + void allVisibleGridViews(std::vector& views) const; void allNotLinkedViews(std::vector& views); void scheduleCreateDisplayModelAndRedrawAllViews(); @@ -129,6 +137,12 @@ class RimProject : public caf::PdmDocument bool show3DWindow() const; bool showPlotWindow() const; + bool subWindowsTiled3DWindow() const; + bool subWindowsTiledPlotWindow() const; + + void setSubWindowsTiledIn3DWindow(bool tiled); + void setSubWindowsTiledInPlotWindow(bool tiled); + void reloadCompletionTypeResultsInAllViews(); void reloadCompletionTypeResultsForEclipseCase(RimEclipseCase* eclipseCase); @@ -142,13 +156,20 @@ class RimProject : public caf::PdmDocument RimWellPath* wellPathFromSimWellName(const QString& simWellName, int branchIndex = -1); RimWellPath* wellPathByName(const QString& wellPathName) const; std::vector allWellPaths() const; + std::vector textAnnotations() const; + std::vector reachCircleAnnotations() const; + std::vector polylineAnnotations() const; std::vector geoMechCases() const; std::vector allFractureTemplateCollections() const; - std::vector allFractureTemplates() const; + std::vector allFractureTemplates() const; + + std::vector allValveTemplateCollections() const; + std::vector allValveTemplates() const; RiaEclipseUnitTools::UnitSystemType commonUnitSystemForAllCases() const; + RimMeasurement* measurement() const; protected: // Overridden methods @@ -160,7 +181,7 @@ class RimProject : public caf::PdmDocument private: template - void fieldsByType(caf::PdmObjectHandle* object, std::vector& typedFields); + void fieldContentsByType(caf::PdmObjectHandle* object, std::vector& typedFields); private: caf::PdmField m_projectFileVersionString; @@ -171,6 +192,9 @@ class RimProject : public caf::PdmDocument caf::PdmField m_show3DWindow; caf::PdmField m_showPlotWindow; + caf::PdmField m_subWindowsTiled3DWindow; + caf::PdmField m_subWindowsTiledPlotWindow; + caf::PdmField nextValidCaseId; // Unique case ID within a project, used to identify a case from Octave scripts caf::PdmField nextValidCaseGroupId; // Unique case group ID within a project, used to identify a case group from Octave scripts @@ -182,7 +206,7 @@ class RimProject : public caf::PdmDocument /// //-------------------------------------------------------------------------------------------------- template -void RimProject::fieldsByType(caf::PdmObjectHandle* object, std::vector& typedFields) +void RimProject::fieldContentsByType(caf::PdmObjectHandle* object, std::vector& typedFields) { if (!object) return; @@ -210,6 +234,6 @@ void RimProject::fieldsByType(caf::PdmObjectHandle* object, std::vector& typ for (const auto& child : children) { - fieldsByType(child, typedFields); + fieldContentsByType(child, typedFields); } } diff --git a/ApplicationCode/ProjectDataModel/RimRegularLegendConfig.cpp b/ApplicationCode/ProjectDataModel/RimRegularLegendConfig.cpp index c4ddeac25b..75de5fa02f 100644 --- a/ApplicationCode/ProjectDataModel/RimRegularLegendConfig.cpp +++ b/ApplicationCode/ProjectDataModel/RimRegularLegendConfig.cpp @@ -31,6 +31,7 @@ #include "RimEnsembleCurveSetColorManager.h" #include "RimEclipseView.h" #include "RimGeoMechResultDefinition.h" +#include "RimGridCrossPlotDataSet.h" #include "RimIntersectionCollection.h" #include "RimStimPlanColors.h" #include "RimViewLinker.h" @@ -125,7 +126,7 @@ RimRegularLegendConfig::RimRegularLegendConfig() m_localAutoNegClosestToZero(0), m_isAllTimeStepsRangeDisabled(false) { - CAF_PDM_InitObject("Legend Definition", ":/Legend.png", "", ""); + CAF_PDM_InitObject("Color Legend", ":/Legend.png", "", ""); CAF_PDM_InitField(&m_showLegend, "ShowLegend", true, "Show Legend", "", "", ""); m_showLegend.uiCapability()->setUiHidden(true); CAF_PDM_InitField(&m_numLevels, "NumberOfLevels", 8, "Number of Levels", "", "A hint on how many tick marks you whish.",""); @@ -149,7 +150,7 @@ RimRegularLegendConfig::RimRegularLegendConfig() m_categoryMapper = new caf::CategoryMapper; - cvf::Font* standardFont = RiaApplication::instance()->standardFont(); + cvf::Font* standardFont = RiaApplication::instance()->defaultSceneFont(); m_scalarMapperLegend = new caf::OverlayScalarMapperLegend(standardFont); m_categoryLegend = new caf::CategoryLegend(standardFont, m_categoryMapper.p()); @@ -256,6 +257,14 @@ void RimRegularLegendConfig::fieldChangedByUi(const caf::PdmFieldHandle* changed { ensembleCurveSet->onLegendDefinitionChanged(); } + + RimGridCrossPlotDataSet* crossPlotCurveSet; + firstAncestorOrThisOfType(crossPlotCurveSet); + if (crossPlotCurveSet) + { + crossPlotCurveSet->destroyCurves(); + crossPlotCurveSet->loadDataAndUpdate(true); + } } //-------------------------------------------------------------------------------------------------- @@ -439,6 +448,14 @@ void RimRegularLegendConfig::updateLegend() } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimRegularLegendConfig::setTickNumberFormat(NumberFormatType numberFormat) +{ + m_tickNumberFormat = numberFormat; +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -537,7 +554,7 @@ void RimRegularLegendConfig::recreateLegend() // has been removed, (and thus the opengl resources has been deleted) The text in // the legend disappeared because of this, so workaround: recreate the legend when needed: - cvf::Font* standardFont = RiaApplication::instance()->standardFont(); + cvf::Font* standardFont = RiaApplication::instance()->defaultSceneFont(); m_scalarMapperLegend = new caf::OverlayScalarMapperLegend(standardFont); m_categoryLegend = new caf::CategoryLegend(standardFont, m_categoryMapper.p()); @@ -714,14 +731,6 @@ bool RimRegularLegendConfig::showLegend() const return m_showLegend; } -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RimRegularLegendConfig::setShowLegend(bool show) -{ - m_showLegend = show; -} - //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -823,6 +832,18 @@ cvf::Color3ubArray RimRegularLegendConfig::colorArrayFromColorType(ColorRangesTy //-------------------------------------------------------------------------------------------------- void RimRegularLegendConfig::defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering) { + if (uiConfigName == "NumLevelsOnly") + { + uiOrdering.add(&m_numLevels); + uiOrdering.skipRemainingFields(true); + } + else if (uiConfigName == "NumIntervalsOnly") + { + m_numLevels.uiCapability()->setUiName("Number of Intervals"); + uiOrdering.add(&m_numLevels); + uiOrdering.skipRemainingFields(true); + } + else { caf::PdmUiOrdering * formatGr = uiOrdering.addNewGroup("Format"); formatGr->add(&m_numLevels); @@ -836,7 +857,6 @@ void RimRegularLegendConfig::defineUiOrdering(QString uiConfigName, caf::PdmUiOr mappingGr->add(&m_userDefinedMaxValue); mappingGr->add(&m_userDefinedMinValue); } - updateFieldVisibility(); } @@ -856,6 +876,9 @@ QList RimRegularLegendConfig::calculateValueOptions(cons this->firstAncestorOrThisOfType(ensembleCurveSet); if (ensembleCurveSet) hasEnsembleCurveSetParent = true; + RimGridCrossPlotDataSet* crossPlotCurveSet = nullptr; + this->firstAncestorOrThisOfType(crossPlotCurveSet); + bool isCategoryResult = false; { RimEclipseCellColors* eclCellColors = nullptr; @@ -868,7 +891,8 @@ QList RimRegularLegendConfig::calculateValueOptions(cons if ( ( eclCellColors && eclCellColors->hasCategoryResult()) || ( gmCellColors && gmCellColors->hasCategoryResult()) || ( eclCellEdgColors && eclCellEdgColors->hasCategoryResult()) - || ( ensembleCurveSet && ensembleCurveSet->currentEnsembleParameterType() == EnsembleParameter::TYPE_TEXT) ) + || ( ensembleCurveSet && ensembleCurveSet->currentEnsembleParameterType() == EnsembleParameter::TYPE_TEXT) + || ( crossPlotCurveSet && crossPlotCurveSet->groupingByCategoryResult())) { isCategoryResult = true; } @@ -881,8 +905,12 @@ QList RimRegularLegendConfig::calculateValueOptions(cons // This is an app enum field, see cafInternalPdmFieldTypeSpecializations.h for the default specialization of this type std::vector mappingTypes; mappingTypes.push_back(LINEAR_DISCRETE); - mappingTypes.push_back(LINEAR_CONTINUOUS); - mappingTypes.push_back(LOG10_CONTINUOUS); + + if (!crossPlotCurveSet) + { + mappingTypes.push_back(LINEAR_CONTINUOUS); + mappingTypes.push_back(LOG10_CONTINUOUS); + } mappingTypes.push_back(LOG10_DISCRETE); if (isCategoryResult) diff --git a/ApplicationCode/ProjectDataModel/RimRegularLegendConfig.h b/ApplicationCode/ProjectDataModel/RimRegularLegendConfig.h index a1ba2857cd..9dd94da5f2 100644 --- a/ApplicationCode/ProjectDataModel/RimRegularLegendConfig.h +++ b/ApplicationCode/ProjectDataModel/RimRegularLegendConfig.h @@ -103,6 +103,8 @@ class RimRegularLegendConfig : public RimLegendConfig ColorRangesType colorRange() { return m_colorRangeMode();} void setMappingMode(MappingType mappingType); MappingType mappingMode() { return m_mappingMode();} + void setTickNumberFormat(NumberFormatType numberFormat); + void disableAllTimeStepsRange(bool doDisable); void setAutomaticRanges(double globalMin, double globalMax, double localMin, double localMax); @@ -121,7 +123,6 @@ class RimRegularLegendConfig : public RimLegendConfig cvf::ScalarMapper* scalarMapper() { return m_currentScalarMapper.p(); } bool showLegend() const; - void setShowLegend(bool show); const caf::TitledOverlayFrame* titledOverlayFrame() const override; caf::TitledOverlayFrame* titledOverlayFrame() override; diff --git a/ApplicationCode/ProjectDataModel/RimReloadCaseTools.cpp b/ApplicationCode/ProjectDataModel/RimReloadCaseTools.cpp new file mode 100644 index 0000000000..5383eff041 --- /dev/null +++ b/ApplicationCode/ProjectDataModel/RimReloadCaseTools.cpp @@ -0,0 +1,180 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2019- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "RimReloadCaseTools.h" + +#include "RiaApplication.h" +#include "RiaFractureDefines.h" +#include "RiaSummaryTools.h" + +#include "RigCaseCellResultsData.h" +#include "RigEclipseCaseData.h" + +#include "Rim2dIntersectionView.h" +#include "Rim2dIntersectionViewCollection.h" +#include "RimEclipseCase.h" +#include "RimEclipseContourMapView.h" +#include "RimEclipseContourMapViewCollection.h" +#include "RimEclipseView.h" +#include "RimFlowPlotCollection.h" +#include "RimGridCrossPlot.h" +#include "RimGridCrossPlotCollection.h" +#include "RimMainPlotCollection.h" +#include "RimProject.h" +#include "RimSummaryCaseMainCollection.h" +#include "RimSummaryPlot.h" +#include "RimSummaryPlotCollection.h" +#include "RimWellLogPlot.h" +#include "RimWellLogPlotCollection.h" + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimReloadCaseTools::reloadAllEclipseData(RimEclipseCase* eclipseCase) +{ + reloadAllEclipseData(eclipseCase, true); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimReloadCaseTools::reloadAllEclipseGridData(RimEclipseCase* eclipseCase) +{ + reloadAllEclipseData(eclipseCase, false); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimReloadCaseTools::reloadAllEclipseData(RimEclipseCase* eclipseCase, bool reloadSummaryData) +{ + CVF_ASSERT(eclipseCase); + + RigEclipseCaseData* eclipseCaseData = eclipseCase->eclipseCaseData(); + if (!eclipseCaseData) return; + + clearAllGridData(eclipseCaseData); + + eclipseCase->reloadEclipseGridFile(); + + updateAll3dViews(eclipseCase); + + if (reloadSummaryData) + { + RimSummaryCaseMainCollection* sumCaseColl = RiaSummaryTools::summaryCaseMainCollection(); + if (sumCaseColl) + { + sumCaseColl->loadAllSummaryCaseData(); + } + } + + updateAllPlots(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimReloadCaseTools::clearAllGridData(RigEclipseCaseData* eclipseCaseData) +{ + if (!eclipseCaseData) return; + + RigCaseCellResultsData* matrixModelResults = eclipseCaseData->results(RiaDefines::MATRIX_MODEL); + if (matrixModelResults) + { + matrixModelResults->clearAllResults(); + } + + RigCaseCellResultsData* fractureModelResults = eclipseCaseData->results(RiaDefines::FRACTURE_MODEL); + if (fractureModelResults) + { + fractureModelResults->clearAllResults(); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimReloadCaseTools::updateAll3dViews(RimEclipseCase* eclipseCase) +{ + if (!eclipseCase) return; + + for (RimEclipseView* reservoirView : eclipseCase->reservoirViews()) + { + CVF_ASSERT(reservoirView); + reservoirView->loadDataAndUpdate(); + reservoirView->updateGridBoxData(); + reservoirView->updateAnnotationItems(); + } + + for (RimEclipseContourMapView* contourMap : eclipseCase->contourMapCollection()->views()) + { + CVF_ASSERT(contourMap); + contourMap->loadDataAndUpdate(); + contourMap->updateGridBoxData(); + contourMap->updateAnnotationItems(); + } + + for (Rim2dIntersectionView* view : eclipseCase->intersectionViewCollection()->views()) + { + view->createDisplayModelAndRedraw(); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimReloadCaseTools::updateAllPlots() +{ + RimProject* project = RiaApplication::instance()->project(); + if (project && project->mainPlotCollection()) + { + RimWellLogPlotCollection* wellPlotCollection = project->mainPlotCollection()->wellLogPlotCollection(); + + if (wellPlotCollection) + { + for (RimWellLogPlot* wellLogPlot : wellPlotCollection->wellLogPlots()) + { + wellLogPlot->loadDataAndUpdate(); + } + } + + RimSummaryPlotCollection* summaryPlotCollection = project->mainPlotCollection()->summaryPlotCollection(); + if (summaryPlotCollection) + { + for (RimSummaryPlot* summaryPlot : summaryPlotCollection->summaryPlots()) + { + summaryPlot->loadDataAndUpdate(); + } + } + + RimGridCrossPlotCollection* gridCrossPlotCollection = project->mainPlotCollection()->gridCrossPlotCollection(); + if (gridCrossPlotCollection) + { + for (RimGridCrossPlot* crossPlot : gridCrossPlotCollection->gridCrossPlots()) + { + crossPlot->loadDataAndUpdate(); + } + } + + RimFlowPlotCollection* flowPlotCollection = project->mainPlotCollection()->flowPlotCollection(); + if (flowPlotCollection) + { + flowPlotCollection->loadDataAndUpdate(); + } + } +} diff --git a/ApplicationCode/ProjectDataModel/RimReloadCaseTools.h b/ApplicationCode/ProjectDataModel/RimReloadCaseTools.h new file mode 100644 index 0000000000..b13b552011 --- /dev/null +++ b/ApplicationCode/ProjectDataModel/RimReloadCaseTools.h @@ -0,0 +1,41 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2019- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +class RimEclipseCase; +class RigEclipseCaseData; + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +class RimReloadCaseTools +{ +public: + // Reload all eclipse data, both grid and summary + static void reloadAllEclipseData(RimEclipseCase* eclipseCase); + + // Reload grid data, but not summary + static void reloadAllEclipseGridData(RimEclipseCase* eclipseCase); + +private: + static void reloadAllEclipseData(RimEclipseCase* eclipseCase, bool reloadSummaryData); + static void clearAllGridData(RigEclipseCaseData* eclipseCaseData); + static void updateAll3dViews(RimEclipseCase* eclipseCase); + static void updateAllPlots(); +}; diff --git a/ApplicationCode/ProjectDataModel/RimReservoirCellResultsStorage.cpp b/ApplicationCode/ProjectDataModel/RimReservoirCellResultsStorage.cpp index e4c3229587..30aee80274 100644 --- a/ApplicationCode/ProjectDataModel/RimReservoirCellResultsStorage.cpp +++ b/ApplicationCode/ProjectDataModel/RimReservoirCellResultsStorage.cpp @@ -91,19 +91,19 @@ void RimReservoirCellResultsStorage::setupBeforeSave() if (!m_cellResults) return; - const std::vector& resInfo = m_cellResults->infoForEachResultIndex(); + const std::vector& resAddrs = m_cellResults->existingResults(); bool hasResultsToStore = false; - for (size_t rIdx = 0; rIdx < resInfo.size(); ++rIdx) + for (size_t rIdx = 0; rIdx < resAddrs.size(); ++rIdx) { - if (resInfo[rIdx].needsToBeStored()) + if ( m_cellResults->resultInfo(resAddrs[rIdx])->needsToBeStored() ) { hasResultsToStore = true; break; } } - if(resInfo.size() && hasResultsToStore) + if(resAddrs.size() && hasResultsToStore) { QDir::root().mkpath(getCacheDirectoryPath()); @@ -122,38 +122,39 @@ void RimReservoirCellResultsStorage::setupBeforeSave() stream << (quint32)0xCEECAC4E; // magic number stream << (quint32)1; // Version number. Increment if needing to extend the format in ways that can not be handled generically by the reader - caf::ProgressInfo progInfo(resInfo.size(), "Saving generated and imported properties"); + caf::ProgressInfo progInfo(resAddrs.size(), "Saving generated and imported properties"); - for (size_t rIdx = 0; rIdx < resInfo.size(); ++rIdx) + for (size_t rIdx = 0; rIdx < resAddrs.size(); ++rIdx) { // If there is no data, we do not store anything for the current result variable // (Even not the metadata, of cause) - size_t timestepCount = m_cellResults->cellScalarResults(resInfo[rIdx].gridScalarResultIndex()).size(); + size_t timestepCount = m_cellResults->cellScalarResults(resAddrs[rIdx]).size(); + const RigEclipseResultInfo* resInfo = m_cellResults->resultInfo(resAddrs[rIdx]); - if (timestepCount && resInfo[rIdx].needsToBeStored()) + if (timestepCount && resInfo->needsToBeStored()) { - progInfo.setProgressDescription(resInfo[rIdx].resultName()); + progInfo.setProgressDescription(resInfo->resultName()); // Create and setup the cache information for this result RimReservoirCellResultsStorageEntryInfo* cacheEntry = new RimReservoirCellResultsStorageEntryInfo; m_resultCacheMetaData.push_back(cacheEntry); - cacheEntry->m_resultType = resInfo[rIdx].resultType(); - cacheEntry->m_resultName = resInfo[rIdx].resultName(); - cacheEntry->m_timeStepDates = resInfo[rIdx].dates(); - cacheEntry->m_daysSinceSimulationStart = resInfo[rIdx].daysSinceSimulationStarts(); + cacheEntry->m_resultType = resInfo->resultType(); + cacheEntry->m_resultName = resInfo->resultName(); + cacheEntry->m_timeStepDates = resInfo->dates(); + cacheEntry->m_daysSinceSimulationStart = resInfo->daysSinceSimulationStarts(); // Take note of the file position for fast lookup later cacheEntry->m_filePosition = cacheFile.pos(); // Write all the scalar values for each time step to the stream, // starting with the number of values - for (size_t tsIdx = 0; tsIdx < resInfo[rIdx].dates().size() ; ++tsIdx) + for (size_t tsIdx = 0; tsIdx < resInfo->dates().size() ; ++tsIdx) { const std::vector* data = nullptr; if (tsIdx < timestepCount) { - data = &(m_cellResults->cellScalarResults(resInfo[rIdx].gridScalarResultIndex(), tsIdx)); + data = &(m_cellResults->cellScalarResults(resAddrs[rIdx], tsIdx)); } if (data && data->size()) @@ -271,13 +272,17 @@ void RimReservoirCellResultsStorage::setCellResults(RigCaseCellResultsData* cell for (size_t rIdx = 0; rIdx < m_resultCacheMetaData.size(); ++rIdx) { RimReservoirCellResultsStorageEntryInfo* resInfo = m_resultCacheMetaData[rIdx]; - size_t resultIndex = m_cellResults->findOrCreateScalarResultIndex(resInfo->m_resultType(), resInfo->m_resultName, true); + + RigEclipseResultAddress resAddr(resInfo->m_resultType(), resInfo->m_resultName); + m_cellResults->createResultEntry(resAddr, true); std::vector reportNumbers; // Hack: Using no report step numbers. Not really used except for Flow Diagnostics... reportNumbers.resize(resInfo->m_timeStepDates().size()); - std::vector timeStepInfos = RigEclipseTimeStepInfo::createTimeStepInfos(resInfo->m_timeStepDates(), reportNumbers, resInfo->m_daysSinceSimulationStart()); + std::vector timeStepInfos = RigEclipseTimeStepInfo::createTimeStepInfos(resInfo->m_timeStepDates(), + reportNumbers, + resInfo->m_daysSinceSimulationStart()); - m_cellResults->setTimeStepInfos(resultIndex, timeStepInfos); + m_cellResults->setTimeStepInfos(resAddr, timeStepInfos); progress.setProgressDescription(resInfo->m_resultName); @@ -285,7 +290,7 @@ void RimReservoirCellResultsStorage::setCellResults(RigCaseCellResultsData* cell { std::vector* data = nullptr; - data = &(m_cellResults->cellScalarResults(resultIndex, tsIdx)); + data = &(m_cellResults->modifiableCellScalarResult(resAddr, tsIdx)); quint64 cellCount = 0; stream >> cellCount; diff --git a/ApplicationCode/ProjectDataModel/RimRiuQwtPlotOwnerInterface.h b/ApplicationCode/ProjectDataModel/RimRiuQwtPlotOwnerInterface.h new file mode 100644 index 0000000000..a7ceae650c --- /dev/null +++ b/ApplicationCode/ProjectDataModel/RimRiuQwtPlotOwnerInterface.h @@ -0,0 +1,42 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2019- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// +#pragma once + +#include "RiaFontCache.h" +#include "RimViewWindow.h" + +namespace caf +{ +class PdmObject; +} + +class QwtPlotCurve; + +class RimRiuQwtPlotOwnerInterface +{ +public: + virtual void detachAllCurves() = 0; + virtual void updateAxisScaling() = 0; + virtual void updateAxisDisplay() = 0; + virtual void updateZoomWindowFromQwt() = 0; + virtual void selectAxisInPropertyEditor(int axis) = 0; + virtual void setAutoZoomForAllAxes(bool enableAutoZoom) = 0; + + virtual caf::PdmObject* findRimPlotObjectFromQwtCurve(const QwtPlotCurve* curve) const = 0; + +}; \ No newline at end of file diff --git a/ApplicationCode/ProjectDataModel/RimScaleLegendConfig.cpp b/ApplicationCode/ProjectDataModel/RimScaleLegendConfig.cpp new file mode 100644 index 0000000000..df64f27127 --- /dev/null +++ b/ApplicationCode/ProjectDataModel/RimScaleLegendConfig.cpp @@ -0,0 +1,613 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2011- Statoil ASA +// Copyright (C) 2013- Ceetron Solutions AS +// Copyright (C) 2011-2012 Ceetron AS +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "RimScaleLegendConfig.h" + +#include "RiaApplication.h" +#include "RiaColorTables.h" +#include "RiaPreferences.h" + +#include "RimCellEdgeColors.h" +#include "RimEclipseCellColors.h" +#include "RimEnsembleCurveSet.h" +#include "RimEnsembleCurveSetCollection.h" +#include "RimEnsembleCurveSetColorManager.h" +#include "RimEclipseView.h" +#include "RimGeoMechResultDefinition.h" +#include "RimIntersectionCollection.h" +#include "RimStimPlanColors.h" +#include "RimViewLinker.h" + +#include "cafTitledOverlayFrame.h" +#include "cafCategoryLegend.h" +#include "cafCategoryMapper.h" +#include "cafOverlayScaleLegend.h" + +#include "cafFactory.h" +#include "cafPdmFieldCvfColor.h" +#include "cafPdmFieldCvfMat4d.h" +#include "cafPdmUiComboBoxEditor.h" +#include "cafPdmUiLineEditor.h" + +#include "cvfScalarMapperContinuousLinear.h" +#include "cvfScalarMapperContinuousLog.h" +#include "cvfScalarMapperDiscreteLinear.h" +#include "cvfScalarMapperDiscreteLog.h" +#include "cvfqtUtils.h" + +#include +#include + +using ColorManager = RimEnsembleCurveSetColorManager; + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +CAF_PDM_SOURCE_INIT(RimScaleLegendConfig, "ScaleLegend"); + + +namespace caf { + template<> + void RimScaleLegendConfig::ColorRangeEnum::setUp() + { + addItem(RimScaleLegendConfig::NORMAL, "NORMAL", "Full color, Red on top"); + addItem(RimScaleLegendConfig::OPPOSITE_NORMAL, "OPPOSITE_NORMAL", "Full color, Blue on top"); + addItem(RimScaleLegendConfig::WHITE_PINK, "WHITE_PIMK", "White to pink"); + addItem(RimScaleLegendConfig::PINK_WHITE, "PINK_WHITE", "Pink to white"); + addItem(RimScaleLegendConfig::BLUE_WHITE_RED, "BLUE_WHITE_RED", "Blue, white, red"); + addItem(RimScaleLegendConfig::RED_WHITE_BLUE, "RED_WHITE_BLUE", "Red, white, blue"); + addItem(RimScaleLegendConfig::WHITE_BLACK, "WHITE_BLACK", "White to black"); + addItem(RimScaleLegendConfig::BLACK_WHITE, "BLACK_WHITE", "Black to white"); + addItem(RimScaleLegendConfig::CATEGORY, "CATEGORY", "Category colors"); + addItem(RimScaleLegendConfig::ANGULAR, "ANGULAR", "Full color cyclic"); + addItem(RimScaleLegendConfig::STIMPLAN, "STIMPLAN", "StimPlan colors"); + addItem(RimScaleLegendConfig::RED_LIGHT_DARK, "RED_DARK_LIGHT", "Red Light to Dark"); + addItem(RimScaleLegendConfig::GREEN_LIGHT_DARK, "GREEN_DARK_LIGHT", "Green Light to Dark"); + addItem(RimScaleLegendConfig::BLUE_LIGHT_DARK, "BLUE_DARK_LIGHT", "Blue Light to Dark"); + addItem(RimScaleLegendConfig::GREEN_RED, "GREEN_RED", "Green to Red"); + addItem(RimScaleLegendConfig::BLUE_MAGENTA, "BLUE_MAGENTA", "Blue to Magenta"); + setDefault(RimScaleLegendConfig::NORMAL); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimScaleLegendConfig::RimScaleLegendConfig() + : m_globalAutoMax(cvf::UNDEFINED_DOUBLE), + m_globalAutoMin(cvf::UNDEFINED_DOUBLE), + m_localAutoMax(cvf::UNDEFINED_DOUBLE), + m_localAutoMin(cvf::UNDEFINED_DOUBLE), + m_isAllTimeStepsRangeDisabled(false) +{ + CAF_PDM_InitObject("Color Legend", ":/Legend.png", "", ""); + CAF_PDM_InitField(&m_showLegend, "ShowLegend", true, "Show Legend", "", "", ""); + m_showLegend.uiCapability()->setUiHidden(true); + CAF_PDM_InitField(&m_numLevels, "NumberOfLevels", 8, "Number of Levels", "", "A hint on how many tick marks you whish.",""); + CAF_PDM_InitField(&m_precision, "Precision", 4, "Significant Digits", "", "The number of significant digits displayed in the legend numbers",""); + + CAF_PDM_InitField(&m_colorRangeMode, "ColorRangeMode", ColorRangeEnum(NORMAL) , "Colors", "", "", ""); + CAF_PDM_InitField(&m_rangeMode, "RangeType", RangeModeEnum(AUTOMATIC_ALLTIMESTEPS), "Range Type", "", "Switches between automatic and user defined range on the legend", ""); + CAF_PDM_InitField(&m_userDefinedMaxValue, "UserDefinedMax", 1.0, "Max", "", "Max value of the legend", ""); + CAF_PDM_InitField(&m_userDefinedMinValue, "UserDefinedMin", 0.0, "Min", "", "Min value of the legend (if mapping is logarithmic only positive values are valid)", ""); + CAF_PDM_InitField(&resultVariableName, "ResultVariableUsage", QString(""), "", "", "", ""); + resultVariableName.uiCapability()->setUiHidden(true); + + cvf::Font* standardFont = RiaApplication::instance()->defaultSceneFont(); + m_scaleLegend = new caf::OverlayScaleLegend(standardFont); + + updateFieldVisibility(); + updateLegend(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimScaleLegendConfig::~RimScaleLegendConfig() +{ + +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimScaleLegendConfig::fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue) +{ + if (changedField == &m_numLevels) + { + int upperLimit = std::numeric_limits::max(); + m_numLevels = cvf::Math::clamp(m_numLevels.v(), 1, upperLimit); + } + else if (changedField == &m_rangeMode) + { + if (m_rangeMode == USER_DEFINED) + { + if (m_userDefinedMaxValue == m_userDefinedMaxValue.defaultValue() && m_globalAutoMax != cvf::UNDEFINED_DOUBLE) + { + m_userDefinedMaxValue = roundToNumSignificantDigits(m_globalAutoMax, m_precision); + } + if (m_userDefinedMinValue == m_userDefinedMinValue.defaultValue() && m_globalAutoMin != cvf::UNDEFINED_DOUBLE) + { + m_userDefinedMinValue = roundToNumSignificantDigits(m_globalAutoMin, m_precision); + } + } + + updateFieldVisibility(); + } + + updateLegend(); + + RimGridView* view = nullptr; + this->firstAncestorOrThisOfType(view); + + if (view) + { + RimViewLinker* viewLinker = view->assosiatedViewLinker(); + if (viewLinker) + { + viewLinker->updateCellResult(); + } + + view->updateCurrentTimeStepAndRedraw(); + + view->crossSectionCollection()->scheduleCreateDisplayModelAndRedraw2dIntersectionViews(); + } + + // Update stim plan templates if relevant + RimStimPlanColors* stimPlanColors; + firstAncestorOrThisOfType(stimPlanColors); + if (stimPlanColors) + { + stimPlanColors->updateStimPlanTemplates(); + } + + // Update ensemble curve set if relevant + RimEnsembleCurveSet* ensembleCurveSet; + firstAncestorOrThisOfType(ensembleCurveSet); + if (ensembleCurveSet) + { + ensembleCurveSet->onLegendDefinitionChanged(); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimScaleLegendConfig::updateLegend() +{ + double adjustedMin = cvf::UNDEFINED_DOUBLE; + double adjustedMax = cvf::UNDEFINED_DOUBLE; + + if (m_rangeMode == AUTOMATIC_ALLTIMESTEPS) + { + adjustedMin = roundToNumSignificantDigits(m_globalAutoMin, m_precision); + adjustedMax = roundToNumSignificantDigits(m_globalAutoMax, m_precision); + } + else if (m_rangeMode == AUTOMATIC_CURRENT_TIMESTEP) + { + adjustedMin = roundToNumSignificantDigits(m_localAutoMin, m_precision); + adjustedMax = roundToNumSignificantDigits(m_localAutoMax, m_precision); + } + else + { + adjustedMin = roundToNumSignificantDigits(m_userDefinedMinValue, m_precision); + adjustedMax = roundToNumSignificantDigits(m_userDefinedMaxValue, m_precision); + } + + cvf::Color3ubArray legendColors = colorArrayFromColorType(m_colorRangeMode()); + + double decadesInRange = 0; + + { + // For linear mapping, use the max value as reference for num valid digits + double absRange = CVF_MAX(cvf::Math::abs(adjustedMax), cvf::Math::abs(adjustedMin)); + decadesInRange = log10(absRange); + } + + decadesInRange = cvf::Math::ceil(decadesInRange); + + // Using Fixed format + //caf::OverlayScaleLegend::NumberFormat nft = m_tickNumberFormat(); + //m_scaleLegend->setTickFormat((caf::OverlayScaleLegend::NumberFormat)nft); + + // Set the fixed number of digits after the decimal point to the number needed to show all the significant digits. + int numDecimalDigits = m_precision(); + m_scaleLegend->setTickPrecision(cvf::Math::clamp(numDecimalDigits, 0, 20)); + + RiaApplication* app = RiaApplication::instance(); + RiaPreferences* preferences = app->preferences(); + m_scaleLegend->enableBackground(preferences->showLegendBackground()); + + if (m_globalAutoMax != cvf::UNDEFINED_DOUBLE ) + { + m_userDefinedMaxValue.uiCapability()->setUiName(QString("Max ") + "(" + QString::number(m_globalAutoMax, 'g', m_precision) + ")"); + } + else + { + m_userDefinedMaxValue.uiCapability()->setUiName(QString()); + } + + if (m_globalAutoMin != cvf::UNDEFINED_DOUBLE ) + { + m_userDefinedMinValue.uiCapability()->setUiName(QString("Min ") + "(" + QString::number(m_globalAutoMin, 'g', m_precision) + ")"); + } + else + { + m_userDefinedMinValue.uiCapability()->setUiName(QString()); + } +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimScaleLegendConfig::disableAllTimeStepsRange(bool doDisable) +{ + // If we enable AllTimesteps, and we have used current timestep, then "restore" the default + if (m_isAllTimeStepsRangeDisabled && !doDisable && m_rangeMode == AUTOMATIC_CURRENT_TIMESTEP) m_rangeMode = AUTOMATIC_ALLTIMESTEPS; + + m_isAllTimeStepsRangeDisabled = doDisable; + + if (doDisable && m_rangeMode == AUTOMATIC_ALLTIMESTEPS) m_rangeMode = AUTOMATIC_CURRENT_TIMESTEP; + +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimScaleLegendConfig::setAutomaticRanges(double globalMin, double globalMax, double localMin, double localMax) +{ + double candidateGlobalAutoMin = roundToNumSignificantDigits(globalMin, m_precision); + double candidateGlobalAutoMax = roundToNumSignificantDigits(globalMax, m_precision); + + double candidateLocalAutoMin = roundToNumSignificantDigits(localMin, m_precision); + double candidateLocalAutoMax = roundToNumSignificantDigits(localMax, m_precision); + + m_globalAutoMin = candidateGlobalAutoMin; + m_globalAutoMax = candidateGlobalAutoMax; + + m_localAutoMin = candidateLocalAutoMin; + m_localAutoMax = candidateLocalAutoMax; + + updateLegend(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimScaleLegendConfig::initAfterRead() +{ + updateFieldVisibility(); +} + +caf::PdmFieldHandle* RimScaleLegendConfig::objectToggleField() +{ + return &m_showLegend; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimScaleLegendConfig::updateFieldVisibility() +{ + bool showRangeItems = true; + + m_numLevels.uiCapability()->setUiHidden(!showRangeItems); + m_precision.uiCapability()->setUiHidden(!showRangeItems); + m_rangeMode.uiCapability()->setUiHidden(!showRangeItems); + + if (showRangeItems && m_rangeMode == USER_DEFINED) + { + m_userDefinedMaxValue.uiCapability()->setUiHidden(false); + m_userDefinedMinValue.uiCapability()->setUiHidden(false); + } + else + { + m_userDefinedMaxValue.uiCapability()->setUiHidden(true); + m_userDefinedMinValue.uiCapability()->setUiHidden(true); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimScaleLegendConfig::setColorRange(ColorRangesType colorMode) +{ + m_colorRangeMode = colorMode; + updateLegend(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimScaleLegendConfig::recreateLegend() +{ + // Due to possible visualization bug, we need to recreate the legend if the last viewer + // has been removed, (and thus the opengl resources has been deleted) The text in + // the legend disappeared because of this, so workaround: recreate the legend when needed: + + cvf::Font* standardFont = RiaApplication::instance()->defaultSceneFont(); + m_scaleLegend = new caf::OverlayScaleLegend(standardFont); + + updateLegend(); +} + +//-------------------------------------------------------------------------------------------------- +/// Rounding the double value to given number of significant digits +//-------------------------------------------------------------------------------------------------- +double RimScaleLegendConfig::roundToNumSignificantDigits(double domainValue, double numSignificantDigits) +{ + double absDomainValue = cvf::Math::abs(domainValue); + if (absDomainValue == 0.0) + { + return 0.0; + } + + double logDecValue = log10(absDomainValue); + logDecValue = cvf::Math::ceil(logDecValue); + + double factor = pow(10.0, numSignificantDigits - logDecValue); + + double tmp = domainValue * factor; + double integerPart; + double fraction = modf(tmp, &integerPart); + + if (cvf::Math::abs(fraction)>= 0.5) (integerPart >= 0) ? integerPart++: integerPart-- ; + + double newDomainValue = integerPart / factor; + + return newDomainValue; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimScaleLegendConfig::setTitle(const QString& title) +{ + auto cvfTitle = cvfqt::Utils::toString(title); + m_scaleLegend->setTitle(cvfTitle); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RimScaleLegendConfig::showLegend() const +{ + return m_showLegend; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimScaleLegendConfig::setShowLegend(bool show) +{ + m_showLegend = show; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +caf::TitledOverlayFrame* RimScaleLegendConfig::titledOverlayFrame() +{ + return m_scaleLegend.p(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +const caf::TitledOverlayFrame* RimScaleLegendConfig::titledOverlayFrame() const +{ + return m_scaleLegend.p(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +cvf::OverlayItem* RimScaleLegendConfig::overlayItem() +{ + return m_scaleLegend.p(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +const cvf::OverlayItem* RimScaleLegendConfig::overlayItem() const +{ + return m_scaleLegend.p(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimLegendConfig::RangeModeType RimScaleLegendConfig::rangeMode() const +{ + return m_rangeMode(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimScaleLegendConfig::setUiValuesFromLegendConfig(const RimScaleLegendConfig* otherLegendConfig) +{ + QString serializedObjectString = otherLegendConfig->writeObjectToXmlString(); + this->readObjectFromXmlString(serializedObjectString, caf::PdmDefaultObjectFactory::instance()); + this->updateLegend(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +cvf::Color3ubArray RimScaleLegendConfig::colorArrayFromColorType(ColorRangesType colorType) +{ + switch (colorType) + { + case RimScaleLegendConfig::NORMAL: + return RiaColorTables::normalPaletteColors().color3ubArray(); + break; + case RimScaleLegendConfig::OPPOSITE_NORMAL: + return RiaColorTables::normalPaletteOppositeOrderingColors().color3ubArray(); + break; + case RimScaleLegendConfig::WHITE_PINK: + return RiaColorTables::whitePinkPaletteColors().color3ubArray(); + break; + case RimScaleLegendConfig::PINK_WHITE: + return RiaColorTables::pinkWhitePaletteColors().color3ubArray(); + break; + case RimScaleLegendConfig::WHITE_BLACK: + return RiaColorTables::whiteBlackPaletteColors().color3ubArray(); + break; + case RimScaleLegendConfig::BLACK_WHITE: + return RiaColorTables::blackWhitePaletteColors().color3ubArray(); + break; + case RimScaleLegendConfig::BLUE_WHITE_RED: + return RiaColorTables::blueWhiteRedPaletteColors().color3ubArray(); + break; + case RimScaleLegendConfig::RED_WHITE_BLUE: + return RiaColorTables::redWhiteBluePaletteColors().color3ubArray(); + break; + case RimScaleLegendConfig::CATEGORY: + return RiaColorTables::categoryPaletteColors().color3ubArray(); + break; + case RimScaleLegendConfig::ANGULAR: + return RiaColorTables::angularPaletteColors().color3ubArray(); + break; + case RimScaleLegendConfig::STIMPLAN: + return RiaColorTables::stimPlanPaletteColors().color3ubArray(); + break; + default: + //if (ColorManager::isEnsembleColorRange(colorType)) return ColorManager::EnsembleColorRanges().at(colorType); + break; + } + + return RiaColorTables::normalPaletteColors().color3ubArray(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimScaleLegendConfig::defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering) +{ + { + caf::PdmUiOrdering * formatGr = uiOrdering.addNewGroup("Format"); + formatGr->add(&m_numLevels); + formatGr->add(&m_precision); + formatGr->add(&m_colorRangeMode); + + caf::PdmUiOrdering * mappingGr = uiOrdering.addNewGroup("Mapping"); + mappingGr->add(&m_rangeMode); + mappingGr->add(&m_userDefinedMaxValue); + mappingGr->add(&m_userDefinedMinValue); + } + + updateFieldVisibility(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QList RimScaleLegendConfig::calculateValueOptions(const caf::PdmFieldHandle* fieldNeedingOptions, bool* useOptionsOnly) +{ + bool hasStimPlanParent = false; + bool hasEnsembleCurveSetParent = false; + + RimStimPlanColors* stimPlanColors = nullptr; + this->firstAncestorOrThisOfType(stimPlanColors); + if (stimPlanColors) hasStimPlanParent = true; + + RimEnsembleCurveSet* ensembleCurveSet = nullptr; + this->firstAncestorOrThisOfType(ensembleCurveSet); + if (ensembleCurveSet) hasEnsembleCurveSetParent = true; + + bool isCategoryResult = false; + { + RimEclipseCellColors* eclCellColors = nullptr; + this->firstAncestorOrThisOfType(eclCellColors); + RimGeoMechResultDefinition* gmCellColors = nullptr; + this->firstAncestorOrThisOfType(gmCellColors); + RimCellEdgeColors* eclCellEdgColors = nullptr; + this->firstAncestorOrThisOfType(eclCellEdgColors); + + if ( ( eclCellColors && eclCellColors->hasCategoryResult()) + || ( gmCellColors && gmCellColors->hasCategoryResult()) + || ( eclCellEdgColors && eclCellEdgColors->hasCategoryResult()) + || ( ensembleCurveSet && ensembleCurveSet->currentEnsembleParameterType() == EnsembleParameter::TYPE_TEXT) ) + { + isCategoryResult = true; + } + } + + QList options; + + if (fieldNeedingOptions == &m_colorRangeMode) + { + // This is an app enum field, see cafInternalPdmFieldTypeSpecializations.h for the default specialization of this type + std::vector rangeTypes; + if (!hasEnsembleCurveSetParent) + { + rangeTypes.push_back(NORMAL); + rangeTypes.push_back(OPPOSITE_NORMAL); + rangeTypes.push_back(WHITE_PINK); + rangeTypes.push_back(PINK_WHITE); + rangeTypes.push_back(BLUE_WHITE_RED); + rangeTypes.push_back(RED_WHITE_BLUE); + rangeTypes.push_back(WHITE_BLACK); + rangeTypes.push_back(BLACK_WHITE); + rangeTypes.push_back(ANGULAR); + } + else + { + //for (const auto& col : ColorManager::EnsembleColorRanges()) + //{ + // rangeTypes.push_back(col.first); + //} + } + + if (hasStimPlanParent) rangeTypes.push_back(STIMPLAN); + + if (isCategoryResult) + { + rangeTypes.push_back(CATEGORY); + } + + for(ColorRangesType colType: rangeTypes) + { + options.push_back(caf::PdmOptionItemInfo(ColorRangeEnum::uiText(colType), colType)); + } + } + else if (fieldNeedingOptions == &m_rangeMode) + { + if (!m_isAllTimeStepsRangeDisabled) + { + QString uiText; + if(!hasEnsembleCurveSetParent) uiText = RangeModeEnum::uiText(RimScaleLegendConfig::AUTOMATIC_ALLTIMESTEPS); + else uiText = "Auto Range"; + + options.push_back(caf::PdmOptionItemInfo(uiText, RimScaleLegendConfig::AUTOMATIC_ALLTIMESTEPS)); + } + if (!hasStimPlanParent && !hasEnsembleCurveSetParent) + { + options.push_back(caf::PdmOptionItemInfo(RangeModeEnum::uiText(RimScaleLegendConfig::AUTOMATIC_CURRENT_TIMESTEP), RimScaleLegendConfig::AUTOMATIC_CURRENT_TIMESTEP)); + } + options.push_back(caf::PdmOptionItemInfo(RangeModeEnum::uiText(RimScaleLegendConfig::USER_DEFINED), RimScaleLegendConfig::USER_DEFINED)); + } + + return options; +} + diff --git a/ApplicationCode/ProjectDataModel/RimScaleLegendConfig.h b/ApplicationCode/ProjectDataModel/RimScaleLegendConfig.h new file mode 100644 index 0000000000..5c031dc056 --- /dev/null +++ b/ApplicationCode/ProjectDataModel/RimScaleLegendConfig.h @@ -0,0 +1,146 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2011- Statoil ASA +// Copyright (C) 2013- Ceetron Solutions AS +// Copyright (C) 2011-2012 Ceetron AS +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "RimLegendConfig.h" + +#include "cvfBase.h" +#include "cvfObject.h" +#include "cvfArray.h" + +#include + +namespace cvf +{ + class ScalarMapperContinuousLog; + class ScalarMapperContinuousLinear; + class OverlayItem; + class ScalarMapperDiscreteLinear; + class ScalarMapperDiscreteLog; + class ScalarMapper; + class String; +} + +namespace caf +{ + class TitledOverlayFrame; + class CategoryLegend; + class CategoryMapper; + class OverlayScaleLegend; +} + +class Rim3dView; +class RimEnsembleCurveSet; + +//================================================================================================== +/// +/// +//================================================================================================== +class RimScaleLegendConfig : public RimLegendConfig +{ + CAF_PDM_HEADER_INIT; +public: + RimScaleLegendConfig(); + ~RimScaleLegendConfig() override; + + caf::PdmField resultVariableName; // Used internally to describe the variable this legend setup is used for + + enum ColorRangesType + { + NORMAL, + OPPOSITE_NORMAL, + WHITE_PINK, + PINK_WHITE, + WHITE_BLACK, + BLACK_WHITE, + BLUE_WHITE_RED, + RED_WHITE_BLUE, + CATEGORY, + ANGULAR, + STIMPLAN, + + GREEN_RED, + BLUE_MAGENTA, + RED_LIGHT_DARK, + GREEN_LIGHT_DARK, + BLUE_LIGHT_DARK + }; + + typedef caf::AppEnum ColorRangeEnum; + + void recreateLegend(); + + void setColorRange(ColorRangesType colorMode); + ColorRangesType colorRange() { return m_colorRangeMode();} + void disableAllTimeStepsRange(bool doDisable); + + void setAutomaticRanges(double globalMin, double globalMax, double localMin, double localMax); + + void setTitle(const QString& title); + + void setUiValuesFromLegendConfig(const RimScaleLegendConfig* otherLegendConfig); + + bool showLegend() const; + void setShowLegend(bool show); + + const caf::TitledOverlayFrame* titledOverlayFrame() const override; + caf::TitledOverlayFrame* titledOverlayFrame() override; + + const cvf::OverlayItem* overlayItem() const; + cvf::OverlayItem* overlayItem(); + + RangeModeType rangeMode() const; + +private: + void fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue) override; + void initAfterRead() override; + caf::PdmFieldHandle* objectToggleField() override; + + void defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering ) override; + QList calculateValueOptions(const caf::PdmFieldHandle* fieldNeedingOptions, bool* useOptionsOnly) override; + + void updateLegend(); + void updateFieldVisibility(); + double roundToNumSignificantDigits(double value, double precision); + + friend class RimViewLinker; + + static cvf::Color3ubArray colorArrayFromColorType(ColorRangesType colorType); + +private: + cvf::ref m_scaleLegend; + + double m_globalAutoMax; + double m_globalAutoMin; + double m_localAutoMax; + double m_localAutoMin; + + bool m_isAllTimeStepsRangeDisabled; + + // Fields + caf::PdmField m_showLegend; + caf::PdmField m_numLevels; + caf::PdmField m_precision; + caf::PdmField m_rangeMode; + caf::PdmField m_userDefinedMaxValue; + caf::PdmField m_userDefinedMinValue; + caf::PdmField > m_colorRangeMode; +}; diff --git a/ApplicationCode/ProjectDataModel/RimScriptCollection.cpp b/ApplicationCode/ProjectDataModel/RimScriptCollection.cpp index 8cbe4d1321..523663027a 100644 --- a/ApplicationCode/ProjectDataModel/RimScriptCollection.cpp +++ b/ApplicationCode/ProjectDataModel/RimScriptCollection.cpp @@ -3,17 +3,17 @@ // Copyright (C) 2011- Statoil ASA // Copyright (C) 2013- Ceetron Solutions AS // Copyright (C) 2011-2012 Ceetron AS -// +// // ResInsight 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 3 of the License, or // (at your option) any later version. -// +// // ResInsight 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 at +// +// See the GNU General Public License at // for more details. // ///////////////////////////////////////////////////////////////////////////////// @@ -31,32 +31,34 @@ CAF_PDM_SOURCE_INIT(RimScriptCollection, "ScriptLocation"); //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- RimScriptCollection::RimScriptCollection() { CAF_PDM_InitObject("ScriptLocation", ":/Folder.png", "", ""); - CAF_PDM_InitFieldNoDefault(&directory, "ScriptDirectory", "Dir", "", "", ""); - CAF_PDM_InitFieldNoDefault(&calcScripts, "CalcScripts", "", "", "", ""); + CAF_PDM_InitFieldNoDefault(&directory, "ScriptDirectory", "Dir", "", "", ""); + CAF_PDM_InitFieldNoDefault(&calcScripts, "CalcScripts", "", "", "", ""); calcScripts.uiCapability()->setUiHidden(true); - CAF_PDM_InitFieldNoDefault(&subDirectories, "SubDirectories", "", "", "", ""); + CAF_PDM_InitFieldNoDefault(&subDirectories, "SubDirectories", "", "", "", ""); subDirectories.uiCapability()->setUiHidden(true); + CAF_PDM_InitField(&m_searchSubFolders, "SearchSubFolders", false, "Add Subfolders", "", "", ""); + directory.uiCapability()->setUiEditorTypeName(caf::PdmUiFilePathEditor::uiEditorTypeName()); } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- RimScriptCollection::~RimScriptCollection() { - calcScripts.deleteAllChildObjects(); - subDirectories.deleteAllChildObjects(); + calcScripts.deleteAllChildObjects(); + subDirectories.deleteAllChildObjects(); } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RimScriptCollection::readContentFromDisc() { @@ -79,19 +81,19 @@ void RimScriptCollection::readContentFromDisc() // Build a list of all scripts in the specified directory { - QString filter = "*.m"; + QString filter = "*.m"; QStringList fileList = caf::Utils::getFilesInDirectory(directory, filter, true); int i; for (i = 0; i < fileList.size(); i++) { - QString fileName = fileList.at(i); + const QString& fileName = fileList.at(i); if (caf::Utils::fileExists(fileName)) { RimCalcScript* calcScript = new RimCalcScript; - calcScript->absolutePath = fileName; - + calcScript->absoluteFileName = fileName; + QFileInfo fi(fileName); calcScript->setUiName(fi.baseName()); @@ -100,13 +102,12 @@ void RimScriptCollection::readContentFromDisc() } } - // Add subfolders + subDirectories.deleteAllChildObjects(); + + if (m_searchSubFolders()) { - QDir dir(directory); + QDir dir(directory); QFileInfoList fileInfoList = dir.entryInfoList(QDir::AllDirs | QDir::NoDotAndDotDot | QDir::Readable); - subDirectories.deleteAllChildObjects(); - - QStringList retFileNames; QListIterator it(fileInfoList); while (it.hasNext()) @@ -114,10 +115,10 @@ void RimScriptCollection::readContentFromDisc() QFileInfo fi = it.next(); RimScriptCollection* scriptLocation = new RimScriptCollection; - scriptLocation->directory = fi.absoluteFilePath(); + scriptLocation->directory = fi.absoluteFilePath(); scriptLocation->setUiName(fi.baseName()); scriptLocation->readContentFromDisc(); - + subDirectories.push_back(scriptLocation); } } @@ -137,7 +138,7 @@ void RimScriptCollection::pathsAndSubPaths(QStringList& pathList) } } - for (size_t i= 0; i < this->subDirectories.size(); ++i) + for (size_t i = 0; i < this->subDirectories.size(); ++i) { if (this->subDirectories[i]) { @@ -149,7 +150,7 @@ void RimScriptCollection::pathsAndSubPaths(QStringList& pathList) //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -RimScriptCollection * RimScriptCollection::findScriptCollection(const QString& path) +RimScriptCollection* RimScriptCollection::findScriptCollection(const QString& path) { if (!this->directory().isEmpty()) { @@ -160,9 +161,9 @@ RimScriptCollection * RimScriptCollection::findScriptCollection(const QString& p for (size_t i = 0; i < this->subDirectories.size(); ++i) { - RimScriptCollection* foundColl = nullptr; - if (this->subDirectories[i]) foundColl = this->subDirectories[i]->findScriptCollection(path); - if (foundColl) return foundColl; + RimScriptCollection* foundColl = nullptr; + if (this->subDirectories[i]) foundColl = this->subDirectories[i]->findScriptCollection(path); + if (foundColl) return foundColl; } return nullptr; @@ -171,7 +172,9 @@ RimScriptCollection * RimScriptCollection::findScriptCollection(const QString& p //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RimScriptCollection::fieldChangedByUi(const caf::PdmFieldHandle *changedField, const QVariant &oldValue, const QVariant &newValue) +void RimScriptCollection::fieldChangedByUi(const caf::PdmFieldHandle* changedField, + const QVariant& oldValue, + const QVariant& newValue) { if (&directory == changedField) { @@ -179,12 +182,18 @@ void RimScriptCollection::fieldChangedByUi(const caf::PdmFieldHandle *changedFie this->setUiName(fi.baseName()); this->readContentFromDisc(); } + else if (&m_searchSubFolders == changedField) + { + this->readContentFromDisc(); + } } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- -void RimScriptCollection::defineEditorAttribute(const caf::PdmFieldHandle* field, QString uiConfigName, caf::PdmUiEditorAttribute* attribute) +void RimScriptCollection::defineEditorAttribute(const caf::PdmFieldHandle* field, + QString uiConfigName, + caf::PdmUiEditorAttribute* attribute) { if (field == &directory) { diff --git a/ApplicationCode/ProjectDataModel/RimScriptCollection.h b/ApplicationCode/ProjectDataModel/RimScriptCollection.h index d3b41147e8..25b0200937 100644 --- a/ApplicationCode/ProjectDataModel/RimScriptCollection.h +++ b/ApplicationCode/ProjectDataModel/RimScriptCollection.h @@ -59,4 +59,7 @@ class RimScriptCollection : public caf::PdmObject protected: void defineEditorAttribute(const caf::PdmFieldHandle* field, QString uiConfigName, caf::PdmUiEditorAttribute* attribute ) override; + +private: + caf::PdmField m_searchSubFolders; }; diff --git a/ApplicationCode/ProjectDataModel/RimSimWellInView.cpp b/ApplicationCode/ProjectDataModel/RimSimWellInView.cpp index fad3f8b63a..7f0bc1032d 100644 --- a/ApplicationCode/ProjectDataModel/RimSimWellInView.cpp +++ b/ApplicationCode/ProjectDataModel/RimSimWellInView.cpp @@ -171,13 +171,13 @@ std::vector RimSimWellInView::wellPipeBranches() const this->firstAncestorOrThisOfTypeAsserted(simWellCollection); RimEclipseCase* eclipseCase = nullptr; - this->firstAncestorOrThisOfTypeAsserted(eclipseCase); - RigEclipseCaseData* caseData = eclipseCase->eclipseCaseData(); - CVF_ASSERT(caseData); - if (caseData) + this->firstAncestorOrThisOfType(eclipseCase); + if (eclipseCase && eclipseCase->eclipseCaseData()) { + RigEclipseCaseData* caseData = eclipseCase->eclipseCaseData(); + bool includeCellCenters = this->isUsingCellCenterForPipe(); - bool detectBrances = simWellCollection->isAutoDetectingBranches; + bool detectBrances = simWellCollection->isAutoDetectingBranches; return caseData->simulationWellBranches(this->name(), includeCellCenters, detectBrances); } diff --git a/ApplicationCode/ProjectDataModel/RimSimWellInViewCollection.cpp b/ApplicationCode/ProjectDataModel/RimSimWellInViewCollection.cpp index 37d1d5cc5e..8d9da2e814 100644 --- a/ApplicationCode/ProjectDataModel/RimSimWellInViewCollection.cpp +++ b/ApplicationCode/ProjectDataModel/RimSimWellInViewCollection.cpp @@ -28,7 +28,7 @@ #include "RigEclipseCaseData.h" #include "RigSimWellData.h" -#include "RimContourMapView.h" +#include "RimEclipseContourMapView.h" #include "RimEclipseCase.h" #include "RimEclipseResultCase.h" #include "RimEclipseView.h" @@ -106,6 +106,17 @@ namespace caf } } +namespace caf +{ + template<> + void RimSimWellInViewCollection::WellPipeColorsEnum::setUp() + { + addItem(RimSimWellInViewCollection::WELLPIPE_COLOR_UNIQUE, "WELLPIPE_COLOR_INDIDUALLY", "Unique Colors"); + addItem(RimSimWellInViewCollection::WELLPIPE_COLOR_UNIFORM, "WELLPIPE_COLOR_UNIFORM", "Uniform Default Color"); + setDefault(RimSimWellInViewCollection::WELLPIPE_COLOR_UNIQUE); + } +} + CAF_PDM_SOURCE_INIT(RimSimWellInViewCollection, "Wells"); //-------------------------------------------------------------------------------------------------- @@ -152,13 +163,8 @@ RimSimWellInViewCollection::RimSimWellInViewCollection() CAF_PDM_InitField(&showConnectionStatusColors, "ShowConnectionStatusColors", true, "Color Pipe Connections", "", "", ""); cvf::Color3f defaultApplyColor = cvf::Color3f::YELLOW; - CAF_PDM_InitField(&m_wellColorForApply, "WellColorForApply", defaultApplyColor, "", "", "", ""); - - CAF_PDM_InitField(&m_applySingleColorToWells, "ApplySingleColorToWells", false, "Uniform Pipe Colors", "", "", ""); - caf::PdmUiPushButtonEditor::configureEditorForField(&m_applySingleColorToWells); - - CAF_PDM_InitField(&m_applyIndividualColorsToWells, "ApplyIndividualColorsToWells", false, "Unique Pipe Colors", "", "", ""); - caf::PdmUiPushButtonEditor::configureEditorForField(&m_applyIndividualColorsToWells); + CAF_PDM_InitField(&m_defaultWellPipeColor, "WellColorForApply", defaultApplyColor, "Uniform Well Color", "", "", ""); + CAF_PDM_InitFieldNoDefault(&m_wellPipeColors, "WellPipeColors", "Individual Pipe Colors", "", "", ""); CAF_PDM_InitField(&pipeCrossSectionVertexCount, "WellPipeVertexCount", 12, "Pipe Vertex Count", "", "", ""); pipeCrossSectionVertexCount.uiCapability()->setUiHidden(true); @@ -415,30 +421,24 @@ void RimSimWellInViewCollection::fieldChangedByUi(const caf::PdmFieldHandle* cha } } - if (&m_applyIndividualColorsToWells == changedField) - { - assignDefaultWellColors(); - - if (m_reservoirView) m_reservoirView->scheduleCreateDisplayModelAndRedraw(); - - m_applyIndividualColorsToWells = false; - } - - if (&m_applySingleColorToWells == changedField) + if (&m_wellPipeColors == changedField || &m_defaultWellPipeColor == changedField) { - cvf::Color3f col = m_wellColorForApply(); - - for (size_t i = 0; i < wells.size(); i++) + if (m_wellPipeColors == WELLPIPE_COLOR_UNIQUE) { - wells[i]->wellPipeColor = col; - wells[i]->updateConnectedEditors(); + assignDefaultWellColors(); } + else + { + cvf::Color3f col = m_defaultWellPipeColor(); + for (size_t i = 0; i < wells.size(); i++) + { + wells[i]->wellPipeColor = col; + wells[i]->updateConnectedEditors(); + } + RimSimWellInViewCollection::updateWellAllocationPlots(); + } if (m_reservoirView) m_reservoirView->scheduleCreateDisplayModelAndRedraw(); - - RimSimWellInViewCollection::updateWellAllocationPlots(); - - m_applySingleColorToWells = false; } if (&m_showWellCells == changedField) @@ -471,8 +471,6 @@ void RimSimWellInViewCollection::fieldChangedByUi(const caf::PdmFieldHandle* cha //-------------------------------------------------------------------------------------------------- void RimSimWellInViewCollection::assignDefaultWellColors() { - - RimEclipseCase* ownerCase; firstAncestorOrThisOfTypeAsserted(ownerCase); @@ -519,7 +517,7 @@ void RimSimWellInViewCollection::defineUiOrdering(QString uiConfigName, caf::Pdm { updateStateForVisibilityCheckboxes(); - bool isContourMap = dynamic_cast(m_reservoirView) != nullptr; + bool isContourMap = dynamic_cast(m_reservoirView) != nullptr; caf::PdmUiGroup* appearanceGroup = uiOrdering.addNewGroup("Visibility"); if (!isContourMap) @@ -549,9 +547,11 @@ void RimSimWellInViewCollection::defineUiOrdering(QString uiConfigName, caf::Pdm colorGroup->setCollapsedByDefault(true); colorGroup->add(&showConnectionStatusColors); colorGroup->add(&wellLabelColor); - colorGroup->add(&m_applyIndividualColorsToWells); - colorGroup->add(&m_applySingleColorToWells); - colorGroup->add(&m_wellColorForApply); + colorGroup->add(&m_wellPipeColors); + if (m_wellPipeColors == WELLPIPE_COLOR_UNIFORM) + { + colorGroup->add(&m_defaultWellPipeColor); + } caf::PdmUiGroup* wellPipeGroup = uiOrdering.addNewGroup("Well Pipe Geometry" ); wellPipeGroup->add(&wellPipeCoordType); @@ -708,39 +708,6 @@ void RimSimWellInViewCollection::initAfterRead() } } -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RimSimWellInViewCollection::defineEditorAttribute(const caf::PdmFieldHandle* field, QString uiConfigName, caf::PdmUiEditorAttribute* attribute) -{ - if (&m_applyIndividualColorsToWells == field) - { - caf::PdmUiPushButtonEditorAttribute* editorAttr = dynamic_cast(attribute); - if (editorAttr) - { - editorAttr->m_buttonText = "Apply"; - } - } - - if (&m_applySingleColorToWells == field) - { - caf::PdmUiPushButtonEditorAttribute* editorAttr = dynamic_cast(attribute); - if (editorAttr) - { - QColor col; - col.setRgbF(m_wellColorForApply().r(), m_wellColorForApply().g(), m_wellColorForApply().b()); - - QPixmap pixmap(20, 20); - pixmap.fill(col); - - QIcon colorIcon(pixmap); - - editorAttr->m_buttonIcon = colorIcon; - editorAttr->m_buttonText = "Apply"; - } - } -} - //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/ProjectDataModel/RimSimWellInViewCollection.h b/ApplicationCode/ProjectDataModel/RimSimWellInViewCollection.h index a58b50acaa..69c9eeae74 100644 --- a/ApplicationCode/ProjectDataModel/RimSimWellInViewCollection.h +++ b/ApplicationCode/ProjectDataModel/RimSimWellInViewCollection.h @@ -82,8 +82,16 @@ class RimSimWellInViewCollection : public caf::PdmObject WELLPIPE_CELLCENTER, WELLPIPE_INTERPOLATED }; + typedef caf::AppEnum WellPipeCoordEnum; + enum WellPipeColors + { + WELLPIPE_COLOR_UNIQUE, + WELLPIPE_COLOR_UNIFORM + }; + + typedef caf::AppEnum WellPipeColorsEnum; caf::PdmField isActive; caf::PdmField showWellsIntersectingVisibleCells; @@ -135,7 +143,6 @@ class RimSimWellInViewCollection : public caf::PdmObject caf::PdmFieldHandle* objectToggleField() override; void initAfterRead() override; - void defineEditorAttribute(const caf::PdmFieldHandle* field, QString uiConfigName, caf::PdmUiEditorAttribute* attribute) override; private: void calculateWellGeometryVisibility(size_t frameIndex); @@ -146,9 +153,8 @@ class RimSimWellInViewCollection : public caf::PdmObject std::vector< std::vector< cvf::ubyte > > m_framesOfResultWellPipeVisibilities; // Fields - caf::PdmField m_wellColorForApply; - caf::PdmField m_applySingleColorToWells; - caf::PdmField m_applyIndividualColorsToWells; + caf::PdmField m_defaultWellPipeColor; + caf::PdmField m_wellPipeColors; caf::PdmField m_showWellLabel; caf::PdmField m_showWellHead; diff --git a/ApplicationCode/ProjectDataModel/RimStimPlanLegendConfig.cpp b/ApplicationCode/ProjectDataModel/RimStimPlanLegendConfig.cpp index 413cb977dd..4f5b98859e 100644 --- a/ApplicationCode/ProjectDataModel/RimStimPlanLegendConfig.cpp +++ b/ApplicationCode/ProjectDataModel/RimStimPlanLegendConfig.cpp @@ -32,7 +32,7 @@ CAF_PDM_SOURCE_INIT(RimStimPlanLegendConfig, "RimStimPlanLegendConfig"); //-------------------------------------------------------------------------------------------------- RimStimPlanLegendConfig::RimStimPlanLegendConfig() { - CAF_PDM_InitObject("StimPlan Legend Definition", ":/Legend.png", "", ""); + CAF_PDM_InitObject("StimPlan Color Legend", ":/Legend.png", "", ""); CAF_PDM_InitField(&m_name, "Name", QString("StimPlan Legend"), "Name", "", "", ""); m_name.uiCapability()->setUiReadOnly(true); diff --git a/ApplicationCode/ProjectDataModel/RimTensorResults.cpp b/ApplicationCode/ProjectDataModel/RimTensorResults.cpp index cb31fa5bfb..cfc60d671e 100644 --- a/ApplicationCode/ProjectDataModel/RimTensorResults.cpp +++ b/ApplicationCode/ProjectDataModel/RimTensorResults.cpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018 Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -62,7 +62,7 @@ RimTensorResults::RimTensorResults() { CAF_PDM_InitObject("Element Tensor Results", ":/CellResult.png", "", ""); - CAF_PDM_InitFieldNoDefault(&arrowColorLegendConfig, "LegendDefinition", "Legend Definition", "", "", ""); + CAF_PDM_InitFieldNoDefault(&arrowColorLegendConfig, "LegendDefinition", "Color Legend", "", "", ""); this->arrowColorLegendConfig = new RimRegularLegendConfig(); arrowColorLegendConfig.uiCapability()->setUiHidden(true); diff --git a/ApplicationCode/ProjectDataModel/RimTensorResults.h b/ApplicationCode/ProjectDataModel/RimTensorResults.h index babb51dc74..598072f5fd 100644 --- a/ApplicationCode/ProjectDataModel/RimTensorResults.h +++ b/ApplicationCode/ProjectDataModel/RimTensorResults.h @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018 Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by diff --git a/ApplicationCode/ProjectDataModel/RimTernaryLegendConfig.cpp b/ApplicationCode/ProjectDataModel/RimTernaryLegendConfig.cpp index bf12807d96..28af25dd0b 100644 --- a/ApplicationCode/ProjectDataModel/RimTernaryLegendConfig.cpp +++ b/ApplicationCode/ProjectDataModel/RimTernaryLegendConfig.cpp @@ -46,7 +46,7 @@ CAF_PDM_SOURCE_INIT(RimTernaryLegendConfig, "RimTernaryLegendConfig"); //-------------------------------------------------------------------------------------------------- RimTernaryLegendConfig::RimTernaryLegendConfig() { - CAF_PDM_InitObject("Ternary Legend Definition", ":/Legend.png", "", ""); + CAF_PDM_InitObject("Ternary Color Legend", ":/Legend.png", "", ""); CAF_PDM_InitField(&m_showLegend, "ShowTernaryLegend", true, "Show Ternary Legend", "", "", ""); m_showLegend.uiCapability()->setUiHidden(true); CAF_PDM_InitField(&precision, "Precision", 2, "Significant digits", "", "The number of significant digits displayed in the legend numbers",""); @@ -226,7 +226,7 @@ void RimTernaryLegendConfig::recreateLegend() // has been removed, (and thus the opengl resources has been deleted) The text in // the legend disappeared because of this, so workaround: recreate the legend when needed: - cvf::Font* standardFont = RiaApplication::instance()->standardFont(); + cvf::Font* standardFont = RiaApplication::instance()->defaultSceneFont(); m_legend = new RivTernarySaturationOverlayItem(standardFont); m_legend->setLayout(cvf::OverlayItem::VERTICAL, cvf::OverlayItem::BOTTOM_LEFT); diff --git a/ApplicationCode/ProjectDataModel/RimTimeStepFilter.cpp b/ApplicationCode/ProjectDataModel/RimTimeStepFilter.cpp index ff6c5d8695..a3c11bb7ce 100644 --- a/ApplicationCode/ProjectDataModel/RimTimeStepFilter.cpp +++ b/ApplicationCode/ProjectDataModel/RimTimeStepFilter.cpp @@ -26,8 +26,8 @@ #include "RimEclipseResultCase.h" #include "RimGeoMechCase.h" +#include "RimReloadCaseTools.h" #include "RimReservoirCellResultsStorage.h" -#include "RimTools.h" #include "cafPdmUiLineEditor.h" #include "cafPdmUiListEditor.h" @@ -89,12 +89,20 @@ RimTimeStepFilter::RimTimeStepFilter() caf::PdmUiPushButtonEditor::configureEditorForField(&m_applyReloadOfCase); } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimTimeStepFilter::clearFilteredTimeSteps() +{ + m_filteredTimeSteps = std::vector(); +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimTimeStepFilter::setTimeStepsFromFile(const std::vector& timeSteps) { - m_dateFormat = RimTools::createTimeFormatStringFromDates(timeSteps); + m_dateFormat = RiaQDateTimeTools::createTimeFormatStringFromDates(timeSteps); std::vector timeStepStrings; for (const QDateTime& date : timeSteps) @@ -109,7 +117,7 @@ void RimTimeStepFilter::setTimeStepsFromFile(const std::vector& timeS if (m_filteredTimeSteps().empty()) { - m_filteredTimeSteps = filteredTimeStepIndicesFromUi(); + m_filteredTimeSteps = filteredTimeStepIndicesFromUi(); } m_filteredTimeStepsUi = m_filteredTimeSteps; } @@ -127,7 +135,7 @@ void RimTimeStepFilter::setTimeStepsFromFile(const std::vector timeStepStrings; for (auto stringDatePair : timeSteps) @@ -192,10 +200,9 @@ void RimTimeStepFilter::fieldChangedByUi(const caf::PdmFieldHandle* changedField { if (updateFilteredTimeStepsFromUi()) { - if (rimEclipseResultCase) { - rimEclipseResultCase->reloadDataAndUpdate(); + RimReloadCaseTools::reloadAllEclipseGridData(rimEclipseResultCase); } else if (rimGeoMechCase) { diff --git a/ApplicationCode/ProjectDataModel/RimTimeStepFilter.h b/ApplicationCode/ProjectDataModel/RimTimeStepFilter.h index 46409f9793..6729e4ea5f 100644 --- a/ApplicationCode/ProjectDataModel/RimTimeStepFilter.h +++ b/ApplicationCode/ProjectDataModel/RimTimeStepFilter.h @@ -48,6 +48,8 @@ class RimTimeStepFilter : public caf::PdmObject public: RimTimeStepFilter(); + void clearFilteredTimeSteps(); + void setTimeStepsFromFile(const std::vector& timeSteps); void setTimeStepsFromFile(const std::vector>& timeSteps); std::vector filteredTimeSteps() const; diff --git a/ApplicationCode/ProjectDataModel/RimTools.cpp b/ApplicationCode/ProjectDataModel/RimTools.cpp index ce82055855..3ea9fe7429 100644 --- a/ApplicationCode/ProjectDataModel/RimTools.cpp +++ b/ApplicationCode/ProjectDataModel/RimTools.cpp @@ -23,6 +23,7 @@ #include "RiaApplication.h" #include "RimCase.h" +#include "RimEclipseCase.h" #include "RimOilField.h" #include "RimProject.h" #include "RimWellLogFile.h" @@ -305,57 +306,28 @@ void RimTools::caseOptionItems(QList* options) } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- -QString RimTools::createTimeFormatStringFromDates(const std::vector& dates) +void RimTools::eclipseCaseOptionItems(QList* options) { - bool hasHoursAndMinutesInTimesteps = false; - bool hasSecondsInTimesteps = false; - bool hasMillisecondsInTimesteps = false; + CVF_ASSERT(options); + if (!options) return; - for (size_t i = 0; i < dates.size(); i++) + RimProject* proj = RiaApplication::instance()->project(); + if (proj) { - if (dates[i].time().msec() != 0.0) - { - hasMillisecondsInTimesteps = true; - hasSecondsInTimesteps = true; - hasHoursAndMinutesInTimesteps = true; - break; - } - else if (dates[i].time().second() != 0.0) - { - hasHoursAndMinutesInTimesteps = true; - hasSecondsInTimesteps = true; - } - else if (dates[i].time().hour() != 0.0 || dates[i].time().minute() != 0.0) - { - hasHoursAndMinutesInTimesteps = true; - } - } + std::vector cases; + proj->allCases(cases); - QString formatString = dateFormatString(); - if (hasHoursAndMinutesInTimesteps) - { - formatString += " - hh:mm"; - if (hasSecondsInTimesteps) + for (RimCase* c : cases) { - formatString += ":ss"; - if (hasMillisecondsInTimesteps) + RimEclipseCase* eclipseCase = dynamic_cast(c); + if (eclipseCase) { - formatString += ".zzz"; + options->push_back(caf::PdmOptionItemInfo(c->caseUserDescription(), c, false, c->uiIcon())); } } } - - return formatString; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -QString RimTools::dateFormatString() -{ - return "dd.MMM yyyy"; } //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/ProjectDataModel/RimTools.h b/ApplicationCode/ProjectDataModel/RimTools.h index 8c8726c40b..3ee9f8e72f 100644 --- a/ApplicationCode/ProjectDataModel/RimTools.h +++ b/ApplicationCode/ProjectDataModel/RimTools.h @@ -53,10 +53,6 @@ class RimTools static void wellPathWithFormationsOptionItems(QList* options); static void wellPathWithFormations(std::vector* wellPaths); static void caseOptionItems(QList* options); - - static QString createTimeFormatStringFromDates(const std::vector& dates); - - static QString dateFormatString(); - + static void eclipseCaseOptionItems(QList* options); static RimWellPathCollection* wellPathCollection(); }; diff --git a/ApplicationCode/ProjectDataModel/RimViewController.cpp b/ApplicationCode/ProjectDataModel/RimViewController.cpp index 941c48f9f8..8cce4e56e8 100644 --- a/ApplicationCode/ProjectDataModel/RimViewController.cpp +++ b/ApplicationCode/ProjectDataModel/RimViewController.cpp @@ -28,7 +28,7 @@ #include "RigGeoMechCaseData.h" #include "RigMainGrid.h" -#include "RimContourMapView.h" +#include "RimEclipseContourMapView.h" #include "Rim3dView.h" #include "RimCase.h" #include "RimCellRangeFilter.h" @@ -76,7 +76,7 @@ RimViewController::RimViewController() CAF_PDM_InitField(&m_showCursor, "ShowCursor", true, " Show Cursor", "", "", ""); CAF_PDM_InitField(&m_syncTimeStep, "SyncTimeStep", true, "Time Step", "", "", ""); CAF_PDM_InitField(&m_syncCellResult, "SyncCellResult", false, "Cell Result", "", "", ""); - CAF_PDM_InitField(&m_syncLegendDefinitions, "SyncLegendDefinitions", true, " Legend Definition", "", "", ""); + CAF_PDM_InitField(&m_syncLegendDefinitions, "SyncLegendDefinitions", true, " Color Legend", "", "", ""); CAF_PDM_InitField(&m_syncVisibleCells, "SyncVisibleCells", false, "Visible Cells", "", "", ""); /// We do not support this. Consider to remove sometime @@ -671,8 +671,8 @@ RimGridView* RimViewController::masterView() const //-------------------------------------------------------------------------------------------------- bool RimViewController::isCameraControlPossible() const { - RimContourMapView* contourMapMasterView = dynamic_cast(masterView()); - RimContourMapView* contourMapManagedView = dynamic_cast(managedEclipseView()); + RimEclipseContourMapView* contourMapMasterView = dynamic_cast(masterView()); + RimEclipseContourMapView* contourMapManagedView = dynamic_cast(managedEclipseView()); return !(contourMapMasterView || contourMapManagedView); } @@ -910,8 +910,8 @@ bool RimViewController::isRangeFilterMappingApplicable() const //-------------------------------------------------------------------------------------------------- bool RimViewController::isCellResultControlAdvisable() const { - bool contourMapMasterView = dynamic_cast(masterView()) != nullptr; - bool contourMapManagedView = dynamic_cast(managedEclipseView()) != nullptr; + bool contourMapMasterView = dynamic_cast(masterView()) != nullptr; + bool contourMapManagedView = dynamic_cast(managedEclipseView()) != nullptr; return !isMasterAndDepViewDifferentType() && contourMapMasterView != contourMapManagedView; } @@ -920,8 +920,8 @@ bool RimViewController::isCellResultControlAdvisable() const //-------------------------------------------------------------------------------------------------- bool RimViewController::isRangeFilterControlAdvisable() const { - bool contourMapMasterView = dynamic_cast(masterView()) != nullptr; - bool contourMapManagedView = dynamic_cast(managedEclipseView()) != nullptr; + bool contourMapMasterView = dynamic_cast(masterView()) != nullptr; + bool contourMapManagedView = dynamic_cast(managedEclipseView()) != nullptr; return isRangeFilterControlPossible() && contourMapMasterView != contourMapManagedView; } @@ -930,8 +930,8 @@ bool RimViewController::isRangeFilterControlAdvisable() const //-------------------------------------------------------------------------------------------------- bool RimViewController::isPropertyFilterControlAdvisable() const { - bool contourMapMasterView = dynamic_cast(masterView()) != nullptr; - bool contourMapManagedView = dynamic_cast(managedEclipseView()) != nullptr; + bool contourMapMasterView = dynamic_cast(masterView()) != nullptr; + bool contourMapManagedView = dynamic_cast(managedEclipseView()) != nullptr; return isPropertyFilterControlPossible() && contourMapMasterView != contourMapManagedView; } diff --git a/ApplicationCode/ProjectDataModel/RimViewLinker.cpp b/ApplicationCode/ProjectDataModel/RimViewLinker.cpp index 77d192bd2e..13f59b9ca7 100644 --- a/ApplicationCode/ProjectDataModel/RimViewLinker.cpp +++ b/ApplicationCode/ProjectDataModel/RimViewLinker.cpp @@ -22,6 +22,7 @@ #include "RiaApplication.h" #include "RigMainGrid.h" +#include "RigFemResultAddress.h" #include "Rim3dView.h" #include "RimCase.h" diff --git a/ApplicationCode/ProjectDataModel/RimViewNameConfig.cpp b/ApplicationCode/ProjectDataModel/RimViewNameConfig.cpp new file mode 100644 index 0000000000..6eca52db7f --- /dev/null +++ b/ApplicationCode/ProjectDataModel/RimViewNameConfig.cpp @@ -0,0 +1,165 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2018- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "RimViewNameConfig.h" + +//================================================================================================== +/// +/// +//================================================================================================== + +CAF_PDM_SOURCE_INIT(RimViewNameConfig, "RimViewNameConfig"); + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimViewNameConfig::RimViewNameConfig(const RimNameConfigHolderInterface* configHolder) + : RimNameConfig(configHolder) + , m_hideCaseNameField(false) + , m_hideAggregationTypeField(false) + , m_hidePropertyField(false) + , m_hideSampleSpacingField(false) +{ + CAF_PDM_InitObject("View Name Generator", "", "", ""); + + CAF_PDM_InitField(&m_addCaseName, "AddCaseName", false, "Add Case Name", "", "", ""); + CAF_PDM_InitField(&m_addAggregationType, "AddAggregationType", true, "Add Aggregation Type", "", "", ""); + CAF_PDM_InitField(&m_addProperty, "AddProperty", true, "Add Property Type", "", "", ""); + CAF_PDM_InitField(&m_addSampleSpacing, "AddSampleSpacing", false, "Add Sample Spacing", "", "", ""); + + m_customName = ""; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimViewNameConfig::setAddCaseName(bool add) +{ + m_addCaseName = add; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RimViewNameConfig::addCaseName() const +{ + return m_addCaseName(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimViewNameConfig::setAddAggregationType(bool add) +{ + m_addAggregationType = add; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RimViewNameConfig::addAggregationType() const +{ + return m_addAggregationType(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimViewNameConfig::setAddProperty(bool add) +{ + m_addProperty = add; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RimViewNameConfig::addProperty() const +{ + return m_addProperty(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimViewNameConfig::setAddSampleSpacing(bool add) +{ + m_addSampleSpacing = add; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RimViewNameConfig::addSampleSpacing() const +{ + return m_addSampleSpacing(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimViewNameConfig::enableAllAutoNameTags(bool enable) +{ + m_addCaseName = enable; + m_addAggregationType = enable; + m_addProperty = enable; + m_addSampleSpacing = enable; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimViewNameConfig::hideCaseNameField(bool hide) +{ + m_hideCaseNameField = hide; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimViewNameConfig::hideAggregationTypeField(bool hide) +{ + m_hideAggregationTypeField = hide; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimViewNameConfig::hidePropertyField(bool hide) +{ + m_hidePropertyField = hide; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimViewNameConfig::hideSampleSpacingField(bool hide) +{ + m_hideSampleSpacingField = hide; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimViewNameConfig::defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering) +{ + RimNameConfig::defineUiOrdering(uiConfigName, uiOrdering); + if (!m_hideCaseNameField) uiOrdering.add(&m_addCaseName); + if (!m_hideAggregationTypeField) uiOrdering.add(&m_addAggregationType); + if (!m_hidePropertyField) uiOrdering.add(&m_addProperty); + if (!m_hideSampleSpacingField) uiOrdering.add(&m_addSampleSpacing); +} diff --git a/ApplicationCode/ProjectDataModel/RimViewNameConfig.h b/ApplicationCode/ProjectDataModel/RimViewNameConfig.h new file mode 100644 index 0000000000..4adeeaf157 --- /dev/null +++ b/ApplicationCode/ProjectDataModel/RimViewNameConfig.h @@ -0,0 +1,65 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2018- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "RimNameConfig.h" + +//================================================================================================== +/// +/// +//================================================================================================== +class RimViewNameConfig : public RimNameConfig +{ + CAF_PDM_HEADER_INIT; + +public: + explicit RimViewNameConfig(const RimNameConfigHolderInterface* configHolder = nullptr); + + void setAddCaseName(bool add); + bool addCaseName() const; + void setAddAggregationType(bool add); + bool addAggregationType() const; + void setAddProperty(bool add); + bool addProperty() const; + void setAddSampleSpacing(bool add); + bool addSampleSpacing() const; + + void enableAllAutoNameTags(bool enable) override; + + void hideCaseNameField(bool hide); + void hideAggregationTypeField(bool hide); + void hidePropertyField(bool hide); + void hideSampleSpacingField(bool hide); + +protected: + void defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering) override; + +private: + caf::PdmField m_addCaseName; + caf::PdmField m_addAggregationType; + caf::PdmField m_addProperty; + caf::PdmField m_addSampleSpacing; + + bool m_hideCaseNameField; + bool m_hideAggregationTypeField; + bool m_hidePropertyField; + bool m_hideSampleSpacingField; +}; + + diff --git a/ApplicationCode/ProjectDataModel/RimViewWindow.cpp b/ApplicationCode/ProjectDataModel/RimViewWindow.cpp index 72bfa65042..afe9046da0 100644 --- a/ApplicationCode/ProjectDataModel/RimViewWindow.cpp +++ b/ApplicationCode/ProjectDataModel/RimViewWindow.cpp @@ -155,6 +155,21 @@ RimMdiWindowGeometry RimViewWindow::mdiWindowGeometry() } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimViewWindow::viewNavigationChanged() +{ + onViewNavigationChanged(); +} + +//-------------------------------------------------------------------------------------------------- +/// Default implementation of virtual method to trigger updates on view navigation (zoom, camera move, etc) +//-------------------------------------------------------------------------------------------------- +void RimViewWindow::onViewNavigationChanged() +{ +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -207,7 +222,6 @@ void RimViewWindow::setAsMdiWindow(int mainWindowID) } } - //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/ProjectDataModel/RimViewWindow.h b/ApplicationCode/ProjectDataModel/RimViewWindow.h index aae0500e23..5fc2ce4ae1 100644 --- a/ApplicationCode/ProjectDataModel/RimViewWindow.h +++ b/ApplicationCode/ProjectDataModel/RimViewWindow.h @@ -18,6 +18,8 @@ #pragma once +#include "RiaDefines.h" + #include "cafPdmObject.h" #include "cafPdmField.h" #include "cafPdmChildField.h" @@ -63,6 +65,12 @@ class RimViewWindow : public caf::PdmObject virtual QImage snapshotWindowContent() = 0; virtual void zoomAll() = 0; + void viewNavigationChanged(); + + + virtual bool hasCustomFontSizes(RiaDefines::FontSettingType fontSettingType, int defaultFontSize) const { return false;} + virtual bool applyFontSize(RiaDefines::FontSettingType fontSettingType, int oldFontSize, int fontSize, bool forceChange = false) { return false;} + protected: void removeMdiWindowFromMdiArea(); @@ -75,6 +83,7 @@ class RimViewWindow : public caf::PdmObject virtual void updateMdiWindowTitle(); // Has real default implementation virtual void deleteViewWidget() = 0; virtual void onLoadDataAndUpdate() = 0; + virtual void onViewNavigationChanged(); virtual bool isWindowVisible() { return m_showWindow();} // Virtual To allow special visibility control ////////// diff --git a/ApplicationCode/ProjectDataModel/RimVirtualPerforationResults.cpp b/ApplicationCode/ProjectDataModel/RimVirtualPerforationResults.cpp index 1f5255a0c9..24b68b1425 100644 --- a/ApplicationCode/ProjectDataModel/RimVirtualPerforationResults.cpp +++ b/ApplicationCode/ProjectDataModel/RimVirtualPerforationResults.cpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018 Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -39,7 +39,7 @@ RimVirtualPerforationResults::RimVirtualPerforationResults() CAF_PDM_InitField(&m_showClosedConnections, "ShowClosedConnections", true, "Show On Closed Connections", "", "", ""); CAF_PDM_InitField(&m_geometryScaleFactor, "GeometryScaleFactor", 2.0, "Geometry Scale Factor", "", "", ""); - CAF_PDM_InitFieldNoDefault(&m_legendConfig, "LegendDefinition", "Legend Definition", "", "", ""); + CAF_PDM_InitFieldNoDefault(&m_legendConfig, "LegendDefinition", "Color Legend", "", "", ""); m_legendConfig.uiCapability()->setUiHidden(true); m_legendConfig = new RimRegularLegendConfig(); diff --git a/ApplicationCode/ProjectDataModel/RimVirtualPerforationResults.h b/ApplicationCode/ProjectDataModel/RimVirtualPerforationResults.h index c536a56738..bd0f5d802a 100644 --- a/ApplicationCode/ProjectDataModel/RimVirtualPerforationResults.h +++ b/ApplicationCode/ProjectDataModel/RimVirtualPerforationResults.h @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018 Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by diff --git a/ApplicationCode/ProjectDataModel/RimWellLogExtractionCurve.cpp b/ApplicationCode/ProjectDataModel/RimWellLogExtractionCurve.cpp index 20f2df7036..ad45826220 100644 --- a/ApplicationCode/ProjectDataModel/RimWellLogExtractionCurve.cpp +++ b/ApplicationCode/ProjectDataModel/RimWellLogExtractionCurve.cpp @@ -287,7 +287,6 @@ void RimWellLogExtractionCurve::fieldChangedByUi(const caf::PdmFieldHandle* chan this->loadDataAndUpdate(true); } else if (changedField == &m_branchDetection || - changedField == &m_branchIndex || changedField == &m_branchIndex) { clearGeneratedSimWellPaths(); @@ -979,4 +978,4 @@ void RimWellLogExtractionCurve::setBranchDetection(bool branchDetection) void RimWellLogExtractionCurve::setBranchIndex(int index) { m_branchIndex = index; -} \ No newline at end of file +} diff --git a/ApplicationCode/ProjectDataModel/RimWellLogExtractionCurve.h b/ApplicationCode/ProjectDataModel/RimWellLogExtractionCurve.h index 36d9f06b1b..da77922b4a 100644 --- a/ApplicationCode/ProjectDataModel/RimWellLogExtractionCurve.h +++ b/ApplicationCode/ProjectDataModel/RimWellLogExtractionCurve.h @@ -21,11 +21,10 @@ #include "RimWellLogCurve.h" -#include "RigFemResultAddress.h" - #include "cafPdmPtrField.h" #include "cafPdmChildField.h" +class RigFemResultAddress; class RigGeoMechWellLogExtractor; class RigWellPath; class RimCase; diff --git a/ApplicationCode/ProjectDataModel/RimWellLogFile.cpp b/ApplicationCode/ProjectDataModel/RimWellLogFile.cpp index a7b403111a..66c935a5ec 100644 --- a/ApplicationCode/ProjectDataModel/RimWellLogFile.cpp +++ b/ApplicationCode/ProjectDataModel/RimWellLogFile.cpp @@ -334,7 +334,7 @@ void RimWellLogFile::defineEditorAttribute(const caf::PdmFieldHandle* field, QSt caf::PdmUiDateEditorAttribute* attrib = dynamic_cast (attribute); if (attrib != nullptr) { - attrib->dateFormat = RimTools::dateFormatString(); + attrib->dateFormat = RiaQDateTimeTools::dateFormatString(); } } diff --git a/ApplicationCode/ProjectDataModel/RimWellLogPlot.cpp b/ApplicationCode/ProjectDataModel/RimWellLogPlot.cpp index 08ccd4408a..4cc20d5ba7 100644 --- a/ApplicationCode/ProjectDataModel/RimWellLogPlot.cpp +++ b/ApplicationCode/ProjectDataModel/RimWellLogPlot.cpp @@ -42,7 +42,7 @@ #include -#include +#include #define RI_LOGPLOT_MINDEPTH_DEFAULT 0.0 #define RI_LOGPLOT_MAXDEPTH_DEFAULT 1000.0 @@ -178,13 +178,17 @@ void RimWellLogPlot::fieldChangedByUi(const caf::PdmFieldHandle* changedField, c { RimWellAllocationPlot* wellAllocPlot; firstAncestorOrThisOfType(wellAllocPlot); - if (wellAllocPlot) wellAllocPlot->loadDataAndUpdate(); - else if (isRftPlotChild()) rftPlot()->loadDataAndUpdate(); - else + if (wellAllocPlot) + { + wellAllocPlot->loadDataAndUpdate(); + } + else if (isRftPlotChild()) { - updateTracks(); - updateDepthZoom(); + rftPlot()->loadDataAndUpdate(); } + + updateTracks(); + updateDepthZoom(); } else if ( changedField == &m_depthUnit) { @@ -586,8 +590,7 @@ void RimWellLogPlot::uiOrderingForDepthAxis(caf::PdmUiOrdering& uiOrdering) { caf::PdmUiGroup* gridGroup = uiOrdering.addNewGroup("Depth Axis"); - RimWellRftPlot* rftp = rftPlot(); - if (!(rftp || pltPlot())) + if (!pltPlot()) { gridGroup->add(&m_depthType); } @@ -595,7 +598,7 @@ void RimWellLogPlot::uiOrderingForDepthAxis(caf::PdmUiOrdering& uiOrdering) RimWellAllocationPlot* wap; firstAncestorOrThisOfType(wap); - if (!(wap || rftp)) + if (!wap) { gridGroup->add(&m_depthUnit); } @@ -698,7 +701,7 @@ QString RimWellLogPlot::createAutoName() const //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RimWellLogPlot::performHolderUpdate() +void RimWellLogPlot::performAutoNameUpdate() { this->m_commonDataSource->updateDefaultOptions(); this->updatePlotTitle(); @@ -1127,7 +1130,6 @@ void RimWellLogPlot::updateDisabledDepthTypes() } else if (isRftPlotChild()) { - m_disabledDepthTypes.insert(MEASURED_DEPTH); m_disabledDepthTypes.insert(PSEUDO_LENGTH); m_disabledDepthTypes.insert(CONNECTION_NUMBER); } @@ -1151,8 +1153,8 @@ void RimWellLogPlot::updatePlotTitle() { if (m_viewer) { - m_viewer->setPlotTitle(this->createAutoName()); - + m_viewer->setPlotTitle(this->createAutoName()); } + updateMdiWindowTitle(); } diff --git a/ApplicationCode/ProjectDataModel/RimWellLogPlot.h b/ApplicationCode/ProjectDataModel/RimWellLogPlot.h index 8272f9bdc5..1d2646a1f8 100644 --- a/ApplicationCode/ProjectDataModel/RimWellLogPlot.h +++ b/ApplicationCode/ProjectDataModel/RimWellLogPlot.h @@ -127,7 +127,7 @@ class RimWellLogPlot : public RimViewWindow, public RimNameConfigHolderInterface void handleKeyPressEvent(QKeyEvent* keyEvent); RimWellLogCurveCommonDataSource* commonDataSource() const; protected: - void performHolderUpdate() override; + void performAutoNameUpdate() override; // Overridden PDM methods void fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue) override; diff --git a/ApplicationCode/ProjectDataModel/RimWellLogRftCurve.cpp b/ApplicationCode/ProjectDataModel/RimWellLogRftCurve.cpp index 202dd0e0cd..c114e6301b 100644 --- a/ApplicationCode/ProjectDataModel/RimWellLogRftCurve.cpp +++ b/ApplicationCode/ProjectDataModel/RimWellLogRftCurve.cpp @@ -268,7 +268,7 @@ QString RimWellLogRftCurve::createCurveAutoName() } if ( !m_timeStep().isNull()) { - name.push_back(m_timeStep().toString(RimTools::dateFormatString())); + name.push_back(m_timeStep().toString(RiaQDateTimeTools::dateFormatString())); } return name.join(", "); diff --git a/ApplicationCode/ProjectDataModel/RimWellLogTrack.cpp b/ApplicationCode/ProjectDataModel/RimWellLogTrack.cpp index 09f1ebf484..13d8347f29 100644 --- a/ApplicationCode/ProjectDataModel/RimWellLogTrack.cpp +++ b/ApplicationCode/ProjectDataModel/RimWellLogTrack.cpp @@ -25,6 +25,7 @@ #include "RiaSimWellBranchTools.h" #include "RigEclipseCaseData.h" +#include "RigEclipseResultAddress.h" #include "RigEclipseWellLogExtractor.h" #include "RigFemPartResultsCollection.h" #include "RigFemResultAddress.h" @@ -1507,9 +1508,13 @@ void RimWellLogTrack::uiOrderingForXAxisSettings(caf::PdmUiOrdering& uiOrdering) gridGroup->add(&m_visibleXRangeMin); gridGroup->add(&m_visibleXRangeMax); gridGroup->add(&m_xAxisGridVisibility); - gridGroup->add(&m_explicitTickIntervals); - gridGroup->add(&m_majorTickInterval); - gridGroup->add(&m_minorTickInterval); + + // TODO Revisit if these settings are required + // See issue https://github.com/OPM/ResInsight/issues/4367 + // gridGroup->add(&m_explicitTickIntervals); + // gridGroup->add(&m_majorTickInterval); + // gridGroup->add(&m_minorTickInterval); + } //-------------------------------------------------------------------------------------------------- @@ -1733,12 +1738,12 @@ void RimWellLogTrack::updateFormationNamesOnPlot() if (eclWellLogExtractor) { RimEclipseCase* eclipseCase = dynamic_cast(m_formationCase()); - cvf::ref resultAccessor = RigResultAccessorFactory::createFromNameAndType(eclipseCase->eclipseCaseData(), - 0, - RiaDefines::PorosityModelType::MATRIX_MODEL, - 0, - RiaDefines::activeFormationNamesResultName(), - RiaDefines::FORMATION_NAMES); + cvf::ref resultAccessor = RigResultAccessorFactory::createFromResultAddress(eclipseCase->eclipseCaseData(), + 0, + RiaDefines::PorosityModelType::MATRIX_MODEL, + 0, + RigEclipseResultAddress(RiaDefines::FORMATION_NAMES, + RiaDefines::activeFormationNamesResultName())); curveData = RimWellLogTrack::curveSamplingPointData(eclWellLogExtractor, resultAccessor.p()); } @@ -1794,9 +1799,12 @@ void RimWellLogTrack::updateWellPathAttributesOnPlot() if (wellPathAttributeSource()) { + std::vector allWellPathComponents; + if (m_showWellPathAttributes || m_showWellPathCompletions) { - m_wellPathAttributePlotObjects.push_back(std::unique_ptr(new RiuWellPathComponentPlotItem(wellPathAttributeSource()))); + m_wellPathAttributePlotObjects.push_back( + std::unique_ptr(new RiuWellPathComponentPlotItem(wellPathAttributeSource()))); } if (m_showWellPathAttributes) @@ -1804,23 +1812,11 @@ void RimWellLogTrack::updateWellPathAttributesOnPlot() if (m_wellPathAttributeCollection) { std::vector attributes = m_wellPathAttributeCollection->attributes(); - std::sort(attributes.begin(), attributes.end(), [](const RimWellPathAttribute* lhs, const RimWellPathAttribute* rhs) - { - return *lhs < *rhs; - }); - - std::set attributesAssignedToLegend; - for (RimWellPathAttribute* attribute : attributes) + for (const RimWellPathAttribute* attribute : attributes) { if (attribute->isEnabled()) { - std::unique_ptr plotItem(new RiuWellPathComponentPlotItem(wellPathAttributeSource(), attribute)); - QString legendTitle = plotItem->legendTitle(); - bool contributeToLegend = m_wellPathAttributesInLegend() && - !attributesAssignedToLegend.count(legendTitle); - plotItem->setContributeToLegend(contributeToLegend); - m_wellPathAttributePlotObjects.push_back(std::move(plotItem)); - attributesAssignedToLegend.insert(legendTitle); + allWellPathComponents.push_back(attribute); } } } @@ -1830,22 +1826,44 @@ void RimWellLogTrack::updateWellPathAttributesOnPlot() const RimWellPathCompletions* completionsCollection = wellPathAttributeSource()->completions(); std::vector allCompletions = completionsCollection->allCompletions(); - std::set completionsAssignedToLegend; for (const RimWellPathComponentInterface* completion : allCompletions) { if (completion->isEnabled()) { - std::unique_ptr plotItem(new RiuWellPathComponentPlotItem(wellPathAttributeSource(), completion)); - QString legendTitle = plotItem->legendTitle(); - bool contributeToLegend = m_wellPathCompletionsInLegend() && - !completionsAssignedToLegend.count(legendTitle); - plotItem->setContributeToLegend(contributeToLegend); - m_wellPathAttributePlotObjects.push_back(std::move(plotItem)); - completionsAssignedToLegend.insert(legendTitle); + allWellPathComponents.push_back(completion); } } } + const std::map sortIndices = {{RiaDefines::WELL_PATH, 0}, + {RiaDefines::CASING, 1}, + {RiaDefines::LINER, 2}, + {RiaDefines::PERFORATION_INTERVAL, 3}, + {RiaDefines::FISHBONES, 4}, + {RiaDefines::FRACTURE, 5}, + {RiaDefines::PACKER, 6}, + {RiaDefines::ICD, 7}, + {RiaDefines::AICD, 8}, + {RiaDefines::ICV, 9}}; + + std::stable_sort(allWellPathComponents.begin(), allWellPathComponents.end(), + [&sortIndices](const RimWellPathComponentInterface* lhs, const RimWellPathComponentInterface* rhs) + { + return sortIndices.at(lhs->componentType()) < sortIndices.at(rhs->componentType()); + }); + + std::set completionsAssignedToLegend; + for (const RimWellPathComponentInterface* component : allWellPathComponents) + { + std::unique_ptr plotItem( + new RiuWellPathComponentPlotItem(wellPathAttributeSource(), component)); + QString legendTitle = plotItem->legendTitle(); + bool contributeToLegend = m_wellPathCompletionsInLegend() && !completionsAssignedToLegend.count(legendTitle); + plotItem->setContributeToLegend(contributeToLegend); + m_wellPathAttributePlotObjects.push_back(std::move(plotItem)); + completionsAssignedToLegend.insert(legendTitle); + } + RimWellLogPlot* wellLogPlot; this->firstAncestorOrThisOfTypeAsserted(wellLogPlot); RimWellLogPlot::DepthTypeEnum depthType = wellLogPlot->depthType(); diff --git a/ApplicationCode/ProjectDataModel/RimWellPath.cpp b/ApplicationCode/ProjectDataModel/RimWellPath.cpp index f5fdce2345..b858cad70c 100644 --- a/ApplicationCode/ProjectDataModel/RimWellPath.cpp +++ b/ApplicationCode/ProjectDataModel/RimWellPath.cpp @@ -347,6 +347,12 @@ void RimWellPath::fieldChangedByUi(const caf::PdmFieldHandle* changedField, cons { proj->reloadCompletionTypeResultsInAllViews(); } + else if (changedField == &m_name) + { + QString previousName = oldValue.toString(); + QString newName = newValue.toString(); + m_completions->updateWellPathNameHasChanged(newName, previousName); + } else { proj->scheduleCreateDisplayModelAndRedrawAllViews(); diff --git a/ApplicationCode/ProjectDataModel/RimWellPathAttribute.cpp b/ApplicationCode/ProjectDataModel/RimWellPathAttribute.cpp index 31e99f5c8d..6ace7191c4 100644 --- a/ApplicationCode/ProjectDataModel/RimWellPathAttribute.cpp +++ b/ApplicationCode/ProjectDataModel/RimWellPathAttribute.cpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018 - Equinor ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -229,14 +229,14 @@ void RimWellPathAttribute::fieldChangedByUi(const caf::PdmFieldHandle* changedFi } else if (m_type() == RiaDefines::PACKER) { - m_endMD = m_startMD + 2; + m_endMD = m_startMD + 1; } } if (changedField == &m_startMD) { if (m_type() == RiaDefines::PACKER) { - m_endMD = m_startMD + 2; + m_endMD = m_startMD + 1; } } diff --git a/ApplicationCode/ProjectDataModel/RimWellPathAttribute.h b/ApplicationCode/ProjectDataModel/RimWellPathAttribute.h index effd3e18c1..66e34c7607 100644 --- a/ApplicationCode/ProjectDataModel/RimWellPathAttribute.h +++ b/ApplicationCode/ProjectDataModel/RimWellPathAttribute.h @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018 - Equinor ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by diff --git a/ApplicationCode/ProjectDataModel/RimWellPathAttributeCollection.cpp b/ApplicationCode/ProjectDataModel/RimWellPathAttributeCollection.cpp index 4e272eb66b..f6332a3987 100644 --- a/ApplicationCode/ProjectDataModel/RimWellPathAttributeCollection.cpp +++ b/ApplicationCode/ProjectDataModel/RimWellPathAttributeCollection.cpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018 - Equinor ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by diff --git a/ApplicationCode/ProjectDataModel/RimWellPathAttributeCollection.h b/ApplicationCode/ProjectDataModel/RimWellPathAttributeCollection.h index 48e0615aea..6c610a2e32 100644 --- a/ApplicationCode/ProjectDataModel/RimWellPathAttributeCollection.h +++ b/ApplicationCode/ProjectDataModel/RimWellPathAttributeCollection.h @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018 - Equinor ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by diff --git a/ApplicationCode/ProjectDataModel/RimWellPathGeometryDef.cpp b/ApplicationCode/ProjectDataModel/RimWellPathGeometryDef.cpp index 290636bc0b..2721af9302 100644 --- a/ApplicationCode/ProjectDataModel/RimWellPathGeometryDef.cpp +++ b/ApplicationCode/ProjectDataModel/RimWellPathGeometryDef.cpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018 - Equinor ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -38,6 +38,7 @@ #include "cafPdmUiTableViewEditor.h" #include "cafPdmUiTreeOrdering.h" #include "cvfGeometryTools.h" +#include "WellPathCommands/PointTangentManipulator/RicWellPathGeometry3dEditor.h" namespace caf @@ -64,6 +65,7 @@ RimWellPathGeometryDef::RimWellPathGeometryDef() { CAF_PDM_InitObject("Well Targets", ":/WellTargets.png", "", ""); + this->setUi3dEditorTypeName(RicWellPathGeometry3dEditor::uiEditorTypeName()); CAF_PDM_InitField(&m_referencePointUtmXyd, "ReferencePosUtmXyd", cvf::Vec3d(0,0,0), "UTM Reference Point", "", "", ""); CAF_PDM_InitField(&m_mdrkbAtFirstTarget, "MdrkbAtFirstTarget", 0.0, "MDRKB at First Target", "", "", ""); @@ -98,11 +100,6 @@ RimWellPathGeometryDef::RimWellPathGeometryDef() //-------------------------------------------------------------------------------------------------- RimWellPathGeometryDef::~RimWellPathGeometryDef() { - RiuViewerCommands::removePickEventHandlerIfActive(m_pickTargetsEventHandler); - - delete m_pickTargetsEventHandler; - - m_pickTargetsEventHandler = nullptr; } //-------------------------------------------------------------------------------------------------- @@ -288,18 +285,8 @@ const RimWellPathTarget* RimWellPathGeometryDef::lastActiveTarget() const //-------------------------------------------------------------------------------------------------- void RimWellPathGeometryDef::enableTargetPointPicking(bool isEnabling) { - if (isEnabling) - { - m_pickPointsEnabled = true; - RiuViewerCommands::setPickEventHandler(m_pickTargetsEventHandler); - updateConnectedEditors(); - } - else - { - RiuViewerCommands::removePickEventHandlerIfActive(m_pickTargetsEventHandler); - m_pickPointsEnabled = false; - updateConnectedEditors(); - } + m_pickPointsEnabled = isEnabling; + this->updateConnectedEditors(); } //-------------------------------------------------------------------------------------------------- @@ -331,7 +318,7 @@ void RimWellPathGeometryDef::fieldChangedByUi(const caf::PdmFieldHandle* changed } else if (changedField == &m_pickPointsEnabled) { - enableTargetPointPicking(m_pickPointsEnabled); + this->updateConnectedEditors(); } updateWellPathVisualization(); @@ -638,6 +625,19 @@ void RimWellPathGeometryDef::defineEditorAttribute(const caf::PdmFieldHandle* fi } } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimWellPathGeometryDef::defineObjectEditorAttribute(QString uiConfigName, caf::PdmUiEditorAttribute* attribute) +{ + RicWellPathGeometry3dEditorAttribute* attrib = dynamic_cast(attribute); + if (attrib) + { + attrib->pickEventHandler = m_pickTargetsEventHandler; + attrib->enablePicking = m_pickPointsEnabled; + } +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/ProjectDataModel/RimWellPathGeometryDef.h b/ApplicationCode/ProjectDataModel/RimWellPathGeometryDef.h index b3cff922fe..522545d401 100644 --- a/ApplicationCode/ProjectDataModel/RimWellPathGeometryDef.h +++ b/ApplicationCode/ProjectDataModel/RimWellPathGeometryDef.h @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018 - Equinor ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -80,6 +80,9 @@ class RimWellPathGeometryDef : public caf::PdmObject + + virtual void defineObjectEditorAttribute(QString uiConfigName, caf::PdmUiEditorAttribute* attribute) override; + private: void fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, @@ -101,11 +104,12 @@ class RimWellPathGeometryDef : public caf::PdmObject caf::PdmChildArrayField m_wellTargets; caf::PdmField< bool > m_pickPointsEnabled; - RicCreateWellTargetsPickEventHandler* m_pickTargetsEventHandler; - // Unused for now. Remove when dust settles + // TODO: Unused for now. Remove when dust settles caf::PdmField > m_wellStartType; caf::PdmField m_kickoffDepthOrMD; caf::PdmPtrField m_parentWell; + + std::shared_ptr m_pickTargetsEventHandler; }; diff --git a/ApplicationCode/ProjectDataModel/Summary/CMakeLists_files.cmake b/ApplicationCode/ProjectDataModel/Summary/CMakeLists_files.cmake index c9f905f1df..9e78eb6e7a 100644 --- a/ApplicationCode/ProjectDataModel/Summary/CMakeLists_files.cmake +++ b/ApplicationCode/ProjectDataModel/Summary/CMakeLists_files.cmake @@ -17,7 +17,6 @@ ${CMAKE_CURRENT_LIST_DIR}/RimSummaryPlot.h ${CMAKE_CURRENT_LIST_DIR}/RimSummaryPlotCollection.h ${CMAKE_CURRENT_LIST_DIR}/RimSummaryCrossPlotCollection.h ${CMAKE_CURRENT_LIST_DIR}/RimSummaryTimeAxisProperties.h -${CMAKE_CURRENT_LIST_DIR}/RimSummaryAxisProperties.h ${CMAKE_CURRENT_LIST_DIR}/RimObservedData.h ${CMAKE_CURRENT_LIST_DIR}/RimObservedDataCollection.h ${CMAKE_CURRENT_LIST_DIR}/RimSummaryObservedDataFile.h @@ -58,7 +57,6 @@ ${CMAKE_CURRENT_LIST_DIR}/RimSummaryPlot.cpp ${CMAKE_CURRENT_LIST_DIR}/RimSummaryPlotCollection.cpp ${CMAKE_CURRENT_LIST_DIR}/RimSummaryCrossPlotCollection.cpp ${CMAKE_CURRENT_LIST_DIR}/RimSummaryTimeAxisProperties.cpp -${CMAKE_CURRENT_LIST_DIR}/RimSummaryAxisProperties.cpp ${CMAKE_CURRENT_LIST_DIR}/RimObservedData.cpp ${CMAKE_CURRENT_LIST_DIR}/RimObservedDataCollection.cpp ${CMAKE_CURRENT_LIST_DIR}/RimSummaryObservedDataFile.cpp diff --git a/ApplicationCode/ProjectDataModel/Summary/RimAsciiDataCurve.cpp b/ApplicationCode/ProjectDataModel/Summary/RimAsciiDataCurve.cpp index 9cdf023e91..484bc53b7c 100644 --- a/ApplicationCode/ProjectDataModel/Summary/RimAsciiDataCurve.cpp +++ b/ApplicationCode/ProjectDataModel/Summary/RimAsciiDataCurve.cpp @@ -31,13 +31,13 @@ #include "RimSummaryTimeAxisProperties.h" #include "RiuQwtPlotCurve.h" -#include "RiuSummaryQwtPlot.h" #include "cafPdmUiComboBoxEditor.h" #include "cafPdmUiListEditor.h" #include "cafPdmUiTreeOrdering.h" #include "qwt_date.h" +#include "qwt_plot.h" CAF_PDM_SOURCE_INIT(RimAsciiDataCurve, "AsciiDataCurve"); diff --git a/ApplicationCode/ProjectDataModel/Summary/RimDerivedEnsembleCase.cpp b/ApplicationCode/ProjectDataModel/Summary/RimDerivedEnsembleCase.cpp index e4218405df..7d6538b846 100644 --- a/ApplicationCode/ProjectDataModel/Summary/RimDerivedEnsembleCase.cpp +++ b/ApplicationCode/ProjectDataModel/Summary/RimDerivedEnsembleCase.cpp @@ -18,6 +18,7 @@ #include "RimDerivedEnsembleCase.h" +#include "RiaLogging.h" #include "RiaSummaryTools.h" #include "RiaTimeHistoryCurveMerger.h" @@ -133,6 +134,16 @@ void RimDerivedEnsembleCase::calculate(const RifEclipseSummaryAddress& address) RifSummaryReaderInterface* reader2 = m_summaryCase2 ? m_summaryCase2->summaryReader() : nullptr; if (!reader1 || !reader2 || !parentEnsemble()) return; + if (!reader1->hasAddress(address) || !reader2->hasAddress(address)) + { + std::string text = address.uiText(); + + RiaLogging::warning("Derived Ensemble : At least one of the ensembles does not contain the summary address : " + + QString::fromStdString(text)); + + return; + } + RiaTimeHistoryCurveMerger merger; std::vector values1; std::vector values2; diff --git a/ApplicationCode/ProjectDataModel/Summary/RimEnsembleCurveFilter.cpp b/ApplicationCode/ProjectDataModel/Summary/RimEnsembleCurveFilter.cpp index 2f6485734c..0c34983db4 100644 --- a/ApplicationCode/ProjectDataModel/Summary/RimEnsembleCurveFilter.cpp +++ b/ApplicationCode/ProjectDataModel/Summary/RimEnsembleCurveFilter.cpp @@ -22,6 +22,7 @@ #include "RimSummaryCase.h" #include "cafPdmUiDoubleSliderEditor.h" +#include "cafPdmUiListEditor.h" #include "cafPdmUiPushButtonEditor.h" #include @@ -46,6 +47,7 @@ RimEnsembleCurveFilter::RimEnsembleCurveFilter() : m_lowerLimit(DOUBLE_INF), m_u m_active = true; CAF_PDM_InitFieldNoDefault(&m_ensembleParameterName, "EnsembleParameter", "Ensemble Parameter", "", "", ""); + m_ensembleParameterName.uiCapability()->setUiEditorTypeName(caf::PdmUiListEditor::uiEditorTypeName()); CAF_PDM_InitFieldNoDefault(&m_minValue, "MinValue", "Min", "", "", ""); m_minValue.uiCapability()->setUiEditorTypeName(caf::PdmUiDoubleSliderEditor::uiEditorTypeName()); @@ -133,10 +135,10 @@ QList RimEnsembleCurveFilter::calculateValueOptions(cons auto curveSet = parentCurveSet(); if (curveSet) { - auto names = curveSet->ensembleParameterNames(); - for (auto& name : names) + auto nameParameterPairs = curveSet->ensembleParameters(); + for (auto& nameParamPair : nameParameterPairs) { - options.push_back(caf::PdmOptionItemInfo(name, name)); + options.push_back(caf::PdmOptionItemInfo(RimEnsembleCurveSet::ensembleParameterUiName(nameParamPair), nameParamPair.first)); } } } @@ -348,10 +350,10 @@ void RimEnsembleCurveFilter::setInitialValues(bool forceDefault) { if (!selectedEnsembleParameter().isValid()) { - auto parameterNames = parentCurveSet()->ensembleParameterNames(); + auto parameterNames = parentCurveSet()->ensembleParameters(); if (!parameterNames.empty()) { - m_ensembleParameterName = parameterNames.front(); + m_ensembleParameterName = parameterNames.front().first; updateConnectedEditors(); } } diff --git a/ApplicationCode/ProjectDataModel/Summary/RimEnsembleCurveSet.cpp b/ApplicationCode/ProjectDataModel/Summary/RimEnsembleCurveSet.cpp index 9b9c41119a..8f1995599a 100644 --- a/ApplicationCode/ProjectDataModel/Summary/RimEnsembleCurveSet.cpp +++ b/ApplicationCode/ProjectDataModel/Summary/RimEnsembleCurveSet.cpp @@ -49,8 +49,8 @@ #include "RiuQwtPlotCurve.h" #include "RiuPlotMainWindow.h" -#include "RiuSummaryQwtPlot.h" #include "RiuSummaryCurveDefSelectionDialog.h" +#include "RiuSummaryQwtPlot.h" #include "cafPdmUiTreeOrdering.h" #include "cafPdmUiListEditor.h" @@ -142,6 +142,7 @@ RimEnsembleCurveSet::RimEnsembleCurveSet() CAF_PDM_InitField(&m_color, "Color", cvf::Color3f(cvf::Color3::BLACK), "Color", "", "", ""); CAF_PDM_InitField(&m_ensembleParameter, "EnsembleParameter", QString(""), "Ensemble Parameter", "", "", ""); + m_ensembleParameter.uiCapability()->setUiEditorTypeName(caf::PdmUiListEditor::uiEditorTypeName()); CAF_PDM_InitFieldNoDefault(&m_plotAxis, "PlotAxis", "Axis", "", "", ""); @@ -444,6 +445,29 @@ EnsembleParameter::Type RimEnsembleCurveSet::currentEnsembleParameterType() cons return EnsembleParameter::TYPE_NONE; } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RimEnsembleCurveSet::ensembleParameterUiName(const RimEnsembleCurveSet::NameParameterPair& paramPair) +{ + QString stem = paramPair.first; + QString variationString; + if (paramPair.second.isNumeric()) + { + switch (paramPair.second.variationBin) + { + case EnsembleParameter::LOW_VARIATION: + variationString = QString(" (Low variation)"); + case EnsembleParameter::MEDIUM_VARIATION: + break; + case EnsembleParameter::HIGH_VARIATION: + variationString = QString(" (High variation)"); + break; + } + } + return QString("%1%2").arg(stem).arg(variationString); +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -518,8 +542,8 @@ void RimEnsembleCurveSet::fieldChangedByUi(const caf::PdmFieldHandle* changedFie { if (m_ensembleParameter().isEmpty()) { - auto params = ensembleParameterNames(); - m_ensembleParameter = !params.empty() ? params.front() : ""; + auto params = ensembleParameters(); + m_ensembleParameter = !params.empty() ? params.front().first : ""; } updateCurveColors(); @@ -741,16 +765,16 @@ QList RimEnsembleCurveSet::calculateValueOptions(const c auto byEnsParamOption = caf::AppEnum(RimEnsembleCurveSet::BY_ENSEMBLE_PARAM); options.push_back(caf::PdmOptionItemInfo(singleColorOption.uiText(), RimEnsembleCurveSet::SINGLE_COLOR)); - if (!ensembleParameterNames().empty()) + if (!ensembleParameters().empty()) { options.push_back(caf::PdmOptionItemInfo(byEnsParamOption.uiText(), RimEnsembleCurveSet::BY_ENSEMBLE_PARAM)); } } else if (fieldNeedingOptions == &m_ensembleParameter) { - for (const auto& param : ensembleParameterNames()) + for (const auto& paramPair : ensembleParameters()) { - options.push_back(caf::PdmOptionItemInfo(param, param)); + options.push_back(caf::PdmOptionItemInfo(ensembleParameterUiName(paramPair), paramPair.first)); } } else if (fieldNeedingOptions == &m_yValuesUiFilterResultSelection) @@ -947,13 +971,13 @@ void RimEnsembleCurveSet::updateEnsembleCurves(const std::vectoraddress().category() != RifEclipseSummaryAddress::SUMMARY_INVALID) { - if(m_showCurves) + if(isCurvesVisible()) { for (auto& sumCase : sumCases) { RimSummaryCurve* curve = new RimSummaryCurve(); curve->setSummaryCaseY(sumCase); - curve->setSummaryAddressY(addr->address()); + curve->setSummaryAddressYAndApplyInterpolation(addr->address()); curve->setLeftOrRightAxisY(m_plotAxis()); addCurve(curve); @@ -993,7 +1017,7 @@ void RimEnsembleCurveSet::updateStatisticsCurves(const std::vectoraddress().category() == RifEclipseSummaryAddress::SUMMARY_INVALID) return; + if (!isCurvesVisible() || m_disableStatisticCurves || !group || addr->address().category() == RifEclipseSummaryAddress::SUMMARY_INVALID) return; // Calculate { @@ -1045,7 +1069,7 @@ void RimEnsembleCurveSet::updateStatisticsCurves(const std::vectorsetLineStyle(RiuQwtPlotCurve::STYLE_SOLID); curve->setSummaryCaseY(m_ensembleStatCase.get()); - curve->setSummaryAddressY(address); + curve->setSummaryAddressYAndApplyInterpolation(address); curve->setLeftOrRightAxisY(m_plotAxis()); curve->updateCurveVisibility(false); @@ -1121,7 +1145,7 @@ void RimEnsembleCurveSet::updateAllTextInPlot() //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -std::vector RimEnsembleCurveSet::ensembleParameterNames() const +std::vector RimEnsembleCurveSet::ensembleParameters() const { RimSummaryCaseCollection* group = m_yValuesSummaryGroup; @@ -1137,7 +1161,15 @@ std::vector RimEnsembleCurveSet::ensembleParameterNames() const } } } - return std::vector(paramSet.begin(), paramSet.end()); + + std::vector parameterVector; + parameterVector.reserve(paramSet.size()); + for (const QString& parameterName : paramSet) + { + parameterVector.push_back(std::make_pair(parameterName, group->ensembleParameter(parameterName))); + } + EnsembleParameter::sortByBinnedVariation(parameterVector); + return parameterVector; } //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/ProjectDataModel/Summary/RimEnsembleCurveSet.h b/ApplicationCode/ProjectDataModel/Summary/RimEnsembleCurveSet.h index 273a3fa37b..3f6af71fa7 100644 --- a/ApplicationCode/ProjectDataModel/Summary/RimEnsembleCurveSet.h +++ b/ApplicationCode/ProjectDataModel/Summary/RimEnsembleCurveSet.h @@ -65,6 +65,8 @@ class RimEnsembleCurveSet : public caf::PdmObject public: enum ColorMode {SINGLE_COLOR, BY_ENSEMBLE_PARAM}; + typedef std::pair NameParameterPair; + RimEnsembleCurveSet(); ~RimEnsembleCurveSet() override; @@ -97,6 +99,7 @@ class RimEnsembleCurveSet : public caf::PdmObject ColorMode colorMode() const; void updateEnsembleLegendItem(); EnsembleParameter::Type currentEnsembleParameterType() const; + static QString ensembleParameterUiName(const NameParameterPair& paramPair); void updateAllCurves(); void updateStatisticsCurves(); @@ -107,7 +110,7 @@ class RimEnsembleCurveSet : public caf::PdmObject void markCachedDataForPurge(); void updateAllTextInPlot(); - std::vector ensembleParameterNames() const; + std::vector ensembleParameters() const; std::vector filterEnsembleCases(const std::vector& sumCases); void disableStatisticCurves(); @@ -124,27 +127,27 @@ class RimEnsembleCurveSet : public caf::PdmObject caf::PdmFieldHandle* userDescriptionField() override; caf::PdmFieldHandle* objectToggleField() override; - void defineEditorAttribute(const caf::PdmFieldHandle* field, QString uiConfigName, caf::PdmUiEditorAttribute* attribute) override; - - QList calculateValueOptions(const caf::PdmFieldHandle* fieldNeedingOptions, bool* useOptionsOnly) override; - void defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering) override; - void defineUiTreeOrdering(caf::PdmUiTreeOrdering& uiTreeOrdering, QString uiConfigName = "") override; + void defineEditorAttribute(const caf::PdmFieldHandle* field, QString uiConfigName, caf::PdmUiEditorAttribute* attribute) override; - void fieldChangedByUi(const caf::PdmFieldHandle* changedField, - const QVariant& oldValue, const QVariant& newValue) override; + QList calculateValueOptions(const caf::PdmFieldHandle* fieldNeedingOptions, bool* useOptionsOnly) override; + void defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering) override; + void defineUiTreeOrdering(caf::PdmUiTreeOrdering& uiTreeOrdering, QString uiConfigName = "") override; - void appendOptionItemsForSummaryAddresses(QList* options, - RimSummaryCaseCollection* summaryCaseGroup, - RimSummaryFilter* summaryFilter); + void fieldChangedByUi(const caf::PdmFieldHandle* changedField, + const QVariant& oldValue, const QVariant& newValue) override; - void updateCurveColors(); - void updateQwtPlotAxis(); + void appendOptionItemsForSummaryAddresses(QList* options, + RimSummaryCaseCollection* summaryCaseGroup, + RimSummaryFilter* summaryFilter); - QString name() const; - QString createAutoName() const; + void updateCurveColors(); + void updateQwtPlotAxis(); - void updateLegendMappingMode(); + QString name() const; + QString createAutoName() const; + void updateLegendMappingMode(); + void sortParameterVectorByBinnedVariation(std::vector& parameterVector) const; private: caf::PdmField m_showCurves; caf::PdmChildArrayField m_curves; diff --git a/ApplicationCode/ProjectDataModel/Summary/RimEnsembleCurveSetCollection.cpp b/ApplicationCode/ProjectDataModel/Summary/RimEnsembleCurveSetCollection.cpp index 0a02f51d9c..0d6fbd62a7 100644 --- a/ApplicationCode/ProjectDataModel/Summary/RimEnsembleCurveSetCollection.cpp +++ b/ApplicationCode/ProjectDataModel/Summary/RimEnsembleCurveSetCollection.cpp @@ -34,7 +34,8 @@ #include "RimSummaryPlotSourceStepping.h" #include "RiuQwtPlotCurve.h" -#include "RiuSummaryQwtPlot.h" + +#include "qwt_plot.h" CAF_PDM_SOURCE_INIT(RimEnsembleCurveSetCollection, "RimEnsembleCurveSetCollection"); diff --git a/ApplicationCode/ProjectDataModel/Summary/RimObservedDataCollection.cpp b/ApplicationCode/ProjectDataModel/Summary/RimObservedDataCollection.cpp index f5a91cbcb1..7e09a7401e 100644 --- a/ApplicationCode/ProjectDataModel/Summary/RimObservedDataCollection.cpp +++ b/ApplicationCode/ProjectDataModel/Summary/RimObservedDataCollection.cpp @@ -48,7 +48,7 @@ CAF_PDM_SOURCE_INIT(RimObservedDataCollection, "ObservedDataCollection"); //-------------------------------------------------------------------------------------------------- RimObservedDataCollection::RimObservedDataCollection() { - CAF_PDM_InitObject("Observed Time History Data", ":/Folder.png", "", ""); + CAF_PDM_InitObject("Observed Data", ":/Folder.png", "", ""); CAF_PDM_InitFieldNoDefault(&m_observedDataArray, "ObservedDataArray", "", "", "", ""); @@ -75,13 +75,9 @@ void RimObservedDataCollection::removeObservedData(RimObservedData* observedData //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -std::vector RimObservedDataCollection::allObservedData() +std::vector RimObservedDataCollection::allObservedData() { - std::vector allObservedData; - - allObservedData.insert(allObservedData.begin(), m_observedDataArray.begin(), m_observedDataArray.end()); - - return allObservedData; + return m_observedDataArray.childObjects(); } //-------------------------------------------------------------------------------------------------- @@ -153,7 +149,6 @@ RimObservedData* RimObservedDataCollection::createAndAddCvsObservedDataFromFile( if (!fileExists(fileName, errorText)) return nullptr; RimObservedData* observedData = nullptr; - bool parseOk = false; RimCsvUserData* userData = new RimCsvUserData(); RicPasteAsciiDataToSummaryPlotFeatureUi* parseOptions = userData->parseOptions(); @@ -190,7 +185,6 @@ RimObservedData* RimObservedDataCollection::createAndAddCvsObservedDataFromFile( { this->m_observedDataArray.push_back(userData); observedData = userData; - parseOk = true; } else { diff --git a/ApplicationCode/ProjectDataModel/Summary/RimObservedDataCollection.h b/ApplicationCode/ProjectDataModel/Summary/RimObservedDataCollection.h index 0bcd4d8b37..5b3834bc22 100644 --- a/ApplicationCode/ProjectDataModel/Summary/RimObservedDataCollection.h +++ b/ApplicationCode/ProjectDataModel/Summary/RimObservedDataCollection.h @@ -21,7 +21,6 @@ #include "cafPdmObject.h" #include "cafPdmChildArrayField.h" -class RimSummaryCase; class RimObservedData; class QFile; @@ -39,7 +38,7 @@ class RimObservedDataCollection : public caf::PdmObject void removeObservedData(RimObservedData* observedData); RimObservedData* createAndAddRsmObservedDataFromFile(const QString& fileName, QString* errorText = nullptr); RimObservedData* createAndAddCvsObservedDataFromFile(const QString& fileName, bool useSavedFieldsValuesInDialog, QString* errorText = nullptr); - std::vector allObservedData(); + std::vector allObservedData(); private: bool fileExists(const QString& fileName, QString* errorText = nullptr); diff --git a/ApplicationCode/ProjectDataModel/Summary/RimSummaryAxisProperties.cpp b/ApplicationCode/ProjectDataModel/Summary/RimSummaryAxisProperties.cpp deleted file mode 100644 index 82b66119b2..0000000000 --- a/ApplicationCode/ProjectDataModel/Summary/RimSummaryAxisProperties.cpp +++ /dev/null @@ -1,340 +0,0 @@ -///////////////////////////////////////////////////////////////////////////////// -// -// Copyright (C) 2016 Statoil ASA -// -// ResInsight 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 3 of the License, or -// (at your option) any later version. -// -// ResInsight 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 at -// for more details. -// -///////////////////////////////////////////////////////////////////////////////// - -#include "RimSummaryAxisProperties.h" - -#include "RiaDefines.h" -#include "RimSummaryPlot.h" - -#include "cafPdmUiSliderEditor.h" - -#include - -// clang-format off -namespace caf -{ -template<> -void caf::AppEnum::setUp() -{ - addItem(RimSummaryAxisProperties::NUMBER_FORMAT_AUTO, "NUMBER_FORMAT_AUTO", "Auto"); - addItem(RimSummaryAxisProperties::NUMBER_FORMAT_DECIMAL, "NUMBER_FORMAT_DECIMAL", "Decimal"); - addItem(RimSummaryAxisProperties::NUMBER_FORMAT_SCIENTIFIC, "NUMBER_FORMAT_SCIENTIFIC", "Scientific"); - - setDefault(RimSummaryAxisProperties::NUMBER_FORMAT_AUTO); -} - -template<> -void caf::AppEnum::setUp() -{ - addItem(RimSummaryAxisProperties::AXIS_TITLE_CENTER, "AXIS_TITLE_CENTER", "Center"); - addItem(RimSummaryAxisProperties::AXIS_TITLE_END, "AXIS_TITLE_END", "At End"); - - setDefault(RimSummaryAxisProperties::AXIS_TITLE_CENTER); -} -} // namespace caf - -CAF_PDM_SOURCE_INIT(RimSummaryAxisProperties, "SummaryYAxisProperties"); - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -RimSummaryAxisProperties::RimSummaryAxisProperties() -{ - CAF_PDM_InitObject("Y-Axis Properties", ":/LeftAxis16x16.png", "", ""); - - CAF_PDM_InitField(&m_isActive, "Active", true, "Active", "", "", ""); - m_isActive.uiCapability()->setUiHidden(true); - - CAF_PDM_InitFieldNoDefault(&m_name, "Name", "Name", "", "", ""); - m_name.uiCapability()->setUiHidden(true); - - CAF_PDM_InitField(&isAutoTitle, "AutoTitle", true, "Auto Title", "", "", ""); - - CAF_PDM_InitField(&m_displayLongName, "DisplayLongName", true, " Names", "", "", ""); - CAF_PDM_InitField(&m_displayShortName, "DisplayShortName", false, " Acronyms", "", "", ""); - CAF_PDM_InitField(&m_displayUnitText, "DisplayUnitText", true, " Units", "", "", ""); - - CAF_PDM_InitFieldNoDefault(&customTitle, "CustomTitle", "Title", "", "", ""); - CAF_PDM_InitFieldNoDefault(&titlePositionEnum, "TitlePosition", "Title Position", "", "", ""); - CAF_PDM_InitField(&titleFontSize, "FontSize", 11, "Font Size", "", "", ""); - - CAF_PDM_InitField(&visibleRangeMax, "VisibleRangeMax", RiaDefines::maximumDefaultValuePlot(), "Max", "", "", ""); - CAF_PDM_InitField(&visibleRangeMin, "VisibleRangeMin", RiaDefines::minimumDefaultValuePlot(), "Min", "", "", ""); - - CAF_PDM_InitFieldNoDefault(&numberFormat, "NumberFormat", "Number Format", "", "", ""); - CAF_PDM_InitField(&numberOfDecimals, "Decimals", 2, "Number of Decimals", "", "", ""); - CAF_PDM_InitField(&scaleFactor, "ScaleFactor", 1.0, "Scale Factor", "", "", ""); - CAF_PDM_InitField(&valuesFontSize, "ValuesFontSize", 11, "Font Size", "", "", ""); - - numberOfDecimals.uiCapability()->setUiEditorTypeName(caf::PdmUiSliderEditor::uiEditorTypeName()); - - CAF_PDM_InitField(&m_isAutoZoom, "AutoZoom", true, "Set Range Automatically", "", "", ""); - CAF_PDM_InitField(&isLogarithmicScaleEnabled, "LogarithmicScale", false, "Logarithmic Scale", "", "", ""); - - updateOptionSensitivity(); -} - -// clang-format on - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -caf::PdmFieldHandle* RimSummaryAxisProperties::userDescriptionField() -{ - return &m_name; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -QList RimSummaryAxisProperties::calculateValueOptions(const caf::PdmFieldHandle* fieldNeedingOptions, - bool* useOptionsOnly) -{ - QList options; - *useOptionsOnly = true; - - if (&titleFontSize == fieldNeedingOptions || &valuesFontSize == fieldNeedingOptions) - { - std::vector fontSizes; - fontSizes.push_back(8); - fontSizes.push_back(9); - fontSizes.push_back(10); - fontSizes.push_back(11); - fontSizes.push_back(12); - fontSizes.push_back(14); - fontSizes.push_back(16); - fontSizes.push_back(18); - fontSizes.push_back(24); - - for (int value : fontSizes) - { - QString text = QString("%1").arg(value); - options.push_back(caf::PdmOptionItemInfo(text, value)); - } - } - else if (fieldNeedingOptions == &scaleFactor) - { - for (int exp = -12; exp <= 12; exp += 3) - { - QString uiText = exp == 0 ? "1" : QString("10 ^ %1").arg(exp); - double value = std::pow(10, exp); - - options.push_back(caf::PdmOptionItemInfo(uiText, value)); - } - } - - return options; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RimSummaryAxisProperties::defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering) -{ - { - caf::PdmUiGroup* titleTextGroup = uiOrdering.addNewGroup("Title Text"); - - titleTextGroup->add(&isAutoTitle); - - if (isAutoTitle()) - { - titleTextGroup->add(&m_displayLongName); - titleTextGroup->add(&m_displayShortName); - titleTextGroup->add(&m_displayUnitText); - - customTitle.uiCapability()->setUiReadOnly(true); - } - else - { - titleTextGroup->add(&customTitle); - customTitle.uiCapability()->setUiReadOnly(false); - } - } - - { - caf::PdmUiGroup* titleGroup = uiOrdering.addNewGroup("Title Layout"); - titleGroup->add(&titlePositionEnum); - titleGroup->add(&titleFontSize); - } - - caf::PdmUiGroup& scaleGroup = *(uiOrdering.addNewGroup("Axis Values")); - scaleGroup.add(&isLogarithmicScaleEnabled); - scaleGroup.add(&numberFormat); - - if (numberFormat() != NUMBER_FORMAT_AUTO) - { - scaleGroup.add(&numberOfDecimals); - scaleGroup.add(&scaleFactor); - } - - scaleGroup.add(&visibleRangeMin); - scaleGroup.add(&visibleRangeMax); - scaleGroup.add(&valuesFontSize); - - uiOrdering.skipRemainingFields(true); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RimSummaryAxisProperties::setNameAndAxis(const QString& name, QwtPlot::Axis axis) -{ - m_name = name; - m_axis = axis; - - if (axis == QwtPlot::yRight) this->setUiIcon(QIcon(":/RightAxis16x16.png")); - if (axis == QwtPlot::xBottom) this->setUiIcon(QIcon(":/BottomAxis16x16.png")); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -QwtPlot::Axis RimSummaryAxisProperties::qwtPlotAxisType() const -{ - return m_axis; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -RiaDefines::PlotAxis RimSummaryAxisProperties::plotAxisType() const -{ - if (m_axis == QwtPlot::yRight) return RiaDefines::PLOT_AXIS_RIGHT; - if (m_axis == QwtPlot::xBottom) return RiaDefines::PLOT_AXIS_BOTTOM; - - return RiaDefines::PLOT_AXIS_LEFT; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -bool RimSummaryAxisProperties::useAutoTitle() const -{ - return isAutoTitle(); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -bool RimSummaryAxisProperties::showDescription() const -{ - return m_displayLongName(); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -bool RimSummaryAxisProperties::showAcronym() const -{ - return m_displayShortName(); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -bool RimSummaryAxisProperties::showUnitText() const -{ - return m_displayUnitText(); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -bool RimSummaryAxisProperties::isAutoZoom() const -{ - return m_isAutoZoom(); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RimSummaryAxisProperties::setAutoZoom(bool enableAutoZoom) -{ - m_isAutoZoom = enableAutoZoom; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -bool RimSummaryAxisProperties::isActive() const -{ - return m_isActive; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RimSummaryAxisProperties::fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, - const QVariant& newValue) -{ - if (changedField == &isAutoTitle) - { - updateOptionSensitivity(); - } - - RimSummaryPlot* rimSummaryPlot = nullptr; - this->firstAncestorOrThisOfType(rimSummaryPlot); - if (rimSummaryPlot) - { - if (changedField == &visibleRangeMax) - { - if (visibleRangeMin > visibleRangeMax) visibleRangeMax = oldValue.toDouble(); - - m_isAutoZoom = false; - } - else if (changedField == &visibleRangeMin) - { - if (visibleRangeMin > visibleRangeMax) visibleRangeMin = oldValue.toDouble(); - - m_isAutoZoom = false; - } - - if (changedField == &isLogarithmicScaleEnabled) - { - rimSummaryPlot->loadDataAndUpdate(); - } - else - { - rimSummaryPlot->updateAxes(); - } - } -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RimSummaryAxisProperties::updateOptionSensitivity() -{ - customTitle.uiCapability()->setUiReadOnly(isAutoTitle); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RimSummaryAxisProperties::initAfterRead() -{ - updateOptionSensitivity(); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -caf::PdmFieldHandle* RimSummaryAxisProperties::objectToggleField() -{ - return &m_isActive; -} diff --git a/ApplicationCode/ProjectDataModel/Summary/RimSummaryAxisProperties.h b/ApplicationCode/ProjectDataModel/Summary/RimSummaryAxisProperties.h deleted file mode 100644 index 81d47587be..0000000000 --- a/ApplicationCode/ProjectDataModel/Summary/RimSummaryAxisProperties.h +++ /dev/null @@ -1,107 +0,0 @@ -///////////////////////////////////////////////////////////////////////////////// -// -// Copyright (C) 2016 Statoil ASA -// -// ResInsight 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 3 of the License, or -// (at your option) any later version. -// -// ResInsight 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 at -// for more details. -// -///////////////////////////////////////////////////////////////////////////////// - -#pragma once - -#include "RiaDefines.h" - -#include "cafAppEnum.h" -#include "cafPdmChildArrayField.h" -#include "cafPdmField.h" -#include "cafPdmObject.h" - -#include "qwt_plot.h" - -#include - -//================================================================================================== -/// -/// -//================================================================================================== -class RimSummaryAxisProperties : public caf::PdmObject -{ - CAF_PDM_HEADER_INIT; - -public: - enum NumberFormatType - { - NUMBER_FORMAT_AUTO, - NUMBER_FORMAT_DECIMAL, - NUMBER_FORMAT_SCIENTIFIC - }; - - enum AxisTitlePositionType - { - AXIS_TITLE_CENTER, - AXIS_TITLE_END - }; - -public: - RimSummaryAxisProperties(); - - void setNameAndAxis(const QString& name, QwtPlot::Axis axis); - QwtPlot::Axis qwtPlotAxisType() const; - RiaDefines::PlotAxis plotAxisType() const; - bool useAutoTitle() const; - bool showDescription() const; - bool showAcronym() const; - bool showUnitText() const; - bool isAutoZoom() const; - void setAutoZoom(bool enableAutoZoom); - - caf::PdmField customTitle; - caf::PdmField titleFontSize; - caf::PdmField> titlePositionEnum; - - caf::PdmField visibleRangeMin; - caf::PdmField visibleRangeMax; - - caf::PdmField> numberFormat; - caf::PdmField numberOfDecimals; - caf::PdmField scaleFactor; - caf::PdmField isLogarithmicScaleEnabled; - caf::PdmField valuesFontSize; - - bool isActive() const; - -protected: - void initAfterRead() override; - caf::PdmFieldHandle* userDescriptionField() override; - caf::PdmFieldHandle* objectToggleField() override; - void fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, - const QVariant& newValue) override; - void defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering) override; - - QList calculateValueOptions(const caf::PdmFieldHandle* fieldNeedingOptions, - bool* useOptionsOnly) override; - -private: - void updateOptionSensitivity(); - -private: - caf::PdmField m_isActive; - - caf::PdmField isAutoTitle; - caf::PdmField m_displayShortName; - caf::PdmField m_displayLongName; - caf::PdmField m_displayUnitText; - caf::PdmField m_isAutoZoom; - - caf::PdmField m_name; - QwtPlot::Axis m_axis; -}; diff --git a/ApplicationCode/ProjectDataModel/Summary/RimSummaryCaseCollection.cpp b/ApplicationCode/ProjectDataModel/Summary/RimSummaryCaseCollection.cpp index 92345b2073..10a6d23a92 100644 --- a/ApplicationCode/ProjectDataModel/Summary/RimSummaryCaseCollection.cpp +++ b/ApplicationCode/ProjectDataModel/Summary/RimSummaryCaseCollection.cpp @@ -36,6 +36,97 @@ CAF_PDM_SOURCE_INIT(RimSummaryCaseCollection, "SummaryCaseSubCollection"); +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +double EnsembleParameter::stdDeviation() const +{ + double N = static_cast(values.size()); + if (N > 1 && isNumeric()) + { + double sumValues = 0.0; + double sumValuesSquared = 0.0; + for (const QVariant& variant : values) + { + double value = variant.toDouble(); + sumValues += value; + sumValuesSquared += value * value; + } + + return std::sqrt((N * sumValuesSquared - sumValues * sumValues) / (N * (N - 1.0))); + } + return 0.0; +} + +//-------------------------------------------------------------------------------------------------- +/// Standard deviation normalized by max absolute value of min/max values. +/// Produces values between 0.0 and sqrt(2.0). +//-------------------------------------------------------------------------------------------------- +double EnsembleParameter::normalizedStdDeviation() const +{ + const double eps = 1.0e-4; + + double maxAbs = std::max(std::fabs(maxValue), std::fabs(minValue)); + if (maxAbs < eps) + { + return 0.0; + } + + double normalisedStdDev = stdDeviation() / maxAbs; + if (normalisedStdDev < eps) + { + return 0.0; + } + return normalisedStdDev; +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void EnsembleParameter::sortByBinnedVariation(std::vector& parameterVector) +{ + double minStdDev = std::numeric_limits::infinity(); + double maxStdDev = 0.0; + for (const auto& paramPair : parameterVector) + { + minStdDev = std::min(minStdDev, paramPair.second.normalizedStdDeviation()); + maxStdDev = std::max(maxStdDev, paramPair.second.normalizedStdDeviation()); + } + if ((maxStdDev - minStdDev) < 1.0e-8) + { + return; + } + + double delta = (maxStdDev - minStdDev) / NR_OF_VARIATION_BINS; + + std::vector bins; + for (int i = 0; i < NR_OF_VARIATION_BINS - 1; ++i) + { + bins.push_back(minStdDev + (i + 1) * delta); + } + + for (NameParameterPair& nameParamPair : parameterVector) + { + int binNumber = 0; + for (double bin : bins) + { + if (nameParamPair.second.normalizedStdDeviation() >= bin) + { + binNumber++; + } + } + nameParamPair.second.variationBin = binNumber; + } + + // Sort by variation bin (highest first) but keep name as sorting parameter when parameters have the same variation index + std::stable_sort(parameterVector.begin(), parameterVector.end(), + [&bins](const NameParameterPair& lhs, const NameParameterPair& rhs) + { + return lhs.second.variationBin > rhs.second.variationBin; + } + ); +} //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -203,8 +294,8 @@ EnsembleParameter RimSummaryCaseCollection::ensembleParameter(const QString& par EnsembleParameter eParam; eParam.name = paramName; - bool numericValuesCount = 0; - bool textValuesCount = 0; + size_t numericValuesCount = 0; + size_t textValuesCount = 0; // Prepare case realization params, and check types for (const auto& rimCase : allSummaryCases()) @@ -283,6 +374,7 @@ EnsembleParameter RimSummaryCaseCollection::ensembleParameter(const QString& par eParam.values.push_back(QVariant(val)); } } + return eParam; } diff --git a/ApplicationCode/ProjectDataModel/Summary/RimSummaryCaseCollection.h b/ApplicationCode/ProjectDataModel/Summary/RimSummaryCaseCollection.h index af6ac1aed6..711214e96d 100644 --- a/ApplicationCode/ProjectDataModel/Summary/RimSummaryCaseCollection.h +++ b/ApplicationCode/ProjectDataModel/Summary/RimSummaryCaseCollection.h @@ -25,6 +25,9 @@ #include "cafPdmObject.h" #include "cafPdmProxyValueField.h" +#include + +#include #include class RimSummaryCase; @@ -35,22 +38,34 @@ class RimSummaryCase; class EnsembleParameter { public: - enum Type { TYPE_NONE, TYPE_NUMERIC, TYPE_TEXT }; + typedef std::pair NameParameterPair; + enum Type { TYPE_NONE, TYPE_NUMERIC, TYPE_TEXT }; + enum Bins { LOW_VARIATION, MEDIUM_VARIATION, HIGH_VARIATION, NR_OF_VARIATION_BINS }; QString name; Type type; std::vector values; double minValue; double maxValue; + int variationBin; EnsembleParameter() : type(TYPE_NONE), minValue(std::numeric_limits::infinity()), - maxValue(-std::numeric_limits::infinity()) { } + maxValue(-std::numeric_limits::infinity()), + variationBin(static_cast(MEDIUM_VARIATION)) + {} bool isValid() const { return !name.isEmpty() && type != TYPE_NONE; } bool isNumeric() const { return type == TYPE_NUMERIC; } bool isText() const { return type == TYPE_TEXT; } + double normalizedStdDeviation() const; + + static void sortByBinnedVariation(std::vector& parameterVector); + +private: + double stdDeviation() const; + }; //================================================================================================== diff --git a/ApplicationCode/ProjectDataModel/Summary/RimSummaryCurve.cpp b/ApplicationCode/ProjectDataModel/Summary/RimSummaryCurve.cpp index d513634176..b946580ce7 100644 --- a/ApplicationCode/ProjectDataModel/Summary/RimSummaryCurve.cpp +++ b/ApplicationCode/ProjectDataModel/Summary/RimSummaryCurve.cpp @@ -45,7 +45,6 @@ #include "RiuQwtPlotCurve.h" #include "RiuPlotMainWindow.h" #include "RiuSummaryCurveDefSelectionDialog.h" -#include "RiuSummaryQwtPlot.h" #include "cafPdmUiComboBoxEditor.h" #include "cafPdmUiListEditor.h" @@ -53,6 +52,7 @@ #include "cafPdmUiTreeOrdering.h" #include "qwt_date.h" +#include "qwt_plot.h" #include @@ -203,6 +203,16 @@ RifEclipseSummaryAddress RimSummaryCurve::summaryAddressY() const return m_yValuesCurveVariable->address(); } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimSummaryCurve::setSummaryAddressYAndApplyInterpolation(const RifEclipseSummaryAddress& address) +{ + setSummaryAddressY(address); + + calculateCurveInterpolationFromAddress(); +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -216,8 +226,6 @@ void RimSummaryCurve::setSummaryAddressY(const RifEclipseSummaryAddress& address m_yValuesCurveVariable->setAddress(address); m_yValuesSummaryFilter->updateFromAddress(address); - - calculateCurveInterpolationFromAddress(); } //-------------------------------------------------------------------------------------------------- @@ -281,7 +289,10 @@ std::vector RimSummaryCurve::errorValuesY() const if (!reader) return values; RifEclipseSummaryAddress addr = errorSummaryAddressY(); - reader->values(addr, &values); + if (reader->hasAddress(addr)) + { + reader->values(addr, &values); + } return values; } @@ -983,7 +994,7 @@ void RimSummaryCurve::fieldChangedByUi(const caf::PdmFieldHandle* changedField, timeSteps.push_back(first); timeSteps.push_back(last); - QString formatString = RimTools::createTimeFormatStringFromDates(timeSteps); + QString formatString = RiaQDateTimeTools::createTimeFormatStringFromDates(timeSteps); description += QString("Time step range for X : '%1' - '%2'") .arg(first.toString(formatString)) @@ -998,7 +1009,7 @@ void RimSummaryCurve::fieldChangedByUi(const caf::PdmFieldHandle* changedField, timeSteps.push_back(first); timeSteps.push_back(last); - QString formatString = RimTools::createTimeFormatStringFromDates(timeSteps); + QString formatString = RiaQDateTimeTools::createTimeFormatStringFromDates(timeSteps); description += "\n"; description += QString("Time step range for Y : '%1' - '%2'") diff --git a/ApplicationCode/ProjectDataModel/Summary/RimSummaryCurve.h b/ApplicationCode/ProjectDataModel/Summary/RimSummaryCurve.h index f5553f5fc3..b919d22b3e 100644 --- a/ApplicationCode/ProjectDataModel/Summary/RimSummaryCurve.h +++ b/ApplicationCode/ProjectDataModel/Summary/RimSummaryCurve.h @@ -54,7 +54,9 @@ class RimSummaryCurve : public RimPlotCurve // Y Axis functions void setSummaryCaseY(RimSummaryCase* sumCase); RimSummaryCase* summaryCaseY() const; + void setSummaryAddressYAndApplyInterpolation(const RifEclipseSummaryAddress& address); void setSummaryAddressY(const RifEclipseSummaryAddress& address); + RifEclipseSummaryAddress summaryAddressY() const; std::string unitNameY() const; std::vector valuesY() const; @@ -76,7 +78,7 @@ class RimSummaryCurve : public RimPlotCurve void updateQwtPlotAxis(); void applyCurveAutoNameSettings(const RimSummaryCurveAutoName& autoNameSettings); - QString curveExportDescription(const RifEclipseSummaryAddress& address = RifEclipseSummaryAddress()) const override; + QString curveExportDescription(const RifEclipseSummaryAddress& address = RifEclipseSummaryAddress()) const override; void forceUpdateCurveAppearanceFromCaseType(); void markCachedDataForPurge(); @@ -97,11 +99,11 @@ class RimSummaryCurve : public RimPlotCurve void defineUiTreeOrdering(caf::PdmUiTreeOrdering& uiTreeOrdering, QString uiConfigName = "") override; private: - RifSummaryReaderInterface* valuesSummaryReaderX() const; - RifSummaryReaderInterface* valuesSummaryReaderY() const; - const std::vector& timeStepsX() const; + RifSummaryReaderInterface* valuesSummaryReaderX() const; + RifSummaryReaderInterface* valuesSummaryReaderY() const; + const std::vector& timeStepsX() const; - void calculateCurveInterpolationFromAddress(); + void calculateCurveInterpolationFromAddress(); // Overridden PDM methods void fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue) override; @@ -109,9 +111,9 @@ class RimSummaryCurve : public RimPlotCurve void defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering) override; void defineEditorAttribute(const caf::PdmFieldHandle* field, QString uiConfigName, caf::PdmUiEditorAttribute* attribute) override; - static void appendOptionItemsForSummaryAddresses(QList* options, - RimSummaryCase* summaryCase, - RimSummaryFilter* summaryFilter); + static void appendOptionItemsForSummaryAddresses(QList* options, + RimSummaryCase* summaryCase, + RimSummaryFilter* summaryFilter); private: // Y values diff --git a/ApplicationCode/ProjectDataModel/Summary/RimSummaryCurveCollection.cpp b/ApplicationCode/ProjectDataModel/Summary/RimSummaryCurveCollection.cpp index 2df7fd9040..5803b8f1e2 100644 --- a/ApplicationCode/ProjectDataModel/Summary/RimSummaryCurveCollection.cpp +++ b/ApplicationCode/ProjectDataModel/Summary/RimSummaryCurveCollection.cpp @@ -30,11 +30,13 @@ #include "RimSummaryPlot.h" #include "RimSummaryPlotSourceStepping.h" -#include "RiuQwtPlotCurve.h" #include "RiuSummaryQwtPlot.h" +#include "RiuQwtPlotCurve.h" #include "cafPdmUiTreeViewEditor.h" +#include "qwt_plot.h" + #include CAF_PDM_SOURCE_INIT(RimSummaryCurveCollection, "RimSummaryCurveCollection"); diff --git a/ApplicationCode/ProjectDataModel/Summary/RimSummaryCurvesCalculator.cpp b/ApplicationCode/ProjectDataModel/Summary/RimSummaryCurvesCalculator.cpp index 6d68260a3e..b024c03941 100644 --- a/ApplicationCode/ProjectDataModel/Summary/RimSummaryCurvesCalculator.cpp +++ b/ApplicationCode/ProjectDataModel/Summary/RimSummaryCurvesCalculator.cpp @@ -1,29 +1,28 @@ ///////////////////////////////////////////////////////////////////////////////// // // Copyright (C) 2016 Statoil ASA -// +// // ResInsight 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 3 of the License, or // (at your option) any later version. -// +// // ResInsight 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 at +// +// See the GNU General Public License at // for more details. // ///////////////////////////////////////////////////////////////////////////////// #include "RimSummaryCurvesCalculator.h" -#include "RigStatisticsCalculator.h" - #include "RiaDefines.h" -#include "RimSummaryCurve.h" -#include "RimSummaryAxisProperties.h" + #include "RimAsciiDataCurve.h" +#include "RimPlotAxisProperties.h" +#include "RimSummaryCurve.h" #include "RiuSummaryQwtPlot.h" #include "RiuSummaryVectorDescriptionMap.h" @@ -32,9 +31,9 @@ #include "qwt_scale_draw.h" #include "qwt_scale_engine.h" +#include #include #include -#include //-------------------------------------------------------------------------------------------------- // e format as [-]9.9e[+|-]999 @@ -49,14 +48,13 @@ class DecimalScaleDraw : public QwtScaleDraw public: DecimalScaleDraw(double scaleFactor, int numberOfDecimals) { - m_scaleFactor = scaleFactor; + m_scaleFactor = scaleFactor; m_numberOfDecimals = numberOfDecimals; } QwtText label(double value) const override { - if (qFuzzyCompare(scaledValue(value) + 1.0, 1.0)) - value = 0.0; + if (qFuzzyCompare(scaledValue(value) + 1.0, 1.0)) value = 0.0; return QString::number(scaledValue(value), 'f', m_numberOfDecimals); } @@ -67,26 +65,25 @@ class DecimalScaleDraw : public QwtScaleDraw return value / m_scaleFactor; } - double m_scaleFactor; - int m_numberOfDecimals; + double m_scaleFactor; + int m_numberOfDecimals; }; //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- class ScientificScaleDraw : public QwtScaleDraw { public: ScientificScaleDraw(double scaleFactor, int numberOfDecimals) { - m_scaleFactor = scaleFactor; + m_scaleFactor = scaleFactor; m_numberOfDecimals = numberOfDecimals; } QwtText label(double value) const override { - if (qFuzzyCompare(scaledValue(value) + 1.0, 1.0)) - value = 0.0; + if (qFuzzyCompare(scaledValue(value) + 1.0, 1.0)) value = 0.0; return QString::number(scaledValue(value), 'e', m_numberOfDecimals); } @@ -97,27 +94,26 @@ class ScientificScaleDraw : public QwtScaleDraw return value / m_scaleFactor; } - double m_scaleFactor; - int m_numberOfDecimals; + double m_scaleFactor; + int m_numberOfDecimals; }; - //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- -RimSummaryPlotYAxisFormatter::RimSummaryPlotYAxisFormatter(RimSummaryAxisProperties* axisProperties, - const std::vector& summaryCurves, - const std::vector& asciiCurves, - const std::set& timeHistoryCurveQuantities) -: m_axisProperties(axisProperties), - m_summaryCurves(summaryCurves), - m_asciiDataCurves(asciiCurves), - m_timeHistoryCurveQuantities(timeHistoryCurveQuantities) +RimSummaryPlotYAxisFormatter::RimSummaryPlotYAxisFormatter(RimPlotAxisProperties* axisProperties, + const std::vector& summaryCurves, + const std::vector& asciiCurves, + const std::set& timeHistoryCurveQuantities) + : m_axisProperties(axisProperties) + , m_summaryCurves(summaryCurves) + , m_asciiDataCurves(asciiCurves) + , m_timeHistoryCurveQuantities(timeHistoryCurveQuantities) { } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RimSummaryPlotYAxisFormatter::applyYAxisPropertiesToPlot(RiuSummaryQwtPlot* qwtPlot) { @@ -131,19 +127,19 @@ void RimSummaryPlotYAxisFormatter::applyYAxisPropertiesToPlot(RiuSummaryQwtPlot* QFont axisTitleYFont = axisTitleY.font(); axisTitleYFont.setBold(true); - axisTitleYFont.setPixelSize(m_axisProperties->titleFontSize); + axisTitleYFont.setPointSize(m_axisProperties->titleFontSize()); axisTitleY.setFont(axisTitleYFont); axisTitleY.setText(axisTitle); - switch (m_axisProperties->titlePositionEnum()) + switch (m_axisProperties->titlePosition()) { - case RimSummaryAxisProperties::AXIS_TITLE_CENTER: - axisTitleY.setRenderFlags(Qt::AlignCenter); - break; - case RimSummaryAxisProperties::AXIS_TITLE_END: - axisTitleY.setRenderFlags(Qt::AlignRight); - break; + case RimPlotAxisProperties::AXIS_TITLE_CENTER: + axisTitleY.setRenderFlags(Qt::AlignCenter); + break; + case RimPlotAxisProperties::AXIS_TITLE_END: + axisTitleY.setRenderFlags(Qt::AlignRight); + break; } qwtPlot->setAxisTitle(m_axisProperties->qwtPlotAxisType(), axisTitleY); @@ -152,41 +148,44 @@ void RimSummaryPlotYAxisFormatter::applyYAxisPropertiesToPlot(RiuSummaryQwtPlot* { QFont yAxisFont = qwtPlot->axisFont(m_axisProperties->qwtPlotAxisType()); yAxisFont.setBold(false); - yAxisFont.setPixelSize(m_axisProperties->valuesFontSize); + yAxisFont.setPointSize(m_axisProperties->valuesFontSize()); qwtPlot->setAxisFont(m_axisProperties->qwtPlotAxisType(), yAxisFont); } { - if (m_axisProperties->numberFormat == RimSummaryAxisProperties::NUMBER_FORMAT_AUTO) + if (m_axisProperties->numberFormat == RimPlotAxisProperties::NUMBER_FORMAT_AUTO) { qwtPlot->setAxisScaleDraw(m_axisProperties->qwtPlotAxisType(), new QwtScaleDraw); } - else if (m_axisProperties->numberFormat == RimSummaryAxisProperties::NUMBER_FORMAT_DECIMAL) + else if (m_axisProperties->numberFormat == RimPlotAxisProperties::NUMBER_FORMAT_DECIMAL) { - qwtPlot->setAxisScaleDraw(m_axisProperties->qwtPlotAxisType(), - new DecimalScaleDraw(m_axisProperties->scaleFactor(), m_axisProperties->numberOfDecimals())); + qwtPlot->setAxisScaleDraw( + m_axisProperties->qwtPlotAxisType(), + new DecimalScaleDraw(m_axisProperties->scaleFactor(), m_axisProperties->numberOfDecimals())); } - else if (m_axisProperties->numberFormat == RimSummaryAxisProperties::NUMBER_FORMAT_SCIENTIFIC) + else if (m_axisProperties->numberFormat == RimPlotAxisProperties::NUMBER_FORMAT_SCIENTIFIC) { - qwtPlot->setAxisScaleDraw(m_axisProperties->qwtPlotAxisType(), - new ScientificScaleDraw(m_axisProperties->scaleFactor(), m_axisProperties->numberOfDecimals())); + qwtPlot->setAxisScaleDraw( + m_axisProperties->qwtPlotAxisType(), + new ScientificScaleDraw(m_axisProperties->scaleFactor(), m_axisProperties->numberOfDecimals())); } } { if (m_axisProperties->isLogarithmicScaleEnabled) { - QwtLogScaleEngine* currentScaleEngine = dynamic_cast(qwtPlot->axisScaleEngine(m_axisProperties->qwtPlotAxisType())); + QwtLogScaleEngine* currentScaleEngine = + dynamic_cast(qwtPlot->axisScaleEngine(m_axisProperties->qwtPlotAxisType())); if (!currentScaleEngine) { qwtPlot->setAxisScaleEngine(m_axisProperties->qwtPlotAxisType(), new QwtLogScaleEngine); qwtPlot->setAxisMaxMinor(m_axisProperties->qwtPlotAxisType(), 5); } - } else { - QwtLinearScaleEngine* currentScaleEngine = dynamic_cast(qwtPlot->axisScaleEngine(m_axisProperties->qwtPlotAxisType())); + QwtLinearScaleEngine* currentScaleEngine = + dynamic_cast(qwtPlot->axisScaleEngine(m_axisProperties->qwtPlotAxisType())); if (!currentScaleEngine) { qwtPlot->setAxisScaleEngine(m_axisProperties->qwtPlotAxisType(), new QwtLinearScaleEngine); @@ -197,7 +196,7 @@ void RimSummaryPlotYAxisFormatter::applyYAxisPropertiesToPlot(RiuSummaryQwtPlot* } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- QString RimSummaryPlotYAxisFormatter::autoAxisTitle() const { @@ -229,7 +228,7 @@ QString RimSummaryPlotYAxisFormatter::autoAxisTitle() const std::string quantityNameForDisplay; { - std::string quantityName = sumAddress.quantityName(); + const std::string& quantityName = sumAddress.quantityName(); if (sumAddress.category() == RifEclipseSummaryAddress::SUMMARY_CALCULATED) { @@ -254,7 +253,6 @@ QString RimSummaryPlotYAxisFormatter::autoAxisTitle() const { quantityNameForDisplay += quantityName; } - } } @@ -265,7 +263,7 @@ QString RimSummaryPlotYAxisFormatter::autoAxisTitle() const QString assembledYAxisText; QString scaleFactorText = ""; - if (m_axisProperties->numberFormat() != RimSummaryAxisProperties::NUMBER_FORMAT_AUTO) + if (m_axisProperties->numberFormat() != RimPlotAxisProperties::NUMBER_FORMAT_AUTO) { if (m_axisProperties->scaleFactor() != 1.0) { @@ -281,20 +279,25 @@ QString RimSummaryPlotYAxisFormatter::autoAxisTitle() const assembledYAxisText += QString::fromStdString(quantIt) + " "; } - if (m_axisProperties->showUnitText() && !unitIt.first.empty()) + if (m_axisProperties->showUnitText()) { - assembledYAxisText += "[" + QString::fromStdString(unitIt.first) + scaleFactorText + "] "; + QString unitAndScaleText = QString::fromStdString(unitIt.first) + scaleFactorText; + + if (!unitAndScaleText.isEmpty()) + { + assembledYAxisText += "[" + unitAndScaleText + "] "; + } } } - if (m_timeHistoryCurveQuantities.size() > 0) + if (!m_timeHistoryCurveQuantities.empty()) { if (!assembledYAxisText.isEmpty()) { assembledYAxisText += " : "; } - for (auto timeQuantity : m_timeHistoryCurveQuantities) + for (const auto& timeQuantity : m_timeHistoryCurveQuantities) { assembledYAxisText += timeQuantity + " "; } @@ -304,7 +307,7 @@ QString RimSummaryPlotYAxisFormatter::autoAxisTitle() const } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- std::string RimSummaryPlotYAxisFormatter::shortCalculationName(const std::string& calculationName) { @@ -318,87 +321,3 @@ std::string RimSummaryPlotYAxisFormatter::shortCalculationName(const std::string return calculationShortName.toStdString(); } - - - - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -RimSummaryPlotYAxisRangeCalculator::RimSummaryPlotYAxisRangeCalculator( - const std::vector& qwtCurves, - const std::vector& yValuesForAllCurves) - : - m_singleCurves(qwtCurves), - m_yValuesForAllCurves(yValuesForAllCurves) -{ -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RimSummaryPlotYAxisRangeCalculator::computeYRange(double* min, double* max) const -{ - double minValue = HUGE_VAL; - double maxValue = -HUGE_VAL; - - for (QwtPlotCurve* curve : m_singleCurves) - { - double minCurveValue = HUGE_VAL; - double maxCurveValue = -HUGE_VAL; - - if (curveValueRangeY(curve, &minCurveValue, &maxCurveValue)) - { - if (minCurveValue < minValue) - { - minValue = minCurveValue; - } - - if (maxCurveValue > maxValue) - { - maxValue = maxCurveValue; - } - } - } - - if (minValue == HUGE_VAL) - { - minValue = RiaDefines::minimumDefaultValuePlot(); - maxValue = RiaDefines::maximumDefaultValuePlot(); - } - - // For logarithmic auto scaling, compute positive curve value closest to zero and use - // this value as the plot visible minimum - - double pos = HUGE_VAL; - double neg = -HUGE_VAL; - - RigStatisticsCalculator::posNegClosestToZero(m_yValuesForAllCurves, pos, neg); - - if (pos != HUGE_VAL) - { - minValue = pos; - } - - *min = minValue; - *max = maxValue; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -bool RimSummaryPlotYAxisRangeCalculator::curveValueRangeY(const QwtPlotCurve* qwtCurve, double* min, double* max) const -{ - if (!qwtCurve) return false; - - if (qwtCurve->data()->size() < 1) - { - return false; - } - - *min = qwtCurve->minYValue(); - *max = qwtCurve->maxYValue(); - - return true; -} - diff --git a/ApplicationCode/ProjectDataModel/Summary/RimSummaryCurvesCalculator.h b/ApplicationCode/ProjectDataModel/Summary/RimSummaryCurvesCalculator.h index 4a063e658f..ac06254368 100644 --- a/ApplicationCode/ProjectDataModel/Summary/RimSummaryCurvesCalculator.h +++ b/ApplicationCode/ProjectDataModel/Summary/RimSummaryCurvesCalculator.h @@ -22,9 +22,11 @@ #include #include +#include + class RimAsciiDataCurve; class RimSummaryCurve; -class RimSummaryAxisProperties; +class RimPlotAxisProperties; class RiuSummaryQwtPlot; @@ -33,7 +35,7 @@ class QwtPlotCurve; class RimSummaryPlotYAxisFormatter { public: - RimSummaryPlotYAxisFormatter(RimSummaryAxisProperties* axisProperties, + RimSummaryPlotYAxisFormatter(RimPlotAxisProperties* axisProperties, const std::vector& summaryCurves, const std::vector& asciiCurves, const std::set& timeHistoryCurveQuantities); @@ -46,26 +48,9 @@ class RimSummaryPlotYAxisFormatter static std::string shortCalculationName(const std::string& calculationName); private: - RimSummaryAxisProperties* m_axisProperties; + RimPlotAxisProperties* m_axisProperties; const std::vector m_summaryCurves; const std::vector m_asciiDataCurves; const std::set m_timeHistoryCurveQuantities; }; - -class RimSummaryPlotYAxisRangeCalculator -{ -public: - RimSummaryPlotYAxisRangeCalculator( const std::vector& qwtCurves, - const std::vector& yValuesForAllCurves); - - void computeYRange(double* min, double* max) const; - -private: - bool curveValueRangeY(const QwtPlotCurve* qwtCurve, double* min, double* max) const; - -private: - const std::vector m_singleCurves; - const std::vector m_yValuesForAllCurves; -}; - diff --git a/ApplicationCode/ProjectDataModel/Summary/RimSummaryObservedDataFile.cpp b/ApplicationCode/ProjectDataModel/Summary/RimSummaryObservedDataFile.cpp index 7d6f49064c..5fdd975a7b 100644 --- a/ApplicationCode/ProjectDataModel/Summary/RimSummaryObservedDataFile.cpp +++ b/ApplicationCode/ProjectDataModel/Summary/RimSummaryObservedDataFile.cpp @@ -1,33 +1,33 @@ ///////////////////////////////////////////////////////////////////////////////// // // Copyright (C) 2017- Statoil ASA -// +// // ResInsight 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 3 of the License, or // (at your option) any later version. -// +// // ResInsight 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 at +// +// See the GNU General Public License at // for more details. // ///////////////////////////////////////////////////////////////////////////////// #include "RimSummaryObservedDataFile.h" -#include "RigObservedData.h" +#include "RifReaderObservedData.h" + #include "RimTools.h" #include -#include "RifReaderObservedData.h" CAF_PDM_SOURCE_INIT(RimSummaryObservedDataFile, "SummaryObservedDataFile"); //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- RimSummaryObservedDataFile::RimSummaryObservedDataFile() { @@ -36,15 +36,12 @@ RimSummaryObservedDataFile::RimSummaryObservedDataFile() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- -RimSummaryObservedDataFile::~RimSummaryObservedDataFile() -{ - -} +RimSummaryObservedDataFile::~RimSummaryObservedDataFile() {} //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RimSummaryObservedDataFile::createSummaryReaderInterface() { @@ -57,7 +54,7 @@ void RimSummaryObservedDataFile::createSummaryReaderInterface() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- RifSummaryReaderInterface* RimSummaryObservedDataFile::summaryReader() { diff --git a/ApplicationCode/ProjectDataModel/Summary/RimSummaryPlot.cpp b/ApplicationCode/ProjectDataModel/Summary/RimSummaryPlot.cpp index 360fa4a08e..4e6181107c 100644 --- a/ApplicationCode/ProjectDataModel/Summary/RimSummaryPlot.cpp +++ b/ApplicationCode/ProjectDataModel/Summary/RimSummaryPlot.cpp @@ -29,7 +29,7 @@ #include "RimEnsembleCurveSet.h" #include "RimGridTimeHistoryCurve.h" #include "RimProject.h" -#include "RimSummaryAxisProperties.h" +#include "RimPlotAxisProperties.h" #include "RimSummaryCase.h" #include "RimSummaryCurve.h" #include "RimSummaryCurveCollection.h" @@ -54,6 +54,7 @@ #include "qwt_plot_curve.h" #include "qwt_plot_renderer.h" #include "qwt_plot_textlabel.h" +#include "qwt_scale_engine.h" #include #include @@ -160,17 +161,17 @@ RimSummaryPlot::RimSummaryPlot() CAF_PDM_InitFieldNoDefault(&m_leftYAxisProperties, "LeftYAxisProperties", "Left Y Axis", "", "", ""); m_leftYAxisProperties.uiCapability()->setUiTreeHidden(true); - m_leftYAxisProperties = new RimSummaryAxisProperties; + m_leftYAxisProperties = new RimPlotAxisProperties; m_leftYAxisProperties->setNameAndAxis("Left Y-Axis", QwtPlot::yLeft); CAF_PDM_InitFieldNoDefault(&m_rightYAxisProperties, "RightYAxisProperties", "Right Y Axis", "", "", ""); m_rightYAxisProperties.uiCapability()->setUiTreeHidden(true); - m_rightYAxisProperties = new RimSummaryAxisProperties; + m_rightYAxisProperties = new RimPlotAxisProperties; m_rightYAxisProperties->setNameAndAxis("Right Y-Axis", QwtPlot::yRight); CAF_PDM_InitFieldNoDefault(&m_bottomAxisProperties, "BottomAxisProperties", "Bottom X Axis", "", "", ""); m_bottomAxisProperties.uiCapability()->setUiTreeHidden(true); - m_bottomAxisProperties = new RimSummaryAxisProperties; + m_bottomAxisProperties = new RimPlotAxisProperties; m_bottomAxisProperties->setNameAndAxis("Bottom X-Axis", QwtPlot::xBottom); CAF_PDM_InitFieldNoDefault(&m_timeAxisProperties, "TimeAxisProperties", "Time Axis", "", "", ""); @@ -238,33 +239,6 @@ RimSummaryTimeAxisProperties* RimSummaryPlot::timeAxisProperties() return m_timeAxisProperties(); } -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RimSummaryPlot::selectAxisInPropertyEditor(int axis) -{ - RiuPlotMainWindowTools::showPlotMainWindow(); - if (axis == QwtPlot::yLeft) - { - RiuPlotMainWindowTools::selectAsCurrentItem(m_leftYAxisProperties); - } - else if (axis == QwtPlot::yRight) - { - RiuPlotMainWindowTools::selectAsCurrentItem(m_rightYAxisProperties); - } - else if (axis == QwtPlot::xBottom) - { - if (m_isCrossPlot) - { - RiuPlotMainWindowTools::selectAsCurrentItem(m_bottomAxisProperties); - } - else - { - RiuPlotMainWindowTools::selectAsCurrentItem(m_timeAxisProperties); - } - } -} - //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -565,6 +539,77 @@ size_t RimSummaryPlot::singleColorCurveCount() const return colorIndex; } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RimSummaryPlot::hasCustomFontSizes(RiaDefines::FontSettingType fontSettingType, int defaultFontSize) const +{ + if (fontSettingType != RiaDefines::PLOT_FONT) return false; + + for (auto plotAxis : allPlotAxes()) + { + if (plotAxis->titleFontSize() != defaultFontSize || plotAxis->valuesFontSize() != defaultFontSize) + { + return true; + } + } + + if (m_legendFontSize() != defaultFontSize) + { + return true; + } + return false; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RimSummaryPlot::applyFontSize(RiaDefines::FontSettingType fontSettingType, int oldFontSize, int fontSize, bool forceChange /*= false*/) +{ + if (fontSettingType != RiaDefines::PLOT_FONT) return false; + + bool anyChange = false; + for (auto plotAxis : allPlotAxes()) + { + if (forceChange || plotAxis->titleFontSize() == oldFontSize) + { + plotAxis->setTitleFontSize(fontSize); + anyChange = true; + } + if (forceChange || plotAxis->valuesFontSize() == oldFontSize) + { + plotAxis->setValuesFontSize(fontSize); + anyChange = true; + } + } + + if (forceChange || m_legendFontSize() == oldFontSize) + { + m_legendFontSize = fontSize; + anyChange = true; + } + + if (anyChange) loadDataAndUpdate(); + + return anyChange; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimSummaryPlot::updateAxisScaling() +{ + loadDataAndUpdate(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimSummaryPlot::updateAxisDisplay() +{ + updateAxes(); +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -582,7 +627,7 @@ void RimSummaryPlot::updateAxis(RiaDefines::PlotAxis plotAxis) qwtAxis = QwtPlot::yRight; } - RimSummaryAxisProperties* yAxisProperties = yAxisPropertiesLeftOrRight(plotAxis); + RimPlotAxisProperties* yAxisProperties = yAxisPropertiesLeftOrRight(plotAxis); if (yAxisProperties->isActive() && hasVisibleCurvesForAxis(plotAxis)) { m_qwtPlot->enableAxis(qwtAxis, true); @@ -639,39 +684,37 @@ void RimSummaryPlot::updateZoomForAxis(RiaDefines::PlotAxis plotAxis) } else { - RimSummaryAxisProperties* yAxisProps = yAxisPropertiesLeftOrRight(plotAxis); + RimPlotAxisProperties* yAxisProps = yAxisPropertiesLeftOrRight(plotAxis); if (yAxisProps->isAutoZoom()) { if (yAxisProps->isLogarithmicScaleEnabled) { - std::vector yValues; - std::vector plotCurves; + std::vector plotCurves; for (RimSummaryCurve* c : visibleSummaryCurvesForAxis(plotAxis)) { - std::vector curveValues = c->valuesY(); - yValues.insert(yValues.end(), curveValues.begin(), curveValues.end()); plotCurves.push_back(c->qwtPlotCurve()); } for (RimGridTimeHistoryCurve* c : visibleTimeHistoryCurvesForAxis(plotAxis)) { - std::vector curveValues = c->yValues(); - yValues.insert(yValues.end(), curveValues.begin(), curveValues.end()); plotCurves.push_back(c->qwtPlotCurve()); } for (RimAsciiDataCurve* c : visibleAsciiDataCurvesForAxis(plotAxis)) { - std::vector curveValues = c->yValues(); - yValues.insert(yValues.end(), curveValues.begin(), curveValues.end()); plotCurves.push_back(c->qwtPlotCurve()); } double min, max; - RimSummaryPlotYAxisRangeCalculator calc(plotCurves, yValues); - calc.computeYRange(&min, &max); + RimPlotAxisLogRangeCalculator calc(QwtPlot::yLeft, plotCurves); + calc.computeAxisRange(&min, &max); + + if (yAxisProps->isAxisInverted()) + { + std::swap(min, max); + } m_qwtPlot->setAxisScale(yAxisProps->qwtPlotAxisType(), min, max); } @@ -684,6 +727,8 @@ void RimSummaryPlot::updateZoomForAxis(RiaDefines::PlotAxis plotAxis) { m_qwtPlot->setAxisScale(yAxisProps->qwtPlotAxisType(), yAxisProps->visibleRangeMin(), yAxisProps->visibleRangeMax()); } + + m_qwtPlot->axisScaleEngine(yAxisProps->qwtPlotAxisType())->setAttribute(QwtScaleEngine::Inverted, yAxisProps->isAxisInverted()); } } @@ -764,9 +809,9 @@ bool RimSummaryPlot::hasVisibleCurvesForAxis(RiaDefines::PlotAxis plotAxis) cons //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -RimSummaryAxisProperties* RimSummaryPlot::yAxisPropertiesLeftOrRight(RiaDefines::PlotAxis leftOrRightPlotAxis) const +RimPlotAxisProperties* RimSummaryPlot::yAxisPropertiesLeftOrRight(RiaDefines::PlotAxis leftOrRightPlotAxis) const { - RimSummaryAxisProperties* yAxisProps = nullptr; + RimPlotAxisProperties* yAxisProps = nullptr; if (leftOrRightPlotAxis == RiaDefines::PLOT_AXIS_LEFT) { @@ -857,12 +902,12 @@ void RimSummaryPlot::updateTimeAxis() QFont font = timeAxisTitle.font(); font.setBold(true); - font.setPixelSize(m_timeAxisProperties->titleFontSize); + font.setPointSize(m_timeAxisProperties->titleFontSize()); timeAxisTitle.setFont(font); timeAxisTitle.setText(axisTitle); - switch ( m_timeAxisProperties->titlePositionEnum() ) + switch ( m_timeAxisProperties->titlePosition() ) { case RimSummaryTimeAxisProperties::AXIS_TITLE_CENTER: timeAxisTitle.setRenderFlags(Qt::AlignCenter); @@ -878,7 +923,7 @@ void RimSummaryPlot::updateTimeAxis() { QFont timeAxisFont = m_qwtPlot->axisFont(QwtPlot::xBottom); timeAxisFont.setBold(false); - timeAxisFont.setPixelSize(m_timeAxisProperties->valuesFontSize); + timeAxisFont.setPointSize(m_timeAxisProperties->valuesFontSize()); m_qwtPlot->setAxisFont(QwtPlot::xBottom, timeAxisFont); } } @@ -892,7 +937,7 @@ void RimSummaryPlot::updateBottomXAxis() QwtPlot::Axis qwtAxis = QwtPlot::xBottom; - RimSummaryAxisProperties* bottomAxisProperties = m_bottomAxisProperties(); + RimPlotAxisProperties* bottomAxisProperties = m_bottomAxisProperties(); if (bottomAxisProperties->isActive()) { @@ -1239,7 +1284,6 @@ void RimSummaryPlot::onLoadDataAndUpdate() if (m_qwtPlot) m_qwtPlot->updateLegend(); this->updateAxes(); - updateZoomInQwt(); } //-------------------------------------------------------------------------------------------------- @@ -1255,6 +1299,8 @@ void RimSummaryPlot::updateZoomInQwt() updateZoomForAxis(RiaDefines::PLOT_AXIS_RIGHT); m_qwtPlot->replot(); + + updateAxisRangesFromQwt(); } } @@ -1267,6 +1313,51 @@ void RimSummaryPlot::updateZoomWindowFromQwt() setAutoZoomForAllAxes(false); } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimSummaryPlot::selectAxisInPropertyEditor(int axis) +{ + RiuPlotMainWindowTools::showPlotMainWindow(); + if (axis == QwtPlot::yLeft) + { + RiuPlotMainWindowTools::selectAsCurrentItem(m_leftYAxisProperties); + } + else if (axis == QwtPlot::yRight) + { + RiuPlotMainWindowTools::selectAsCurrentItem(m_rightYAxisProperties); + } + else if (axis == QwtPlot::xBottom) + { + if (m_isCrossPlot) + { + RiuPlotMainWindowTools::selectAsCurrentItem(m_bottomAxisProperties); + } + else + { + RiuPlotMainWindowTools::selectAsCurrentItem(m_timeAxisProperties); + } + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimSummaryPlot::setAutoZoomForAllAxes(bool enableAutoZoom) +{ + m_leftYAxisProperties->setAutoZoom(enableAutoZoom); + m_rightYAxisProperties->setAutoZoom(enableAutoZoom); + + if (m_isCrossPlot) + { + m_bottomAxisProperties->setAutoZoom(enableAutoZoom); + } + else + { + m_timeAxisProperties->setAutoZoom(enableAutoZoom); + } +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -1274,8 +1365,9 @@ void RimSummaryPlot::updateAxisRangesFromQwt() { if (!m_qwtPlot) return; - QwtInterval leftAxis, rightAxis, timeAxis; - m_qwtPlot->currentVisibleWindow(&leftAxis, &rightAxis, &timeAxis); + QwtInterval leftAxis = m_qwtPlot->currentAxisRange(QwtPlot::yLeft); + QwtInterval rightAxis = m_qwtPlot->currentAxisRange(QwtPlot::yRight); + QwtInterval timeAxis = m_qwtPlot->currentAxisRange(QwtPlot::xBottom); m_leftYAxisProperties->visibleRangeMax = leftAxis.maxValue(); m_leftYAxisProperties->visibleRangeMin = leftAxis.minValue(); @@ -1301,21 +1393,11 @@ void RimSummaryPlot::updateAxisRangesFromQwt() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- -void RimSummaryPlot::setAutoZoomForAllAxes(bool enableAutoZoom) +std::set RimSummaryPlot::allPlotAxes() const { - m_leftYAxisProperties->setAutoZoom(enableAutoZoom); - m_rightYAxisProperties->setAutoZoom(enableAutoZoom); - - if (m_isCrossPlot) - { - m_bottomAxisProperties->setAutoZoom(enableAutoZoom); - } - else - { - m_timeAxisProperties->setAutoZoom(enableAutoZoom); - } + return { m_timeAxisProperties, m_bottomAxisProperties, m_leftYAxisProperties, m_rightYAxisProperties }; } //-------------------------------------------------------------------------------------------------- @@ -1499,7 +1581,7 @@ void RimSummaryPlot::updateMdiWindowTitle() QwtLegend* legend = new QwtLegend(m_qwtPlot); auto font = legend->font(); - font.setPixelSize(m_legendFontSize()); + font.setPointSize(m_legendFontSize()); legend->setFont(font); m_qwtPlot->insertLegend(legend, QwtPlot::BottomLegend); } diff --git a/ApplicationCode/ProjectDataModel/Summary/RimSummaryPlot.h b/ApplicationCode/ProjectDataModel/Summary/RimSummaryPlot.h index 7af9067aaa..e833dc7b3d 100644 --- a/ApplicationCode/ProjectDataModel/Summary/RimSummaryPlot.h +++ b/ApplicationCode/ProjectDataModel/Summary/RimSummaryPlot.h @@ -26,6 +26,7 @@ #include "RifEclipseSummaryAddress.h" +#include "RimRiuQwtPlotOwnerInterface.h" #include "RimViewWindow.h" #include "qwt_plot_textlabel.h" @@ -44,7 +45,8 @@ class RimEnsembleCurveSet; class RimEnsembleCurveSetCollection; class RimSummaryCurveFilter_OBSOLETE; class RimSummaryTimeAxisProperties; -class RimSummaryAxisProperties; +class RimPlotAxisPropertiesInterface; +class RimPlotAxisProperties; class RiuSummaryQwtPlot; class RimSummaryPlotNameHelper; @@ -55,7 +57,7 @@ class QwtPlotCurve; /// /// //================================================================================================== -class RimSummaryPlot : public RimViewWindow +class RimSummaryPlot : public RimViewWindow, public RimRiuQwtPlotOwnerInterface { CAF_PDM_HEADER_INIT; @@ -84,7 +86,6 @@ class RimSummaryPlot : public RimViewWindow void addAsciiDataCruve(RimAsciiDataCurve* curve); - caf::PdmObject* findRimPlotObjectFromQwtCurve(const QwtPlotCurve* curve) const; size_t curveCount() const; void detachAllCurves(); @@ -92,19 +93,16 @@ class RimSummaryPlot : public RimViewWindow void updateCaseNameHasChanged(); void updateAxes(); - void zoomAll() override; + void zoomAll() override; void updateZoomInQwt(); - void updateZoomWindowFromQwt(); bool isLogarithmicScaleEnabled(RiaDefines::PlotAxis plotAxis) const; RimSummaryTimeAxisProperties* timeAxisProperties(); time_t firstTimeStepOfFirstCurve(); - void selectAxisInPropertyEditor(int axis); - - QWidget* viewWidget() override; + QWidget* viewWidget() override; QString asciiDataForPlotExport(DateTimePeriod resamplingPeriod = DateTimePeriod::NONE) const; @@ -134,8 +132,22 @@ class RimSummaryPlot : public RimViewWindow bool containsResamplableCurves() const; size_t singleColorCurveCount() const; - // RimViewWindow overrides + + + bool hasCustomFontSizes(RiaDefines::FontSettingType fontSettingType, int defaultFontSize) const override; + bool applyFontSize(RiaDefines::FontSettingType fontSettingType, int oldFontSize, int fontSize, bool forceChange = false) override; + public: + // Rim2dPlotInterface overrides + void updateAxisScaling() override; + void updateAxisDisplay() override; + void updateZoomWindowFromQwt() override; + void selectAxisInPropertyEditor(int axis) override; + void setAutoZoomForAllAxes(bool enableAutoZoom) override; + caf::PdmObject* findRimPlotObjectFromQwtCurve(const QwtPlotCurve* curve) const override; + +public: + // RimViewWindow overrides QWidget* createViewWidget(QWidget* mainWindowParent) override; void deleteViewWidget() override; void initAfterRead() override; @@ -164,7 +176,7 @@ class RimSummaryPlot : public RimViewWindow std::vector visibleAsciiDataCurvesForAxis(RiaDefines::PlotAxis plotAxis) const; bool hasVisibleCurvesForAxis(RiaDefines::PlotAxis plotAxis) const; - RimSummaryAxisProperties* yAxisPropertiesLeftOrRight(RiaDefines::PlotAxis leftOrRightPlotAxis) const; + RimPlotAxisProperties* yAxisPropertiesLeftOrRight(RiaDefines::PlotAxis leftOrRightPlotAxis) const; void updateAxis(RiaDefines::PlotAxis plotAxis); void updateZoomForAxis(RiaDefines::PlotAxis plotAxis); @@ -173,7 +185,8 @@ class RimSummaryPlot : public RimViewWindow void updateBottomXAxis(); void updateAxisRangesFromQwt(); - void setAutoZoomForAllAxes(bool enableAutoZoom); + + std::set allPlotAxes() const; private: caf::PdmField m_showPlotTitle; @@ -189,10 +202,10 @@ class RimSummaryPlot : public RimViewWindow caf::PdmChildArrayField m_asciiDataCurves; - caf::PdmChildField m_leftYAxisProperties; - caf::PdmChildField m_rightYAxisProperties; + caf::PdmChildField m_leftYAxisProperties; + caf::PdmChildField m_rightYAxisProperties; - caf::PdmChildField m_bottomAxisProperties; + caf::PdmChildField m_bottomAxisProperties; caf::PdmChildField m_timeAxisProperties; QPointer m_qwtPlot; diff --git a/ApplicationCode/ProjectDataModel/Summary/RimSummaryPlotSourceStepping.cpp b/ApplicationCode/ProjectDataModel/Summary/RimSummaryPlotSourceStepping.cpp index f3fd72eea5..bef4ebd249 100644 --- a/ApplicationCode/ProjectDataModel/Summary/RimSummaryPlotSourceStepping.cpp +++ b/ApplicationCode/ProjectDataModel/Summary/RimSummaryPlotSourceStepping.cpp @@ -102,22 +102,6 @@ void RimSummaryPlotSourceStepping::applyPrevCase() modifyCurrentIndex(&m_summaryCase, -1); } -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RimSummaryPlotSourceStepping::applyNextEnsemble() -{ - modifyCurrentIndex(&m_ensemble, 1); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RimSummaryPlotSourceStepping::applyPrevEnsemble() -{ - modifyCurrentIndex(&m_ensemble, -1); -} - //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -380,8 +364,8 @@ void RimSummaryPlotSourceStepping::fieldChangedByUi(const caf::PdmFieldHandle* c ensembleCurveColl->updateConnectedEditors(); } - RiuPlotMainWindow* mainPlotWindow = RiaApplication::instance()->getOrCreateMainPlotWindow(); - bool forceUpdateOfFieldsInToolbar = true; + RiuPlotMainWindow* mainPlotWindow = RiaApplication::instance()->getOrCreateMainPlotWindow(); + bool forceUpdateOfFieldsInToolbar = true; mainPlotWindow->updateSummaryPlotToolBar(forceUpdateOfFieldsInToolbar); return; @@ -389,9 +373,6 @@ void RimSummaryPlotSourceStepping::fieldChangedByUi(const caf::PdmFieldHandle* c bool triggerLoadDataAndUpdate = false; - std::string oldValueString = oldValue.toString().toStdString(); - std::string newValueString = newValue.toString().toStdString(); - if (changedField == &m_summaryCase) { if (m_summaryCase()) @@ -799,11 +780,29 @@ std::vector RimSummaryPlotSourceStepping::computeVisibleFi analyzer.appendAdresses(addressesCurveCollection()); RifEclipseSummaryAddress::SummaryVarCategory category = RifEclipseSummaryAddress::SUMMARY_INVALID; + + if (!analyzer.categories().empty()) { if (analyzer.categories().size() == 1) { category = *(analyzer.categories().begin()); } + else + { + bool allCategoriesAreDependingOnWellName = true; + for (auto c : analyzer.categories()) + { + if (!RifEclipseSummaryAddress::isDependentOnWellName(c)) + { + allCategoriesAreDependingOnWellName = false; + } + } + + if (allCategoriesAreDependingOnWellName) + { + category = RifEclipseSummaryAddress::SUMMARY_WELL; + } + } } if (category != RifEclipseSummaryAddress::SUMMARY_INVALID) diff --git a/ApplicationCode/ProjectDataModel/Summary/RimSummaryPlotSourceStepping.h b/ApplicationCode/ProjectDataModel/Summary/RimSummaryPlotSourceStepping.h index 3ae616aff9..3fb33e26ca 100644 --- a/ApplicationCode/ProjectDataModel/Summary/RimSummaryPlotSourceStepping.h +++ b/ApplicationCode/ProjectDataModel/Summary/RimSummaryPlotSourceStepping.h @@ -58,9 +58,6 @@ class RimSummaryPlotSourceStepping : public caf::PdmObject void applyNextCase(); void applyPrevCase(); - void applyNextEnsemble(); - void applyPrevEnsemble(); - void applyNextQuantity(); void applyPrevQuantity(); diff --git a/ApplicationCode/ProjectDataModel/Summary/RimSummaryTimeAxisProperties.cpp b/ApplicationCode/ProjectDataModel/Summary/RimSummaryTimeAxisProperties.cpp index c6af806b1a..0b44863edb 100644 --- a/ApplicationCode/ProjectDataModel/Summary/RimSummaryTimeAxisProperties.cpp +++ b/ApplicationCode/ProjectDataModel/Summary/RimSummaryTimeAxisProperties.cpp @@ -18,6 +18,10 @@ #include "RimSummaryTimeAxisProperties.h" +#include "RiaApplication.h" +#include "RiaFontCache.h" +#include "RiaPreferences.h" + #include "RimSummaryPlot.h" #include "cafPdmUiLineEditor.h" @@ -28,15 +32,6 @@ namespace caf { -template<> -void caf::AppEnum< RimSummaryTimeAxisProperties::AxisTitlePositionType >::setUp() -{ - addItem(RimSummaryTimeAxisProperties::AXIS_TITLE_CENTER, "AXIS_TITLE_CENTER", "Center"); - addItem(RimSummaryTimeAxisProperties::AXIS_TITLE_END, "AXIS_TITLE_END", "At End"); - - setDefault(RimSummaryTimeAxisProperties::AXIS_TITLE_CENTER); -} - template<> void caf::AppEnum< RimSummaryTimeAxisProperties::TimeModeType >::setUp() { @@ -77,10 +72,6 @@ RimSummaryTimeAxisProperties::RimSummaryTimeAxisProperties() CAF_PDM_InitField(&showTitle, "ShowTitle", false, "Show Title", "", "", ""); CAF_PDM_InitField(&title, "Title", QString("Time"), "Title", "", "", ""); - CAF_PDM_InitFieldNoDefault(&titlePositionEnum, "TitlePosition", "Title Position", "", "", ""); - - CAF_PDM_InitField(&titleFontSize, "FontSize", 11, "Font Size", "", "", ""); - CAF_PDM_InitField(&valuesFontSize, "ValuesFontSize", 11, "Font Size", "", "", ""); CAF_PDM_InitField(&m_isAutoZoom, "AutoZoom", true, "Set Range Automatically", "", "", ""); CAF_PDM_InitFieldNoDefault(&m_timeMode, "TimeMode", "Time Mode", "", "", ""); @@ -98,6 +89,52 @@ RimSummaryTimeAxisProperties::RimSummaryTimeAxisProperties() CAF_PDM_InitFieldNoDefault(&m_visibleTimeRangeMin, "VisibleTimeModeRangeMin", "Min", "", "", ""); m_visibleDateRangeMin.uiCapability()->setUiEditorTypeName(caf::PdmUiLineEditor::uiEditorTypeName()); + CAF_PDM_InitFieldNoDefault(&m_titlePositionEnum, "TitlePosition", "Title Position", "", "", ""); + CAF_PDM_InitField(&m_titleFontSize, "FontSize", 10, "Font Size", "", "", ""); + m_titleFontSize = RiaFontCache::pointSizeFromFontSizeEnum(RiaApplication::instance()->preferences()->defaultPlotFontSize()); + CAF_PDM_InitField(&m_valuesFontSize, "ValuesFontSize", 10, "Font Size", "", "", ""); + m_valuesFontSize = RiaFontCache::pointSizeFromFontSizeEnum(RiaApplication::instance()->preferences()->defaultPlotFontSize()); + +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimPlotAxisPropertiesInterface::AxisTitlePositionType RimSummaryTimeAxisProperties::titlePosition() const +{ + return m_titlePositionEnum(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +int RimSummaryTimeAxisProperties::titleFontSize() const +{ + return m_titleFontSize; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimSummaryTimeAxisProperties::setTitleFontSize(int fontSize) +{ + m_titleFontSize = fontSize; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +int RimSummaryTimeAxisProperties::valuesFontSize() const +{ + return m_valuesFontSize; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimSummaryTimeAxisProperties::setValuesFontSize(int fontSize) +{ + m_valuesFontSize = fontSize; } //-------------------------------------------------------------------------------------------------- @@ -240,8 +277,8 @@ QList RimSummaryTimeAxisProperties::calculateValueOption QList options; *useOptionsOnly = true; - if (&titleFontSize == fieldNeedingOptions || - &valuesFontSize == fieldNeedingOptions) + if (&m_titleFontSize == fieldNeedingOptions || + &m_valuesFontSize == fieldNeedingOptions) { std::vector fontSizes; fontSizes.push_back(8); @@ -272,6 +309,22 @@ caf::PdmFieldHandle* RimSummaryTimeAxisProperties::objectToggleField() return &m_isActive; } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimSummaryTimeAxisProperties::TimeModeType RimSummaryTimeAxisProperties::timeMode() const +{ + return m_timeMode(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimSummaryTimeAxisProperties::setTimeMode(TimeModeType val) +{ + m_timeMode = val; +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -340,8 +393,8 @@ void RimSummaryTimeAxisProperties::defineUiOrdering(QString uiConfigName, caf::P caf::PdmUiGroup& titleGroup = *(uiOrdering.addNewGroup("Axis Title")); titleGroup.add(&showTitle); titleGroup.add(&title); - titleGroup.add(&titlePositionEnum); - titleGroup.add(&titleFontSize); + titleGroup.add(&m_titlePositionEnum); + titleGroup.add(&m_titleFontSize); caf::PdmUiGroup* timeGroup = uiOrdering.addNewGroup("Time Values"); timeGroup->add(&m_timeMode); @@ -356,7 +409,7 @@ void RimSummaryTimeAxisProperties::defineUiOrdering(QString uiConfigName, caf::P timeGroup->add(&m_visibleTimeRangeMax); timeGroup->add(&m_visibleTimeRangeMin); } - timeGroup->add(&valuesFontSize); + timeGroup->add(&m_valuesFontSize); uiOrdering.skipRemainingFields(true); } diff --git a/ApplicationCode/ProjectDataModel/Summary/RimSummaryTimeAxisProperties.h b/ApplicationCode/ProjectDataModel/Summary/RimSummaryTimeAxisProperties.h index 252c0c5623..bc8c018078 100644 --- a/ApplicationCode/ProjectDataModel/Summary/RimSummaryTimeAxisProperties.h +++ b/ApplicationCode/ProjectDataModel/Summary/RimSummaryTimeAxisProperties.h @@ -19,6 +19,8 @@ #pragma once +#include "RimPlotAxisPropertiesInterface.h" + #include "cafPdmObject.h" #include "cafPdmField.h" #include "cafPdmChildArrayField.h" @@ -31,18 +33,11 @@ /// /// //================================================================================================== -class RimSummaryTimeAxisProperties : public caf::PdmObject +class RimSummaryTimeAxisProperties : public caf::PdmObject, public RimPlotAxisPropertiesInterface { CAF_PDM_HEADER_INIT; public: - - enum AxisTitlePositionType - { - AXIS_TITLE_CENTER, - AXIS_TITLE_END - }; - enum TimeModeType { DATE, @@ -61,16 +56,19 @@ class RimSummaryTimeAxisProperties : public caf::PdmObject public: RimSummaryTimeAxisProperties(); - caf::PdmField titleFontSize; caf::PdmField title; caf::PdmField showTitle; - caf::PdmField< caf::AppEnum< AxisTitlePositionType > > titlePositionEnum; - caf::PdmField valuesFontSize; - TimeModeType timeMode() const { return m_timeMode(); } - void setTimeMode(TimeModeType val) { m_timeMode = val; } - double fromTimeTToDisplayUnitScale(); - double fromDaysToDisplayUnitScale(); + + AxisTitlePositionType titlePosition() const override; + int titleFontSize() const override; + void setTitleFontSize(int fontSize) override; + int valuesFontSize() const override; + void setValuesFontSize(int fontSize) override; + TimeModeType timeMode() const; + void setTimeMode(TimeModeType val); + double fromTimeTToDisplayUnitScale(); + double fromDaysToDisplayUnitScale(); double visibleRangeMin() const; double visibleRangeMax() const; @@ -104,4 +102,9 @@ class RimSummaryTimeAxisProperties : public caf::PdmObject caf::PdmField m_visibleTimeRangeMin; caf::PdmField m_visibleTimeRangeMax; caf::PdmField m_isAutoZoom; + + caf::PdmField m_titleFontSize; + caf::PdmField> m_titlePositionEnum; + caf::PdmField m_valuesFontSize; + }; diff --git a/ApplicationCode/ReservoirDataModel/CMakeLists_files.cmake b/ApplicationCode/ReservoirDataModel/CMakeLists_files.cmake index 804817e441..4058f706c7 100644 --- a/ApplicationCode/ReservoirDataModel/CMakeLists_files.cmake +++ b/ApplicationCode/ReservoirDataModel/CMakeLists_files.cmake @@ -45,7 +45,6 @@ ${CMAKE_CURRENT_LIST_DIR}/RigWellLogCurveData.h ${CMAKE_CURRENT_LIST_DIR}/RigWellLogExtractionTools.h ${CMAKE_CURRENT_LIST_DIR}/RigHexIntersectionTools.h ${CMAKE_CURRENT_LIST_DIR}/RigTimeHistoryResultAccessor.h -${CMAKE_CURRENT_LIST_DIR}/RigObservedData.h ${CMAKE_CURRENT_LIST_DIR}/RigLasFileExporter.h ${CMAKE_CURRENT_LIST_DIR}/RigSimulationWellCoordsAndMD.h ${CMAKE_CURRENT_LIST_DIR}/RigFishbonesGeometry.h @@ -53,6 +52,7 @@ ${CMAKE_CURRENT_LIST_DIR}/RigTesselatorTools.h ${CMAKE_CURRENT_LIST_DIR}/RigCellGeometryTools.h ${CMAKE_CURRENT_LIST_DIR}/RigWellPathIntersectionTools.h ${CMAKE_CURRENT_LIST_DIR}/RigEclipseResultInfo.h +${CMAKE_CURRENT_LIST_DIR}/RigEclipseResultAddress.h ${CMAKE_CURRENT_LIST_DIR}/RigTofAccumulatedPhaseFractionsCalculator.h ${CMAKE_CURRENT_LIST_DIR}/RigTransmissibilityEquations.h ${CMAKE_CURRENT_LIST_DIR}/RigNumberOfFloodedPoreVolumesCalculator.h @@ -65,6 +65,11 @@ ${CMAKE_CURRENT_LIST_DIR}/RigWellResultPoint.h ${CMAKE_CURRENT_LIST_DIR}/RigWellPathGeometryTools.h ${CMAKE_CURRENT_LIST_DIR}/RigCaseRealizationParameters.h ${CMAKE_CURRENT_LIST_DIR}/RigGeoMechBoreHoleStressCalculator.h +${CMAKE_CURRENT_LIST_DIR}/RigPolyLinesData.h +${CMAKE_CURRENT_LIST_DIR}/RigCaseCellResultCalculator.h +${CMAKE_CURRENT_LIST_DIR}/RigGridCrossPlotCurveGrouping.h +${CMAKE_CURRENT_LIST_DIR}/RigEclipseCrossPlotDataExtractor.h +${CMAKE_CURRENT_LIST_DIR}/RigEquil.h ) @@ -109,7 +114,6 @@ ${CMAKE_CURRENT_LIST_DIR}/RigEclipseMultiPropertyStatCalc.cpp ${CMAKE_CURRENT_LIST_DIR}/RigWellLogCurveData.cpp ${CMAKE_CURRENT_LIST_DIR}/RigHexIntersectionTools.cpp ${CMAKE_CURRENT_LIST_DIR}/RigTimeHistoryResultAccessor.cpp -${CMAKE_CURRENT_LIST_DIR}/RigObservedData.cpp ${CMAKE_CURRENT_LIST_DIR}/RigLasFileExporter.cpp ${CMAKE_CURRENT_LIST_DIR}/RigSimulationWellCoordsAndMD.cpp ${CMAKE_CURRENT_LIST_DIR}/RigFishbonesGeometry.cpp @@ -129,6 +133,10 @@ ${CMAKE_CURRENT_LIST_DIR}/RigWellResultPoint.cpp ${CMAKE_CURRENT_LIST_DIR}/RigWellPathGeometryTools.cpp ${CMAKE_CURRENT_LIST_DIR}/RigCaseRealizationParameters.cpp ${CMAKE_CURRENT_LIST_DIR}/RigGeoMechBoreHoleStressCalculator.cpp +${CMAKE_CURRENT_LIST_DIR}/RigPolyLinesData.cpp +${CMAKE_CURRENT_LIST_DIR}/RigCaseCellResultCalculator.cpp +${CMAKE_CURRENT_LIST_DIR}/RigEclipseCrossPlotDataExtractor.cpp +${CMAKE_CURRENT_LIST_DIR}/RigEquil.cpp ) list(APPEND CODE_HEADER_FILES diff --git a/ApplicationCode/ReservoirDataModel/Completions/RigCompletionData.cpp b/ApplicationCode/ReservoirDataModel/Completions/RigCompletionData.cpp index 79014a9e4d..eb2bfbcbea 100644 --- a/ApplicationCode/ReservoirDataModel/Completions/RigCompletionData.cpp +++ b/ApplicationCode/ReservoirDataModel/Completions/RigCompletionData.cpp @@ -102,6 +102,30 @@ RigCompletionData& RigCompletionData::operator=(const RigCompletionData& other) return *this; } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RigCompletionData::isPerforationValve(CompletionType type) +{ + return type == PERFORATION_AICD || type == PERFORATION_ICD || type == PERFORATION_ICV; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RigCompletionData::isValve(CompletionType type) +{ + return isPerforationValve(type) || type == FISHBONES_ICD; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RigCompletionData::isWsegValveTypes(CompletionType type) +{ + return type == FISHBONES_ICD || type == PERFORATION_ICD || type == PERFORATION_ICV; +} + //================================================================================================== /// //================================================================================================== diff --git a/ApplicationCode/ReservoirDataModel/Completions/RigCompletionData.h b/ApplicationCode/ReservoirDataModel/Completions/RigCompletionData.h index c4ee7f9d3c..f14c27b2b3 100644 --- a/ApplicationCode/ReservoirDataModel/Completions/RigCompletionData.h +++ b/ApplicationCode/ReservoirDataModel/Completions/RigCompletionData.h @@ -66,7 +66,10 @@ class RigCompletionData FISHBONES, FRACTURE, PERFORATION, - ICD, + FISHBONES_ICD, + PERFORATION_ICD, + PERFORATION_AICD, + PERFORATION_ICV, CT_UNDEFINED }; @@ -78,6 +81,11 @@ class RigCompletionData bool operator<(const RigCompletionData& other) const; RigCompletionData& operator=(const RigCompletionData& other); + + static bool isPerforationValve(CompletionType type); + static bool isValve(CompletionType type); + static bool isWsegValveTypes(CompletionType type); + void setFromFracture(double transmissibility, double skinFactor, double diameter); void setSecondOrderingValue(double orderingValue); void setDiameter(double diameter); diff --git a/ApplicationCode/ReservoirDataModel/Completions/RigCompletionDataGridCell.cpp b/ApplicationCode/ReservoirDataModel/Completions/RigCompletionDataGridCell.cpp index 23b305025e..7461d0f1a7 100644 --- a/ApplicationCode/ReservoirDataModel/Completions/RigCompletionDataGridCell.cpp +++ b/ApplicationCode/ReservoirDataModel/Completions/RigCompletionDataGridCell.cpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018 Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by diff --git a/ApplicationCode/ReservoirDataModel/Completions/RigCompletionDataGridCell.h b/ApplicationCode/ReservoirDataModel/Completions/RigCompletionDataGridCell.h index b2565e1bed..dafae4cf85 100644 --- a/ApplicationCode/ReservoirDataModel/Completions/RigCompletionDataGridCell.h +++ b/ApplicationCode/ReservoirDataModel/Completions/RigCompletionDataGridCell.h @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018 Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by diff --git a/ApplicationCode/ReservoirDataModel/Completions/RigEclipseToStimPlanCalculator.cpp b/ApplicationCode/ReservoirDataModel/Completions/RigEclipseToStimPlanCalculator.cpp index 9f3cd5396a..05e423f314 100644 --- a/ApplicationCode/ReservoirDataModel/Completions/RigEclipseToStimPlanCalculator.cpp +++ b/ApplicationCode/ReservoirDataModel/Completions/RigEclipseToStimPlanCalculator.cpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018 Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -149,8 +149,6 @@ double RigEclipseToStimPlanCalculator::areaWeightedMatrixPermeability() const RiaWeightedMeanCalculator calc; { - std::map reservoirCellAndIntersectedArea; - for (const auto& singleCellCalc : m_singleFractureCellCalculators) { const RigEclipseToStimPlanCellTransmissibilityCalculator& calulator = singleCellCalc.second; diff --git a/ApplicationCode/ReservoirDataModel/Completions/RigEclipseToStimPlanCalculator.h b/ApplicationCode/ReservoirDataModel/Completions/RigEclipseToStimPlanCalculator.h index 9e93c1dac8..85eeb715b5 100644 --- a/ApplicationCode/ReservoirDataModel/Completions/RigEclipseToStimPlanCalculator.h +++ b/ApplicationCode/ReservoirDataModel/Completions/RigEclipseToStimPlanCalculator.h @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018 Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by diff --git a/ApplicationCode/ReservoirDataModel/Completions/RigEclipseToStimPlanCellTransmissibilityCalculator.cpp b/ApplicationCode/ReservoirDataModel/Completions/RigEclipseToStimPlanCellTransmissibilityCalculator.cpp index c80668a664..e69d8d34e8 100644 --- a/ApplicationCode/ReservoirDataModel/Completions/RigEclipseToStimPlanCellTransmissibilityCalculator.cpp +++ b/ApplicationCode/ReservoirDataModel/Completions/RigEclipseToStimPlanCellTransmissibilityCalculator.cpp @@ -73,7 +73,7 @@ const std::vector& RigEclipseToStimPlanCellTransmissibilityCalculator::c } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- const std::vector& RigEclipseToStimPlanCellTransmissibilityCalculator::contributingEclipseCellIntersectionAreas() const { @@ -81,7 +81,7 @@ const std::vector& RigEclipseToStimPlanCellTransmissibilityCalculator::c } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- const std::vector& RigEclipseToStimPlanCellTransmissibilityCalculator::contributingEclipseCellPermeabilities() const { @@ -103,21 +103,6 @@ double RigEclipseToStimPlanCellTransmissibilityCalculator::areaOpenForFlow() con return area; } -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -double RigEclipseToStimPlanCellTransmissibilityCalculator::aggregatedMatrixTransmissibility() const -{ - double totalTransmissibility = 0.0; - - for (const auto& trans : m_contributingEclipseCellTransmissibilities) - { - totalTransmissibility += trans; - } - - return totalTransmissibility; -} - //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -377,5 +362,6 @@ cvf::ref const RigEclipseCaseData* eclipseCaseData = eclipseCase->eclipseCaseData(); // Create result accessor object for main grid at time step zero (static result date is always at first time step - return RigResultAccessorFactory::createFromUiResultName(eclipseCaseData, 0, porosityModel, 0, uiResultName); + return RigResultAccessorFactory::createFromResultAddress( + eclipseCaseData, 0, porosityModel, 0, RigEclipseResultAddress(uiResultName)); } diff --git a/ApplicationCode/ReservoirDataModel/Completions/RigEclipseToStimPlanCellTransmissibilityCalculator.h b/ApplicationCode/ReservoirDataModel/Completions/RigEclipseToStimPlanCellTransmissibilityCalculator.h index e6b759c081..78711f2adb 100644 --- a/ApplicationCode/ReservoirDataModel/Completions/RigEclipseToStimPlanCellTransmissibilityCalculator.h +++ b/ApplicationCode/ReservoirDataModel/Completions/RigEclipseToStimPlanCellTransmissibilityCalculator.h @@ -58,7 +58,6 @@ class RigEclipseToStimPlanCellTransmissibilityCalculator const std::vector& contributingEclipseCellPermeabilities() const; double areaOpenForFlow() const; - double aggregatedMatrixTransmissibility() const; const RigFractureCell& fractureCell() const; diff --git a/ApplicationCode/ReservoirDataModel/RigActiveCellInfo.cpp b/ApplicationCode/ReservoirDataModel/RigActiveCellInfo.cpp index f2fe73a522..55bf12f502 100644 --- a/ApplicationCode/ReservoirDataModel/RigActiveCellInfo.cpp +++ b/ApplicationCode/ReservoirDataModel/RigActiveCellInfo.cpp @@ -94,9 +94,12 @@ void RigActiveCellInfo::setCellResultIndex(size_t reservoirCellIndex, size_t res m_cellIndexToResultIndex[reservoirCellIndex] = reservoirCellResultIndex; - if (reservoirCellResultIndex >= m_reservoirCellResultCount) + #pragma omp critical { - m_reservoirCellResultCount = reservoirCellResultIndex + 1; + if ( reservoirCellResultIndex >= m_reservoirCellResultCount ) + { + m_reservoirCellResultCount = reservoirCellResultIndex + 1; + } } } diff --git a/ApplicationCode/ReservoirDataModel/RigCaseCellResultCalculator.cpp b/ApplicationCode/ReservoirDataModel/RigCaseCellResultCalculator.cpp new file mode 100644 index 0000000000..18e8886bd1 --- /dev/null +++ b/ApplicationCode/ReservoirDataModel/RigCaseCellResultCalculator.cpp @@ -0,0 +1,170 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2019- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "RigCaseCellResultCalculator.h" + +#include "RiaApplication.h" +#include "RiaLogging.h" + +#include "RigCaseCellResultsData.h" +#include "RigEclipseCaseData.h" +#include "RigEclipseResultAddress.h" +#include "RigGridManager.h" +#include "RigMainGrid.h" +#include "RigResultAccessorFactory.h" +#include "RigResultModifier.h" +#include "RigResultModifierFactory.h" + +#include "RimEclipseCase.h" +#include "RimProject.h" + +#include "cvfAssert.h" + +#include +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RigCaseCellResultCalculator::computeDifference(RigEclipseCaseData* sourceCase, + RiaDefines::PorosityModelType porosityModel, + const RigEclipseResultAddress& address) +{ + CVF_ASSERT(address.isValid()); + CVF_ASSERT(address.hasDifferenceCase() || address.isTimeLapse()); + + // Assume at this stage that data for the case is available + // It is up to the caller to make sure the case is read from file + + RigEclipseCaseData* baseCase = sourceCase; + + if (address.hasDifferenceCase()) + { + { + auto eclipseCases = RiaApplication::instance()->project()->eclipseCases(); + for (RimEclipseCase* c : eclipseCases) + { + if (c && c->caseId() == address.m_differenceCaseId && c->eclipseCaseData()) + { + baseCase = c->eclipseCaseData(); + } + } + } + } + + if (!baseCase || !sourceCase) + { + RiaLogging::error("Missing input case for difference calculator"); + + return false; + } + + RigMainGrid* sourceMainGrid = sourceCase->mainGrid(); + RigMainGrid* baseMainGrid = baseCase->mainGrid(); + + if (!RigGridManager::isMainGridDimensionsEqual(sourceMainGrid, baseMainGrid)) + { + RiaLogging::error("Case difference : Grid cases do not match"); + + return false; + } + + RigCaseCellResultsData* baseCaseResults = baseCase->results(porosityModel); + RigCaseCellResultsData* sourceCaseResults = sourceCase->results(porosityModel); + + if (!baseCaseResults || !sourceCaseResults) + { + RiaLogging::error("Missing result data for difference calculator"); + + return false; + } + + RigEclipseResultAddress nativeAddress(address); + nativeAddress.m_differenceCaseId = RigEclipseResultAddress::noCaseDiffValue(); + nativeAddress.m_timeLapseBaseFrameIdx = RigEclipseResultAddress::noTimeLapseValue(); + if (!sourceCaseResults->ensureKnownResultLoaded(nativeAddress)) + { + RiaLogging::error("Failed to load destination diff result"); + + return false; + } + + if (!baseCaseResults->ensureKnownResultLoaded(nativeAddress)) + { + RiaLogging::error("Failed to load difference result"); + + return false; + } + + // Initialize difference result with infinity for correct number of time steps and values per time step + { + const std::vector>& srcFrames = sourceCaseResults->cellScalarResults(nativeAddress); + std::vector>& diffResultFrames = sourceCaseResults->modifiableCellScalarResultTimesteps(address); + diffResultFrames.resize(srcFrames.size()); + for (size_t fIdx = 0; fIdx < srcFrames.size(); ++fIdx) + { + const std::vector& srcVals = srcFrames[fIdx]; + std::vector& dstVals = diffResultFrames[fIdx]; + + dstVals.resize(srcVals.size(), std::numeric_limits::infinity()); + } + } + + size_t baseFrameCount = baseCaseResults->cellScalarResults(nativeAddress).size(); + size_t sourceFrameCount = sourceCaseResults->cellScalarResults(nativeAddress).size(); + size_t maxFrameCount = std::min(baseFrameCount, sourceFrameCount); + size_t maxGridCount = std::min(baseMainGrid->gridCount(), sourceMainGrid->gridCount()); + + for (size_t gridIdx = 0; gridIdx < maxGridCount; ++gridIdx) + { + auto grid = sourceMainGrid->gridByIndex(gridIdx); + const RigActiveCellInfo* activeCellInfo = sourceCaseResults->activeCellInfo(); + + for (size_t fIdx = 0; fIdx < maxFrameCount; ++fIdx) + { + cvf::ref sourceResultAccessor = + RigResultAccessorFactory::createFromResultAddress(sourceCase, gridIdx, porosityModel, fIdx, nativeAddress); + + cvf::ref resultModifier = + RigResultModifierFactory::createResultModifier(sourceCase, gridIdx, porosityModel, fIdx, address); + + size_t baseFrameIdx = fIdx; + if (address.isTimeLapse()) + { + baseFrameIdx = address.m_timeLapseBaseFrameIdx; + } + + cvf::ref baseResultAccessor = + RigResultAccessorFactory::createFromResultAddress(baseCase, gridIdx, porosityModel, baseFrameIdx, nativeAddress); + + for (size_t localGridCellIdx = 0; localGridCellIdx < grid->cellCount(); localGridCellIdx++) + { + size_t reservoirCellIndex = grid->reservoirCellIndex(localGridCellIdx); + if (activeCellInfo->isActive(reservoirCellIndex)) + { + double sourceVal = sourceResultAccessor->cellScalar(localGridCellIdx); + double baseVal = baseResultAccessor->cellScalar(localGridCellIdx); + + double difference = sourceVal - baseVal; + + resultModifier->setCellScalar(localGridCellIdx, difference); + } + } + } + } + + return true; +} diff --git a/ApplicationCode/ReservoirDataModel/RigCaseCellResultCalculator.h b/ApplicationCode/ReservoirDataModel/RigCaseCellResultCalculator.h new file mode 100644 index 0000000000..7e6beff785 --- /dev/null +++ b/ApplicationCode/ReservoirDataModel/RigCaseCellResultCalculator.h @@ -0,0 +1,35 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2019- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "RiaPorosityModel.h" + +class RigEclipseCaseData; +class RigEclipseResultAddress; + +//================================================================================================== +/// +//================================================================================================== +class RigCaseCellResultCalculator +{ +public: + static bool computeDifference(RigEclipseCaseData* destination, + RiaDefines::PorosityModelType porosityModel, + const RigEclipseResultAddress& address); +}; diff --git a/ApplicationCode/ReservoirDataModel/RigCaseCellResultsData.cpp b/ApplicationCode/ReservoirDataModel/RigCaseCellResultsData.cpp index 156fac906c..d6f363f4cd 100644 --- a/ApplicationCode/ReservoirDataModel/RigCaseCellResultsData.cpp +++ b/ApplicationCode/ReservoirDataModel/RigCaseCellResultsData.cpp @@ -23,10 +23,12 @@ #include "RiaApplication.h" #include "RiaLogging.h" +#include "RigCaseCellResultCalculator.h" #include "RigEclipseCaseData.h" #include "RigEclipseMultiPropertyStatCalc.h" #include "RigEclipseNativeStatCalc.h" #include "RigEclipseResultInfo.h" +#include "RigFormationNames.h" #include "RigMainGrid.h" #include "RigStatisticsDataCache.h" #include "RigStatisticsMath.h" @@ -43,13 +45,14 @@ #include #include -#include +#include //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -RigCaseCellResultsData::RigCaseCellResultsData(RigEclipseCaseData* ownerCaseData) +RigCaseCellResultsData::RigCaseCellResultsData(RigEclipseCaseData* ownerCaseData, RiaDefines::PorosityModelType porosityModel) : m_activeCellInfo(nullptr) + , m_porosityModel(porosityModel) { CVF_ASSERT(ownerCaseData != nullptr); CVF_ASSERT(ownerCaseData->mainGrid() != nullptr); @@ -77,121 +80,121 @@ void RigCaseCellResultsData::setActiveCellInfo(RigActiveCellInfo* activeCellInfo //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RigCaseCellResultsData::minMaxCellScalarValues(size_t scalarResultIndex, double& min, double& max) +void RigCaseCellResultsData::minMaxCellScalarValues(const RigEclipseResultAddress& resVarAddr, double& min, double& max) { - m_statisticsDataCache[scalarResultIndex]->minMaxCellScalarValues(min, max); + statistics(resVarAddr)->minMaxCellScalarValues(min, max); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RigCaseCellResultsData::minMaxCellScalarValues(size_t scalarResultIndex, size_t timeStepIndex, double& min, double& max) +void RigCaseCellResultsData::minMaxCellScalarValues(const RigEclipseResultAddress& resVarAddr, size_t timeStepIndex, double& min, double& max) { - m_statisticsDataCache[scalarResultIndex]->minMaxCellScalarValues(timeStepIndex, min, max); + statistics(resVarAddr)->minMaxCellScalarValues(timeStepIndex, min, max); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RigCaseCellResultsData::posNegClosestToZero(size_t scalarResultIndex, double& pos, double& neg) +void RigCaseCellResultsData::posNegClosestToZero(const RigEclipseResultAddress& resVarAddr, double& pos, double& neg) { - m_statisticsDataCache[scalarResultIndex]->posNegClosestToZero(pos, neg); + statistics(resVarAddr)->posNegClosestToZero(pos, neg); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RigCaseCellResultsData::posNegClosestToZero(size_t scalarResultIndex, size_t timeStepIndex, double& pos, double& neg) +void RigCaseCellResultsData::posNegClosestToZero(const RigEclipseResultAddress& resVarAddr, size_t timeStepIndex, double& pos, double& neg) { - m_statisticsDataCache[scalarResultIndex]->posNegClosestToZero(timeStepIndex, pos, neg); + statistics(resVarAddr)->posNegClosestToZero(timeStepIndex, pos, neg); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -const std::vector& RigCaseCellResultsData::cellScalarValuesHistogram(size_t scalarResultIndex) +const std::vector& RigCaseCellResultsData::cellScalarValuesHistogram(const RigEclipseResultAddress& resVarAddr) { - return m_statisticsDataCache[scalarResultIndex]->cellScalarValuesHistogram(); + return statistics(resVarAddr)->cellScalarValuesHistogram(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -const std::vector& RigCaseCellResultsData::cellScalarValuesHistogram(size_t scalarResultIndex, size_t timeStepIndex) +const std::vector& RigCaseCellResultsData::cellScalarValuesHistogram(const RigEclipseResultAddress& resVarAddr, size_t timeStepIndex) { - return m_statisticsDataCache[scalarResultIndex]->cellScalarValuesHistogram(timeStepIndex); + return statistics(resVarAddr)->cellScalarValuesHistogram(timeStepIndex); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RigCaseCellResultsData::p10p90CellScalarValues(size_t scalarResultIndex, double& p10, double& p90) +void RigCaseCellResultsData::p10p90CellScalarValues(const RigEclipseResultAddress& resVarAddr, double& p10, double& p90) { - m_statisticsDataCache[scalarResultIndex]->p10p90CellScalarValues(p10, p90); + statistics(resVarAddr)->p10p90CellScalarValues(p10, p90); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RigCaseCellResultsData::p10p90CellScalarValues(size_t scalarResultIndex, size_t timeStepIndex, double& p10, double& p90) +void RigCaseCellResultsData::p10p90CellScalarValues(const RigEclipseResultAddress& resVarAddr, size_t timeStepIndex, double& p10, double& p90) { - m_statisticsDataCache[scalarResultIndex]->p10p90CellScalarValues(timeStepIndex, p10, p90); + statistics(resVarAddr)->p10p90CellScalarValues(timeStepIndex, p10, p90); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RigCaseCellResultsData::meanCellScalarValues(size_t scalarResultIndex, double& meanValue) +void RigCaseCellResultsData::meanCellScalarValues(const RigEclipseResultAddress& resVarAddr, double& meanValue) { - m_statisticsDataCache[scalarResultIndex]->meanCellScalarValues(meanValue); + statistics(resVarAddr)->meanCellScalarValues(meanValue); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RigCaseCellResultsData::meanCellScalarValues(size_t scalarResultIndex, size_t timeStepIndex, double& meanValue) +void RigCaseCellResultsData::meanCellScalarValues(const RigEclipseResultAddress& resVarAddr, size_t timeStepIndex, double& meanValue) { - m_statisticsDataCache[scalarResultIndex]->meanCellScalarValues(timeStepIndex, meanValue); + statistics(resVarAddr)->meanCellScalarValues(timeStepIndex, meanValue); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -const std::vector& RigCaseCellResultsData::uniqueCellScalarValues(size_t scalarResultIndex) +const std::vector& RigCaseCellResultsData::uniqueCellScalarValues(const RigEclipseResultAddress& resVarAddr) { - return m_statisticsDataCache[scalarResultIndex]->uniqueCellScalarValues(); + return statistics(resVarAddr)->uniqueCellScalarValues(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RigCaseCellResultsData::sumCellScalarValues(size_t scalarResultIndex, double& sumValue) +void RigCaseCellResultsData::sumCellScalarValues(const RigEclipseResultAddress& resVarAddr, double& sumValue) { - m_statisticsDataCache[scalarResultIndex]->sumCellScalarValues(sumValue); + statistics(resVarAddr)->sumCellScalarValues(sumValue); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RigCaseCellResultsData::sumCellScalarValues(size_t scalarResultIndex, size_t timeStepIndex, double& sumValue) +void RigCaseCellResultsData::sumCellScalarValues(const RigEclipseResultAddress& resVarAddr, size_t timeStepIndex, double& sumValue) { - m_statisticsDataCache[scalarResultIndex]->sumCellScalarValues(timeStepIndex, sumValue); + statistics(resVarAddr)->sumCellScalarValues(timeStepIndex, sumValue); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RigCaseCellResultsData::mobileVolumeWeightedMean(size_t scalarResultIndex, double& meanValue) +void RigCaseCellResultsData::mobileVolumeWeightedMean(const RigEclipseResultAddress& resVarAddr, double& meanValue) { - m_statisticsDataCache[scalarResultIndex]->mobileVolumeWeightedMean(meanValue); + statistics(resVarAddr)->mobileVolumeWeightedMean(meanValue); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RigCaseCellResultsData::mobileVolumeWeightedMean(size_t scalarResultIndex, size_t timeStepIndex, double& meanValue) +void RigCaseCellResultsData::mobileVolumeWeightedMean(const RigEclipseResultAddress& resVarAddr, size_t timeStepIndex, double& meanValue) { - m_statisticsDataCache[scalarResultIndex]->mobileVolumeWeightedMean(timeStepIndex, meanValue); + statistics(resVarAddr)->mobileVolumeWeightedMean(timeStepIndex, meanValue); } //-------------------------------------------------------------------------------------------------- @@ -205,8 +208,9 @@ size_t RigCaseCellResultsData::resultCount() const //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -size_t RigCaseCellResultsData::timeStepCount(size_t scalarResultIndex) const +size_t RigCaseCellResultsData::timeStepCount(const RigEclipseResultAddress& resVarAddr) const { + size_t scalarResultIndex = findScalarResultIndexFromAddress(resVarAddr); CVF_TIGHT_ASSERT(scalarResultIndex < resultCount()); return m_cellScalarResults[scalarResultIndex].size(); @@ -215,8 +219,10 @@ size_t RigCaseCellResultsData::timeStepCount(size_t scalarResultIndex) const //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -const std::vector>& RigCaseCellResultsData::cellScalarResults(size_t scalarResultIndex) const +const std::vector>& RigCaseCellResultsData::cellScalarResults(const RigEclipseResultAddress& resVarAddr) const { + size_t scalarResultIndex = findScalarResultIndexFromAddress(resVarAddr); + CVF_TIGHT_ASSERT(scalarResultIndex < resultCount()); return m_cellScalarResults[scalarResultIndex]; @@ -225,8 +231,10 @@ const std::vector>& RigCaseCellResultsData::cellScalarResult //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -std::vector>& RigCaseCellResultsData::cellScalarResults(size_t scalarResultIndex) +std::vector>& RigCaseCellResultsData::modifiableCellScalarResultTimesteps(const RigEclipseResultAddress& resVarAddr) { + size_t scalarResultIndex = findScalarResultIndexFromAddress(resVarAddr); + CVF_TIGHT_ASSERT(scalarResultIndex < resultCount()); return m_cellScalarResults[scalarResultIndex]; @@ -235,8 +243,10 @@ std::vector>& RigCaseCellResultsData::cellScalarResults(size //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -std::vector& RigCaseCellResultsData::cellScalarResults(size_t scalarResultIndex, size_t timeStepIndex) +std::vector& RigCaseCellResultsData::modifiableCellScalarResult(const RigEclipseResultAddress& resVarAddr, size_t timeStepIndex) { + size_t scalarResultIndex = findScalarResultIndexFromAddress(resVarAddr); + CVF_TIGHT_ASSERT(scalarResultIndex < resultCount()); CVF_TIGHT_ASSERT(timeStepIndex < m_cellScalarResults[scalarResultIndex].size()); @@ -246,64 +256,23 @@ std::vector& RigCaseCellResultsData::cellScalarResults(size_t scalarResu //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -size_t RigCaseCellResultsData::findScalarResultIndex(RiaDefines::ResultCatType type, const QString& resultName) const -{ - std::vector::const_iterator it; - for (it = m_resultInfos.begin(); it != m_resultInfos.end(); ++it) - { - if (it->resultType() == type && it->resultName() == resultName) - { - return it->gridScalarResultIndex(); - } - } - - return cvf::UNDEFINED_SIZE_T; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -size_t RigCaseCellResultsData::findScalarResultIndex(const QString& resultName) const +const std::vector& RigCaseCellResultsData::cellScalarResults(const RigEclipseResultAddress& resVarAddr, size_t timeStepIndex) const { - size_t scalarResultIndex = this->findScalarResultIndex(RiaDefines::STATIC_NATIVE, resultName); - - if (scalarResultIndex == cvf::UNDEFINED_SIZE_T) - { - scalarResultIndex = this->findScalarResultIndex(RiaDefines::DYNAMIC_NATIVE, resultName); - } - - if (scalarResultIndex == cvf::UNDEFINED_SIZE_T) - { - scalarResultIndex = this->findScalarResultIndex(RiaDefines::SOURSIMRL, resultName); - } - - if (scalarResultIndex == cvf::UNDEFINED_SIZE_T) - { - scalarResultIndex = this->findScalarResultIndex(RiaDefines::GENERATED, resultName); - } - - if (scalarResultIndex == cvf::UNDEFINED_SIZE_T) - { - scalarResultIndex = this->findScalarResultIndex(RiaDefines::INPUT_PROPERTY, resultName); - } - - if (scalarResultIndex == cvf::UNDEFINED_SIZE_T) - { - scalarResultIndex = this->findScalarResultIndex(RiaDefines::FORMATION_NAMES, resultName); - } + size_t scalarResultIndex = findScalarResultIndexFromAddress(resVarAddr); + CVF_TIGHT_ASSERT(scalarResultIndex < resultCount()); + CVF_TIGHT_ASSERT(timeStepIndex < m_cellScalarResults[scalarResultIndex].size()); - return scalarResultIndex; + return m_cellScalarResults[scalarResultIndex][timeStepIndex]; } //-------------------------------------------------------------------------------------------------- /// Adds an empty scalar set, and returns the scalarResultIndex to it. /// if resultName already exists, it just returns the scalarResultIndex to the existing result. //-------------------------------------------------------------------------------------------------- -size_t RigCaseCellResultsData::findOrCreateScalarResultIndex(RiaDefines::ResultCatType type, - const QString& resultName, +size_t RigCaseCellResultsData::findOrCreateScalarResultIndex(const RigEclipseResultAddress& resVarAddr, bool needsToBeStored) { - size_t scalarResultIndex = this->findScalarResultIndex(type, resultName); + size_t scalarResultIndex = this->findScalarResultIndexFromAddress(resVarAddr); // If the result exists, do nothing @@ -316,11 +285,15 @@ size_t RigCaseCellResultsData::findOrCreateScalarResultIndex(RiaDefines::ResultC scalarResultIndex = this->resultCount(); m_cellScalarResults.push_back(std::vector>()); - RigEclipseResultInfo resInfo(type, resultName, needsToBeStored, false, scalarResultIndex); + + RigEclipseResultInfo resInfo(resVarAddr, needsToBeStored, false, scalarResultIndex); + m_resultInfos.push_back(resInfo); // Create statistics calculator and add statistics cache object // Todo: Move to a "factory" method + + QString resultName = resVarAddr.m_resultName; cvf::ref statisticsCalculator; @@ -328,9 +301,9 @@ size_t RigCaseCellResultsData::findOrCreateScalarResultIndex(RiaDefines::ResultC { cvf::ref calc = new RigEclipseMultiPropertyStatCalc(); - calc->addNativeStatisticsCalculator(this, findScalarResultIndex(RiaDefines::STATIC_NATIVE, "TRANX")); - calc->addNativeStatisticsCalculator(this, findScalarResultIndex(RiaDefines::STATIC_NATIVE, "TRANY")); - calc->addNativeStatisticsCalculator(this, findScalarResultIndex(RiaDefines::STATIC_NATIVE, "TRANZ")); + calc->addNativeStatisticsCalculator(this, RigEclipseResultAddress(RiaDefines::STATIC_NATIVE, "TRANX")); + calc->addNativeStatisticsCalculator(this, RigEclipseResultAddress(RiaDefines::STATIC_NATIVE, "TRANY")); + calc->addNativeStatisticsCalculator(this, RigEclipseResultAddress(RiaDefines::STATIC_NATIVE, "TRANZ")); statisticsCalculator = calc; } @@ -338,12 +311,12 @@ size_t RigCaseCellResultsData::findOrCreateScalarResultIndex(RiaDefines::ResultC { cvf::ref calc = new RigEclipseMultiPropertyStatCalc(); - calc->addNativeStatisticsCalculator(this, findScalarResultIndex(RiaDefines::STATIC_NATIVE, "MULTX")); - calc->addNativeStatisticsCalculator(this, findScalarResultIndex(RiaDefines::STATIC_NATIVE, "MULTX-")); - calc->addNativeStatisticsCalculator(this, findScalarResultIndex(RiaDefines::STATIC_NATIVE, "MULTY")); - calc->addNativeStatisticsCalculator(this, findScalarResultIndex(RiaDefines::STATIC_NATIVE, "MULTY-")); - calc->addNativeStatisticsCalculator(this, findScalarResultIndex(RiaDefines::STATIC_NATIVE, "MULTZ")); - calc->addNativeStatisticsCalculator(this, findScalarResultIndex(RiaDefines::STATIC_NATIVE, "MULTZ-")); + calc->addNativeStatisticsCalculator(this, RigEclipseResultAddress(RiaDefines::STATIC_NATIVE, "MULTX")); + calc->addNativeStatisticsCalculator(this, RigEclipseResultAddress(RiaDefines::STATIC_NATIVE, "MULTX-")); + calc->addNativeStatisticsCalculator(this, RigEclipseResultAddress(RiaDefines::STATIC_NATIVE, "MULTY")); + calc->addNativeStatisticsCalculator(this, RigEclipseResultAddress(RiaDefines::STATIC_NATIVE, "MULTY-")); + calc->addNativeStatisticsCalculator(this, RigEclipseResultAddress(RiaDefines::STATIC_NATIVE, "MULTZ")); + calc->addNativeStatisticsCalculator(this, RigEclipseResultAddress(RiaDefines::STATIC_NATIVE, "MULTZ-")); statisticsCalculator = calc; } @@ -351,71 +324,71 @@ size_t RigCaseCellResultsData::findOrCreateScalarResultIndex(RiaDefines::ResultC { cvf::ref calc = new RigEclipseMultiPropertyStatCalc(); calc->addNativeStatisticsCalculator(this, - findScalarResultIndex(RiaDefines::STATIC_NATIVE, RiaDefines::riTranXResultName())); + RigEclipseResultAddress(RiaDefines::STATIC_NATIVE, RiaDefines::riTranXResultName())); calc->addNativeStatisticsCalculator(this, - findScalarResultIndex(RiaDefines::STATIC_NATIVE, RiaDefines::riTranYResultName())); + RigEclipseResultAddress(RiaDefines::STATIC_NATIVE, RiaDefines::riTranYResultName())); calc->addNativeStatisticsCalculator(this, - findScalarResultIndex(RiaDefines::STATIC_NATIVE, RiaDefines::riTranZResultName())); + RigEclipseResultAddress(RiaDefines::STATIC_NATIVE, RiaDefines::riTranZResultName())); statisticsCalculator = calc; } else if (resultName == RiaDefines::combinedRiMultResultName()) { cvf::ref calc = new RigEclipseMultiPropertyStatCalc(); calc->addNativeStatisticsCalculator(this, - findScalarResultIndex(RiaDefines::STATIC_NATIVE, RiaDefines::riMultXResultName())); + RigEclipseResultAddress(RiaDefines::STATIC_NATIVE, RiaDefines::riMultXResultName())); calc->addNativeStatisticsCalculator(this, - findScalarResultIndex(RiaDefines::STATIC_NATIVE, RiaDefines::riMultYResultName())); + RigEclipseResultAddress(RiaDefines::STATIC_NATIVE, RiaDefines::riMultYResultName())); calc->addNativeStatisticsCalculator(this, - findScalarResultIndex(RiaDefines::STATIC_NATIVE, RiaDefines::riMultZResultName())); + RigEclipseResultAddress(RiaDefines::STATIC_NATIVE, RiaDefines::riMultZResultName())); statisticsCalculator = calc; } else if (resultName == RiaDefines::combinedRiAreaNormTranResultName()) { cvf::ref calc = new RigEclipseMultiPropertyStatCalc(); calc->addNativeStatisticsCalculator( - this, findScalarResultIndex(RiaDefines::STATIC_NATIVE, RiaDefines::riAreaNormTranXResultName())); + this, RigEclipseResultAddress(RiaDefines::STATIC_NATIVE, RiaDefines::riAreaNormTranXResultName())); calc->addNativeStatisticsCalculator( - this, findScalarResultIndex(RiaDefines::STATIC_NATIVE, RiaDefines::riAreaNormTranYResultName())); + this, RigEclipseResultAddress(RiaDefines::STATIC_NATIVE, RiaDefines::riAreaNormTranYResultName())); calc->addNativeStatisticsCalculator( - this, findScalarResultIndex(RiaDefines::STATIC_NATIVE, RiaDefines::riAreaNormTranZResultName())); + this, RigEclipseResultAddress(RiaDefines::STATIC_NATIVE, RiaDefines::riAreaNormTranZResultName())); statisticsCalculator = calc; } else if (resultName == RiaDefines::combinedWaterFluxResultName()) { cvf::ref calc = new RigEclipseMultiPropertyStatCalc(); - calc->addNativeStatisticsCalculator(this, findScalarResultIndex(RiaDefines::DYNAMIC_NATIVE, "FLRWATI+")); - calc->addNativeStatisticsCalculator(this, findScalarResultIndex(RiaDefines::DYNAMIC_NATIVE, "FLRWATJ+")); - calc->addNativeStatisticsCalculator(this, findScalarResultIndex(RiaDefines::DYNAMIC_NATIVE, "FLRWATK+")); + calc->addNativeStatisticsCalculator(this, RigEclipseResultAddress(RiaDefines::DYNAMIC_NATIVE, "FLRWATI+")); + calc->addNativeStatisticsCalculator(this, RigEclipseResultAddress(RiaDefines::DYNAMIC_NATIVE, "FLRWATJ+")); + calc->addNativeStatisticsCalculator(this, RigEclipseResultAddress(RiaDefines::DYNAMIC_NATIVE, "FLRWATK+")); statisticsCalculator = calc; } else if (resultName == RiaDefines::combinedOilFluxResultName()) { cvf::ref calc = new RigEclipseMultiPropertyStatCalc(); - calc->addNativeStatisticsCalculator(this, findScalarResultIndex(RiaDefines::DYNAMIC_NATIVE, "FLROILI+")); - calc->addNativeStatisticsCalculator(this, findScalarResultIndex(RiaDefines::DYNAMIC_NATIVE, "FLROILJ+")); - calc->addNativeStatisticsCalculator(this, findScalarResultIndex(RiaDefines::DYNAMIC_NATIVE, "FLROILK+")); + calc->addNativeStatisticsCalculator(this, RigEclipseResultAddress(RiaDefines::DYNAMIC_NATIVE, "FLROILI+")); + calc->addNativeStatisticsCalculator(this, RigEclipseResultAddress(RiaDefines::DYNAMIC_NATIVE, "FLROILJ+")); + calc->addNativeStatisticsCalculator(this, RigEclipseResultAddress(RiaDefines::DYNAMIC_NATIVE, "FLROILK+")); statisticsCalculator = calc; } else if (resultName == RiaDefines::combinedGasFluxResultName()) { cvf::ref calc = new RigEclipseMultiPropertyStatCalc(); - calc->addNativeStatisticsCalculator(this, findScalarResultIndex(RiaDefines::DYNAMIC_NATIVE, "FLRGASI+")); - calc->addNativeStatisticsCalculator(this, findScalarResultIndex(RiaDefines::DYNAMIC_NATIVE, "FLRGASJ+")); - calc->addNativeStatisticsCalculator(this, findScalarResultIndex(RiaDefines::DYNAMIC_NATIVE, "FLRGASK+")); + calc->addNativeStatisticsCalculator(this, RigEclipseResultAddress(RiaDefines::DYNAMIC_NATIVE, "FLRGASI+")); + calc->addNativeStatisticsCalculator(this, RigEclipseResultAddress(RiaDefines::DYNAMIC_NATIVE, "FLRGASJ+")); + calc->addNativeStatisticsCalculator(this, RigEclipseResultAddress(RiaDefines::DYNAMIC_NATIVE, "FLRGASK+")); statisticsCalculator = calc; } else if (resultName.endsWith("IJK")) { cvf::ref calc = new RigEclipseMultiPropertyStatCalc(); QString baseName = resultName.left(resultName.size() - 3); - calc->addNativeStatisticsCalculator(this, findScalarResultIndex(RiaDefines::GENERATED, QString("%1I").arg(baseName))); - calc->addNativeStatisticsCalculator(this, findScalarResultIndex(RiaDefines::GENERATED, QString("%1J").arg(baseName))); - calc->addNativeStatisticsCalculator(this, findScalarResultIndex(RiaDefines::GENERATED, QString("%1K").arg(baseName))); + calc->addNativeStatisticsCalculator(this, RigEclipseResultAddress(RiaDefines::GENERATED, QString("%1I").arg(baseName))); + calc->addNativeStatisticsCalculator(this, RigEclipseResultAddress(RiaDefines::GENERATED, QString("%1J").arg(baseName))); + calc->addNativeStatisticsCalculator(this, RigEclipseResultAddress(RiaDefines::GENERATED, QString("%1K").arg(baseName))); statisticsCalculator = calc; } else { - statisticsCalculator = new RigEclipseNativeStatCalc(this, scalarResultIndex); + statisticsCalculator = new RigEclipseNativeStatCalc(this, resVarAddr); } cvf::ref dataCache = new RigStatisticsDataCache(statisticsCalculator.p()); @@ -429,11 +402,13 @@ size_t RigCaseCellResultsData::findOrCreateScalarResultIndex(RiaDefines::ResultC //-------------------------------------------------------------------------------------------------- QStringList RigCaseCellResultsData::resultNames(RiaDefines::ResultCatType resType) const { - QStringList varList; + QStringList varList; std::vector::const_iterator it; for (it = m_resultInfos.begin(); it != m_resultInfos.end(); ++it) { - if (it->resultType() == resType) + if (it->resultType() == resType && + !it->eclipseResultAddress().isTimeLapse() && + !it->eclipseResultAddress().hasDifferenceCase()) { varList.push_back(it->resultName()); } @@ -460,16 +435,17 @@ const RigActiveCellInfo* RigCaseCellResultsData::activeCellInfo() const //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RigCaseCellResultsData::recalculateStatistics(size_t scalarResultIndex) +void RigCaseCellResultsData::recalculateStatistics(const RigEclipseResultAddress& resVarAddr) { - m_statisticsDataCache[scalarResultIndex]->clearAllStatistics(); + m_statisticsDataCache[findScalarResultIndexFromAddress(resVarAddr)]->clearAllStatistics(); } //-------------------------------------------------------------------------------------------------- /// Returns whether the result data in question is addressed by Active Cell Index //-------------------------------------------------------------------------------------------------- -bool RigCaseCellResultsData::isUsingGlobalActiveIndex(size_t scalarResultIndex) const +bool RigCaseCellResultsData::isUsingGlobalActiveIndex(const RigEclipseResultAddress& resVarAddr) const { + size_t scalarResultIndex = findScalarResultIndexFromAddress(resVarAddr); CVF_TIGHT_ASSERT(scalarResultIndex < m_cellScalarResults.size()); if (!m_cellScalarResults[scalarResultIndex].size()) return true; @@ -513,11 +489,11 @@ std::vector RigCaseCellResultsData::allTimeStepDatesFromEclipseReader //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -std::vector RigCaseCellResultsData::timeStepDates(size_t scalarResultIndex) const +std::vector RigCaseCellResultsData::timeStepDates(const RigEclipseResultAddress& resVarAddr) const { - if (scalarResultIndex < m_resultInfos.size()) + if (findScalarResultIndexFromAddress(resVarAddr) < m_resultInfos.size()) { - return m_resultInfos[scalarResultIndex].dates(); + return m_resultInfos[findScalarResultIndexFromAddress(resVarAddr)].dates(); } else return std::vector(); @@ -528,7 +504,7 @@ std::vector RigCaseCellResultsData::timeStepDates(size_t scalarResult //-------------------------------------------------------------------------------------------------- std::vector RigCaseCellResultsData::timeStepDates() const { - size_t scalarResWithMostTimeSteps = cvf::UNDEFINED_SIZE_T; + RigEclipseResultAddress scalarResWithMostTimeSteps; maxTimeStepCount(&scalarResWithMostTimeSteps); return timeStepDates(scalarResWithMostTimeSteps); @@ -539,7 +515,7 @@ std::vector RigCaseCellResultsData::timeStepDates() const //-------------------------------------------------------------------------------------------------- std::vector RigCaseCellResultsData::daysSinceSimulationStart() const { - size_t scalarResWithMostTimeSteps = cvf::UNDEFINED_SIZE_T; + RigEclipseResultAddress scalarResWithMostTimeSteps; maxTimeStepCount(&scalarResWithMostTimeSteps); return daysSinceSimulationStart(scalarResWithMostTimeSteps); @@ -548,11 +524,11 @@ std::vector RigCaseCellResultsData::daysSinceSimulationStart() const //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -std::vector RigCaseCellResultsData::daysSinceSimulationStart(size_t scalarResultIndex) const +std::vector RigCaseCellResultsData::daysSinceSimulationStart(const RigEclipseResultAddress& resVarAddr) const { - if (scalarResultIndex < m_resultInfos.size()) + if (findScalarResultIndexFromAddress(resVarAddr) < m_resultInfos.size()) { - return m_resultInfos[scalarResultIndex].daysSinceSimulationStarts(); + return m_resultInfos[findScalarResultIndexFromAddress(resVarAddr)].daysSinceSimulationStarts(); } else { @@ -563,10 +539,10 @@ std::vector RigCaseCellResultsData::daysSinceSimulationStart(size_t scal //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -int RigCaseCellResultsData::reportStepNumber(size_t scalarResultIndex, size_t timeStepIndex) const +int RigCaseCellResultsData::reportStepNumber(const RigEclipseResultAddress& resVarAddr, size_t timeStepIndex) const { - if (scalarResultIndex < m_resultInfos.size() && m_resultInfos[scalarResultIndex].timeStepInfos().size() > timeStepIndex) - return m_resultInfos[scalarResultIndex].timeStepInfos()[timeStepIndex].m_reportNumber; + if (findScalarResultIndexFromAddress(resVarAddr) < m_resultInfos.size() && m_resultInfos[findScalarResultIndexFromAddress(resVarAddr)].timeStepInfos().size() > timeStepIndex) + return m_resultInfos[findScalarResultIndexFromAddress(resVarAddr)].timeStepInfos()[timeStepIndex].m_reportNumber; else return -1; } @@ -574,10 +550,10 @@ int RigCaseCellResultsData::reportStepNumber(size_t scalarResultIndex, size_t ti //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -std::vector RigCaseCellResultsData::timeStepInfos(size_t scalarResultIndex) const +std::vector RigCaseCellResultsData::timeStepInfos(const RigEclipseResultAddress& resVarAddr) const { - if (scalarResultIndex < m_resultInfos.size()) - return m_resultInfos[scalarResultIndex].timeStepInfos(); + if (findScalarResultIndexFromAddress(resVarAddr) < m_resultInfos.size()) + return m_resultInfos[findScalarResultIndexFromAddress(resVarAddr)].timeStepInfos(); else return std::vector(); } @@ -585,36 +561,35 @@ std::vector RigCaseCellResultsData::timeStepInfos(size_t //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RigCaseCellResultsData::setTimeStepInfos(size_t scalarResultIndex, const std::vector& timeStepInfos) +void RigCaseCellResultsData::setTimeStepInfos(const RigEclipseResultAddress& resVarAddr, const std::vector& timeStepInfos) { - CVF_ASSERT(scalarResultIndex < m_resultInfos.size()); + CVF_ASSERT(findScalarResultIndexFromAddress(resVarAddr) < m_resultInfos.size()); - m_resultInfos[scalarResultIndex].setTimeStepInfos(timeStepInfos); + m_resultInfos[findScalarResultIndexFromAddress(resVarAddr)].setTimeStepInfos(timeStepInfos); - std::vector>& dataValues = this->cellScalarResults(scalarResultIndex); + std::vector>& dataValues = this->modifiableCellScalarResultTimesteps(resVarAddr); dataValues.resize(timeStepInfos.size()); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -size_t RigCaseCellResultsData::maxTimeStepCount(size_t* scalarResultIndexWithMostTimeSteps) const +size_t RigCaseCellResultsData::maxTimeStepCount(RigEclipseResultAddress* resultAddressWithMostTimeSteps) const { - size_t maxTsCount = 0; - size_t scalarResultIndexWithMaxTsCount = cvf::UNDEFINED_SIZE_T; + size_t maxTsCount = 0; + RigEclipseResultAddress scalarResultIndexWithMaxTsCount; for (size_t i = 0; i < m_resultInfos.size(); i++) { if (m_resultInfos[i].timeStepInfos().size() > maxTsCount) { - maxTsCount = m_resultInfos[i].timeStepInfos().size(); - scalarResultIndexWithMaxTsCount = i; - } - } + maxTsCount = m_resultInfos[i].timeStepInfos().size(); - if (scalarResultIndexWithMostTimeSteps) - { - *scalarResultIndexWithMostTimeSteps = scalarResultIndexWithMaxTsCount; + if (resultAddressWithMostTimeSteps) + { + *resultAddressWithMostTimeSteps = m_resultInfos[i].eclipseResultAddress(); + } + } } return maxTsCount; @@ -626,13 +601,11 @@ size_t RigCaseCellResultsData::maxTimeStepCount(size_t* scalarResultIndexWithMos QString RigCaseCellResultsData::makeResultNameUnique(const QString& resultNameProposal) const { QString newResultName = resultNameProposal; - size_t resultIndex = cvf::UNDEFINED_SIZE_T; int nameNum = 1; int stringLength = newResultName.size(); while (true) { - resultIndex = this->findScalarResultIndex(newResultName); - if (resultIndex == cvf::UNDEFINED_SIZE_T) break; + if( !this->hasResultEntry(RigEclipseResultAddress(newResultName))) break; newResultName.truncate(stringLength); newResultName += "_" + QString::number(nameNum); @@ -647,7 +620,16 @@ QString RigCaseCellResultsData::makeResultNameUnique(const QString& resultNamePr //-------------------------------------------------------------------------------------------------- void RigCaseCellResultsData::clearScalarResult(RiaDefines::ResultCatType type, const QString& resultName) { - size_t scalarResultIndex = this->findScalarResultIndex(type, resultName); + clearScalarResult(RigEclipseResultAddress(type, resultName)); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RigCaseCellResultsData::clearScalarResult(const RigEclipseResultAddress& resultAddress) +{ + size_t scalarResultIndex = findScalarResultIndexFromAddress(resultAddress); + if (scalarResultIndex == cvf::UNDEFINED_SIZE_T) return; for (size_t tsIdx = 0; tsIdx < m_cellScalarResults[scalarResultIndex].size(); ++tsIdx) @@ -656,15 +638,7 @@ void RigCaseCellResultsData::clearScalarResult(RiaDefines::ResultCatType type, c m_cellScalarResults[scalarResultIndex][tsIdx].swap(empty); } - recalculateStatistics(scalarResultIndex); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RigCaseCellResultsData::clearScalarResult(const RigEclipseResultInfo& resultInfo) -{ - clearScalarResult(resultInfo.resultType(), resultInfo.resultName()); + recalculateStatistics(resultAddress); } //-------------------------------------------------------------------------------------------------- @@ -697,9 +671,10 @@ void RigCaseCellResultsData::freeAllocatedResultsData() //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -bool RigCaseCellResultsData::isResultLoaded(const RigEclipseResultInfo& resultInfo) const +bool RigCaseCellResultsData::isResultLoaded(const RigEclipseResultAddress& resultAddr) const { - size_t scalarResultIndex = this->findScalarResultIndex(resultInfo.resultType(), resultInfo.resultName()); + size_t scalarResultIndex = findScalarResultIndexFromAddress(resultAddr); + CVF_TIGHT_ASSERT(scalarResultIndex != cvf::UNDEFINED_SIZE_T); if (scalarResultIndex != cvf::UNDEFINED_SIZE_T) { @@ -717,7 +692,7 @@ size_t RigCaseCellResultsData::addStaticScalarResult(RiaDefines::ResultCatType t bool needsToBeStored, size_t resultValueCount) { - size_t resultIdx = findOrCreateScalarResultIndex(type, resultName, needsToBeStored); + size_t resultIdx = findOrCreateScalarResultIndex(RigEclipseResultAddress(type, resultName), needsToBeStored); m_cellScalarResults[resultIdx].resize(1, std::vector()); m_cellScalarResults[resultIdx][0].resize(resultValueCount, HUGE_VAL); @@ -750,19 +725,20 @@ bool RigCaseCellResultsData::updateResultName(RiaDefines::ResultCatType resultTy const std::vector* RigCaseCellResultsData::getResultIndexableStaticResult(RigActiveCellInfo* actCellInfo, RigCaseCellResultsData* gridCellResults, - QString porvResultName, + QString resultName, std::vector& activeCellsResultsTempContainer) { size_t resultCellCount = actCellInfo->reservoirCellResultCount(); size_t reservoirCellCount = actCellInfo->reservoirCellCount(); + RigEclipseResultAddress resVarAddr(RiaDefines::STATIC_NATIVE, resultName); - size_t scalarResultIndexPorv = gridCellResults->findOrLoadScalarResult(RiaDefines::STATIC_NATIVE, porvResultName); + size_t scalarResultIndexPorv = gridCellResults->findOrLoadKnownScalarResult(resVarAddr); if (scalarResultIndexPorv == cvf::UNDEFINED_SIZE_T) return nullptr; - const std::vector* porvResults = &(gridCellResults->cellScalarResults(scalarResultIndexPorv, 0)); + const std::vector* porvResults = &(gridCellResults->cellScalarResults(resVarAddr, 0)); - if (!gridCellResults->isUsingGlobalActiveIndex(scalarResultIndexPorv)) + if (!gridCellResults->isUsingGlobalActiveIndex(resVarAddr)) { // PORV is given for all cells @@ -846,15 +822,12 @@ void RigCaseCellResultsData::createPlaceholderResultEntries() { // SOIL { - size_t soilIndex = findScalarResultIndex(RiaDefines::DYNAMIC_NATIVE, "SOIL"); - if (soilIndex == cvf::UNDEFINED_SIZE_T) + if (!hasResultEntry(RigEclipseResultAddress(RiaDefines::DYNAMIC_NATIVE, "SOIL"))) { - size_t swatIndex = findScalarResultIndex(RiaDefines::DYNAMIC_NATIVE, "SWAT"); - size_t sgasIndex = findScalarResultIndex(RiaDefines::DYNAMIC_NATIVE, "SGAS"); - - if (swatIndex != cvf::UNDEFINED_SIZE_T || sgasIndex != cvf::UNDEFINED_SIZE_T) + if ( hasResultEntry(RigEclipseResultAddress(RiaDefines::DYNAMIC_NATIVE, "SWAT")) + || hasResultEntry(RigEclipseResultAddress(RiaDefines::DYNAMIC_NATIVE, "SGAS")) ) { - soilIndex = findOrCreateScalarResultIndex(RiaDefines::DYNAMIC_NATIVE, "SOIL", false); + size_t soilIndex = findOrCreateScalarResultIndex(RigEclipseResultAddress(RiaDefines::DYNAMIC_NATIVE, "SOIL"), false); this->setMustBeCalculated(soilIndex); } } @@ -863,68 +836,67 @@ void RigCaseCellResultsData::createPlaceholderResultEntries() // Oil Volume if (RiaApplication::enableDevelopmentFeatures()) { - size_t soilIndex = findOrCreateScalarResultIndex(RiaDefines::DYNAMIC_NATIVE, "SOIL", false); - if (soilIndex != cvf::UNDEFINED_SIZE_T) + if (hasResultEntry(RigEclipseResultAddress(RiaDefines::DYNAMIC_NATIVE, "SOIL"))) { - findOrCreateScalarResultIndex(RiaDefines::DYNAMIC_NATIVE, RiaDefines::riOilVolumeResultName(), false); + findOrCreateScalarResultIndex(RigEclipseResultAddress(RiaDefines::DYNAMIC_NATIVE, RiaDefines::riOilVolumeResultName()), false); } } // Completion type { - size_t completionTypeIndex = findScalarResultIndex(RiaDefines::DYNAMIC_NATIVE, RiaDefines::completionTypeResultName()); - if (completionTypeIndex == cvf::UNDEFINED_SIZE_T) - { - findOrCreateScalarResultIndex(RiaDefines::DYNAMIC_NATIVE, RiaDefines::completionTypeResultName(), false); - } + findOrCreateScalarResultIndex(RigEclipseResultAddress (RiaDefines::DYNAMIC_NATIVE, RiaDefines::completionTypeResultName()), false); } // FLUX { - size_t waterIndex = findScalarResultIndex(RiaDefines::DYNAMIC_NATIVE, RiaDefines::combinedWaterFluxResultName()); - if (waterIndex == cvf::UNDEFINED_SIZE_T && - findScalarResultIndex(RiaDefines::DYNAMIC_NATIVE, "FLRWATI+") != cvf::UNDEFINED_SIZE_T && - findScalarResultIndex(RiaDefines::DYNAMIC_NATIVE, "FLRWATJ+") != cvf::UNDEFINED_SIZE_T && - findScalarResultIndex(RiaDefines::DYNAMIC_NATIVE, "FLRWATK+") != cvf::UNDEFINED_SIZE_T) + if ( hasResultEntry(RigEclipseResultAddress(RiaDefines::DYNAMIC_NATIVE, "FLRWATI+")) + && hasResultEntry(RigEclipseResultAddress(RiaDefines::DYNAMIC_NATIVE, "FLRWATJ+")) + && hasResultEntry(RigEclipseResultAddress(RiaDefines::DYNAMIC_NATIVE, "FLRWATK+"))) { - findOrCreateScalarResultIndex(RiaDefines::DYNAMIC_NATIVE, RiaDefines::combinedWaterFluxResultName(), false); + findOrCreateScalarResultIndex(RigEclipseResultAddress(RiaDefines::DYNAMIC_NATIVE, RiaDefines::combinedWaterFluxResultName()), false); } - size_t oilIndex = findScalarResultIndex(RiaDefines::DYNAMIC_NATIVE, RiaDefines::combinedOilFluxResultName()); - if (oilIndex == cvf::UNDEFINED_SIZE_T && - findScalarResultIndex(RiaDefines::DYNAMIC_NATIVE, "FLROILI+") != cvf::UNDEFINED_SIZE_T && - findScalarResultIndex(RiaDefines::DYNAMIC_NATIVE, "FLROILJ+") != cvf::UNDEFINED_SIZE_T && - findScalarResultIndex(RiaDefines::DYNAMIC_NATIVE, "FLROILK+") != cvf::UNDEFINED_SIZE_T) + + if ( hasResultEntry(RigEclipseResultAddress(RiaDefines::DYNAMIC_NATIVE, "FLROILI+")) + && hasResultEntry(RigEclipseResultAddress(RiaDefines::DYNAMIC_NATIVE, "FLROILJ+")) + && hasResultEntry(RigEclipseResultAddress(RiaDefines::DYNAMIC_NATIVE, "FLROILK+"))) { - findOrCreateScalarResultIndex(RiaDefines::DYNAMIC_NATIVE, RiaDefines::combinedOilFluxResultName(), false); + findOrCreateScalarResultIndex(RigEclipseResultAddress(RiaDefines::DYNAMIC_NATIVE, RiaDefines::combinedOilFluxResultName()), false); } - size_t gasIndex = findScalarResultIndex(RiaDefines::DYNAMIC_NATIVE, RiaDefines::combinedGasFluxResultName()); - if (gasIndex == cvf::UNDEFINED_SIZE_T && - findScalarResultIndex(RiaDefines::DYNAMIC_NATIVE, "FLRGASI+") != cvf::UNDEFINED_SIZE_T && - findScalarResultIndex(RiaDefines::DYNAMIC_NATIVE, "FLRGASJ+") != cvf::UNDEFINED_SIZE_T && - findScalarResultIndex(RiaDefines::DYNAMIC_NATIVE, "FLRGASK+") != cvf::UNDEFINED_SIZE_T) + + if ( + hasResultEntry(RigEclipseResultAddress(RiaDefines::DYNAMIC_NATIVE, "FLRGASI+")) + && hasResultEntry(RigEclipseResultAddress(RiaDefines::DYNAMIC_NATIVE, "FLRGASJ+")) + && hasResultEntry(RigEclipseResultAddress(RiaDefines::DYNAMIC_NATIVE, "FLRGASK+"))) { - findOrCreateScalarResultIndex(RiaDefines::DYNAMIC_NATIVE, RiaDefines::combinedGasFluxResultName(), false); + findOrCreateScalarResultIndex(RigEclipseResultAddress(RiaDefines::DYNAMIC_NATIVE, RiaDefines::combinedGasFluxResultName()), false); } } // TRANSXYZ { - size_t tranX, tranY, tranZ; - if (findTransmissibilityResults(tranX, tranY, tranZ)) + if (hasCompleteTransmissibilityResults()) { addStaticScalarResult(RiaDefines::STATIC_NATIVE, RiaDefines::combinedTransmissibilityResultName(), false, 0); } } // MULTXYZ { - addStaticScalarResult(RiaDefines::STATIC_NATIVE, RiaDefines::combinedMultResultName(), false, 0); + if (hasResultEntry(RigEclipseResultAddress(RiaDefines::STATIC_NATIVE, "MULTX")) && + hasResultEntry(RigEclipseResultAddress(RiaDefines::STATIC_NATIVE, "MULTX-")) && + hasResultEntry(RigEclipseResultAddress(RiaDefines::STATIC_NATIVE, "MULTY")) && + hasResultEntry(RigEclipseResultAddress(RiaDefines::STATIC_NATIVE, "MULTY-")) && + hasResultEntry(RigEclipseResultAddress(RiaDefines::STATIC_NATIVE, "MULTZ")) && + hasResultEntry(RigEclipseResultAddress(RiaDefines::STATIC_NATIVE, "MULTZ-"))) + { + addStaticScalarResult(RiaDefines::STATIC_NATIVE, RiaDefines::combinedMultResultName(), false, 0); + } } // riTRANSXYZ and X,Y,Z { - if (findScalarResultIndex(RiaDefines::STATIC_NATIVE, "PERMX") != cvf::UNDEFINED_SIZE_T && - findScalarResultIndex(RiaDefines::STATIC_NATIVE, "PERMY") != cvf::UNDEFINED_SIZE_T && - findScalarResultIndex(RiaDefines::STATIC_NATIVE, "PERMZ") != cvf::UNDEFINED_SIZE_T) + if (hasResultEntry(RigEclipseResultAddress(RiaDefines::STATIC_NATIVE, "PERMX")) && + hasResultEntry(RigEclipseResultAddress(RiaDefines::STATIC_NATIVE, "PERMY")) && + hasResultEntry(RigEclipseResultAddress(RiaDefines::STATIC_NATIVE, "PERMZ"))) { addStaticScalarResult(RiaDefines::STATIC_NATIVE, RiaDefines::riTranXResultName(), false, 0); addStaticScalarResult(RiaDefines::STATIC_NATIVE, RiaDefines::riTranYResultName(), false, 0); @@ -935,11 +907,11 @@ void RigCaseCellResultsData::createPlaceholderResultEntries() // riMULTXYZ and X, Y, Z { - size_t tranX, tranY, tranZ; - if (findTransmissibilityResults(tranX, tranY, tranZ) && - findScalarResultIndex(RiaDefines::STATIC_NATIVE, RiaDefines::riTranXResultName()) != cvf::UNDEFINED_SIZE_T && - findScalarResultIndex(RiaDefines::STATIC_NATIVE, RiaDefines::riTranYResultName()) != cvf::UNDEFINED_SIZE_T && - findScalarResultIndex(RiaDefines::STATIC_NATIVE, RiaDefines::riTranZResultName()) != cvf::UNDEFINED_SIZE_T) + + if (hasCompleteTransmissibilityResults() && + hasResultEntry(RigEclipseResultAddress(RiaDefines::STATIC_NATIVE, RiaDefines::riTranXResultName())) && + hasResultEntry(RigEclipseResultAddress(RiaDefines::STATIC_NATIVE, RiaDefines::riTranYResultName())) && + hasResultEntry(RigEclipseResultAddress(RiaDefines::STATIC_NATIVE, RiaDefines::riTranZResultName()))) { addStaticScalarResult(RiaDefines::STATIC_NATIVE, RiaDefines::riMultXResultName(), false, 0); addStaticScalarResult(RiaDefines::STATIC_NATIVE, RiaDefines::riMultYResultName(), false, 0); @@ -950,23 +922,22 @@ void RigCaseCellResultsData::createPlaceholderResultEntries() // riTRANSXYZbyArea and X, Y, Z { - if (findScalarResultIndex(RiaDefines::STATIC_NATIVE, "TRANX") != cvf::UNDEFINED_SIZE_T) + if (hasResultEntry(RigEclipseResultAddress(RiaDefines::STATIC_NATIVE, "TRANX"))) { addStaticScalarResult(RiaDefines::STATIC_NATIVE, RiaDefines::riAreaNormTranXResultName(), false, 0); } - if (findScalarResultIndex(RiaDefines::STATIC_NATIVE, "TRANY") != cvf::UNDEFINED_SIZE_T) + if (hasResultEntry(RigEclipseResultAddress(RiaDefines::STATIC_NATIVE, "TRANY"))) { addStaticScalarResult(RiaDefines::STATIC_NATIVE, RiaDefines::riAreaNormTranYResultName(), false, 0); } - if (findScalarResultIndex(RiaDefines::STATIC_NATIVE, "TRANZ") != cvf::UNDEFINED_SIZE_T) + if (hasResultEntry(RigEclipseResultAddress(RiaDefines::STATIC_NATIVE, "TRANZ"))) { addStaticScalarResult(RiaDefines::STATIC_NATIVE, RiaDefines::riAreaNormTranZResultName(), false, 0); } - size_t tranX, tranY, tranZ; - if (findTransmissibilityResults(tranX, tranY, tranZ)) + if (hasCompleteTransmissibilityResults()) { addStaticScalarResult(RiaDefines::STATIC_NATIVE, RiaDefines::combinedRiAreaNormTranResultName(), false, 0); } @@ -979,7 +950,7 @@ void RigCaseCellResultsData::createPlaceholderResultEntries() // Mobile Pore Volume { - if (findScalarResultIndex(RiaDefines::STATIC_NATIVE, "PORV") != cvf::UNDEFINED_SIZE_T) + if (hasResultEntry(RigEclipseResultAddress(RiaDefines::STATIC_NATIVE, "PORV")) ) { addStaticScalarResult(RiaDefines::STATIC_NATIVE, RiaDefines::mobilePoreVolumeName(), false, 0); } @@ -989,76 +960,166 @@ void RigCaseCellResultsData::createPlaceholderResultEntries() //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -bool RigCaseCellResultsData::findTransmissibilityResults(size_t& tranX, size_t& tranY, size_t& tranZ) const +bool RigCaseCellResultsData::hasCompleteTransmissibilityResults() const { - tranX = findScalarResultIndex(RiaDefines::STATIC_NATIVE, "TRANX"); - tranY = findScalarResultIndex(RiaDefines::STATIC_NATIVE, "TRANY"); - tranZ = findScalarResultIndex(RiaDefines::STATIC_NATIVE, "TRANZ"); - - if (tranX == cvf::UNDEFINED_SIZE_T || tranY == cvf::UNDEFINED_SIZE_T || tranZ == cvf::UNDEFINED_SIZE_T) + if ( hasResultEntry(RigEclipseResultAddress(RiaDefines::STATIC_NATIVE, "TRANX")) + && hasResultEntry(RigEclipseResultAddress(RiaDefines::STATIC_NATIVE, "TRANY")) + && hasResultEntry(RigEclipseResultAddress(RiaDefines::STATIC_NATIVE, "TRANZ"))) { - return false; + return true; } - return true; + return false; } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- -size_t RigCaseCellResultsData::findOrLoadScalarResult(const QString& resultName) +std::vector RigCaseCellResultsData::existingResults() const { - size_t scalarResultIndex = this->findOrLoadScalarResult(RiaDefines::STATIC_NATIVE, resultName); - - if (scalarResultIndex == cvf::UNDEFINED_SIZE_T) + std::vector addresses; + for (const auto & ri: m_resultInfos) { - scalarResultIndex = this->findOrLoadScalarResult(RiaDefines::DYNAMIC_NATIVE, resultName); + addresses.emplace_back(ri.eclipseResultAddress()); } - if (scalarResultIndex == cvf::UNDEFINED_SIZE_T) - { - scalarResultIndex = this->findOrLoadScalarResult(RiaDefines::SOURSIMRL, resultName); - } + return addresses; +} - if (scalarResultIndex == cvf::UNDEFINED_SIZE_T) - { - scalarResultIndex = this->findScalarResultIndex(RiaDefines::GENERATED, resultName); - } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +const RigEclipseResultInfo* RigCaseCellResultsData::resultInfo(const RigEclipseResultAddress& resVarAddr) const +{ + return &(m_resultInfos[findScalarResultIndexFromAddress(resVarAddr)]); +} - if (scalarResultIndex == cvf::UNDEFINED_SIZE_T) - { - scalarResultIndex = this->findScalarResultIndex(RiaDefines::INPUT_PROPERTY, resultName); - } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RigCaseCellResultsData::ensureKnownResultLoaded(const RigEclipseResultAddress& resultAddress) +{ + size_t resultIndex = findOrLoadKnownScalarResult(resultAddress); - return scalarResultIndex; + return (resultIndex != cvf::UNDEFINED_SIZE_T); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RigCaseCellResultsData::hasResultEntry(const RigEclipseResultAddress& resultAddress) const +{ + size_t resultIndex = findScalarResultIndexFromAddress(resultAddress); + + return (resultIndex != cvf::UNDEFINED_SIZE_T); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RigCaseCellResultsData::createResultEntry(const RigEclipseResultAddress& resultAddress, bool needsToBeStored) +{ + findOrCreateScalarResultIndex(resultAddress, needsToBeStored); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RigCaseCellResultsData::ensureKnownResultLoadedForTimeStep(const RigEclipseResultAddress& resultAddress, + size_t timeStepIndex) +{ + CAF_ASSERT(resultAddress.m_resultCatType != RiaDefines::UNDEFINED); + + findOrLoadKnownScalarResultForTimeStep(resultAddress, + timeStepIndex); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -size_t RigCaseCellResultsData::findOrLoadScalarResult(RiaDefines::ResultCatType type, const QString& resultName) +size_t RigCaseCellResultsData::findOrLoadKnownScalarResult(const RigEclipseResultAddress& resVarAddr) { - size_t scalarResultIndex = this->findScalarResultIndex(type, resultName); + if (!resVarAddr.isValid()) + { + return cvf::UNDEFINED_SIZE_T; + } + else if (resVarAddr.m_resultCatType == RiaDefines::UNDEFINED) + { + RigEclipseResultAddress resVarAddressWithType = resVarAddr; + + resVarAddressWithType.m_resultCatType = RiaDefines::STATIC_NATIVE; + + size_t scalarResultIndex = this->findOrLoadKnownScalarResult(resVarAddressWithType); + + if (scalarResultIndex == cvf::UNDEFINED_SIZE_T) + { + resVarAddressWithType.m_resultCatType = RiaDefines::DYNAMIC_NATIVE; + scalarResultIndex = this->findOrLoadKnownScalarResult(resVarAddressWithType); + } + + if (scalarResultIndex == cvf::UNDEFINED_SIZE_T) + { + resVarAddressWithType.m_resultCatType = RiaDefines::SOURSIMRL; + scalarResultIndex = this->findOrLoadKnownScalarResult(resVarAddressWithType); + } + + if (scalarResultIndex == cvf::UNDEFINED_SIZE_T) + { + resVarAddressWithType.m_resultCatType = RiaDefines::GENERATED; + scalarResultIndex = this->findScalarResultIndexFromAddress(resVarAddressWithType); + } + + if (scalarResultIndex == cvf::UNDEFINED_SIZE_T) + { + resVarAddressWithType.m_resultCatType = RiaDefines::INPUT_PROPERTY; + scalarResultIndex = this->findScalarResultIndexFromAddress(resVarAddressWithType); + } + + if (scalarResultIndex == cvf::UNDEFINED_SIZE_T) + { + resVarAddressWithType.m_resultCatType = RiaDefines::FORMATION_NAMES; + scalarResultIndex = this->findScalarResultIndexFromAddress(resVarAddressWithType); // Use Load ? + } + + return scalarResultIndex; + } + + + size_t scalarResultIndex = this->findScalarResultIndexFromAddress(resVarAddr); + if (scalarResultIndex == cvf::UNDEFINED_SIZE_T) return cvf::UNDEFINED_SIZE_T; + RiaDefines::ResultCatType type = resVarAddr.m_resultCatType; + QString resultName = resVarAddr.m_resultName; + + if (resVarAddr.hasDifferenceCase() || resVarAddr.isTimeLapse()) + { + if (!RigCaseCellResultCalculator::computeDifference(this->m_ownerCaseData, m_porosityModel, resVarAddr)) + { + return cvf::UNDEFINED_SIZE_T; + } + + return scalarResultIndex; + } + // Load dependency data sets if (type == RiaDefines::STATIC_NATIVE) { if (resultName == RiaDefines::combinedTransmissibilityResultName()) { - this->findOrLoadScalarResult(type, "TRANX"); - this->findOrLoadScalarResult(type, "TRANY"); - this->findOrLoadScalarResult(type, "TRANZ"); + this->findOrLoadKnownScalarResult(RigEclipseResultAddress(type, "TRANX")); + this->findOrLoadKnownScalarResult(RigEclipseResultAddress(type, "TRANY")); + this->findOrLoadKnownScalarResult(RigEclipseResultAddress(type, "TRANZ")); } else if (resultName == RiaDefines::combinedMultResultName()) { - this->findOrLoadScalarResult(type, "MULTX"); - this->findOrLoadScalarResult(type, "MULTX-"); - this->findOrLoadScalarResult(type, "MULTY"); - this->findOrLoadScalarResult(type, "MULTY-"); - this->findOrLoadScalarResult(type, "MULTZ"); - this->findOrLoadScalarResult(type, "MULTZ-"); + this->findOrLoadKnownScalarResult(RigEclipseResultAddress(type, "MULTX" )); + this->findOrLoadKnownScalarResult(RigEclipseResultAddress(type, "MULTX-")); + this->findOrLoadKnownScalarResult(RigEclipseResultAddress(type, "MULTY" )); + this->findOrLoadKnownScalarResult(RigEclipseResultAddress(type, "MULTY-")); + this->findOrLoadKnownScalarResult(RigEclipseResultAddress(type, "MULTZ" )); + this->findOrLoadKnownScalarResult(RigEclipseResultAddress(type, "MULTZ-")); } else if (resultName == RiaDefines::combinedRiTranResultName()) { @@ -1102,21 +1163,21 @@ size_t RigCaseCellResultsData::findOrLoadScalarResult(RiaDefines::ResultCatType { if (resultName == RiaDefines::combinedWaterFluxResultName()) { - this->findOrLoadScalarResult(type, "FLRWATI+"); - this->findOrLoadScalarResult(type, "FLRWATJ+"); - this->findOrLoadScalarResult(type, "FLRWATK+"); + this->findOrLoadKnownScalarResult(RigEclipseResultAddress(type, "FLRWATI+")); + this->findOrLoadKnownScalarResult(RigEclipseResultAddress(type, "FLRWATJ+")); + this->findOrLoadKnownScalarResult(RigEclipseResultAddress(type, "FLRWATK+")); } else if (resultName == RiaDefines::combinedOilFluxResultName()) { - this->findOrLoadScalarResult(type, "FLROILI+"); - this->findOrLoadScalarResult(type, "FLROILJ+"); - this->findOrLoadScalarResult(type, "FLROILK+"); + this->findOrLoadKnownScalarResult(RigEclipseResultAddress(type, "FLROILI+")); + this->findOrLoadKnownScalarResult(RigEclipseResultAddress(type, "FLROILJ+")); + this->findOrLoadKnownScalarResult(RigEclipseResultAddress(type, "FLROILK+")); } else if (resultName == RiaDefines::combinedGasFluxResultName()) { - this->findOrLoadScalarResult(type, "FLRGASI+"); - this->findOrLoadScalarResult(type, "FLRGASJ+"); - this->findOrLoadScalarResult(type, "FLRGASK+"); + this->findOrLoadKnownScalarResult(RigEclipseResultAddress(type, "FLRGASI+")); + this->findOrLoadKnownScalarResult(RigEclipseResultAddress(type, "FLRGASJ+")); + this->findOrLoadKnownScalarResult(RigEclipseResultAddress(type, "FLRGASK+")); } } @@ -1130,13 +1191,13 @@ size_t RigCaseCellResultsData::findOrLoadScalarResult(RiaDefines::ResultCatType if (this->mustBeCalculated(scalarResultIndex)) { // Trigger loading of SWAT, SGAS to establish time step count if no data has been loaded from file at this point - findOrLoadScalarResult(RiaDefines::DYNAMIC_NATIVE, "SWAT"); - findOrLoadScalarResult(RiaDefines::DYNAMIC_NATIVE, "SGAS"); + findOrLoadKnownScalarResult(RigEclipseResultAddress(RiaDefines::DYNAMIC_NATIVE, "SWAT")); + findOrLoadKnownScalarResult(RigEclipseResultAddress(RiaDefines::DYNAMIC_NATIVE, "SGAS")); - this->cellScalarResults(scalarResultIndex).resize(this->maxTimeStepCount()); + m_cellScalarResults[scalarResultIndex].resize(this->maxTimeStepCount()); for (size_t timeStepIdx = 0; timeStepIdx < this->maxTimeStepCount(); timeStepIdx++) { - std::vector& values = this->cellScalarResults(scalarResultIndex)[timeStepIdx]; + std::vector& values = m_cellScalarResults[scalarResultIndex][timeStepIdx]; if (values.size() == 0) { computeSOILForTimeStep(timeStepIdx); @@ -1149,7 +1210,7 @@ size_t RigCaseCellResultsData::findOrLoadScalarResult(RiaDefines::ResultCatType else if (resultName == RiaDefines::completionTypeResultName()) { caf::ProgressInfo progressInfo(this->maxTimeStepCount(), "Calculate Completion Type Results"); - this->cellScalarResults(scalarResultIndex).resize(this->maxTimeStepCount()); + m_cellScalarResults[scalarResultIndex].resize(this->maxTimeStepCount()); for (size_t timeStepIdx = 0; timeStepIdx < this->maxTimeStepCount(); ++timeStepIdx) { computeCompletionTypeForTimeStep(timeStepIdx); @@ -1177,13 +1238,13 @@ size_t RigCaseCellResultsData::findOrLoadScalarResult(RiaDefines::ResultCatType if (type == RiaDefines::DYNAMIC_NATIVE && timeStepCount > 0) { - this->cellScalarResults(scalarResultIndex).resize(timeStepCount); + m_cellScalarResults[scalarResultIndex].resize(timeStepCount); size_t i; for (i = 0; i < timeStepCount; i++) { - std::vector& values = this->cellScalarResults(scalarResultIndex)[i]; - if (!m_readerInterface->dynamicResult(resultName, RiaDefines::MATRIX_MODEL, i, &values)) + std::vector& values = m_cellScalarResults[scalarResultIndex][i]; + if (!m_readerInterface->dynamicResult(resultName, m_porosityModel, i, &values)) { resultLoadingSucess = false; } @@ -1200,10 +1261,10 @@ size_t RigCaseCellResultsData::findOrLoadScalarResult(RiaDefines::ResultCatType } else if (type == RiaDefines::STATIC_NATIVE) { - this->cellScalarResults(scalarResultIndex).resize(1); + m_cellScalarResults[scalarResultIndex].resize(1); - std::vector& values = this->cellScalarResults(scalarResultIndex)[0]; - if (!m_readerInterface->staticResult(resultName, RiaDefines::MATRIX_MODEL, &values)) + std::vector& values = m_cellScalarResults[scalarResultIndex][0]; + if (!m_readerInterface->staticResult(resultName, m_porosityModel, &values)) { resultLoadingSucess = false; } @@ -1221,7 +1282,7 @@ size_t RigCaseCellResultsData::findOrLoadScalarResult(RiaDefines::ResultCatType if (!resultLoadingSucess) { // Remove last scalar result because loading of result failed - this->cellScalarResults(scalarResultIndex).clear(); + m_cellScalarResults[scalarResultIndex].clear(); } } @@ -1246,12 +1307,12 @@ size_t RigCaseCellResultsData::findOrLoadScalarResult(RiaDefines::ResultCatType { size_t timeStepCount = this->infoForEachResultIndex()[scalarResultIndex].timeStepInfos().size(); - this->cellScalarResults(scalarResultIndex).resize(timeStepCount); + m_cellScalarResults[scalarResultIndex].resize(timeStepCount); size_t i; for (i = 0; i < timeStepCount; i++) { - std::vector& values = this->cellScalarResults(scalarResultIndex)[i]; + std::vector& values = m_cellScalarResults[scalarResultIndex][i]; eclReader->sourSimRlResult(resultName, i, &values); } } @@ -1260,24 +1321,27 @@ size_t RigCaseCellResultsData::findOrLoadScalarResult(RiaDefines::ResultCatType return scalarResultIndex; } + //-------------------------------------------------------------------------------------------------- /// This method is intended to be used for multicase cross statistical calculations, when /// we need process one timestep at a time, freeing memory as we go. //-------------------------------------------------------------------------------------------------- -size_t RigCaseCellResultsData::findOrLoadScalarResultForTimeStep(RiaDefines::ResultCatType type, - const QString& resultName, - size_t timeStepIndex) +size_t RigCaseCellResultsData::findOrLoadKnownScalarResultForTimeStep(const RigEclipseResultAddress& resVarAddr, + size_t timeStepIndex) { + RiaDefines::ResultCatType type = resVarAddr.m_resultCatType; + QString resultName = resVarAddr.m_resultName; + // Special handling for SOIL if (type == RiaDefines::DYNAMIC_NATIVE && resultName.toUpper() == "SOIL") { - size_t soilScalarResultIndex = this->findScalarResultIndex(type, resultName); + size_t soilScalarResultIndex = this->findScalarResultIndexFromAddress(resVarAddr); if (this->mustBeCalculated(soilScalarResultIndex)) { - this->cellScalarResults(soilScalarResultIndex).resize(this->maxTimeStepCount()); + m_cellScalarResults[soilScalarResultIndex].resize(this->maxTimeStepCount()); - std::vector& values = this->cellScalarResults(soilScalarResultIndex)[timeStepIndex]; + std::vector& values = m_cellScalarResults[soilScalarResultIndex][timeStepIndex]; if (values.size() == 0) { computeSOILForTimeStep(timeStepIndex); @@ -1288,12 +1352,12 @@ size_t RigCaseCellResultsData::findOrLoadScalarResultForTimeStep(RiaDefines::Res } else if (type == RiaDefines::DYNAMIC_NATIVE && resultName == RiaDefines::completionTypeResultName()) { - size_t completionTypeScalarResultIndex = this->findScalarResultIndex(type, resultName); + size_t completionTypeScalarResultIndex = this->findScalarResultIndexFromAddress(resVarAddr); computeCompletionTypeForTimeStep(timeStepIndex); return completionTypeScalarResultIndex; } - size_t scalarResultIndex = this->findScalarResultIndex(type, resultName); + size_t scalarResultIndex = this->findScalarResultIndexFromAddress(resVarAddr); if (scalarResultIndex == cvf::UNDEFINED_SIZE_T) return cvf::UNDEFINED_SIZE_T; if (type == RiaDefines::GENERATED) @@ -1309,12 +1373,12 @@ size_t RigCaseCellResultsData::findOrLoadScalarResultForTimeStep(RiaDefines::Res if (type == RiaDefines::DYNAMIC_NATIVE && timeStepCount > 0) { - this->cellScalarResults(scalarResultIndex).resize(timeStepCount); + m_cellScalarResults[scalarResultIndex].resize(timeStepCount); - std::vector& values = this->cellScalarResults(scalarResultIndex)[timeStepIndex]; + std::vector& values = m_cellScalarResults[scalarResultIndex][timeStepIndex]; if (values.size() == 0) { - if (!m_readerInterface->dynamicResult(resultName, RiaDefines::MATRIX_MODEL, timeStepIndex, &values)) + if (!m_readerInterface->dynamicResult(resultName, m_porosityModel, timeStepIndex, &values)) { resultLoadingSucess = false; } @@ -1322,10 +1386,10 @@ size_t RigCaseCellResultsData::findOrLoadScalarResultForTimeStep(RiaDefines::Res } else if (type == RiaDefines::STATIC_NATIVE) { - this->cellScalarResults(scalarResultIndex).resize(1); + m_cellScalarResults[scalarResultIndex].resize(1); - std::vector& values = this->cellScalarResults(scalarResultIndex)[0]; - if (!m_readerInterface->staticResult(resultName, RiaDefines::MATRIX_MODEL, &values)) + std::vector& values = m_cellScalarResults[scalarResultIndex][0]; + if (!m_readerInterface->staticResult(resultName, m_porosityModel, &values)) { resultLoadingSucess = false; } @@ -1347,9 +1411,9 @@ size_t RigCaseCellResultsData::findOrLoadScalarResultForTimeStep(RiaDefines::Res { size_t timeStepCount = this->infoForEachResultIndex()[scalarResultIndex].timeStepInfos().size(); - this->cellScalarResults(scalarResultIndex).resize(timeStepCount); + m_cellScalarResults[scalarResultIndex].resize(timeStepCount); - std::vector& values = this->cellScalarResults(scalarResultIndex)[timeStepIndex]; + std::vector& values = m_cellScalarResults[scalarResultIndex][timeStepIndex]; if (values.size() == 0) { @@ -1369,9 +1433,13 @@ void RigCaseCellResultsData::computeSOILForTimeStep(size_t timeStepIndex) // Compute SGAS based on SWAT if the simulation contains no oil testAndComputeSgasForTimeStep(timeStepIndex); - size_t scalarIndexSWAT = findOrLoadScalarResultForTimeStep(RiaDefines::DYNAMIC_NATIVE, "SWAT", timeStepIndex); - size_t scalarIndexSGAS = findOrLoadScalarResultForTimeStep(RiaDefines::DYNAMIC_NATIVE, "SGAS", timeStepIndex); - size_t scalarIndexSSOL = findOrLoadScalarResultForTimeStep(RiaDefines::DYNAMIC_NATIVE, "SSOL", timeStepIndex); + RigEclipseResultAddress SWATAddr(RiaDefines::DYNAMIC_NATIVE, "SWAT"); + RigEclipseResultAddress SGASAddr(RiaDefines::DYNAMIC_NATIVE, "SGAS"); + RigEclipseResultAddress SSOLAddr(RiaDefines::DYNAMIC_NATIVE, "SSOL"); + + size_t scalarIndexSWAT = findOrLoadKnownScalarResultForTimeStep(RigEclipseResultAddress(RiaDefines::DYNAMIC_NATIVE, "SWAT"), timeStepIndex); + size_t scalarIndexSGAS = findOrLoadKnownScalarResultForTimeStep(RigEclipseResultAddress(RiaDefines::DYNAMIC_NATIVE, "SGAS"), timeStepIndex); + size_t scalarIndexSSOL = findOrLoadKnownScalarResultForTimeStep(RigEclipseResultAddress(RiaDefines::DYNAMIC_NATIVE, "SSOL"), timeStepIndex); // Early exit if none of SWAT or SGAS is present if (scalarIndexSWAT == cvf::UNDEFINED_SIZE_T && scalarIndexSGAS == cvf::UNDEFINED_SIZE_T) @@ -1384,7 +1452,7 @@ void RigCaseCellResultsData::computeSOILForTimeStep(size_t timeStepIndex) if (scalarIndexSWAT != cvf::UNDEFINED_SIZE_T) { - std::vector& swatForTimeStep = this->cellScalarResults(scalarIndexSWAT, timeStepIndex); + const std::vector& swatForTimeStep = this->cellScalarResults(SWATAddr, timeStepIndex); if (swatForTimeStep.size() > 0) { soilResultValueCount = swatForTimeStep.size(); @@ -1394,7 +1462,7 @@ void RigCaseCellResultsData::computeSOILForTimeStep(size_t timeStepIndex) if (scalarIndexSGAS != cvf::UNDEFINED_SIZE_T) { - std::vector& sgasForTimeStep = this->cellScalarResults(scalarIndexSGAS, timeStepIndex); + const std::vector& sgasForTimeStep = this->cellScalarResults(SGASAddr, timeStepIndex); if (sgasForTimeStep.size() > 0) { soilResultValueCount = qMax(soilResultValueCount, sgasForTimeStep.size()); @@ -1405,25 +1473,25 @@ void RigCaseCellResultsData::computeSOILForTimeStep(size_t timeStepIndex) } // Make sure memory is allocated for the new SOIL results + RigEclipseResultAddress SOILAddr(RiaDefines::DYNAMIC_NATIVE, "SOIL"); + size_t soilResultScalarIndex = this->findScalarResultIndexFromAddress(SOILAddr); + m_cellScalarResults[soilResultScalarIndex].resize(soilTimeStepCount); - size_t soilResultScalarIndex = this->findScalarResultIndex(RiaDefines::DYNAMIC_NATIVE, "SOIL"); - this->cellScalarResults(soilResultScalarIndex).resize(soilTimeStepCount); - - if (this->cellScalarResults(soilResultScalarIndex, timeStepIndex).size() > 0) + if (this->cellScalarResults(SOILAddr, timeStepIndex).size() > 0) { // Data is computed and allocated, nothing more to do return; } - this->cellScalarResults(soilResultScalarIndex, timeStepIndex).resize(soilResultValueCount); + m_cellScalarResults[soilResultScalarIndex][timeStepIndex].resize(soilResultValueCount); - std::vector* swatForTimeStep = nullptr; - std::vector* sgasForTimeStep = nullptr; - std::vector* ssolForTimeStep = nullptr; + const std::vector* swatForTimeStep = nullptr; + const std::vector* sgasForTimeStep = nullptr; + const std::vector* ssolForTimeStep = nullptr; if (scalarIndexSWAT != cvf::UNDEFINED_SIZE_T) { - swatForTimeStep = &(this->cellScalarResults(scalarIndexSWAT, timeStepIndex)); + swatForTimeStep = &(this->cellScalarResults(SWATAddr, timeStepIndex)); if (swatForTimeStep->size() == 0) { swatForTimeStep = nullptr; @@ -1432,7 +1500,7 @@ void RigCaseCellResultsData::computeSOILForTimeStep(size_t timeStepIndex) if (scalarIndexSGAS != cvf::UNDEFINED_SIZE_T) { - sgasForTimeStep = &(this->cellScalarResults(scalarIndexSGAS, timeStepIndex)); + sgasForTimeStep = &(this->cellScalarResults(SGASAddr, timeStepIndex)); if (sgasForTimeStep->size() == 0) { sgasForTimeStep = nullptr; @@ -1441,14 +1509,14 @@ void RigCaseCellResultsData::computeSOILForTimeStep(size_t timeStepIndex) if (scalarIndexSSOL != cvf::UNDEFINED_SIZE_T) { - ssolForTimeStep = &(this->cellScalarResults(scalarIndexSSOL, timeStepIndex)); + ssolForTimeStep = &(this->cellScalarResults(SSOLAddr, timeStepIndex)); if (ssolForTimeStep->size() == 0) { ssolForTimeStep = nullptr; } } - std::vector& soilForTimeStep = this->cellScalarResults(soilResultScalarIndex, timeStepIndex); + std::vector& soilForTimeStep = this->modifiableCellScalarResult(SOILAddr, timeStepIndex); #pragma omp parallel for for (int idx = 0; idx < static_cast(soilResultValueCount); idx++) @@ -1478,7 +1546,7 @@ void RigCaseCellResultsData::computeSOILForTimeStep(size_t timeStepIndex) //-------------------------------------------------------------------------------------------------- void RigCaseCellResultsData::testAndComputeSgasForTimeStep(size_t timeStepIndex) { - size_t scalarIndexSWAT = findOrLoadScalarResultForTimeStep(RiaDefines::DYNAMIC_NATIVE, "SWAT", timeStepIndex); + size_t scalarIndexSWAT = findOrLoadKnownScalarResultForTimeStep(RigEclipseResultAddress(RiaDefines::DYNAMIC_NATIVE, "SWAT"), timeStepIndex); if (scalarIndexSWAT == cvf::UNDEFINED_SIZE_T) { return; @@ -1492,10 +1560,10 @@ void RigCaseCellResultsData::testAndComputeSgasForTimeStep(size_t timeStepIndex) // Simulation type is gas and water. No SGAS is present, compute SGAS based on SWAT - size_t scalarIndexSGAS = this->findOrCreateScalarResultIndex(RiaDefines::DYNAMIC_NATIVE, "SGAS", false); - if (this->cellScalarResults(scalarIndexSGAS).size() > timeStepIndex) + size_t scalarIndexSGAS = this->findOrCreateScalarResultIndex(RigEclipseResultAddress(RiaDefines::DYNAMIC_NATIVE, "SGAS"), false); + if (m_cellScalarResults[scalarIndexSGAS].size() > timeStepIndex) { - std::vector& values = this->cellScalarResults(scalarIndexSGAS)[timeStepIndex]; + std::vector& values = m_cellScalarResults[scalarIndexSGAS][timeStepIndex]; if (values.size() > 0) return; } @@ -1503,7 +1571,7 @@ void RigCaseCellResultsData::testAndComputeSgasForTimeStep(size_t timeStepIndex) size_t swatTimeStepCount = 0; { - std::vector& swatForTimeStep = this->cellScalarResults(scalarIndexSWAT, timeStepIndex); + std::vector& swatForTimeStep = m_cellScalarResults[scalarIndexSWAT][timeStepIndex]; if (swatForTimeStep.size() > 0) { swatResultValueCount = swatForTimeStep.size(); @@ -1511,26 +1579,26 @@ void RigCaseCellResultsData::testAndComputeSgasForTimeStep(size_t timeStepIndex) } } - this->cellScalarResults(scalarIndexSGAS).resize(swatTimeStepCount); + m_cellScalarResults[scalarIndexSGAS].resize(swatTimeStepCount); - if (this->cellScalarResults(scalarIndexSGAS, timeStepIndex).size() > 0) + if (m_cellScalarResults[scalarIndexSGAS][timeStepIndex].size() > 0) { return; } - this->cellScalarResults(scalarIndexSGAS, timeStepIndex).resize(swatResultValueCount); + m_cellScalarResults[scalarIndexSGAS][timeStepIndex].resize(swatResultValueCount); std::vector* swatForTimeStep = nullptr; { - swatForTimeStep = &(this->cellScalarResults(scalarIndexSWAT, timeStepIndex)); + swatForTimeStep = &(m_cellScalarResults[scalarIndexSWAT][timeStepIndex]); if (swatForTimeStep->size() == 0) { swatForTimeStep = nullptr; } } - std::vector& sgasForTimeStep = this->cellScalarResults(scalarIndexSGAS, timeStepIndex); + std::vector& sgasForTimeStep = m_cellScalarResults[scalarIndexSGAS][timeStepIndex]; #pragma omp parallel for for (int idx = 0; idx < static_cast(swatResultValueCount); idx++) @@ -1554,12 +1622,12 @@ void RigCaseCellResultsData::computeDepthRelatedResults() size_t actCellCount = activeCellInfo()->reservoirActiveCellCount(); if (actCellCount == 0) return; - size_t depthResultIndex = findOrLoadScalarResult(RiaDefines::STATIC_NATIVE, "DEPTH"); - size_t dxResultIndex = findOrLoadScalarResult(RiaDefines::STATIC_NATIVE, "DX"); - size_t dyResultIndex = findOrLoadScalarResult(RiaDefines::STATIC_NATIVE, "DY"); - size_t dzResultIndex = findOrLoadScalarResult(RiaDefines::STATIC_NATIVE, "DZ"); - size_t topsResultIndex = findOrLoadScalarResult(RiaDefines::STATIC_NATIVE, "TOPS"); - size_t bottomResultIndex = findOrLoadScalarResult(RiaDefines::STATIC_NATIVE, "BOTTOM"); + size_t depthResultIndex = findOrLoadKnownScalarResult(RigEclipseResultAddress(RiaDefines::STATIC_NATIVE, "DEPTH" )); + size_t dxResultIndex = findOrLoadKnownScalarResult(RigEclipseResultAddress(RiaDefines::STATIC_NATIVE, "DX" )); + size_t dyResultIndex = findOrLoadKnownScalarResult(RigEclipseResultAddress(RiaDefines::STATIC_NATIVE, "DY" )); + size_t dzResultIndex = findOrLoadKnownScalarResult(RigEclipseResultAddress(RiaDefines::STATIC_NATIVE, "DZ" )); + size_t topsResultIndex = findOrLoadKnownScalarResult(RigEclipseResultAddress(RiaDefines::STATIC_NATIVE, "TOPS" )); + size_t bottomResultIndex = findOrLoadKnownScalarResult(RigEclipseResultAddress(RiaDefines::STATIC_NATIVE, "BOTTOM")); bool computeDepth = false; bool computeDx = false; @@ -1604,12 +1672,12 @@ void RigCaseCellResultsData::computeDepthRelatedResults() computeBottom = true; } - std::vector>& depth = this->cellScalarResults(depthResultIndex); - std::vector>& dx = this->cellScalarResults(dxResultIndex); - std::vector>& dy = this->cellScalarResults(dyResultIndex); - std::vector>& dz = this->cellScalarResults(dzResultIndex); - std::vector>& tops = this->cellScalarResults(topsResultIndex); - std::vector>& bottom = this->cellScalarResults(bottomResultIndex); + std::vector>& depth = m_cellScalarResults[depthResultIndex]; + std::vector>& dx = m_cellScalarResults[dxResultIndex]; + std::vector>& dy = m_cellScalarResults[dyResultIndex]; + std::vector>& dz = m_cellScalarResults[dzResultIndex]; + std::vector>& tops = m_cellScalarResults[topsResultIndex]; + std::vector>& bottom = m_cellScalarResults[bottomResultIndex]; // Make sure the size is at least active cells { @@ -1825,34 +1893,34 @@ void RigCaseCellResultsData::computeRiTransComponent(const QString& riTransCompo // Get the needed result indices we depend on - size_t permResultIdx = findOrLoadScalarResult(RiaDefines::STATIC_NATIVE, permCompName); - size_t ntgResultIdx = findOrLoadScalarResult(RiaDefines::STATIC_NATIVE, "NTG"); + size_t permResultIdx = findOrLoadKnownScalarResult(RigEclipseResultAddress(RiaDefines::STATIC_NATIVE, permCompName)); + size_t ntgResultIdx = findOrLoadKnownScalarResult(RigEclipseResultAddress(RiaDefines::STATIC_NATIVE, "NTG")); bool hasNTGResults = ntgResultIdx != cvf::UNDEFINED_SIZE_T; // Get the result index of the output - size_t riTransResultIdx = this->findScalarResultIndex(RiaDefines::STATIC_NATIVE, riTransComponentResultName); + size_t riTransResultIdx = this->findScalarResultIndexFromAddress(RigEclipseResultAddress( RiaDefines::STATIC_NATIVE, riTransComponentResultName)); CVF_ASSERT(riTransResultIdx != cvf::UNDEFINED_SIZE_T); // Get the result count, to handle that one of them might be globally defined - size_t permxResultValueCount = this->cellScalarResults(permResultIdx)[0].size(); + size_t permxResultValueCount = m_cellScalarResults[permResultIdx][0].size(); size_t resultValueCount = permxResultValueCount; if (hasNTGResults) { - size_t ntgResultValueCount = this->cellScalarResults(ntgResultIdx)[0].size(); + size_t ntgResultValueCount = m_cellScalarResults[ntgResultIdx][0].size(); resultValueCount = CVF_MIN(permxResultValueCount, ntgResultValueCount); } // Get all the actual result values - std::vector& permResults = this->cellScalarResults(permResultIdx)[0]; - std::vector& riTransResults = this->cellScalarResults(riTransResultIdx)[0]; + std::vector& permResults = m_cellScalarResults[permResultIdx][0]; + std::vector& riTransResults = m_cellScalarResults[riTransResultIdx][0]; std::vector* ntgResults = nullptr; if (hasNTGResults) { - ntgResults = &(this->cellScalarResults(ntgResultIdx)[0]); + ntgResults = &( m_cellScalarResults[ntgResultIdx][0]); } // Set up output container to correct number of results @@ -1864,12 +1932,12 @@ void RigCaseCellResultsData::computeRiTransComponent(const QString& riTransCompo ResultIndexFunction permIdxFunc = nullptr; ResultIndexFunction ntgIdxFunc = nullptr; { - bool isPermUsingResIdx = this->isUsingGlobalActiveIndex(permResultIdx); - bool isTransUsingResIdx = this->isUsingGlobalActiveIndex(riTransResultIdx); + bool isPermUsingResIdx = this->isUsingGlobalActiveIndex(RigEclipseResultAddress(RiaDefines::STATIC_NATIVE, permCompName)); + bool isTransUsingResIdx = this->isUsingGlobalActiveIndex(RigEclipseResultAddress(RiaDefines::STATIC_NATIVE, riTransComponentResultName)); bool isNtgUsingResIdx = false; if (hasNTGResults) { - isNtgUsingResIdx = this->isUsingGlobalActiveIndex(ntgResultIdx); + isNtgUsingResIdx = this->isUsingGlobalActiveIndex(RigEclipseResultAddress(RiaDefines::STATIC_NATIVE, "NTG")); } // Set up result index function pointers @@ -1977,35 +2045,34 @@ void RigCaseCellResultsData::computeRiTransComponent(const QString& riTransCompo //-------------------------------------------------------------------------------------------------- void RigCaseCellResultsData::computeNncCombRiTrans() { - size_t riCombTransScalarResultIndex = - this->findScalarResultIndex(RiaDefines::STATIC_NATIVE, RiaDefines::combinedRiTranResultName()); - if (m_ownerMainGrid->nncData()->staticConnectionScalarResult(riCombTransScalarResultIndex)) return; + RigEclipseResultAddress riCombTransEclResAddr(RiaDefines::STATIC_NATIVE, RiaDefines::combinedRiTranResultName()); + if (m_ownerMainGrid->nncData()->staticConnectionScalarResult( riCombTransEclResAddr )) return; double cdarchy = darchysValue(); // Get the needed result indices we depend on - size_t permXResultIdx = findOrLoadScalarResult(RiaDefines::STATIC_NATIVE, "PERMX"); - size_t permYResultIdx = findOrLoadScalarResult(RiaDefines::STATIC_NATIVE, "PERMY"); - size_t permZResultIdx = findOrLoadScalarResult(RiaDefines::STATIC_NATIVE, "PERMZ"); + size_t permXResultIdx = findOrLoadKnownScalarResult(RigEclipseResultAddress(RiaDefines::STATIC_NATIVE, "PERMX")); + size_t permYResultIdx = findOrLoadKnownScalarResult(RigEclipseResultAddress(RiaDefines::STATIC_NATIVE, "PERMY")); + size_t permZResultIdx = findOrLoadKnownScalarResult(RigEclipseResultAddress(RiaDefines::STATIC_NATIVE, "PERMZ")); - size_t ntgResultIdx = findOrLoadScalarResult(RiaDefines::STATIC_NATIVE, "NTG"); + size_t ntgResultIdx = findOrLoadKnownScalarResult(RigEclipseResultAddress(RiaDefines::STATIC_NATIVE, "NTG")); bool hasNTGResults = ntgResultIdx != cvf::UNDEFINED_SIZE_T; // Get all the actual result values - std::vector& permXResults = this->cellScalarResults(permXResultIdx)[0]; - std::vector& permYResults = this->cellScalarResults(permYResultIdx)[0]; - std::vector& permZResults = this->cellScalarResults(permZResultIdx)[0]; + std::vector& permXResults = m_cellScalarResults[permXResultIdx][0]; + std::vector& permYResults = m_cellScalarResults[permYResultIdx][0]; + std::vector& permZResults = m_cellScalarResults[permZResultIdx][0]; std::vector& riCombTransResults = m_ownerMainGrid->nncData()->makeStaticConnectionScalarResult(RigNNCData::propertyNameRiCombTrans()); - m_ownerMainGrid->nncData()->setScalarResultIndex(RigNNCData::propertyNameRiCombTrans(), riCombTransScalarResultIndex); + m_ownerMainGrid->nncData()->setEclResultAddress(RigNNCData::propertyNameRiCombTrans(), riCombTransEclResAddr); std::vector* ntgResults = nullptr; if (hasNTGResults) { - ntgResults = &(this->cellScalarResults(ntgResultIdx)[0]); + ntgResults = &(m_cellScalarResults[ntgResultIdx][0]); } // Prepare how to index the result values: @@ -2014,13 +2081,13 @@ void RigCaseCellResultsData::computeNncCombRiTrans() ResultIndexFunction permZIdxFunc = nullptr; ResultIndexFunction ntgIdxFunc = nullptr; { - bool isPermXUsingResIdx = this->isUsingGlobalActiveIndex(permXResultIdx); - bool isPermYUsingResIdx = this->isUsingGlobalActiveIndex(permYResultIdx); - bool isPermZUsingResIdx = this->isUsingGlobalActiveIndex(permZResultIdx); + bool isPermXUsingResIdx = this->isUsingGlobalActiveIndex(RigEclipseResultAddress(RiaDefines::STATIC_NATIVE, "PERMX")); + bool isPermYUsingResIdx = this->isUsingGlobalActiveIndex(RigEclipseResultAddress(RiaDefines::STATIC_NATIVE, "PERMY")); + bool isPermZUsingResIdx = this->isUsingGlobalActiveIndex(RigEclipseResultAddress(RiaDefines::STATIC_NATIVE, "PERMZ")); bool isNtgUsingResIdx = false; if (hasNTGResults) { - isNtgUsingResIdx = this->isUsingGlobalActiveIndex(ntgResultIdx); + isNtgUsingResIdx = this->isUsingGlobalActiveIndex(RigEclipseResultAddress(RiaDefines::STATIC_NATIVE, "NTG")); } // Set up result index function pointers @@ -2195,26 +2262,25 @@ void RigCaseCellResultsData::computeRiMULTComponent(const QString& riMultCompNam // Get the needed result indices we depend on - size_t transResultIdx = findOrLoadScalarResult(RiaDefines::STATIC_NATIVE, transCompName); - size_t riTransResultIdx = findOrLoadScalarResult(RiaDefines::STATIC_NATIVE, riTransCompName); + size_t transResultIdx = findOrLoadKnownScalarResult(RigEclipseResultAddress(RiaDefines::STATIC_NATIVE, transCompName )); + size_t riTransResultIdx = findOrLoadKnownScalarResult(RigEclipseResultAddress(RiaDefines::STATIC_NATIVE, riTransCompName)); // Get the result index of the output - size_t riMultResultIdx = this->findScalarResultIndex(RiaDefines::STATIC_NATIVE, riMultCompName); + size_t riMultResultIdx = this->findScalarResultIndexFromAddress( RigEclipseResultAddress(RiaDefines::STATIC_NATIVE, riMultCompName)); CVF_ASSERT(riMultResultIdx != cvf::UNDEFINED_SIZE_T); // Get the result count, to handle that one of them might be globally defined - CVF_ASSERT(this->cellScalarResults(riTransResultIdx)[0].size() == this->cellScalarResults(transResultIdx)[0].size()); + CVF_ASSERT(m_cellScalarResults[riTransResultIdx][0].size() == m_cellScalarResults[transResultIdx][0].size()); - size_t resultValueCount = this->cellScalarResults(transResultIdx)[0].size(); + size_t resultValueCount = m_cellScalarResults[transResultIdx][0].size(); // Get all the actual result values - std::vector& riTransResults = this->cellScalarResults(riTransResultIdx)[0]; - std::vector& transResults = this->cellScalarResults(transResultIdx)[0]; - - std::vector& riMultResults = this->cellScalarResults(riMultResultIdx)[0]; + std::vector& riTransResults = m_cellScalarResults[riTransResultIdx][0]; + std::vector& transResults = m_cellScalarResults[transResultIdx][0]; + std::vector& riMultResults = m_cellScalarResults[riMultResultIdx][0]; // Set up output container to correct number of results @@ -2231,22 +2297,22 @@ void RigCaseCellResultsData::computeRiMULTComponent(const QString& riMultCompNam //-------------------------------------------------------------------------------------------------- void RigCaseCellResultsData::computeNncCombRiMULT() { - size_t riCombMultScalarResultIndex = - this->findScalarResultIndex(RiaDefines::STATIC_NATIVE, RiaDefines::combinedRiMultResultName()); - size_t riCombTransScalarResultIndex = - this->findScalarResultIndex(RiaDefines::STATIC_NATIVE, RiaDefines::combinedRiTranResultName()); - size_t combTransScalarResultIndex = - this->findScalarResultIndex(RiaDefines::STATIC_NATIVE, RiaDefines::combinedTransmissibilityResultName()); + auto riCombMultEclResAddr = RigEclipseResultAddress(RiaDefines::STATIC_NATIVE, RiaDefines::combinedRiMultResultName()); + auto riCombTransEclResAddr = RigEclipseResultAddress(RiaDefines::STATIC_NATIVE, RiaDefines::combinedRiTranResultName()); + auto combTransEclResAddr = RigEclipseResultAddress(RiaDefines::STATIC_NATIVE, RiaDefines::combinedTransmissibilityResultName()); - if (m_ownerMainGrid->nncData()->staticConnectionScalarResult(riCombMultScalarResultIndex)) return; + if (m_ownerMainGrid->nncData()->staticConnectionScalarResult(riCombMultEclResAddr)) return; std::vector& riMultResults = m_ownerMainGrid->nncData()->makeStaticConnectionScalarResult(RigNNCData::propertyNameRiCombMult()); + const std::vector* riTransResults = - m_ownerMainGrid->nncData()->staticConnectionScalarResult(riCombTransScalarResultIndex); + m_ownerMainGrid->nncData()->staticConnectionScalarResult(riCombTransEclResAddr); + const std::vector* transResults = - m_ownerMainGrid->nncData()->staticConnectionScalarResult(combTransScalarResultIndex); - m_ownerMainGrid->nncData()->setScalarResultIndex(RigNNCData::propertyNameRiCombMult(), riCombMultScalarResultIndex); + m_ownerMainGrid->nncData()->staticConnectionScalarResult(combTransEclResAddr); + + m_ownerMainGrid->nncData()->setEclResultAddress(RigNNCData::propertyNameRiCombMult(), riCombMultEclResAddr); for (size_t nncConIdx = 0; nncConIdx < riMultResults.size(); ++nncConIdx) { @@ -2286,21 +2352,21 @@ void RigCaseCellResultsData::computeRiTRANSbyAreaComponent(const QString& riTran // Get the needed result indices we depend on - size_t tranCompScResIdx = findOrLoadScalarResult(RiaDefines::STATIC_NATIVE, transCompName); + size_t tranCompScResIdx = findOrLoadKnownScalarResult(RigEclipseResultAddress(RiaDefines::STATIC_NATIVE, transCompName)); // Get the result index of the output - size_t riTranByAreaScResIdx = this->findScalarResultIndex(RiaDefines::STATIC_NATIVE, riTransByAreaCompResultName); + size_t riTranByAreaScResIdx = this->findScalarResultIndexFromAddress( RigEclipseResultAddress(RiaDefines::STATIC_NATIVE, riTransByAreaCompResultName)); CVF_ASSERT(riTranByAreaScResIdx != cvf::UNDEFINED_SIZE_T); // Get the result count, to handle that one of them might be globally defined - size_t resultValueCount = this->cellScalarResults(tranCompScResIdx)[0].size(); + size_t resultValueCount = m_cellScalarResults[tranCompScResIdx][0].size(); // Get all the actual result values - std::vector& transResults = this->cellScalarResults(tranCompScResIdx)[0]; - std::vector& riTransByAreaResults = this->cellScalarResults(riTranByAreaScResIdx)[0]; + std::vector& transResults = m_cellScalarResults[tranCompScResIdx][0]; + std::vector& riTransByAreaResults = m_cellScalarResults[riTranByAreaScResIdx][0]; // Set up output container to correct number of results @@ -2308,7 +2374,7 @@ void RigCaseCellResultsData::computeRiTRANSbyAreaComponent(const QString& riTran // Prepare how to index the result values: - bool isUsingResIdx = this->isUsingGlobalActiveIndex(tranCompScResIdx); + bool isUsingResIdx = this->isUsingGlobalActiveIndex(RigEclipseResultAddress(RiaDefines::STATIC_NATIVE, transCompName)); // Set up result index function pointers @@ -2367,18 +2433,20 @@ void RigCaseCellResultsData::computeRiTRANSbyAreaComponent(const QString& riTran //-------------------------------------------------------------------------------------------------- void RigCaseCellResultsData::computeNncCombRiTRANSbyArea() { - size_t riCombTransByAreaScResIdx = - this->findScalarResultIndex(RiaDefines::STATIC_NATIVE, RiaDefines::combinedRiAreaNormTranResultName()); - size_t combTransScalarResultIndex = - this->findScalarResultIndex(RiaDefines::STATIC_NATIVE, RiaDefines::combinedTransmissibilityResultName()); + auto riCombTransByAreaEclResAddr = + RigEclipseResultAddress(RiaDefines::STATIC_NATIVE, RiaDefines::combinedRiAreaNormTranResultName()); + auto combTransEclResAddr = + RigEclipseResultAddress(RiaDefines::STATIC_NATIVE, RiaDefines::combinedTransmissibilityResultName()); - if (m_ownerMainGrid->nncData()->staticConnectionScalarResult(riCombTransByAreaScResIdx)) return; + if (m_ownerMainGrid->nncData()->staticConnectionScalarResult(riCombTransByAreaEclResAddr)) return; std::vector& riAreaNormTransResults = m_ownerMainGrid->nncData()->makeStaticConnectionScalarResult(RigNNCData::propertyNameRiCombTransByArea()); - m_ownerMainGrid->nncData()->setScalarResultIndex(RigNNCData::propertyNameRiCombTransByArea(), riCombTransByAreaScResIdx); + + m_ownerMainGrid->nncData()->setEclResultAddress(RigNNCData::propertyNameRiCombTransByArea(), riCombTransByAreaEclResAddr); + const std::vector* transResults = - m_ownerMainGrid->nncData()->staticConnectionScalarResult(combTransScalarResultIndex); + m_ownerMainGrid->nncData()->staticConnectionScalarResult(combTransEclResAddr); const std::vector& connections = m_ownerMainGrid->nncData()->connections(); @@ -2398,14 +2466,14 @@ void RigCaseCellResultsData::computeNncCombRiTRANSbyArea() void RigCaseCellResultsData::computeCompletionTypeForTimeStep(size_t timeStep) { size_t completionTypeResultIndex = - this->findScalarResultIndex(RiaDefines::DYNAMIC_NATIVE, RiaDefines::completionTypeResultName()); + this->findScalarResultIndexFromAddress(RigEclipseResultAddress(RiaDefines::DYNAMIC_NATIVE, RiaDefines::completionTypeResultName())); - if (this->cellScalarResults(completionTypeResultIndex).size() < this->maxTimeStepCount()) + if (m_cellScalarResults[completionTypeResultIndex].size() < this->maxTimeStepCount()) { - this->cellScalarResults(completionTypeResultIndex).resize(this->maxTimeStepCount()); + m_cellScalarResults[completionTypeResultIndex].resize(this->maxTimeStepCount()); } - std::vector& completionTypeResult = this->cellScalarResults(completionTypeResultIndex, timeStep); + std::vector& completionTypeResult = m_cellScalarResults[completionTypeResultIndex][timeStep]; size_t resultValues = m_ownerMainGrid->globalCellArray().size(); @@ -2437,13 +2505,15 @@ double RigCaseCellResultsData::darchysValue() //-------------------------------------------------------------------------------------------------- void RigCaseCellResultsData::computeCellVolumes() { - size_t cellVolIdx = this->findOrCreateScalarResultIndex(RiaDefines::STATIC_NATIVE, RiaDefines::riCellVolumeResultName(), false); + size_t cellVolIdx = this->findOrCreateScalarResultIndex(RigEclipseResultAddress(RiaDefines::STATIC_NATIVE, + RiaDefines::riCellVolumeResultName()), + false); - if (this->cellScalarResults(cellVolIdx).empty()) + if (m_cellScalarResults[cellVolIdx].empty()) { - this->cellScalarResults(cellVolIdx).resize(1); + m_cellScalarResults[cellVolIdx].resize(1); } - std::vector& cellVolumeResults = this->cellScalarResults(cellVolIdx)[0]; + std::vector& cellVolumeResults = m_cellScalarResults[cellVolIdx][0]; size_t cellResultCount = m_activeCellInfo->reservoirCellResultCount(); cellVolumeResults.resize(cellResultCount, std::numeric_limits::infinity()); @@ -2471,18 +2541,22 @@ void RigCaseCellResultsData::computeCellVolumes() //-------------------------------------------------------------------------------------------------- void RigCaseCellResultsData::computeOilVolumes() { - size_t cellVolIdx = this->findOrCreateScalarResultIndex(RiaDefines::STATIC_NATIVE, RiaDefines::riCellVolumeResultName(), false); - const std::vector& cellVolumeResults = this->cellScalarResults(cellVolIdx)[0]; + size_t cellVolIdx = this->findOrCreateScalarResultIndex(RigEclipseResultAddress(RiaDefines::STATIC_NATIVE, + RiaDefines::riCellVolumeResultName()), + false); + const std::vector& cellVolumeResults = m_cellScalarResults[cellVolIdx][0]; - size_t soilIdx = this->findOrLoadScalarResult(RiaDefines::DYNAMIC_NATIVE, "SOIL"); - size_t oilVolIdx = this->findOrCreateScalarResultIndex(RiaDefines::DYNAMIC_NATIVE, RiaDefines::riOilVolumeResultName(), false); - this->cellScalarResults(oilVolIdx).resize(this->maxTimeStepCount()); + size_t soilIdx = this->findOrLoadKnownScalarResult(RigEclipseResultAddress(RiaDefines::DYNAMIC_NATIVE, "SOIL")); + size_t oilVolIdx = this->findOrCreateScalarResultIndex( RigEclipseResultAddress(RiaDefines::DYNAMIC_NATIVE, + RiaDefines::riOilVolumeResultName()), + false); + m_cellScalarResults[oilVolIdx].resize(this->maxTimeStepCount()); size_t cellResultCount = m_activeCellInfo->reservoirCellResultCount(); for (size_t timeStepIdx = 0; timeStepIdx < this->maxTimeStepCount(); timeStepIdx++) { - const std::vector& soilResults = this->cellScalarResults(soilIdx)[timeStepIdx]; - std::vector& oilVolumeResults = this->cellScalarResults(oilVolIdx)[timeStepIdx]; + const std::vector& soilResults = m_cellScalarResults[soilIdx][timeStepIdx]; + std::vector& oilVolumeResults = m_cellScalarResults[oilVolIdx][timeStepIdx]; oilVolumeResults.resize(cellResultCount, 0u); #pragma omp parallel for @@ -2523,9 +2597,9 @@ void RigCaseCellResultsData::computeMobilePV() multpvResults = RigCaseCellResultsData::getResultIndexableStaticResult(this->activeCellInfo(), this, "MULTPV", multpvDataTemp); - size_t mobPVIdx = this->findOrCreateScalarResultIndex(RiaDefines::STATIC_NATIVE, RiaDefines::mobilePoreVolumeName(), false); + size_t mobPVIdx = this->findOrCreateScalarResultIndex(RigEclipseResultAddress(RiaDefines::STATIC_NATIVE, RiaDefines::mobilePoreVolumeName()), false); - std::vector& mobPVResults = this->cellScalarResults(mobPVIdx)[0]; + std::vector& mobPVResults = m_cellScalarResults[mobPVIdx][0]; // Set up output container to correct number of results mobPVResults.resize(porvResults->size()); @@ -2577,6 +2651,78 @@ void RigCaseCellResultsData::setHdf5Filename(const QString& hdf5SourSimFilename) } } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RigCaseCellResultsData::setActiveFormationNames(RigFormationNames* activeFormationNames) +{ + m_activeFormationNamesData = activeFormationNames; + + size_t totalGlobCellCount = m_ownerMainGrid->globalCellArray().size(); + this->addStaticScalarResult(RiaDefines::FORMATION_NAMES, + RiaDefines::activeFormationNamesResultName(), + false, + totalGlobCellCount); + + std::vector& fnData = this->modifiableCellScalarResult(RigEclipseResultAddress(RiaDefines::FORMATION_NAMES, + RiaDefines::activeFormationNamesResultName()), 0); + + if (m_activeFormationNamesData.isNull()) + { + for ( size_t cIdx = 0; cIdx < totalGlobCellCount; ++cIdx ) + { + fnData[cIdx] = HUGE_VAL; + } + + return; + } + + size_t localCellCount = m_ownerMainGrid->cellCount(); + for (size_t cIdx = 0; cIdx < localCellCount; ++cIdx) + { + size_t i (cvf::UNDEFINED_SIZE_T), j(cvf::UNDEFINED_SIZE_T), k(cvf::UNDEFINED_SIZE_T); + + if(!m_ownerMainGrid->ijkFromCellIndex(cIdx, &i, &j, &k)) continue; + + int formNameIdx = activeFormationNames->formationIndexFromKLayerIdx(k); + if (formNameIdx != -1) + { + fnData[cIdx] = formNameIdx; + } + else + { + fnData[cIdx] = HUGE_VAL; + } + } + + for (size_t cIdx = localCellCount; cIdx < totalGlobCellCount; ++cIdx) + { + size_t mgrdCellIdx = m_ownerMainGrid->globalCellArray()[cIdx].mainGridCellIndex(); + + size_t i (cvf::UNDEFINED_SIZE_T), j(cvf::UNDEFINED_SIZE_T), k(cvf::UNDEFINED_SIZE_T); + + if(!m_ownerMainGrid->ijkFromCellIndex(mgrdCellIdx, &i, &j, &k)) continue; + + int formNameIdx = activeFormationNames->formationIndexFromKLayerIdx(k); + if (formNameIdx != -1) + { + fnData[cIdx] = formNameIdx; + } + else + { + fnData[cIdx] = HUGE_VAL; + } + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RigFormationNames* RigCaseCellResultsData::activeFormationNames() +{ + return m_activeFormationNamesData.p(); +} + //-------------------------------------------------------------------------------------------------- /// If we have any results on any time step, assume we have loaded results //-------------------------------------------------------------------------------------------------- @@ -2587,7 +2733,7 @@ bool RigCaseCellResultsData::isDataPresent(size_t scalarResultIndex) const return false; } - const std::vector>& data = this->cellScalarResults(scalarResultIndex); + const std::vector>& data = m_cellScalarResults[scalarResultIndex]; for (size_t tsIdx = 0; tsIdx < data.size(); ++tsIdx) { @@ -2656,3 +2802,132 @@ void RigCaseCellResultsData::assignValuesToTemporaryLgrs(const QString& re RiaLogging::warning("Detected invalid/undefined cells when assigning result values to temporary LGRs"); } } + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RigStatisticsDataCache* RigCaseCellResultsData::statistics(const RigEclipseResultAddress& resVarAddr) +{ + return m_statisticsDataCache[findScalarResultIndexFromAddress(resVarAddr)].p(); +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +size_t RigCaseCellResultsData::findScalarResultIndexFromAddress(const RigEclipseResultAddress& resVarAddr) const +{ + if (!resVarAddr.isValid()) + { + return cvf::UNDEFINED_SIZE_T; + } + else if (resVarAddr.m_resultCatType == RiaDefines::UNDEFINED) + { + RigEclipseResultAddress resVarAddressWithType = resVarAddr; + + resVarAddressWithType.m_resultCatType = RiaDefines::STATIC_NATIVE; + + size_t scalarResultIndex = this->findScalarResultIndexFromAddress(resVarAddressWithType); + + if (scalarResultIndex == cvf::UNDEFINED_SIZE_T) + { + resVarAddressWithType.m_resultCatType = RiaDefines::DYNAMIC_NATIVE; + scalarResultIndex = this->findScalarResultIndexFromAddress(resVarAddressWithType); + } + + if (scalarResultIndex == cvf::UNDEFINED_SIZE_T) + { + resVarAddressWithType.m_resultCatType = RiaDefines::SOURSIMRL; + scalarResultIndex = this->findScalarResultIndexFromAddress(resVarAddressWithType); + } + + if (scalarResultIndex == cvf::UNDEFINED_SIZE_T) + { + resVarAddressWithType.m_resultCatType = RiaDefines::GENERATED; + scalarResultIndex = this->findScalarResultIndexFromAddress(resVarAddressWithType); + } + + if (scalarResultIndex == cvf::UNDEFINED_SIZE_T) + { + resVarAddressWithType.m_resultCatType = RiaDefines::INPUT_PROPERTY; + scalarResultIndex = this->findScalarResultIndexFromAddress(resVarAddressWithType); + } + + if (scalarResultIndex == cvf::UNDEFINED_SIZE_T) + { + resVarAddressWithType.m_resultCatType = RiaDefines::FORMATION_NAMES; + scalarResultIndex = this->findScalarResultIndexFromAddress(resVarAddressWithType); + } + + return scalarResultIndex; + } + else + { + std::vector::const_iterator it; + for (it = m_resultInfos.begin(); it != m_resultInfos.end(); ++it) + { + if (it->eclipseResultAddress() == resVarAddr) + { + return it->gridScalarResultIndex(); + } + } + + return cvf::UNDEFINED_SIZE_T; + } +} + +#include "RimEclipseResultCase.h" + +//-------------------------------------------------------------------------------------------------- +/// Copy result meta data from main case to all other cases in grid case group +/// This code was originally part of RimStatisticsCaseEvaluator, but moved here to be a general solution +/// for all cases +//-------------------------------------------------------------------------------------------------- +void RigCaseCellResultsData::copyResultsMetaDataFromMainCase(RigEclipseCaseData* mainCaseResultsData, + RiaDefines::PorosityModelType poroModel, + std::vector destinationCases) +{ + std::vector resAddresses = mainCaseResultsData->results(poroModel)->existingResults(); + std::vector timeStepInfos = mainCaseResultsData->results(poroModel)->timeStepInfos(resAddresses[0]); + + const std::vector resultInfos = mainCaseResultsData->results(poroModel)->infoForEachResultIndex(); + + for ( size_t i = 0; i < destinationCases.size(); i++ ) + { + RimEclipseResultCase* rimReservoir = dynamic_cast(destinationCases[i]); + + if ( !rimReservoir ) continue; // Input reservoir + if (mainCaseResultsData == rimReservoir->eclipseCaseData()) continue; // Do not copy ontop of itself + + RigCaseCellResultsData* cellResultsStorage = rimReservoir->results(poroModel); + + for ( size_t resIdx = 0; resIdx < resultInfos.size(); resIdx++ ) + { + RigEclipseResultAddress resVarAddr = resultInfos[resIdx].eclipseResultAddress(); + + bool needsToBeStored = resultInfos[resIdx].needsToBeStored(); + bool mustBeCalculated = resultInfos[resIdx].mustBeCalculated(); + + size_t scalarResultIndex = cellResultsStorage->findScalarResultIndexFromAddress(resVarAddr); + + if ( scalarResultIndex == cvf::UNDEFINED_SIZE_T ) + { + cellResultsStorage->createResultEntry(resVarAddr, needsToBeStored); + + if ( mustBeCalculated ) + { + scalarResultIndex = cellResultsStorage->findScalarResultIndexFromAddress(resVarAddr); + cellResultsStorage->setMustBeCalculated(scalarResultIndex); + } + + cellResultsStorage->setTimeStepInfos(resVarAddr, timeStepInfos); + + std::vector< std::vector >& dataValues = cellResultsStorage->modifiableCellScalarResultTimesteps(resVarAddr); + dataValues.resize(timeStepInfos.size()); + } + } + + cellResultsStorage->createPlaceholderResultEntries(); + } +} + diff --git a/ApplicationCode/ReservoirDataModel/RigCaseCellResultsData.h b/ApplicationCode/ReservoirDataModel/RigCaseCellResultsData.h index 6b7a04516c..cac97fc235 100644 --- a/ApplicationCode/ReservoirDataModel/RigCaseCellResultsData.h +++ b/ApplicationCode/ReservoirDataModel/RigCaseCellResultsData.h @@ -21,6 +21,9 @@ #pragma once #include "RiaDefines.h" +#include "RiaPorosityModel.h" + +#include "RigEclipseResultAddress.h" #include "cvfCollection.h" @@ -29,6 +32,7 @@ #include #include + class RifReaderInterface; class RigActiveCellInfo; class RigMainGrid; @@ -36,6 +40,11 @@ class RigEclipseResultInfo; class RigStatisticsDataCache; class RigEclipseTimeStepInfo; class RigEclipseCaseData; +class RigFormationNames; + +class RimEclipseCase; + + //================================================================================================== /// Class containing the results for the complete number of active cells. Both main grid and LGR's @@ -43,107 +52,116 @@ class RigEclipseCaseData; class RigCaseCellResultsData : public cvf::Object { public: - explicit RigCaseCellResultsData(RigEclipseCaseData* ownerCaseData); + explicit RigCaseCellResultsData(RigEclipseCaseData* ownerCaseData, RiaDefines::PorosityModelType porosityModel); + + // Initialization void setReaderInterface(RifReaderInterface* readerInterface); void setHdf5Filename(const QString& hdf5SourSimFilename ); + void setActiveFormationNames(RigFormationNames* activeFormationNames); + RigFormationNames* activeFormationNames(); void setMainGrid(RigMainGrid* ownerGrid); void setActiveCellInfo(RigActiveCellInfo* activeCellInfo); RigActiveCellInfo* activeCellInfo(); const RigActiveCellInfo* activeCellInfo() const; - // Max and min values of the results - void recalculateStatistics(size_t scalarResultIndex); - void minMaxCellScalarValues(size_t scalarResultIndex, double& min, double& max); - void minMaxCellScalarValues(size_t scalarResultIndex, size_t timeStepIndex, double& min, double& max); - void posNegClosestToZero(size_t scalarResultIndex, double& pos, double& neg); - void posNegClosestToZero(size_t scalarResultIndex, size_t timeStepIndex, double& pos, double& neg); - const std::vector& cellScalarValuesHistogram(size_t scalarResultIndex); - const std::vector& cellScalarValuesHistogram(size_t scalarResultIndex, size_t timeStepIndex); - void p10p90CellScalarValues(size_t scalarResultIndex, double& p10, double& p90); - void p10p90CellScalarValues(size_t scalarResultIndex, size_t timeStepIndex, double& p10, double& p90); - void meanCellScalarValues(size_t scalarResultIndex, double& meanValue); - void meanCellScalarValues(size_t scalarResultIndex, size_t timeStepIndex, double& meanValue); - const std::vector& uniqueCellScalarValues(size_t scalarResultIndex); - void sumCellScalarValues(size_t scalarResultIndex, double& sumValue); - void sumCellScalarValues(size_t scalarResultIndex, size_t timeStepIndex, double& sumValue); - void mobileVolumeWeightedMean(size_t scalarResultIndex, double& meanValue); - void mobileVolumeWeightedMean(size_t scalarResultIndex, size_t timeStepIndex, double& meanValue); + // Access the results data + + const std::vector< std::vector > & cellScalarResults(const RigEclipseResultAddress& resVarAddr) const; + const std::vector& cellScalarResults(const RigEclipseResultAddress& resVarAddr, size_t timeStepIndex) const; + std::vector< std::vector > & modifiableCellScalarResultTimesteps(const RigEclipseResultAddress& resVarAddr); + std::vector& modifiableCellScalarResult(const RigEclipseResultAddress& resVarAddr, size_t timeStepIndex); + + bool isUsingGlobalActiveIndex(const RigEclipseResultAddress& resVarAddr) const; + + static const std::vector* getResultIndexableStaticResult(RigActiveCellInfo* actCellInfo, + RigCaseCellResultsData* gridCellResults, + QString porvResultName, + std::vector &activeCellsResultsTempContainer); + // Statistic values of the results + + void recalculateStatistics(const RigEclipseResultAddress& resVarAddr); + void minMaxCellScalarValues(const RigEclipseResultAddress& resVarAddr, double& min, double& max); + void minMaxCellScalarValues(const RigEclipseResultAddress& resVarAddr, size_t timeStepIndex, double& min, double& max); + void posNegClosestToZero(const RigEclipseResultAddress& resVarAddr, double& pos, double& neg); + void posNegClosestToZero(const RigEclipseResultAddress& resVarAddr, size_t timeStepIndex, double& pos, double& neg); + const std::vector& cellScalarValuesHistogram(const RigEclipseResultAddress& resVarAddr); + const std::vector& cellScalarValuesHistogram(const RigEclipseResultAddress& resVarAddr, size_t timeStepIndex); + void p10p90CellScalarValues(const RigEclipseResultAddress& resVarAddr, double& p10, double& p90); + void p10p90CellScalarValues(const RigEclipseResultAddress& resVarAddr, size_t timeStepIndex, double& p10, double& p90); + void meanCellScalarValues(const RigEclipseResultAddress& resVarAddr, double& meanValue); + void meanCellScalarValues(const RigEclipseResultAddress& resVarAddr, size_t timeStepIndex, double& meanValue); + const std::vector& uniqueCellScalarValues(const RigEclipseResultAddress& resVarAddr); + void sumCellScalarValues(const RigEclipseResultAddress& resVarAddr, double& sumValue); + void sumCellScalarValues(const RigEclipseResultAddress& resVarAddr, size_t timeStepIndex, double& sumValue); + void mobileVolumeWeightedMean(const RigEclipseResultAddress& resVarAddr, double& meanValue); + void mobileVolumeWeightedMean(const RigEclipseResultAddress& resVarAddr, size_t timeStepIndex, double& meanValue); + // Access meta-information about the results - size_t resultCount() const; - size_t timeStepCount(size_t scalarResultIndex) const; - size_t maxTimeStepCount(size_t* scalarResultIndex = nullptr) const; - QStringList resultNames(RiaDefines::ResultCatType type) const; - bool isUsingGlobalActiveIndex(size_t scalarResultIndex) const; - bool hasFlowDiagUsableFluxes() const; + + size_t timeStepCount(const RigEclipseResultAddress& resVarAddr) const; + size_t maxTimeStepCount(RigEclipseResultAddress* resultAddressWithMostTimeSteps = nullptr) const; std::vector allTimeStepDatesFromEclipseReader() const; std::vector timeStepDates() const; - std::vector timeStepDates(size_t scalarResultIndex) const; + std::vector timeStepDates(const RigEclipseResultAddress& resVarAddr) const; std::vector daysSinceSimulationStart() const; - std::vector daysSinceSimulationStart(size_t scalarResultIndex) const; - int reportStepNumber(size_t scalarResultIndex, size_t timeStepIndex) const; + std::vector daysSinceSimulationStart(const RigEclipseResultAddress& resVarAddr) const; + int reportStepNumber(const RigEclipseResultAddress& resVarAddr, size_t timeStepIndex) const; - std::vector timeStepInfos(size_t scalarResultIndex) const; - void setTimeStepInfos(size_t scalarResultIndex, const std::vector& timeStepInfos); - - size_t findOrLoadScalarResultForTimeStep(RiaDefines::ResultCatType type, const QString& resultName, size_t timeStepIndex); - size_t findOrLoadScalarResult(RiaDefines::ResultCatType type, const QString& resultName); - size_t findOrLoadScalarResult(const QString& resultName); ///< Simplified search. Assumes unique names across types. + std::vector timeStepInfos(const RigEclipseResultAddress& resVarAddr) const; + void setTimeStepInfos(const RigEclipseResultAddress& resVarAddr, const std::vector& timeStepInfos); - // Find or create a slot for the results - - size_t findOrCreateScalarResultIndex(RiaDefines::ResultCatType type, const QString& resultName, bool needsToBeStored); - size_t findScalarResultIndex(RiaDefines::ResultCatType type, const QString& resultName) const; - size_t findScalarResultIndex(const QString& resultName) const; + void clearScalarResult(RiaDefines::ResultCatType type, const QString & resultName); + void clearScalarResult(const RigEclipseResultAddress& resultAddress); + void clearAllResults(); + void freeAllocatedResultsData(); + void eraseAllSourSimData(); + QStringList resultNames(RiaDefines::ResultCatType type) const; + std::vector existingResults() const; + const RigEclipseResultInfo* resultInfo(const RigEclipseResultAddress& resVarAddr) const; + bool updateResultName(RiaDefines::ResultCatType resultType, QString& oldName, const QString& newName); QString makeResultNameUnique(const QString& resultNameProposal) const; + void ensureKnownResultLoadedForTimeStep(const RigEclipseResultAddress& resultAddress, size_t timeStepIndex); + bool ensureKnownResultLoaded(const RigEclipseResultAddress& resultAddress); + bool hasResultEntry(const RigEclipseResultAddress& resultAddress) const; + bool isResultLoaded(const RigEclipseResultAddress& resultAddress) const; + void createResultEntry(const RigEclipseResultAddress& resultAddress, bool needsToBeStored); void createPlaceholderResultEntries(); void computeDepthRelatedResults(); void computeCellVolumes(); + bool hasFlowDiagUsableFluxes() const; - void clearScalarResult(RiaDefines::ResultCatType type, const QString & resultName); - void clearScalarResult(const RigEclipseResultInfo& resultInfo); - void clearAllResults(); - void freeAllocatedResultsData(); - bool isResultLoaded(const RigEclipseResultInfo& resultInfo) const; - - - // Access the results data - - const std::vector< std::vector > & cellScalarResults(size_t scalarResultIndex) const; - std::vector< std::vector > & cellScalarResults(size_t scalarResultIndex); - std::vector& cellScalarResults(size_t scalarResultIndex, size_t timeStepIndex); + static void copyResultsMetaDataFromMainCase(RigEclipseCaseData* mainCaseResultsData, + RiaDefines::PorosityModelType poroModel, + std::vector destinationCases); +private: + size_t findOrLoadKnownScalarResult(const RigEclipseResultAddress& resVarAddr); + size_t findOrLoadKnownScalarResultForTimeStep(const RigEclipseResultAddress& resVarAddr, + size_t timeStepIndex); + size_t findOrCreateScalarResultIndex(const RigEclipseResultAddress& resVarAddr, bool needsToBeStored); - bool updateResultName(RiaDefines::ResultCatType resultType, QString& oldName, const QString& newName); + size_t findScalarResultIndexFromAddress(const RigEclipseResultAddress& resVarAddr ) const; - static const std::vector* getResultIndexableStaticResult(RigActiveCellInfo* actCellInfo, - RigCaseCellResultsData* gridCellResults, - QString porvResultName, - std::vector &activeCellsResultsTempContainer); + size_t addStaticScalarResult(RiaDefines::ResultCatType type, + const QString& resultName, + bool needsToBeStored, + size_t resultValueCount); -public: const std::vector& infoForEachResultIndex(); + size_t resultCount() const; bool mustBeCalculated(size_t scalarResultIndex) const; void setMustBeCalculated(size_t scalarResultIndex); - void eraseAllSourSimData(); - -public: - size_t addStaticScalarResult(RiaDefines::ResultCatType type, - const QString& resultName, - bool needsToBeStored, - size_t resultValueCount); - - bool - findTransmissibilityResults(size_t& tranX, size_t& tranY, size_t& tranZ) const; -private: // from RimReservoirCellResultsStorage void computeSOILForTimeStep(size_t timeStepIndex); void testAndComputeSgasForTimeStep(size_t timeStepIndex); + bool hasCompleteTransmissibilityResults() const; + void computeRiTransComponent(const QString& riTransComponentResultName); void computeNncCombRiTrans(); @@ -162,16 +180,18 @@ class RigCaseCellResultsData : public cvf::Object void assignValuesToTemporaryLgrs(const QString& resultName, std::vector& values); - cvf::ref m_readerInterface; + RigStatisticsDataCache* statistics(const RigEclipseResultAddress& resVarAddr); private: + cvf::ref m_readerInterface; + cvf::ref m_activeFormationNamesData; + std::vector< std::vector< std::vector > > m_cellScalarResults; ///< Scalar results on the complete reservoir for each Result index (ResultVariable) and timestep cvf::Collection m_statisticsDataCache; - -private: std::vector m_resultInfos; RigMainGrid* m_ownerMainGrid; RigEclipseCaseData* m_ownerCaseData; RigActiveCellInfo* m_activeCellInfo; + RiaDefines::PorosityModelType m_porosityModel; }; diff --git a/ApplicationCode/ReservoirDataModel/RigCaseToCaseRangeFilterMapper.h b/ApplicationCode/ReservoirDataModel/RigCaseToCaseRangeFilterMapper.h index 1b00489345..55a6a7d25b 100644 --- a/ApplicationCode/ReservoirDataModel/RigCaseToCaseRangeFilterMapper.h +++ b/ApplicationCode/ReservoirDataModel/RigCaseToCaseRangeFilterMapper.h @@ -18,7 +18,7 @@ ///////////////////////////////////////////////////////////////////////////////// #pragma once -#include +#include class RimCellRangeFilter; class RigMainGrid; diff --git a/ApplicationCode/ReservoirDataModel/RigCell.cpp b/ApplicationCode/ReservoirDataModel/RigCell.cpp index fa68e9cd1e..8d0e2537d6 100644 --- a/ApplicationCode/ReservoirDataModel/RigCell.cpp +++ b/ApplicationCode/ReservoirDataModel/RigCell.cpp @@ -25,7 +25,7 @@ #include "cvfPlane.h" #include "cvfRay.h" -#include +#include static size_t undefinedCornersArray[8] = {cvf::UNDEFINED_SIZE_T, cvf::UNDEFINED_SIZE_T, @@ -125,6 +125,8 @@ bool RigCell::isLongPyramidCell(double maxHeightFactor, double nodeNearTolerance if (zeroLengthEdgeCount == 3) { return true; + + #if 0 // More advanced checks turned off since the start. Why did I do that ? // Collapse of a complete face is detected. This is possibly the top of a pyramid // "face" has the index to the collapsed face. We need the size of the opposite face @@ -193,6 +195,7 @@ bool RigCell::isLongPyramidCell(double maxHeightFactor, double nodeNearTolerance return true; } } + #endif } // Check the ratio of the length of opposite edges. diff --git a/ApplicationCode/ReservoirDataModel/RigCellGeometryTools.cpp b/ApplicationCode/ReservoirDataModel/RigCellGeometryTools.cpp index 6bf94fe9fa..9815582181 100644 --- a/ApplicationCode/ReservoirDataModel/RigCellGeometryTools.cpp +++ b/ApplicationCode/ReservoirDataModel/RigCellGeometryTools.cpp @@ -29,8 +29,9 @@ #include "cvfMath.h" -#include +#include #include +#include //-------------------------------------------------------------------------------------------------- /// Efficient Computation of Volume of Hexahedral Cells @@ -85,16 +86,30 @@ double RigCellGeometryTools::calculateCellVolume(const std::array } //-------------------------------------------------------------------------------------------------- -/// +/// A reasonable approximation to the overlap volume //-------------------------------------------------------------------------------------------------- -std::array RigCellGeometryTools::estimateHexOverlapWithBoundingBox(const std::array& hexCorners, const cvf::BoundingBox& boundingBox, cvf::BoundingBox* overlapBoundingBox) +bool RigCellGeometryTools::estimateHexOverlapWithBoundingBox(const std::array& hexCorners, const cvf::BoundingBox& boundingBox, std::array* overlapElement, cvf::BoundingBox* overlapBoundingBox) { - CVF_ASSERT(overlapBoundingBox); + CVF_ASSERT(overlapElement && overlapBoundingBox); *overlapBoundingBox = cvf::BoundingBox(); + std::array overlapCorners = hexCorners; - // A reasonable approximation to the overlap volume - cvf::Plane topPlane; topPlane.setFromPoints(hexCorners[0], hexCorners[1], hexCorners[2]); - cvf::Plane bottomPlane; bottomPlane.setFromPoints(hexCorners[4], hexCorners[5], hexCorners[6]); + + std::vector uniqueTopPoints = { hexCorners[0], hexCorners[1], hexCorners[2], hexCorners[3] }; + uniqueTopPoints.erase(std::unique(uniqueTopPoints.begin(), uniqueTopPoints.end()), uniqueTopPoints.end()); + if (uniqueTopPoints.size() < 3) return false; + + cvf::Plane topPlane; + if (!topPlane.setFromPoints(uniqueTopPoints[0], uniqueTopPoints[1], uniqueTopPoints[2])) + return false; + + std::vector uniqueBottomPoints = {hexCorners[4], hexCorners[5], hexCorners[6], hexCorners[7]}; + uniqueBottomPoints.erase(std::unique(uniqueBottomPoints.begin(), uniqueBottomPoints.end()), uniqueBottomPoints.end()); + if (uniqueBottomPoints.size() < 3) return false; + + cvf::Plane bottomPlane; + if (!bottomPlane.setFromPoints(uniqueBottomPoints[0], uniqueBottomPoints[1], uniqueBottomPoints[2])) + return false; for (size_t i = 0; i < 4; ++i) { @@ -104,8 +119,8 @@ std::array RigCellGeometryTools::estimateHexOverlapWithBoundingBo corner.z() = cvf::Math::clamp(corner.z(), boundingBox.min().z(), boundingBox.max().z()); cvf::Vec3d maxZCorner = corner; maxZCorner.z() = boundingBox.max().z(); cvf::Vec3d minZCorner = corner; minZCorner.z() = boundingBox.min().z(); - topPlane.intersect(minZCorner, maxZCorner, &corner); - overlapBoundingBox->add(corner); + if (topPlane.intersect(minZCorner, maxZCorner, &corner)) + overlapBoundingBox->add(corner); } for (size_t i = 4; i < 8; ++i) { @@ -115,16 +130,20 @@ std::array RigCellGeometryTools::estimateHexOverlapWithBoundingBo corner.z() = cvf::Math::clamp(corner.z(), boundingBox.min().z(), boundingBox.max().z()); cvf::Vec3d maxZCorner = corner; maxZCorner.z() = boundingBox.max().z(); cvf::Vec3d minZCorner = corner; minZCorner.z() = boundingBox.min().z(); - bottomPlane.intersect(minZCorner, maxZCorner, &corner); - overlapBoundingBox->add(corner); + if (bottomPlane.intersect(minZCorner, maxZCorner, &corner)) + overlapBoundingBox->add(corner); } - return overlapCorners; + + *overlapElement = overlapCorners; + return true; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RigCellGeometryTools::createPolygonFromLineSegments(std::list> &intersectionLineSegments, std::vector> &polygons) +void RigCellGeometryTools::createPolygonFromLineSegments(std::list>& intersectionLineSegments, + std::vector>& polygons, + double tolerance) { bool startNewPolygon = true; while (!intersectionLineSegments.empty()) @@ -146,7 +165,6 @@ void RigCellGeometryTools::createPolygonFromLineSegments(std::list >::iterator lIt = intersectionLineSegments.begin(); lIt != intersectionLineSegments.end(); lIt++) { @@ -191,9 +209,50 @@ void RigCellGeometryTools::createPolygonFromLineSegments(std::list* vertices, double epsilon) +{ + CVF_ASSERT(vertices); + if (vertices->size() < 3) return; + std::pair maxDistPoint(0u, 0.0); + for (size_t i = 1; i < vertices->size() - 1; ++i) + { + cvf::Vec3d v = vertices->at(i); + double u; + cvf::Vec3d v_proj = cvf::GeometryTools::projectPointOnLine(vertices->front(), vertices->back(), v, &u); + double distance = (v_proj - v).length(); + if (distance > maxDistPoint.second) + { + maxDistPoint = std::make_pair(i, distance); + } + } + + if (maxDistPoint.second > epsilon) + { + std::vector newVertices1(vertices->begin(), vertices->begin() + maxDistPoint.first + 1); + std::vector newVertices2(vertices->begin() + maxDistPoint.first, vertices->end()); + + // Recurse + simplifyPolygon(&newVertices1, epsilon); + simplifyPolygon(&newVertices2, epsilon); + + std::vector newVertices(newVertices1.begin(), newVertices1.end() - 1); + newVertices.insert(newVertices.end(), newVertices2.begin(), newVertices2.end()); + *vertices = newVertices; + } + else + { + std::vector newVertices = {vertices->front(), vertices->back()}; + *vertices = newVertices; + } } //================================================================================================== @@ -627,7 +686,6 @@ std::vector RigCellGeometryTools::unionOfPolygons(const std::vector< std::vector unionPolygon; for (ClipperLib::Path pathInSol : solution) { - std::vector clippedPolygon; for (ClipperLib::IntPoint IntPosition : pathInSol) { unionPolygon.push_back(fromClipperPoint(IntPosition)); diff --git a/ApplicationCode/ReservoirDataModel/RigCellGeometryTools.h b/ApplicationCode/ReservoirDataModel/RigCellGeometryTools.h index 9de7ae10d8..e76d114a05 100644 --- a/ApplicationCode/ReservoirDataModel/RigCellGeometryTools.h +++ b/ApplicationCode/ReservoirDataModel/RigCellGeometryTools.h @@ -32,12 +32,15 @@ class RigCellGeometryTools { public: static double calculateCellVolume(const std::array& hexCorners); - static std::array estimateHexOverlapWithBoundingBox(const std::array& hexCorners, + static bool estimateHexOverlapWithBoundingBox(const std::array& hexCorners, const cvf::BoundingBox& boundingBox2dExtrusion, + std::array* overlapCorners, cvf::BoundingBox* overlapBoundingBox); static void createPolygonFromLineSegments(std::list>& intersectionLineSegments, - std::vector>& polygons); + std::vector>& polygons, + double tolerance = 1.0e-4); + static void simplifyPolygon(std::vector* vertices, double epsilon); static void findCellLocalXYZ(const std::array& hexCorners, cvf::Vec3d& localXdirection, diff --git a/ApplicationCode/ReservoirDataModel/RigEclipseCaseData.cpp b/ApplicationCode/ReservoirDataModel/RigEclipseCaseData.cpp index c61253611d..06d354953e 100644 --- a/ApplicationCode/ReservoirDataModel/RigEclipseCaseData.cpp +++ b/ApplicationCode/ReservoirDataModel/RigEclipseCaseData.cpp @@ -3,17 +3,17 @@ // Copyright (C) 2011- Statoil ASA // Copyright (C) 2013- Ceetron Solutions AS // Copyright (C) 2011-2012 Ceetron AS -// +// // ResInsight 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 3 of the License, or // (at your option) any later version. -// +// // ResInsight 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 at +// +// See the GNU General Public License at // for more details. // ///////////////////////////////////////////////////////////////////////////////// @@ -22,8 +22,11 @@ #include "RiaApplication.h" +#include "RifReaderEclipseOutput.h" + #include "RigActiveCellInfo.h" #include "RigCaseCellResultsData.h" +#include "RigEquil.h" #include "RigFormationNames.h" #include "RigMainGrid.h" #include "RigResultAccessorFactory.h" @@ -40,17 +43,18 @@ #include //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- RigEclipseCaseData::RigEclipseCaseData(RimEclipseCase* ownerCase) + : m_hasParsedDeckForEquilData(false) { - m_mainGrid = new RigMainGrid(); + m_mainGrid = new RigMainGrid(); m_ownerCase = ownerCase; - m_matrixModelResults = new RigCaseCellResultsData(this); - m_fractureModelResults = new RigCaseCellResultsData(this); + m_matrixModelResults = new RigCaseCellResultsData(this, RiaDefines::MATRIX_MODEL); + m_fractureModelResults = new RigCaseCellResultsData(this, RiaDefines::FRACTURE_MODEL); - m_activeCellInfo = new RigActiveCellInfo; + m_activeCellInfo = new RigActiveCellInfo; m_fractureActiveCellInfo = new RigActiveCellInfo; m_matrixModelResults->setActiveCellInfo(m_activeCellInfo.p()); @@ -60,15 +64,12 @@ RigEclipseCaseData::RigEclipseCaseData(RimEclipseCase* ownerCase) } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- -RigEclipseCaseData::~RigEclipseCaseData() -{ - -} +RigEclipseCaseData::~RigEclipseCaseData() {} //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- RigMainGrid* RigEclipseCaseData::mainGrid() { @@ -76,7 +77,7 @@ RigMainGrid* RigEclipseCaseData::mainGrid() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- const RigMainGrid* RigEclipseCaseData::mainGrid() const { @@ -84,7 +85,7 @@ const RigMainGrid* RigEclipseCaseData::mainGrid() const } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RigEclipseCaseData::setMainGrid(RigMainGrid* mainGrid) { @@ -95,7 +96,7 @@ void RigEclipseCaseData::setMainGrid(RigMainGrid* mainGrid) } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RigEclipseCaseData::allGrids(std::vector* grids) { @@ -114,7 +115,7 @@ void RigEclipseCaseData::allGrids(std::vector* grids) } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RigEclipseCaseData::allGrids(std::vector* grids) const { @@ -141,18 +142,17 @@ const RigGridBase* RigEclipseCaseData::grid(size_t index) const return m_mainGrid->gridByIndex(index); } - //-------------------------------------------------------------------------------------------------- /// Get grid by index. The main grid has index 0, so the first lgr has index 1 //-------------------------------------------------------------------------------------------------- -RigGridBase* RigEclipseCaseData::grid(size_t index) +RigGridBase* RigEclipseCaseData::grid(size_t index) { CVF_ASSERT(m_mainGrid.notNull()); return m_mainGrid->gridByIndex(index); } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- const RigGridBase* RigEclipseCaseData::grid(const QString& gridName) const { @@ -176,7 +176,7 @@ const RigGridBase* RigEclipseCaseData::grid(const QString& gridName) const } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- size_t RigEclipseCaseData::gridCount() const { @@ -184,35 +184,34 @@ size_t RigEclipseCaseData::gridCount() const return m_mainGrid->gridCount(); } - //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RigEclipseCaseData::computeWellCellsPrGrid() { // If we have computed this already, return - if (m_wellCellsInGrid.size()) return; + if (m_wellCellsInGrid.size()) return; std::vector grids; this->allGrids(&grids); // Debug code used to display grid names and grid sizes -/* - size_t totCellCount = 0; - for (auto g : grids) - { - qDebug() << g->gridName().data(); - qDebug() << g->cellCountI() << " " << g->cellCountJ() << " " << g->cellCountK() << " "; + /* + size_t totCellCount = 0; + for (auto g : grids) + { + qDebug() << g->gridName().data(); + qDebug() << g->cellCountI() << " " << g->cellCountJ() << " " << g->cellCountK() << " "; - size_t cellCount = g->cellCount(); - totCellCount += cellCount; - qDebug() << cellCount; + size_t cellCount = g->cellCount(); + totCellCount += cellCount; + qDebug() << cellCount; - qDebug() << "\n"; - } + qDebug() << "\n"; + } - qDebug() << "\nTotal cell count " << totCellCount; -*/ + qDebug() << "\nTotal cell count " << totCellCount; + */ size_t gIdx; @@ -242,7 +241,7 @@ void RigEclipseCaseData::computeWellCellsPrGrid() size_t tIdx; for (tIdx = 0; tIdx < m_simWellData[wIdx]->m_wellCellsTimeSteps.size(); ++tIdx) { - RigWellResultFrame& wellCells = m_simWellData[wIdx]->m_wellCellsTimeSteps[tIdx]; + RigWellResultFrame& wellCells = m_simWellData[wIdx]->m_wellCellsTimeSteps[tIdx]; // Well result branches for (size_t sIdx = 0; sIdx < wellCells.m_wellResultBranches.size(); ++sIdx) @@ -255,7 +254,7 @@ void RigEclipseCaseData::computeWellCellsPrGrid() size_t gridIndex = wellSegment.m_branchResultPoints[cdIdx].m_gridIndex; size_t gridCellIndex = wellSegment.m_branchResultPoints[cdIdx].m_gridCellIndex; - if(gridIndex < m_wellCellsInGrid.size() && gridCellIndex < m_wellCellsInGrid[gridIndex]->size()) + if (gridIndex < m_wellCellsInGrid.size() && gridCellIndex < m_wellCellsInGrid[gridIndex]->size()) { // NOTE : We do not check if the grid cell is active as we do for well head. // If we add test for active cell, thorough testing and verification of the new behaviour must be adressed @@ -270,7 +269,7 @@ void RigEclipseCaseData::computeWellCellsPrGrid() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RigEclipseCaseData::setSimWellData(const cvf::Collection& data) { @@ -281,9 +280,8 @@ void RigEclipseCaseData::setSimWellData(const cvf::Collection& d computeWellCellsPrGrid(); } - //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- std::set RigEclipseCaseData::findSortedWellNames() const { @@ -300,7 +298,7 @@ std::set RigEclipseCaseData::findSortedWellNames() const } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- const RigSimWellData* RigEclipseCaseData::findSimWellData(QString wellName) const { @@ -316,7 +314,7 @@ const RigSimWellData* RigEclipseCaseData::findSimWellData(QString wellName) cons } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- const cvf::UByteArray* RigEclipseCaseData::wellCellsInGrid(size_t gridIndex) { @@ -326,9 +324,8 @@ const cvf::UByteArray* RigEclipseCaseData::wellCellsInGrid(size_t gridIndex) return m_wellCellsInGrid[gridIndex].p(); } - //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- const cvf::UIntArray* RigEclipseCaseData::gridCellToResultWellIndex(size_t gridIndex) { @@ -339,7 +336,7 @@ const cvf::UIntArray* RigEclipseCaseData::gridCellToResultWellIndex(size_t gridI } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- const RigCell& RigEclipseCaseData::cellFromWellResultCell(const RigWellResultPoint& wellResultCell) const { @@ -355,16 +352,16 @@ const RigCell& RigEclipseCaseData::cellFromWellResultCell(const RigWellResultPoi } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- -bool RigEclipseCaseData::findSharedSourceFace(cvf::StructGridInterface::FaceType& sharedSourceFace, - const RigWellResultPoint& sourceWellCellResult, - const RigWellResultPoint& otherWellCellResult) const +bool RigEclipseCaseData::findSharedSourceFace(cvf::StructGridInterface::FaceType& sharedSourceFace, + const RigWellResultPoint& sourceWellCellResult, + const RigWellResultPoint& otherWellCellResult) const { - size_t gridIndex = sourceWellCellResult.m_gridIndex; + size_t gridIndex = sourceWellCellResult.m_gridIndex; size_t gridCellIndex = sourceWellCellResult.m_gridCellIndex; - size_t otherGridIndex = otherWellCellResult.m_gridIndex; + size_t otherGridIndex = otherWellCellResult.m_gridIndex; size_t otherGridCellIndex = otherWellCellResult.m_gridCellIndex; if (gridIndex != otherGridIndex) return false; @@ -373,7 +370,7 @@ bool RigEclipseCaseData::findSharedSourceFace(cvf::StructGridInterface::FaceType allGrids(&grids); const RigGridBase* grid = grids[gridIndex]; - size_t i, j, k; + size_t i, j, k; grid->ijkFromCellIndex(gridCellIndex, &i, &j, &k); size_t faceIdx; @@ -386,7 +383,6 @@ bool RigEclipseCaseData::findSharedSourceFace(cvf::StructGridInterface::FaceType if (grid->isCellValid(ni, nj, nk)) { - size_t neighborCellIndex = grid->cellIndexFromIJK(ni, nj, nk); if (neighborCellIndex == otherGridCellIndex) @@ -400,8 +396,6 @@ bool RigEclipseCaseData::findSharedSourceFace(cvf::StructGridInterface::FaceType return false; } - - //-------------------------------------------------------------------------------------------------- /// Helper class used to find min/max range for valid and active cells //-------------------------------------------------------------------------------------------------- @@ -409,10 +403,9 @@ class CellRangeBB { public: CellRangeBB() - : m_min(cvf::UNDEFINED_SIZE_T, cvf::UNDEFINED_SIZE_T, cvf::UNDEFINED_SIZE_T), - m_max(cvf::Vec3st::ZERO) + : m_min(cvf::UNDEFINED_SIZE_T, cvf::UNDEFINED_SIZE_T, cvf::UNDEFINED_SIZE_T) + , m_max(cvf::Vec3st::ZERO) { - } void add(size_t i, size_t j, size_t k) @@ -431,9 +424,8 @@ class CellRangeBB cvf::Vec3st m_max; }; - //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RigEclipseCaseData::computeActiveCellIJKBBox() { @@ -464,7 +456,7 @@ void RigEclipseCaseData::computeActiveCellIJKBBox() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RigEclipseCaseData::computeActiveCellBoundingBoxes() { @@ -473,7 +465,7 @@ void RigEclipseCaseData::computeActiveCellBoundingBoxes() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- std::vector RigEclipseCaseData::simulationWellNames() const { @@ -486,7 +478,7 @@ std::vector RigEclipseCaseData::simulationWellNames() const } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- bool RigEclipseCaseData::hasSimulationWell(const QString& simWellName) const { @@ -545,15 +537,16 @@ std::vector RigEclipseCaseData::simulationWellBranches(const } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- -void RigEclipseCaseData::setVirtualPerforationTransmissibilities(RigVirtualPerforationTransmissibilities* virtualPerforationTransmissibilities) +void RigEclipseCaseData::setVirtualPerforationTransmissibilities( + RigVirtualPerforationTransmissibilities* virtualPerforationTransmissibilities) { m_virtualPerforationTransmissibilities = virtualPerforationTransmissibilities; } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- const RigVirtualPerforationTransmissibilities* RigEclipseCaseData::virtualPerforationTransmissibilities() const { @@ -561,7 +554,36 @@ const RigVirtualPerforationTransmissibilities* RigEclipseCaseData::virtualPerfor } //-------------------------------------------------------------------------------------------------- -/// +/// +//-------------------------------------------------------------------------------------------------- +void RigEclipseCaseData::ensureDeckIsParsedForEquilData(const QString& dataDeckFile, const QString& includeFileAbsolutePathPrefix) +{ + if (!m_hasParsedDeckForEquilData) + { + RifReaderEclipseOutput::importEquilData(dataDeckFile, includeFileAbsolutePathPrefix, this); + + m_hasParsedDeckForEquilData = true; + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector RigEclipseCaseData::equilData() const +{ + return m_equil; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RigEclipseCaseData::setEquilData(const std::vector& equilObjects) +{ + m_equil = equilObjects; +} + +//-------------------------------------------------------------------------------------------------- +/// //-------------------------------------------------------------------------------------------------- RigActiveCellInfo* RigEclipseCaseData::activeCellInfo(RiaDefines::PorosityModelType porosityModel) { @@ -574,7 +596,7 @@ RigActiveCellInfo* RigEclipseCaseData::activeCellInfo(RiaDefines::PorosityModelT } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- const RigActiveCellInfo* RigEclipseCaseData::activeCellInfo(RiaDefines::PorosityModelType porosityModel) const { @@ -587,7 +609,7 @@ const RigActiveCellInfo* RigEclipseCaseData::activeCellInfo(RiaDefines::Porosity } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RigEclipseCaseData::setActiveCellInfo(RiaDefines::PorosityModelType porosityModel, RigActiveCellInfo* activeCellInfo) { @@ -603,14 +625,12 @@ void RigEclipseCaseData::setActiveCellInfo(RiaDefines::PorosityModelType porosit } } - //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- bool RigEclipseCaseData::hasFractureResults() const { - if (activeCellInfo(RiaDefines::FRACTURE_MODEL) - && activeCellInfo(RiaDefines::FRACTURE_MODEL)->reservoirActiveCellCount() > 0) + if (activeCellInfo(RiaDefines::FRACTURE_MODEL) && activeCellInfo(RiaDefines::FRACTURE_MODEL)->reservoirActiveCellCount() > 0) { return true; } @@ -619,7 +639,7 @@ bool RigEclipseCaseData::hasFractureResults() const } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RigEclipseCaseData::computeActiveCellsGeometryBoundingBox() { @@ -671,66 +691,19 @@ void RigEclipseCaseData::computeActiveCellsGeometryBoundingBox() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RigEclipseCaseData::setActiveFormationNames(RigFormationNames* activeFormationNames) { - m_activeFormationNamesData = activeFormationNames; - - size_t totalGlobCellCount = m_mainGrid->globalCellArray().size(); - size_t resIndex = m_matrixModelResults->addStaticScalarResult(RiaDefines::FORMATION_NAMES, - RiaDefines::activeFormationNamesResultName(), - false, - totalGlobCellCount); - - std::vector& fnData = m_matrixModelResults->cellScalarResults(resIndex,0); - - if (m_activeFormationNamesData.isNull()) - { - for ( size_t cIdx = 0; cIdx < totalGlobCellCount; ++cIdx ) - { - fnData[cIdx] = HUGE_VAL; - } - - return; - } - - size_t localCellCount = m_mainGrid->cellCount(); - for (size_t cIdx = 0; cIdx < localCellCount; ++cIdx) - { - size_t i (cvf::UNDEFINED_SIZE_T), j(cvf::UNDEFINED_SIZE_T), k(cvf::UNDEFINED_SIZE_T); - - if(!m_mainGrid->ijkFromCellIndex(cIdx, &i, &j, &k)) continue; - - int formNameIdx = activeFormationNames->formationIndexFromKLayerIdx(k); - if (formNameIdx != -1) - { - fnData[cIdx] = formNameIdx; - } - else - { - fnData[cIdx] = HUGE_VAL; - } - } - - for (size_t cIdx = localCellCount; cIdx < totalGlobCellCount; ++cIdx) - { - size_t mgrdCellIdx = m_mainGrid->globalCellArray()[cIdx].mainGridCellIndex(); - - size_t i (cvf::UNDEFINED_SIZE_T), j(cvf::UNDEFINED_SIZE_T), k(cvf::UNDEFINED_SIZE_T); - - if(!m_mainGrid->ijkFromCellIndex(mgrdCellIdx, &i, &j, &k)) continue; + m_matrixModelResults->setActiveFormationNames(activeFormationNames); +} - int formNameIdx = activeFormationNames->formationIndexFromKLayerIdx(k); - if (formNameIdx != -1) - { - fnData[cIdx] = formNameIdx; - } - else - { - fnData[cIdx] = HUGE_VAL; - } - } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RigEclipseCaseData::setActiveFormationNamesAndUpdatePlots(RigFormationNames* activeFormationNames) +{ + setActiveFormationNames(activeFormationNames); RimProject* project = RiaApplication::instance()->project(); if (project) @@ -743,15 +716,15 @@ void RigEclipseCaseData::setActiveFormationNames(RigFormationNames* activeFormat } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- RigFormationNames* RigEclipseCaseData::activeFormationNames() { - return m_activeFormationNamesData.p(); + return m_matrixModelResults->activeFormationNames(); } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- RigCaseCellResultsData* RigEclipseCaseData::results(RiaDefines::PorosityModelType porosityModel) { @@ -764,7 +737,7 @@ RigCaseCellResultsData* RigEclipseCaseData::results(RiaDefines::PorosityModelTyp } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- const RigCaseCellResultsData* RigEclipseCaseData::results(RiaDefines::PorosityModelType porosityModel) const { @@ -777,36 +750,20 @@ const RigCaseCellResultsData* RigEclipseCaseData::results(RiaDefines::PorosityMo } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- const std::vector* RigEclipseCaseData::resultValues(RiaDefines::PorosityModelType porosityModel, - RiaDefines::ResultCatType type, - const QString& resultName, - size_t timeStepIndex) + RiaDefines::ResultCatType type, + const QString& resultName, + size_t timeStepIndex) { RigCaseCellResultsData* gridCellResults = this->results(porosityModel); - size_t scalarResultIndex = gridCellResults->findOrLoadScalarResult(type, resultName); const std::vector* swatResults = nullptr; - if (scalarResultIndex != cvf::UNDEFINED_SIZE_T) + if (gridCellResults->ensureKnownResultLoaded(RigEclipseResultAddress(type, resultName))) { - swatResults = &(gridCellResults->cellScalarResults(scalarResultIndex, timeStepIndex)); + swatResults = &(gridCellResults->cellScalarResults(RigEclipseResultAddress(type, resultName), timeStepIndex)); } return swatResults; } - -/* -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RigCaseData::closeReaderInterface() -{ - RifReaderInterface* readerInterface = m_matrixModelResults->readerInterface(); - - if (readerInterface) - { - readerInterface->close(); - } -} -*/ diff --git a/ApplicationCode/ReservoirDataModel/RigEclipseCaseData.h b/ApplicationCode/ReservoirDataModel/RigEclipseCaseData.h index d136f0e952..d5b0b0b543 100644 --- a/ApplicationCode/ReservoirDataModel/RigEclipseCaseData.h +++ b/ApplicationCode/ReservoirDataModel/RigEclipseCaseData.h @@ -48,6 +48,7 @@ class RigCell; class RigWellPath; class RimEclipseCase; class RigVirtualPerforationTransmissibilities; +class RigEquil; struct RigWellResultPoint; @@ -87,6 +88,7 @@ class RigEclipseCaseData : public cvf::Object bool hasFractureResults() const; void setActiveFormationNames(RigFormationNames* activeFormationNames); + void setActiveFormationNamesAndUpdatePlots(RigFormationNames* activeFormationNames); RigFormationNames* activeFormationNames(); void setSimWellData(const cvf::Collection& data); @@ -117,6 +119,10 @@ class RigEclipseCaseData : public cvf::Object void clearWellCellsInGridCache() { m_wellCellsInGrid.clear(); } + void ensureDeckIsParsedForEquilData(const QString& dataDeckFile, const QString& includeFileAbsolutePathPrefix); + std::vector equilData() const; + void setEquilData(const std::vector& equilObjects); + private: void computeActiveCellIJKBBox(); void computeWellCellsPrGrid(); @@ -132,8 +138,6 @@ class RigEclipseCaseData : public cvf::Object cvf::ref m_matrixModelResults; cvf::ref m_fractureModelResults; - cvf::ref m_activeFormationNamesData; - cvf::ref m_virtualPerforationTransmissibilities; cvf::Collection m_simWellData; //< A WellResults object for each well in the reservoir @@ -142,5 +146,8 @@ class RigEclipseCaseData : public cvf::Object RiaEclipseUnitTools::UnitSystem m_unitsType; + bool m_hasParsedDeckForEquilData; + std::vector m_equil; + mutable std::map, cvf::Collection> m_simWellBranchCache; }; diff --git a/ApplicationCode/ReservoirDataModel/RigEclipseCrossPlotDataExtractor.cpp b/ApplicationCode/ReservoirDataModel/RigEclipseCrossPlotDataExtractor.cpp new file mode 100644 index 0000000000..64e408278b --- /dev/null +++ b/ApplicationCode/ReservoirDataModel/RigEclipseCrossPlotDataExtractor.cpp @@ -0,0 +1,162 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2019- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// +#include "RigEclipseCrossPlotDataExtractor.h" + +#include "RiaQDateTimeTools.h" + +#include "RigActiveCellInfo.h" +#include "RigActiveCellsResultAccessor.h" +#include "RigCaseCellResultsData.h" +#include "RigEclipseCaseData.h" +#include "RigEclipseResultAddress.h" +#include "RigFormationNames.h" +#include "RigMainGrid.h" + +#include +#include + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RigEclipseCrossPlotResult RigEclipseCrossPlotDataExtractor::extract(RigEclipseCaseData* caseData, + int resultTimeStep, + const RigEclipseResultAddress& xAddress, + const RigEclipseResultAddress& yAddress, + RigGridCrossPlotCurveGrouping groupingType, + const RigEclipseResultAddress& groupAddress, + std::map timeStepCellVisibilityMap) +{ + RigEclipseCrossPlotResult result; + + RigCaseCellResultsData* resultData = caseData->results(RiaDefines::MATRIX_MODEL); + if (!resultData) return result; + + RigFormationNames* activeFormationNames = resultData->activeFormationNames(); + + const std::vector>* catValuesForAllSteps = nullptr; + + if (xAddress.isValid() && yAddress.isValid()) + { + RigActiveCellInfo* activeCellInfo = resultData->activeCellInfo(); + const RigMainGrid* mainGrid = caseData->mainGrid(); + + if (!resultData->ensureKnownResultLoaded(xAddress)) + { + return result; + } + + if (!resultData->ensureKnownResultLoaded(yAddress)) + { + return result; + } + + const std::vector>& xValuesForAllSteps = resultData->cellScalarResults(xAddress); + const std::vector>& yValuesForAllSteps = resultData->cellScalarResults(yAddress); + + if (groupingType == GROUP_BY_RESULT && groupAddress.isValid()) + { + if (resultData->ensureKnownResultLoaded(groupAddress)) + { + catValuesForAllSteps = &resultData->cellScalarResults(groupAddress); + } + } + + std::set timeStepsToInclude; + if (resultTimeStep == -1) + { + size_t nStepsInData = std::max(xValuesForAllSteps.size(), yValuesForAllSteps.size()); + bool xValid = xValuesForAllSteps.size() == 1u || xValuesForAllSteps.size() == nStepsInData; + bool yValid = yValuesForAllSteps.size() == 1u || yValuesForAllSteps.size() == nStepsInData; + + if (!(xValid && yValid)) return result; + + for (size_t i = 0; i < nStepsInData; ++i) + { + timeStepsToInclude.insert((int)i); + } + } + else + { + timeStepsToInclude.insert(static_cast(resultTimeStep)); + } + + for (int timeStep : timeStepsToInclude) + { + const cvf::UByteArray* cellVisibility = nullptr; + if (timeStepCellVisibilityMap.count(timeStep)) + { + cellVisibility = &timeStepCellVisibilityMap[timeStep]; + } + + int xIndex = timeStep >= (int)xValuesForAllSteps.size() ? 0 : timeStep; + int yIndex = timeStep >= (int)yValuesForAllSteps.size() ? 0 : timeStep; + + RigActiveCellsResultAccessor xAccessor(mainGrid, &xValuesForAllSteps[xIndex], activeCellInfo); + RigActiveCellsResultAccessor yAccessor(mainGrid, &yValuesForAllSteps[yIndex], activeCellInfo); + std::unique_ptr catAccessor; + if (catValuesForAllSteps) + { + int catIndex = timeStep >= (int)catValuesForAllSteps->size() ? 0 : timeStep; + catAccessor.reset( + new RigActiveCellsResultAccessor(mainGrid, &(catValuesForAllSteps->at(catIndex)), activeCellInfo)); + } + + for (size_t globalCellIdx = 0; globalCellIdx < activeCellInfo->reservoirCellCount(); ++globalCellIdx) + { + if (cellVisibility && !(*cellVisibility)[globalCellIdx]) continue; + + double xValue = xAccessor.cellScalarGlobIdx(globalCellIdx); + double yValue = yAccessor.cellScalarGlobIdx(globalCellIdx); + + if (xValue == HUGE_VAL || yValue == HUGE_VAL) continue; + + result.xValues.push_back(xValue); + result.yValues.push_back(yValue); + + if (groupingType == GROUP_BY_TIME) + { + result.groupValuesDiscrete.push_back(timeStep); + } + else if (groupingType == GROUP_BY_FORMATION) + { + if (activeFormationNames) + { + int category = 0; + size_t i(cvf::UNDEFINED_SIZE_T), j(cvf::UNDEFINED_SIZE_T), k(cvf::UNDEFINED_SIZE_T); + if (mainGrid->ijkFromCellIndex(globalCellIdx, &i, &j, &k)) + { + category = activeFormationNames->formationIndexFromKLayerIdx(k); + } + result.groupValuesDiscrete.push_back(category); + } + } + else if (groupingType == GROUP_BY_RESULT) + { + double catValue = HUGE_VAL; + if (catAccessor) + { + catValue = catAccessor->cellScalarGlobIdx(globalCellIdx); + } + result.groupValuesContinuous.push_back(catValue); + } + } + } + } + + return result; +} diff --git a/ApplicationCode/ReservoirDataModel/RigEclipseCrossPlotDataExtractor.h b/ApplicationCode/ReservoirDataModel/RigEclipseCrossPlotDataExtractor.h new file mode 100644 index 0000000000..ca6fdc9937 --- /dev/null +++ b/ApplicationCode/ReservoirDataModel/RigEclipseCrossPlotDataExtractor.h @@ -0,0 +1,52 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2019- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// +#pragma once + +#include "RigGridCrossPlotCurveGrouping.h" + +#include "cvfBase.h" +#include "cvfArray.h" + +#include +#include +#include + +class RigEclipseCaseData; +class RigEclipseResultAddress; + +class QString; + +struct RigEclipseCrossPlotResult +{ + std::vector xValues; + std::vector yValues; + std::vector groupValuesContinuous; + std::vector groupValuesDiscrete; +}; + +class RigEclipseCrossPlotDataExtractor +{ +public: + static RigEclipseCrossPlotResult extract(RigEclipseCaseData* eclipseCase, + int resultTimeStep, + const RigEclipseResultAddress& xAddress, + const RigEclipseResultAddress& yAddress, + RigGridCrossPlotCurveGrouping groupingType, + const RigEclipseResultAddress& groupAddress, + std::map timeStepCellVisibilityMap); +}; diff --git a/ApplicationCode/ReservoirDataModel/RigEclipseMultiPropertyStatCalc.cpp b/ApplicationCode/ReservoirDataModel/RigEclipseMultiPropertyStatCalc.cpp index 5ff4e3cfb4..34128b2e7e 100644 --- a/ApplicationCode/ReservoirDataModel/RigEclipseMultiPropertyStatCalc.cpp +++ b/ApplicationCode/ReservoirDataModel/RigEclipseMultiPropertyStatCalc.cpp @@ -127,11 +127,11 @@ size_t RigEclipseMultiPropertyStatCalc::timeStepCount() //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RigEclipseMultiPropertyStatCalc::addNativeStatisticsCalculator(RigCaseCellResultsData* cellResultsData, size_t scalarResultIndex) +void RigEclipseMultiPropertyStatCalc::addNativeStatisticsCalculator(RigCaseCellResultsData* cellResultsData, const RigEclipseResultAddress& eclipseResultAddress) { - if (scalarResultIndex != cvf::UNDEFINED_SIZE_T) + if (eclipseResultAddress.isValid()) { - this->addStatisticsCalculator(new RigEclipseNativeStatCalc(cellResultsData, scalarResultIndex)); + this->addStatisticsCalculator(new RigEclipseNativeStatCalc(cellResultsData, eclipseResultAddress)); } } diff --git a/ApplicationCode/ReservoirDataModel/RigEclipseMultiPropertyStatCalc.h b/ApplicationCode/ReservoirDataModel/RigEclipseMultiPropertyStatCalc.h index 3bd91f5f7e..e4c33b3e8a 100644 --- a/ApplicationCode/ReservoirDataModel/RigEclipseMultiPropertyStatCalc.h +++ b/ApplicationCode/ReservoirDataModel/RigEclipseMultiPropertyStatCalc.h @@ -29,7 +29,7 @@ class RigHistogramCalculator; class RigCaseCellResultsData; - +class RigEclipseResultAddress; //================================================================================================== /// @@ -39,7 +39,7 @@ class RigEclipseMultiPropertyStatCalc : public RigStatisticsCalculator public: RigEclipseMultiPropertyStatCalc(); void addStatisticsCalculator(RigStatisticsCalculator* statisticsCalculator); - void addNativeStatisticsCalculator(RigCaseCellResultsData* cellResultsData, size_t scalarResultIndices); + void addNativeStatisticsCalculator(RigCaseCellResultsData* cellResultsData, const RigEclipseResultAddress& scalarResultIndices); void minMaxCellScalarValues(size_t timeStepIndex, double& min, double& max) override; void posNegClosestToZero(size_t timeStepIndex, double& pos, double& neg) override; diff --git a/ApplicationCode/ReservoirDataModel/RigEclipseNativeStatCalc.cpp b/ApplicationCode/ReservoirDataModel/RigEclipseNativeStatCalc.cpp index 81a07041c6..bb6d97d268 100644 --- a/ApplicationCode/ReservoirDataModel/RigEclipseNativeStatCalc.cpp +++ b/ApplicationCode/ReservoirDataModel/RigEclipseNativeStatCalc.cpp @@ -30,9 +30,9 @@ //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -RigEclipseNativeStatCalc::RigEclipseNativeStatCalc(RigCaseCellResultsData* cellResultsData, size_t scalarResultIndex) - : m_resultsData(cellResultsData), - m_scalarResultIndex(scalarResultIndex) +RigEclipseNativeStatCalc::RigEclipseNativeStatCalc(RigCaseCellResultsData* cellResultsData, const RigEclipseResultAddress& eclipseResultAddress) + : m_resultsData(cellResultsData) + , m_eclipseResultAddress(eclipseResultAddress) { } @@ -93,7 +93,7 @@ void RigEclipseNativeStatCalc::valueSumAndSampleCount(size_t timeStepIndex, doub //-------------------------------------------------------------------------------------------------- size_t RigEclipseNativeStatCalc::timeStepCount() { - return m_resultsData->timeStepCount(m_scalarResultIndex); + return m_resultsData->timeStepCount(m_eclipseResultAddress); } //-------------------------------------------------------------------------------------------------- @@ -101,19 +101,19 @@ size_t RigEclipseNativeStatCalc::timeStepCount() //-------------------------------------------------------------------------------------------------- void RigEclipseNativeStatCalc::mobileVolumeWeightedMean(size_t timeStepIndex, double& mean) { - size_t mobPVResultIndex = m_resultsData->findOrLoadScalarResult(RiaDefines::ResultCatType::STATIC_NATIVE, RiaDefines::mobilePoreVolumeName()); + RigEclipseResultAddress mobPorvAddress(RiaDefines::ResultCatType::STATIC_NATIVE, RiaDefines::mobilePoreVolumeName()); // For statistics result cases, the pore volume is not available, as RigCaseCellResultsData::createPlaceholderResultEntries // has not been executed - if (mobPVResultIndex == cvf::UNDEFINED_SIZE_T) + if (!m_resultsData->ensureKnownResultLoaded(mobPorvAddress)) { return; } - const std::vector& weights = m_resultsData->cellScalarResults(mobPVResultIndex, 0); - const std::vector& values = m_resultsData->cellScalarResults(m_scalarResultIndex, timeStepIndex); + const std::vector& weights = m_resultsData->cellScalarResults(mobPorvAddress, 0); + const std::vector& values = m_resultsData->cellScalarResults(m_eclipseResultAddress, timeStepIndex); const RigActiveCellInfo* actCellInfo = m_resultsData->activeCellInfo(); - RigWeightedMeanCalc::weightedMeanOverCells(&weights, &values, nullptr, false, actCellInfo, m_resultsData->isUsingGlobalActiveIndex(m_scalarResultIndex), &mean); + RigWeightedMeanCalc::weightedMeanOverCells(&weights, &values, nullptr, false, actCellInfo, m_resultsData->isUsingGlobalActiveIndex(m_eclipseResultAddress), &mean); } diff --git a/ApplicationCode/ReservoirDataModel/RigEclipseNativeStatCalc.h b/ApplicationCode/ReservoirDataModel/RigEclipseNativeStatCalc.h index 84271c83f7..cd704e9f7c 100644 --- a/ApplicationCode/ReservoirDataModel/RigEclipseNativeStatCalc.h +++ b/ApplicationCode/ReservoirDataModel/RigEclipseNativeStatCalc.h @@ -33,7 +33,7 @@ class RigHistogramCalculator; class RigEclipseNativeStatCalc : public RigStatisticsCalculator { public: - RigEclipseNativeStatCalc(RigCaseCellResultsData* cellResultsData, size_t scalarResultIndex); + RigEclipseNativeStatCalc(RigCaseCellResultsData* cellResultsData, const RigEclipseResultAddress& eclipseResultAddress); void minMaxCellScalarValues(size_t timeStepIndex, double& min, double& max) override; void posNegClosestToZero(size_t timeStepIndex, double& pos, double& neg) override; @@ -45,17 +45,17 @@ class RigEclipseNativeStatCalc : public RigStatisticsCalculator private: RigCaseCellResultsData* m_resultsData; - size_t m_scalarResultIndex; + RigEclipseResultAddress m_eclipseResultAddress; template void traverseCells(StatisticsAccumulator& accumulator, size_t timeStepIndex) { - if (timeStepIndex >= m_resultsData->cellScalarResults(m_scalarResultIndex).size()) + if (timeStepIndex >= m_resultsData->cellScalarResults(m_eclipseResultAddress).size()) { return; } - std::vector& values = m_resultsData->cellScalarResults(m_scalarResultIndex, timeStepIndex); + const std::vector& values = m_resultsData->cellScalarResults(m_eclipseResultAddress, timeStepIndex); if (values.empty()) { @@ -66,13 +66,14 @@ class RigEclipseNativeStatCalc : public RigStatisticsCalculator const RigActiveCellInfo* actCellInfo = m_resultsData->activeCellInfo(); size_t cellCount = actCellInfo->reservoirCellCount(); + bool isUsingGlobalActiveIndex = m_resultsData->isUsingGlobalActiveIndex(m_eclipseResultAddress); for (size_t cIdx = 0; cIdx < cellCount; ++cIdx) { // Filter out inactive cells if (!actCellInfo->isActive(cIdx)) continue; size_t cellResultIndex = cIdx; - if (m_resultsData->isUsingGlobalActiveIndex(m_scalarResultIndex)) + if (isUsingGlobalActiveIndex) { cellResultIndex = actCellInfo->cellResultIndex(cIdx); } diff --git a/ApplicationCode/ReservoirDataModel/RigEclipseNativeVisibleCellsStatCalc.cpp b/ApplicationCode/ReservoirDataModel/RigEclipseNativeVisibleCellsStatCalc.cpp index 735803dd8e..597c4762f9 100644 --- a/ApplicationCode/ReservoirDataModel/RigEclipseNativeVisibleCellsStatCalc.cpp +++ b/ApplicationCode/ReservoirDataModel/RigEclipseNativeVisibleCellsStatCalc.cpp @@ -25,16 +25,16 @@ #include "RigStatisticsMath.h" #include "RigWeightedMeanCalc.h" -#include +#include //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- RigEclipseNativeVisibleCellsStatCalc::RigEclipseNativeVisibleCellsStatCalc(RigCaseCellResultsData* cellResultsData, - size_t scalarResultIndex, + const RigEclipseResultAddress& scalarResultIndex, const cvf::UByteArray* cellVisibilities) : m_caseData(cellResultsData), - m_scalarResultIndex(scalarResultIndex), + m_resultAddress(scalarResultIndex), m_cellVisibilities(cellVisibilities) { @@ -97,7 +97,7 @@ void RigEclipseNativeVisibleCellsStatCalc::uniqueValues(size_t timeStepIndex, st //-------------------------------------------------------------------------------------------------- size_t RigEclipseNativeVisibleCellsStatCalc::timeStepCount() { - return m_caseData->timeStepCount(m_scalarResultIndex); + return m_caseData->timeStepCount(m_resultAddress); } //-------------------------------------------------------------------------------------------------- @@ -105,13 +105,15 @@ size_t RigEclipseNativeVisibleCellsStatCalc::timeStepCount() //-------------------------------------------------------------------------------------------------- void RigEclipseNativeVisibleCellsStatCalc::mobileVolumeWeightedMean(size_t timeStepIndex, double &result) { - size_t mobPVResultIndex = m_caseData->findOrLoadScalarResult(RiaDefines::ResultCatType::STATIC_NATIVE, RiaDefines::mobilePoreVolumeName()); + RigEclipseResultAddress mobPorvAddress(RiaDefines::ResultCatType::STATIC_NATIVE, RiaDefines::mobilePoreVolumeName()); - const std::vector& weights = m_caseData->cellScalarResults(mobPVResultIndex)[0]; - const std::vector& values = m_caseData->cellScalarResults(m_scalarResultIndex, timeStepIndex); + m_caseData->ensureKnownResultLoaded(mobPorvAddress); + + const std::vector& weights = m_caseData->cellScalarResults(mobPorvAddress, 0); + const std::vector& values = m_caseData->cellScalarResults(m_resultAddress, timeStepIndex); const RigActiveCellInfo* actCellInfo = m_caseData->activeCellInfo(); - RigWeightedMeanCalc::weightedMeanOverCells(&weights, &values, m_cellVisibilities.p(), true, actCellInfo, m_caseData->isUsingGlobalActiveIndex(m_scalarResultIndex), &result); + RigWeightedMeanCalc::weightedMeanOverCells(&weights, &values, m_cellVisibilities.p(), true, actCellInfo, m_caseData->isUsingGlobalActiveIndex(m_resultAddress), &result); } diff --git a/ApplicationCode/ReservoirDataModel/RigEclipseNativeVisibleCellsStatCalc.h b/ApplicationCode/ReservoirDataModel/RigEclipseNativeVisibleCellsStatCalc.h index 65b921cfc3..9ea9977326 100644 --- a/ApplicationCode/ReservoirDataModel/RigEclipseNativeVisibleCellsStatCalc.h +++ b/ApplicationCode/ReservoirDataModel/RigEclipseNativeVisibleCellsStatCalc.h @@ -36,7 +36,7 @@ class RigEclipseNativeVisibleCellsStatCalc : public RigStatisticsCalculator { public: RigEclipseNativeVisibleCellsStatCalc(RigCaseCellResultsData* cellResultsData, - size_t scalarResultIndex, + const RigEclipseResultAddress& scalarResultIndex, const cvf::UByteArray* cellVisibilities); void minMaxCellScalarValues(size_t timeStepIndex, double& min, double& max) override; @@ -50,13 +50,13 @@ class RigEclipseNativeVisibleCellsStatCalc : public RigStatisticsCalculator private: RigCaseCellResultsData* m_caseData; - size_t m_scalarResultIndex; + RigEclipseResultAddress m_resultAddress; cvf::cref m_cellVisibilities; template void traverseCells(StatisticsAccumulator& accumulator, size_t timeStepIndex) { - std::vector& values = m_caseData->cellScalarResults(m_scalarResultIndex, timeStepIndex); + const std::vector& values = m_caseData->cellScalarResults(m_resultAddress, timeStepIndex); if (values.empty()) { @@ -74,7 +74,7 @@ class RigEclipseNativeVisibleCellsStatCalc : public RigStatisticsCalculator if (!(*m_cellVisibilities)[cIdx]) continue; size_t cellResultIndex = cIdx; - if (m_caseData->isUsingGlobalActiveIndex(m_scalarResultIndex)) + if (m_caseData->isUsingGlobalActiveIndex(m_resultAddress)) { cellResultIndex = actCellInfo->cellResultIndex(cIdx); } diff --git a/ApplicationCode/ReservoirDataModel/RigEclipseResultAddress.h b/ApplicationCode/ReservoirDataModel/RigEclipseResultAddress.h new file mode 100644 index 0000000000..5e600ccf41 --- /dev/null +++ b/ApplicationCode/ReservoirDataModel/RigEclipseResultAddress.h @@ -0,0 +1,114 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2019- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// +#pragma once + +#include "RiaDefines.h" + +#include + +class RigEclipseResultAddress +{ +public: + RigEclipseResultAddress() + : m_resultCatType(RiaDefines::UNDEFINED) + , m_timeLapseBaseFrameIdx(NO_TIME_LAPSE) + , m_differenceCaseId(NO_CASE_DIFF) + {} + + explicit RigEclipseResultAddress(const QString& resultName) + : m_resultCatType(RiaDefines::UNDEFINED) + , m_resultName(resultName) + , m_timeLapseBaseFrameIdx(NO_TIME_LAPSE) + , m_differenceCaseId(NO_CASE_DIFF) + {} + + explicit RigEclipseResultAddress(RiaDefines::ResultCatType type, const QString& resultName, int timeLapseBaseTimeStep = NO_TIME_LAPSE, int differenceCaseId = NO_CASE_DIFF) + : m_resultCatType(type) + , m_resultName(resultName) + , m_timeLapseBaseFrameIdx(timeLapseBaseTimeStep) + , m_differenceCaseId(differenceCaseId) + {} + + + bool isValid() const + { + if (m_resultName.isEmpty() || m_resultName == RiaDefines::undefinedResultName()) + { + return false; + } + else + { + return true; + } + } + + static constexpr int allTimeLapsesValue() { return ALL_TIME_LAPSES; } + static constexpr int noTimeLapseValue() { return NO_TIME_LAPSE; } + static constexpr int noCaseDiffValue() { return NO_CASE_DIFF; } + + bool isTimeLapse() const { return m_timeLapseBaseFrameIdx > NO_TIME_LAPSE;} + bool representsAllTimeLapses() const { return m_timeLapseBaseFrameIdx == ALL_TIME_LAPSES;} + + bool hasDifferenceCase() const { return m_differenceCaseId > NO_CASE_DIFF; } + + bool operator< (const RigEclipseResultAddress& other ) const + { + if (m_differenceCaseId != other.m_differenceCaseId) + { + return (m_differenceCaseId < other.m_differenceCaseId); + } + + if (m_timeLapseBaseFrameIdx != other.m_timeLapseBaseFrameIdx) + { + return (m_timeLapseBaseFrameIdx < other.m_timeLapseBaseFrameIdx); + } + + if (m_resultCatType != other.m_resultCatType) + { + return (m_resultCatType < other.m_resultCatType); + } + + return (m_resultName < other.m_resultName); + } + + bool operator==(const RigEclipseResultAddress& other ) const + { + if ( m_resultCatType != other.m_resultCatType + || m_resultName != other.m_resultName + || m_timeLapseBaseFrameIdx != other.m_timeLapseBaseFrameIdx + || m_differenceCaseId != other.m_differenceCaseId) + { + return false; + } + + return true; + } + + RiaDefines::ResultCatType m_resultCatType; + QString m_resultName; + + int m_timeLapseBaseFrameIdx; + int m_differenceCaseId; + +private: + static const int ALL_TIME_LAPSES = -2; + static const int NO_TIME_LAPSE = -1; + static const int NO_CASE_DIFF = -1; +}; + + diff --git a/ApplicationCode/ReservoirDataModel/RigEclipseResultInfo.cpp b/ApplicationCode/ReservoirDataModel/RigEclipseResultInfo.cpp index 817749a334..06a230a222 100644 --- a/ApplicationCode/ReservoirDataModel/RigEclipseResultInfo.cpp +++ b/ApplicationCode/ReservoirDataModel/RigEclipseResultInfo.cpp @@ -53,12 +53,14 @@ std::vector RigEclipseTimeStepInfo::createTimeStepInfos( //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -RigEclipseResultInfo::RigEclipseResultInfo(RiaDefines::ResultCatType resultType, - QString resultName, bool needsToBeStored, bool mustBeCalculated, size_t gridScalarResultIndex) : m_resultType(resultType), - m_needsToBeStored(needsToBeStored), - m_mustBeCalculated(mustBeCalculated), - m_resultName(resultName), - m_gridScalarResultIndex(gridScalarResultIndex) +RigEclipseResultInfo::RigEclipseResultInfo(const RigEclipseResultAddress& resultAddress, + bool needsToBeStored, + bool mustBeCalculated, + size_t gridScalarResultIndex) + : m_resultAddress(resultAddress) + , m_needsToBeStored(needsToBeStored) + , m_mustBeCalculated(mustBeCalculated) + , m_gridScalarResultIndex(gridScalarResultIndex) { } @@ -67,7 +69,7 @@ RigEclipseResultInfo::RigEclipseResultInfo(RiaDefines::ResultCatType resultType, //-------------------------------------------------------------------------------------------------- RiaDefines::ResultCatType RigEclipseResultInfo::resultType() const { - return m_resultType; + return m_resultAddress.m_resultCatType; } //-------------------------------------------------------------------------------------------------- @@ -75,7 +77,7 @@ RiaDefines::ResultCatType RigEclipseResultInfo::resultType() const //-------------------------------------------------------------------------------------------------- void RigEclipseResultInfo::setResultType(RiaDefines::ResultCatType newType) { - m_resultType = newType; + m_resultAddress.m_resultCatType = newType; } //-------------------------------------------------------------------------------------------------- @@ -83,7 +85,7 @@ void RigEclipseResultInfo::setResultType(RiaDefines::ResultCatType newType) //-------------------------------------------------------------------------------------------------- const QString& RigEclipseResultInfo::resultName() const { - return m_resultName; + return m_resultAddress.m_resultName; } //-------------------------------------------------------------------------------------------------- @@ -91,7 +93,7 @@ const QString& RigEclipseResultInfo::resultName() const //-------------------------------------------------------------------------------------------------- void RigEclipseResultInfo::setResultName(const QString& name) { - m_resultName = name; + m_resultAddress.m_resultName = name; } //-------------------------------------------------------------------------------------------------- @@ -194,13 +196,5 @@ std::vector RigEclipseResultInfo::reportNumbers() const //-------------------------------------------------------------------------------------------------- bool RigEclipseResultInfo::operator<(const RigEclipseResultInfo& rhs) const { - if (m_resultType != rhs.resultType()) - { - return m_resultType < rhs.resultType(); - } - if (m_resultName != rhs.resultName()) - { - return m_resultName < rhs.resultName(); - } - return false; + return m_resultAddress < rhs.m_resultAddress; } diff --git a/ApplicationCode/ReservoirDataModel/RigEclipseResultInfo.h b/ApplicationCode/ReservoirDataModel/RigEclipseResultInfo.h index 62c920712a..cbf92758d8 100644 --- a/ApplicationCode/ReservoirDataModel/RigEclipseResultInfo.h +++ b/ApplicationCode/ReservoirDataModel/RigEclipseResultInfo.h @@ -18,6 +18,8 @@ #pragma once +#include "RigEclipseResultAddress.h" + #include "RiaDefines.h" #include @@ -49,35 +51,39 @@ class RigEclipseTimeStepInfo class RigEclipseResultInfo { public: - RigEclipseResultInfo(RiaDefines::ResultCatType resultType, - QString resultName, + RigEclipseResultInfo(const RigEclipseResultAddress& resultAddress, bool needsToBeStored = false, bool mustBeCalculated = false, size_t gridScalarResultIndex = 0u); RiaDefines::ResultCatType resultType() const; - void setResultType(RiaDefines::ResultCatType newType); const QString& resultName() const; - void setResultName(const QString& name); bool needsToBeStored() const; - bool mustBeCalculated() const; - void setMustBeCalculated(bool mustCalculate); - size_t gridScalarResultIndex() const; - - const std::vector& timeStepInfos() const; - void setTimeStepInfos(const std::vector& timeSteps); std::vector dates() const; std::vector daysSinceSimulationStarts() const; std::vector reportNumbers() const; bool operator<(const RigEclipseResultInfo& rhs) const; + + const RigEclipseResultAddress& eclipseResultAddress() const { return m_resultAddress;} + private: - RiaDefines::ResultCatType m_resultType; + friend class RigCaseCellResultsData; + void setResultType(RiaDefines::ResultCatType newType); + void setResultName(const QString& name); + bool mustBeCalculated() const; + void setMustBeCalculated(bool mustCalculate); + size_t gridScalarResultIndex() const; + + const std::vector& timeStepInfos() const; + void setTimeStepInfos(const std::vector& timeSteps); + + RigEclipseResultAddress m_resultAddress; + size_t m_gridScalarResultIndex; + std::vector m_timeStepInfos; + bool m_needsToBeStored; bool m_mustBeCalculated; - QString m_resultName; - size_t m_gridScalarResultIndex; - std::vector m_timeStepInfos; }; diff --git a/ApplicationCode/ReservoirDataModel/RigEquil.cpp b/ApplicationCode/ReservoirDataModel/RigEquil.cpp new file mode 100644 index 0000000000..507a902c89 --- /dev/null +++ b/ApplicationCode/ReservoirDataModel/RigEquil.cpp @@ -0,0 +1,184 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2019- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "RigEquil.h" + +#include + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RigEquil::RigEquil(double datumDepth, + double datumDepthPressure, + double waterOilContactDepth, + double waterOilContactCapillaryPressure, + double gasOilContactDepth, + double gasOilContactCapillaryPressure, + bool liveOilInitConstantRs, + bool wetGasInitConstantRv, + int initializationTargetAccuracy) + : datum_depth(datumDepth) + , datum_depth_ps(datumDepthPressure) + , water_oil_contact_depth(waterOilContactDepth) + , water_oil_contact_capillary_pressure(waterOilContactCapillaryPressure) + , gas_oil_contact_depth(gasOilContactDepth) + , gas_oil_contact_capillary_pressure(gasOilContactCapillaryPressure) + , live_oil_init_proc(liveOilInitConstantRs) + , wet_gas_init_proc(wetGasInitConstantRv) + , init_target_accuracy(initializationTargetAccuracy) +{ +} + +double RigEquil::datumDepth() const +{ + return this->datum_depth; +} + +double RigEquil::datumDepthPressure() const +{ + return this->datum_depth_ps; +} + +double RigEquil::waterOilContactDepth() const +{ + return this->water_oil_contact_depth; +} + +double RigEquil::waterOilContactCapillaryPressure() const +{ + return this->water_oil_contact_capillary_pressure; +} + +double RigEquil::gasOilContactDepth() const +{ + return this->gas_oil_contact_depth; +} + +double RigEquil::gasOilContactCapillaryPressure() const +{ + return this->gas_oil_contact_capillary_pressure; +} + +bool RigEquil::liveOilInitConstantRs() const +{ + return this->live_oil_init_proc; +} + +bool RigEquil::wetGasInitConstantRv() const +{ + return this->wet_gas_init_proc; +} + +int RigEquil::initializationTargetAccuracy() const +{ + return this->init_target_accuracy; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RigEquil RigEquil::defaultObject() +{ + double datumDepth = 0.0; + double datuDepthPressure = 0.0; + double waterOilContactDepth = 0.0; + double waterOilContactCapillaryPressure = 0.0; + double gasOilContactDepth = 0.0; + double gasOilContactCapillaryPressure = 0.0; + int liveOilInitConstantRs = -1; + int wetGasInitConstantRv = -1; + int initializationTargetAccuracy = -5; + + return RigEquil(datumDepth, + datuDepthPressure, + waterOilContactDepth, + waterOilContactCapillaryPressure, + gasOilContactDepth, + gasOilContactCapillaryPressure, + liveOilInitConstantRs, + wetGasInitConstantRv, + initializationTargetAccuracy); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RigEquil RigEquil::parseString(const QString& keywordData) +{ + double datumDepth = 0.0; + double datuDepthPressure = 0.0; + double waterOilContactDepth = 0.0; + double waterOilContactCapillaryPressure = 0.0; + double gasOilContactDepth = 0.0; + double gasOilContactCapillaryPressure = 0.0; + bool liveOilInitConstantRs = false; + bool wetGasInitConstantRv = false; + int initializationTargetAccuracy = -5; + + QString line(keywordData); + line.replace("\t", " "); + + QStringList items = line.split(" "); + if (items.size() > 0) + { + datumDepth = items.at(0).toDouble(); + } + + if (items.size() > 1) + { + datuDepthPressure = items.at(1).toDouble(); + } + if (items.size() > 2) + { + waterOilContactDepth = items.at(2).toDouble(); + } + if (items.size() > 3) + { + waterOilContactCapillaryPressure = items.at(3).toDouble(); + } + if (items.size() > 4) + { + gasOilContactDepth = items.at(4).toDouble(); + } + if (items.size() > 5) + { + gasOilContactCapillaryPressure = items.at(5).toDouble(); + } + if (items.size() > 6) + { + liveOilInitConstantRs = items.at(6).toInt() > 0 ? true : false; + } + if (items.size() > 7) + { + wetGasInitConstantRv = items.at(7).toInt() > 0 ? true : false; + } + if (items.size() > 8) + { + initializationTargetAccuracy = items.at(8).toInt(); + } + + return RigEquil(datumDepth, + datuDepthPressure, + waterOilContactDepth, + waterOilContactCapillaryPressure, + gasOilContactDepth, + gasOilContactCapillaryPressure, + liveOilInitConstantRs, + wetGasInitConstantRv, + initializationTargetAccuracy); +} diff --git a/ApplicationCode/ReservoirDataModel/RigEquil.h b/ApplicationCode/ReservoirDataModel/RigEquil.h new file mode 100644 index 0000000000..8c5132b8dc --- /dev/null +++ b/ApplicationCode/ReservoirDataModel/RigEquil.h @@ -0,0 +1,66 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2019- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include + +//-------------------------------------------------------------------------------------------------- +// +// Inspired by /opm-common/src/opm/parser/eclipse/EclipseState/InitConfig/Equil.cpp +// +//-------------------------------------------------------------------------------------------------- +class RigEquil +{ +public: + explicit RigEquil(double datumDepth, + double datuDepthPressure, + double waterOilContactDepth, + double waterOilContactCapillaryPressure, + double gasOilContactDepth, + double gasOilContactCapillaryPressure, + bool liveOilInitConstantRs, + bool wetGasInitConstantRv, + int initializationTargetAccuracy); + + double datumDepth() const; + double datumDepthPressure() const; + double waterOilContactDepth() const; + double waterOilContactCapillaryPressure() const; + double gasOilContactDepth() const; + double gasOilContactCapillaryPressure() const; + + bool liveOilInitConstantRs() const; + bool wetGasInitConstantRv() const; + int initializationTargetAccuracy() const; + + static RigEquil defaultObject(); + static RigEquil parseString(const QString& keywordData); + +private: + double datum_depth; + double datum_depth_ps; + double water_oil_contact_depth; + double water_oil_contact_capillary_pressure; + double gas_oil_contact_depth; + double gas_oil_contact_capillary_pressure; + + bool live_oil_init_proc; + bool wet_gas_init_proc; + int init_target_accuracy; +}; diff --git a/ApplicationCode/ReservoirDataModel/RigFault.cpp b/ApplicationCode/ReservoirDataModel/RigFault.cpp index aa43dca582..39c2dddef8 100644 --- a/ApplicationCode/ReservoirDataModel/RigFault.cpp +++ b/ApplicationCode/ReservoirDataModel/RigFault.cpp @@ -87,6 +87,39 @@ const std::vector& RigFault::connectionIndices() const return m_connectionIndices; } +//-------------------------------------------------------------------------------------------------- +/// Order FaultCellAndFace by i, j, face then k. +//-------------------------------------------------------------------------------------------------- +bool RigFault::ordering(CellAndFace first, CellAndFace second) +{ + size_t i1, i2, j1, j2, k1, k2; + cvf::StructGridInterface::FaceType f1, f2; + std::tie(i1, j1, k1, f1) = first; + std::tie(i2, j2, k2, f2) = second; + if (i1 == i2) + { + if (j1 == j2) + { + if (f1 == f2) + { + return k1 < k2; + } + else + { + return f1 < f2; + } + } + else + { + return j1 < j2; + } + } + else + { + return i1 < i2; + } +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/ReservoirDataModel/RigFault.h b/ApplicationCode/ReservoirDataModel/RigFault.h index 06bb609c74..53b7b413db 100644 --- a/ApplicationCode/ReservoirDataModel/RigFault.h +++ b/ApplicationCode/ReservoirDataModel/RigFault.h @@ -28,8 +28,9 @@ #include -#include #include +#include +#include class RigMainGrid; @@ -75,7 +76,8 @@ class RigFaultsPrCellAccumulator : public cvf::Object class RigFault : public cvf::Object { public: - + typedef std::tuple CellAndFace; + struct FaultFace { FaultFace(size_t nativeReservoirCellIndex, cvf::StructGridInterface::FaceType nativeFace, size_t oppositeReservoirCellIndex) : @@ -106,6 +108,8 @@ class RigFault : public cvf::Object std::vector& connectionIndices(); const std::vector& connectionIndices() const; + static bool ordering(CellAndFace first, CellAndFace second); + private: QString m_name; diff --git a/ApplicationCode/ReservoirDataModel/RigFishbonesGeometry.cpp b/ApplicationCode/ReservoirDataModel/RigFishbonesGeometry.cpp index cc87ac523f..4976a560c7 100644 --- a/ApplicationCode/ReservoirDataModel/RigFishbonesGeometry.cpp +++ b/ApplicationCode/ReservoirDataModel/RigFishbonesGeometry.cpp @@ -183,7 +183,6 @@ cvf::Vec3d RigFisbonesGeometry::closestMainAxis(const cvf::Vec3d& vec) if (cvf::Math::abs(vec.z()) > maxValue) { maxComponent = 2; - maxValue = cvf::Math::abs(vec.z()); } if (maxComponent == 0) diff --git a/ApplicationCode/ReservoirDataModel/RigFlowDiagInterfaceTools.h b/ApplicationCode/ReservoirDataModel/RigFlowDiagInterfaceTools.h index d4af8d46e0..cb73761634 100644 --- a/ApplicationCode/ReservoirDataModel/RigFlowDiagInterfaceTools.h +++ b/ApplicationCode/ReservoirDataModel/RigFlowDiagInterfaceTools.h @@ -110,7 +110,7 @@ namespace RigFlowDiagInterfaceTools { { auto satfunc = Opm::ECLSaturationFunc(G, init); - Opm::ECLFluxCalc calc(G, init, 9.80665, true); + Opm::ECLFluxCalc calc(G, init, 9.80665); auto getFlux = [&calc, &rstrt] (const Opm::ECLPhaseIndex p) diff --git a/ApplicationCode/ReservoirDataModel/RigFlowDiagResultFrames.cpp b/ApplicationCode/ReservoirDataModel/RigFlowDiagResultFrames.cpp index 17802af085..2f74a9b760 100644 --- a/ApplicationCode/ReservoirDataModel/RigFlowDiagResultFrames.cpp +++ b/ApplicationCode/ReservoirDataModel/RigFlowDiagResultFrames.cpp @@ -17,7 +17,7 @@ // ///////////////////////////////////////////////////////////////////////////////// -#include +#include #include "RigFlowDiagResultFrames.h" diff --git a/ApplicationCode/ReservoirDataModel/RigFlowDiagSolverInterface.cpp b/ApplicationCode/ReservoirDataModel/RigFlowDiagSolverInterface.cpp index 50d3d9bad8..1ed3c85107 100644 --- a/ApplicationCode/ReservoirDataModel/RigFlowDiagSolverInterface.cpp +++ b/ApplicationCode/ReservoirDataModel/RigFlowDiagSolverInterface.cpp @@ -321,10 +321,10 @@ RigFlowDiagTimeStepResult RigFlowDiagSolverInterface::calculate(size_t timeStepI CVF_ASSERT(currentRestartData); - size_t resultIndexWithMaxTimeSteps = cvf::UNDEFINED_SIZE_T; - m_eclipseCase->eclipseCaseData()->results(RiaDefines::MATRIX_MODEL)->maxTimeStepCount(&resultIndexWithMaxTimeSteps); + RigEclipseResultAddress addrToMaxTimeStepCountResult; + m_eclipseCase->eclipseCaseData()->results(RiaDefines::MATRIX_MODEL)->maxTimeStepCount(&addrToMaxTimeStepCountResult); - int reportStepNumber = m_eclipseCase->eclipseCaseData()->results(RiaDefines::MATRIX_MODEL)->reportStepNumber(resultIndexWithMaxTimeSteps, timeStepIndex); + int reportStepNumber = m_eclipseCase->eclipseCaseData()->results(RiaDefines::MATRIX_MODEL)->reportStepNumber(addrToMaxTimeStepCountResult, timeStepIndex); if ( !currentRestartData->selectReportStep(reportStepNumber) ) { diff --git a/ApplicationCode/ReservoirDataModel/RigFlowDiagStatCalc.cpp b/ApplicationCode/ReservoirDataModel/RigFlowDiagStatCalc.cpp index 51ea27d4ab..695fc33818 100644 --- a/ApplicationCode/ReservoirDataModel/RigFlowDiagStatCalc.cpp +++ b/ApplicationCode/ReservoirDataModel/RigFlowDiagStatCalc.cpp @@ -26,7 +26,7 @@ #include "RimEclipseResultCase.h" -#include +#include //-------------------------------------------------------------------------------------------------- /// @@ -119,10 +119,11 @@ void RigFlowDiagStatCalc::mobileVolumeWeightedMean(size_t timeStepIndex, double& if (!eclCase) return; RigCaseCellResultsData* caseCellResultsData = eclCase->results(RiaDefines::MATRIX_MODEL); + RigEclipseResultAddress mobPoreVolResAddr(RiaDefines::ResultCatType::STATIC_NATIVE, RiaDefines::mobilePoreVolumeName()); - size_t mobPVResultIndex = caseCellResultsData->findOrLoadScalarResult(RiaDefines::ResultCatType::STATIC_NATIVE, RiaDefines::mobilePoreVolumeName()); + caseCellResultsData->ensureKnownResultLoaded(mobPoreVolResAddr); - const std::vector& weights = caseCellResultsData->cellScalarResults(mobPVResultIndex, 0); + const std::vector& weights = caseCellResultsData->cellScalarResults(mobPoreVolResAddr, 0); const std::vector* values = m_resultsData->resultValues(m_resVarAddr, timeStepIndex); const RigActiveCellInfo* actCellInfo = m_resultsData->activeCellInfo(m_resVarAddr); diff --git a/ApplicationCode/ReservoirDataModel/RigFlowDiagVisibleCellsStatCalc.cpp b/ApplicationCode/ReservoirDataModel/RigFlowDiagVisibleCellsStatCalc.cpp index da57faf89c..fd3cf0d2f4 100644 --- a/ApplicationCode/ReservoirDataModel/RigFlowDiagVisibleCellsStatCalc.cpp +++ b/ApplicationCode/ReservoirDataModel/RigFlowDiagVisibleCellsStatCalc.cpp @@ -26,7 +26,7 @@ #include "RimEclipseResultCase.h" -#include +#include //-------------------------------------------------------------------------------------------------- /// @@ -109,9 +109,10 @@ void RigFlowDiagVisibleCellsStatCalc::mobileVolumeWeightedMean(size_t timeStepIn RigCaseCellResultsData* caseCellResultsData = eclCase->results(RiaDefines::MATRIX_MODEL); - size_t mobPVResultIndex = caseCellResultsData->findOrLoadScalarResult(RiaDefines::ResultCatType::STATIC_NATIVE, RiaDefines::mobilePoreVolumeName()); - - const std::vector& weights = caseCellResultsData->cellScalarResults(mobPVResultIndex, 0); + RigEclipseResultAddress mobPorvAddr(RiaDefines::ResultCatType::STATIC_NATIVE, RiaDefines::mobilePoreVolumeName()); + + caseCellResultsData->ensureKnownResultLoaded(mobPorvAddr); + const std::vector& weights = caseCellResultsData->cellScalarResults(mobPorvAddr, 0); const std::vector* values = m_resultsData->resultValues(m_resVarAddr, timeStepIndex); const RigActiveCellInfo* actCellInfo = m_resultsData->activeCellInfo(m_resVarAddr); diff --git a/ApplicationCode/ReservoirDataModel/RigGridCrossPlotCurveGrouping.h b/ApplicationCode/ReservoirDataModel/RigGridCrossPlotCurveGrouping.h new file mode 100644 index 0000000000..cfbb485339 --- /dev/null +++ b/ApplicationCode/ReservoirDataModel/RigGridCrossPlotCurveGrouping.h @@ -0,0 +1,27 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2019- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// +#pragma once + +enum RigGridCrossPlotCurveGrouping +{ + NO_GROUPING, + GROUP_BY_TIME, + GROUP_BY_FORMATION, + GROUP_BY_RESULT +}; + diff --git a/ApplicationCode/ReservoirDataModel/RigGridManager.cpp b/ApplicationCode/ReservoirDataModel/RigGridManager.cpp index bd153f09cb..f79b148425 100644 --- a/ApplicationCode/ReservoirDataModel/RigGridManager.cpp +++ b/ApplicationCode/ReservoirDataModel/RigGridManager.cpp @@ -1,28 +1,28 @@ ///////////////////////////////////////////////////////////////////////////////// // // Copyright (C) 2011-2012 Statoil ASA, Ceetron AS -// +// // ResInsight 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 3 of the License, or // (at your option) any later version. -// +// // ResInsight 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 at +// +// See the GNU General Public License at // for more details. // ///////////////////////////////////////////////////////////////////////////////// #include "RigGridManager.h" + #include "RigEclipseCaseData.h" #include "RigMainGrid.h" - //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RigGridManager::addCase(RigEclipseCaseData* eclipseCase) { @@ -31,7 +31,7 @@ void RigGridManager::addCase(RigEclipseCaseData* eclipseCase) } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RigGridManager::removeCase(RigEclipseCaseData* eclipseCase) { @@ -46,7 +46,7 @@ void RigGridManager::removeCase(RigEclipseCaseData* eclipseCase) } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- RigMainGrid* RigGridManager::findEqualGrid(RigMainGrid* candidateGrid) { @@ -61,9 +61,8 @@ RigMainGrid* RigGridManager::findEqualGrid(RigMainGrid* candidateGrid) return nullptr; } - //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- bool RigGridManager::isEqual(RigMainGrid* gridA, RigMainGrid* gridB) { @@ -87,7 +86,7 @@ bool RigGridManager::isEqual(RigMainGrid* gridA, RigMainGrid* gridB) } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RigGridManager::clear() { @@ -95,9 +94,10 @@ void RigGridManager::clear() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- -bool RigGridManager::isGridDimensionsEqual(const std::vector< std::vector >& mainCaseGridDimensions, const std::vector< std::vector >& caseGridDimensions) +bool RigGridManager::isGridDimensionsEqual(const std::vector>& mainCaseGridDimensions, + const std::vector>& caseGridDimensions) { if (mainCaseGridDimensions.size() != caseGridDimensions.size()) { @@ -112,17 +112,32 @@ bool RigGridManager::isGridDimensionsEqual(const std::vector< std::vector > if (mainCaseGridDimensions[j][0] != caseGridDimensions[j][0]) return false; // nx if (mainCaseGridDimensions[j][1] != caseGridDimensions[j][1]) return false; // ny if (mainCaseGridDimensions[j][2] != caseGridDimensions[j][2]) return false; // nz - } return true; } //-------------------------------------------------------------------------------------------------- -/// +/// +//-------------------------------------------------------------------------------------------------- +bool RigGridManager::isMainGridDimensionsEqual(RigMainGrid* gridA, RigMainGrid* gridB) +{ + if (gridA == nullptr || gridB == nullptr) return false; + + if (gridA == gridB) return true; + + if (gridA->cellCountI() != gridB->cellCountI()) return false; + if (gridA->cellCountJ() != gridB->cellCountJ()) return false; + if (gridA->cellCountK() != gridB->cellCountK()) return false; + + return true; +} + +//-------------------------------------------------------------------------------------------------- +/// //-------------------------------------------------------------------------------------------------- -RigGridManager::CaseToGridMap::CaseToGridMap(RigEclipseCaseData* eclipseCase, RigMainGrid* mainGrid) : -m_eclipseCase(eclipseCase), - m_mainGrid(mainGrid) +RigGridManager::CaseToGridMap::CaseToGridMap(RigEclipseCaseData* eclipseCase, RigMainGrid* mainGrid) + : m_eclipseCase(eclipseCase) + , m_mainGrid(mainGrid) { } diff --git a/ApplicationCode/ReservoirDataModel/RigGridManager.h b/ApplicationCode/ReservoirDataModel/RigGridManager.h index 6f96b20f16..df4c4d3fae 100644 --- a/ApplicationCode/ReservoirDataModel/RigGridManager.h +++ b/ApplicationCode/ReservoirDataModel/RigGridManager.h @@ -1,17 +1,17 @@ ///////////////////////////////////////////////////////////////////////////////// // // Copyright (C) 2011-2012 Statoil ASA, Ceetron AS -// +// // ResInsight 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 3 of the License, or // (at your option) any later version. -// +// // ResInsight 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 at +// +// See the GNU General Public License at // for more details. // ///////////////////////////////////////////////////////////////////////////////// @@ -19,8 +19,8 @@ #pragma once #include "cvfBase.h" -#include "cvfObject.h" #include "cvfCollection.h" +#include "cvfObject.h" #include @@ -31,26 +31,28 @@ class RigGridManager : public cvf::Object { public: void addCase(RigEclipseCaseData* eclipseCase); - + void removeCase(RigEclipseCaseData* eclipseCase); - + RigMainGrid* findEqualGrid(RigMainGrid* candidateGrid); void clear(); static bool isEqual(RigMainGrid* gridA, RigMainGrid* gridB); - static bool isGridDimensionsEqual(const std::vector< std::vector >& mainCaseGridDimensions, const std::vector< std::vector >& caseGridDimensions); + static bool isMainGridDimensionsEqual(RigMainGrid* gridA, RigMainGrid* gridB); + static bool isGridDimensionsEqual(const std::vector>& mainCaseGridDimensions, + const std::vector>& caseGridDimensions); + private: class CaseToGridMap : public cvf::Object { public: CaseToGridMap(RigEclipseCaseData* eclipseCase, RigMainGrid* mainGrid); - RigEclipseCaseData* m_eclipseCase; - RigMainGrid* m_mainGrid; + RigEclipseCaseData* m_eclipseCase; + RigMainGrid* m_mainGrid; }; - private: cvf::Collection m_caseToGrid; }; diff --git a/ApplicationCode/ReservoirDataModel/RigLocalGrid.cpp b/ApplicationCode/ReservoirDataModel/RigLocalGrid.cpp index 0a597ec0f2..84d48e8045 100644 --- a/ApplicationCode/ReservoirDataModel/RigLocalGrid.cpp +++ b/ApplicationCode/ReservoirDataModel/RigLocalGrid.cpp @@ -23,7 +23,6 @@ RigLocalGrid::RigLocalGrid(RigMainGrid* mainGrid): RigGridBase(mainGrid), m_parentGrid(nullptr), - m_positionInParentGrid(cvf::UNDEFINED_SIZE_T), m_isTempGrid(false), m_associatedWellPathName("") { @@ -51,22 +50,6 @@ void RigLocalGrid::setParentGrid(RigGridBase * parentGrid) m_parentGrid = parentGrid; } -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -size_t RigLocalGrid::positionInParentGrid() const -{ - return m_positionInParentGrid; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RigLocalGrid::setPositionInParentGrid(size_t positionInParentGrid) -{ - m_positionInParentGrid = positionInParentGrid; -} - //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/ReservoirDataModel/RigLocalGrid.h b/ApplicationCode/ReservoirDataModel/RigLocalGrid.h index 2ce563522b..2f7a250e3f 100644 --- a/ApplicationCode/ReservoirDataModel/RigLocalGrid.h +++ b/ApplicationCode/ReservoirDataModel/RigLocalGrid.h @@ -28,9 +28,6 @@ class RigLocalGrid : public RigGridBase RigGridBase * parentGrid() const; void setParentGrid(RigGridBase * parentGrid); - size_t positionInParentGrid() const; - void setPositionInParentGrid(size_t positionInParentGrid); - void setAsTempGrid(bool isTemp); bool isTempGrid() const override; @@ -39,7 +36,6 @@ class RigLocalGrid : public RigGridBase private: RigGridBase * m_parentGrid; - size_t m_positionInParentGrid; bool m_isTempGrid; std::string m_associatedWellPathName; }; diff --git a/ApplicationCode/ReservoirDataModel/RigMainGrid.cpp b/ApplicationCode/ReservoirDataModel/RigMainGrid.cpp index 5786191508..e9223343e8 100644 --- a/ApplicationCode/ReservoirDataModel/RigMainGrid.cpp +++ b/ApplicationCode/ReservoirDataModel/RigMainGrid.cpp @@ -39,6 +39,9 @@ RigMainGrid::RigMainGrid() m_flipXAxis = false; m_flipYAxis = false; + + m_useMapAxes = false; + m_mapAxes = defaultMapAxes(); } RigMainGrid::~RigMainGrid() {} @@ -157,36 +160,6 @@ size_t RigMainGrid::findReservoirCellIndexFromPoint(const cvf::Vec3d& point) con return cellContainingPoint; } -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -std::vector RigMainGrid::findAllReservoirCellIndicesMatching2dPoint(const cvf::Vec2d& point2d) const -{ - cvf::BoundingBox gridBoundingVox = boundingBox(); - cvf::Vec3d highestPoint(point2d, gridBoundingVox.max().z()); - cvf::Vec3d lowestPoint(point2d, gridBoundingVox.min().z()); - - cvf::BoundingBox rayBBox; - rayBBox.add(highestPoint); - rayBBox.add(lowestPoint); - - std::vector cellIndices; - m_mainGrid->findIntersectingCells(rayBBox, &cellIndices); - - cvf::Vec3d hexCorners[8]; - for (size_t cellIndex : cellIndices) - { - m_mainGrid->cellCornerVertices(cellIndex, hexCorners); - - if (RigHexIntersectionTools::lineIntersectsHexCell(highestPoint, lowestPoint, hexCorners)) - { - cellIndices.push_back(cellIndex); - } - } - - return cellIndices; -} - //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -406,7 +379,15 @@ void RigMainGrid::setFaults(const cvf::Collection& faults) //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -const cvf::Collection& RigMainGrid::faults() +const cvf::Collection& RigMainGrid::faults() const +{ + return m_faults; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +cvf::Collection& RigMainGrid::faults() { return m_faults; } @@ -779,3 +760,84 @@ const std::string& RigMainGrid::associatedWellPathName() const static const std::string EMPTY_STRING; return EMPTY_STRING; } + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RigMainGrid::setUseMapAxes(bool useMapAxes) +{ + m_useMapAxes = useMapAxes; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RigMainGrid::useMapAxes() const +{ + return m_useMapAxes; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RigMainGrid::setMapAxes(const std::array& mapAxes) +{ + m_mapAxes = mapAxes; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +const std::array& RigMainGrid::mapAxes() const +{ + return m_mapAxes; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::array RigMainGrid::mapAxesF() const +{ + std::array floatAxes; + for (size_t i = 0; i < 6; ++i) + { + floatAxes[i] = (float)m_mapAxes[i]; + } + return floatAxes; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +cvf::Mat4d RigMainGrid::mapAxisTransform() const +{ + cvf::Mat4d mapAxisTrans; + if (m_useMapAxes) + { + cvf::Vec3d origin(m_mapAxes[2], m_mapAxes[3], 0.0); + cvf::Vec3d xAxis = cvf::Vec3d(m_mapAxes[4] - origin[0], m_mapAxes[5] - origin[1], 0.0).getNormalized(); + cvf::Vec3d yAxis = cvf::Vec3d(m_mapAxes[0] - origin[0], m_mapAxes[1] - origin[1], 0.0).getNormalized(); + cvf::Vec3d zAxis(0.0, 0.0, 1.0); + mapAxisTrans = cvf::Mat4d::fromCoordSystemAxes(&xAxis, &yAxis, &zAxis); + mapAxisTrans.setTranslation(origin); + mapAxisTrans.invert(); + } + else + { + mapAxisTrans.setIdentity(); + } + return mapAxisTrans; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::array RigMainGrid::defaultMapAxes() +{ + const double origin[2] = {0.0, 0.0}; + const double xPoint[2] = {1.0, 0.0}; + const double yPoint[2] = {0.0, 1.0}; + + // Order (see Elipse Reference Manual for keyword MAPAXES): Y_x, Y_y, O_x, O_y, X_x, X_y + return { yPoint[0], yPoint[1], origin[0], origin[1], xPoint[0], xPoint[1] }; +} diff --git a/ApplicationCode/ReservoirDataModel/RigMainGrid.h b/ApplicationCode/ReservoirDataModel/RigMainGrid.h index 7bcc725fbe..c0d64da439 100644 --- a/ApplicationCode/ReservoirDataModel/RigMainGrid.h +++ b/ApplicationCode/ReservoirDataModel/RigMainGrid.h @@ -58,7 +58,6 @@ class RigMainGrid : public RigGridBase const RigCell& cellByGridAndGridLocalCellIdx(size_t gridIdx, size_t gridLocalCellIdx) const; size_t reservoirCellIndexByGridAndGridLocalCellIndex(size_t gridIdx, size_t gridLocalCellIdx) const; size_t findReservoirCellIndexFromPoint(const cvf::Vec3d& point) const; - std::vector findAllReservoirCellIndicesMatching2dPoint(const cvf::Vec2d& point2d) const; void addLocalGrid(RigLocalGrid* localGrid); size_t gridCountOnFile() const; @@ -71,7 +70,8 @@ class RigMainGrid : public RigGridBase RigNNCData* nncData(); void setFaults(const cvf::Collection& faults); - const cvf::Collection& faults(); + const cvf::Collection& faults() const; + cvf::Collection& faults(); void calculateFaults(const RigActiveCellInfo* activeCellInfo); void distributeNNCsToFaults(); @@ -93,11 +93,19 @@ class RigMainGrid : public RigGridBase bool isTempGrid() const override; const std::string& associatedWellPathName() const override; + void setUseMapAxes(bool useMapAxes); + bool useMapAxes() const; + void setMapAxes(const std::array& mapAxes); + const std::array& mapAxes() const; + std::array mapAxesF() const; + + cvf::Mat4d mapAxisTransform() const; private: void initAllSubCellsMainGridCellIndex(); void buildCellSearchTree(); bool hasFaultWithName(const QString& name) const; + static std::array defaultMapAxes(); private: std::vector m_nodes; ///< Global vertex table std::vector m_cells; ///< Global array of all cells in the reservoir (including the ones in LGR's) @@ -115,5 +123,8 @@ class RigMainGrid : public RigGridBase bool m_flipXAxis; bool m_flipYAxis; + + bool m_useMapAxes; + std::array m_mapAxes; }; diff --git a/ApplicationCode/ReservoirDataModel/RigNNCData.cpp b/ApplicationCode/ReservoirDataModel/RigNNCData.cpp index 89ef3b8705..2947d98038 100644 --- a/ApplicationCode/ReservoirDataModel/RigNNCData.cpp +++ b/ApplicationCode/ReservoirDataModel/RigNNCData.cpp @@ -20,6 +20,7 @@ #include "RigNNCData.h" #include "RigMainGrid.h" #include "cvfGeometryTools.h" +#include "RigEclipseResultAddress.h" //-------------------------------------------------------------------------------------------------- @@ -43,7 +44,6 @@ void RigNNCData::processConnections(const RigMainGrid& mainGrid) const RigCell& c1 = mainGrid.globalCellArray()[m_connections[cnIdx].m_c1GlobIdx]; const RigCell& c2 = mainGrid.globalCellArray()[m_connections[cnIdx].m_c2GlobIdx]; - bool foundAnyOverlap = false; std::vector connectionPolygon; std::vector connectionIntersections; cvf::StructGridInterface::FaceType connectionFace = cvf::StructGridInterface::NO_FACE; @@ -52,7 +52,6 @@ void RigNNCData::processConnections(const RigMainGrid& mainGrid) if (connectionFace != cvf::StructGridInterface::NO_FACE) { - foundAnyOverlap = true; // Found an overlap polygon. Store data about connection m_connections[cnIdx].m_c1Face = connectionFace; @@ -200,9 +199,9 @@ std::vector& RigNNCData::makeStaticConnectionScalarResult(QString nncDat //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -const std::vector* RigNNCData::staticConnectionScalarResult(size_t scalarResultIndex) const +const std::vector* RigNNCData::staticConnectionScalarResult(const RigEclipseResultAddress& resVarAddr) const { - QString nncDataType = getNNCDataTypeFromScalarResultIndex(scalarResultIndex); + QString nncDataType = getNNCDataTypeFromScalarResultIndex(resVarAddr); if (nncDataType.isNull()) return nullptr; std::map > >::const_iterator it = m_connectionResults.find(nncDataType); @@ -250,9 +249,9 @@ std::vector< std::vector >& RigNNCData::makeDynamicConnectionScalarResul //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -const std::vector< std::vector >* RigNNCData::dynamicConnectionScalarResult(size_t scalarResultIndex) const +const std::vector< std::vector >* RigNNCData::dynamicConnectionScalarResult(const RigEclipseResultAddress& resVarAddr) const { - QString nncDataType = getNNCDataTypeFromScalarResultIndex(scalarResultIndex); + QString nncDataType = getNNCDataTypeFromScalarResultIndex(resVarAddr); if (nncDataType.isNull()) return nullptr; auto it = m_connectionResults.find(nncDataType); @@ -270,9 +269,9 @@ const std::vector< std::vector >* RigNNCData::dynamicConnectionScalarRes //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -const std::vector* RigNNCData::dynamicConnectionScalarResult(size_t scalarResultIndex, size_t timeStep) const +const std::vector* RigNNCData::dynamicConnectionScalarResult(const RigEclipseResultAddress& resVarAddr, size_t timeStep) const { - QString nncDataType = getNNCDataTypeFromScalarResultIndex(scalarResultIndex); + QString nncDataType = getNNCDataTypeFromScalarResultIndex(resVarAddr); if (nncDataType.isNull()) return nullptr; auto it = m_connectionResults.find(nncDataType); @@ -329,9 +328,9 @@ std::vector< std::vector >& RigNNCData::makeGeneratedConnectionScalarRes //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -const std::vector< std::vector >* RigNNCData::generatedConnectionScalarResult(size_t scalarResultIndex) const +const std::vector< std::vector >* RigNNCData::generatedConnectionScalarResult(const RigEclipseResultAddress& resVarAddr) const { - QString nncDataType = getNNCDataTypeFromScalarResultIndex(scalarResultIndex); + QString nncDataType = getNNCDataTypeFromScalarResultIndex(resVarAddr); if (nncDataType.isNull()) return nullptr; auto it = m_connectionResults.find(nncDataType); @@ -349,9 +348,9 @@ const std::vector< std::vector >* RigNNCData::generatedConnectionScalarR //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -const std::vector* RigNNCData::generatedConnectionScalarResult(size_t scalarResultIndex, size_t timeStep) const +const std::vector* RigNNCData::generatedConnectionScalarResult(const RigEclipseResultAddress& resVarAddr, size_t timeStep) const { - QString nncDataType = getNNCDataTypeFromScalarResultIndex(scalarResultIndex); + QString nncDataType = getNNCDataTypeFromScalarResultIndex(resVarAddr); if (nncDataType.isNull()) return nullptr; auto it = m_connectionResults.find(nncDataType); @@ -369,9 +368,9 @@ const std::vector* RigNNCData::generatedConnectionScalarResult(size_t sc //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -std::vector< std::vector >* RigNNCData::generatedConnectionScalarResult(size_t scalarResultIndex) +std::vector< std::vector >* RigNNCData::generatedConnectionScalarResult(const RigEclipseResultAddress& resVarAddr) { - QString nncDataType = getNNCDataTypeFromScalarResultIndex(scalarResultIndex); + QString nncDataType = getNNCDataTypeFromScalarResultIndex(resVarAddr); if (nncDataType.isNull()) return nullptr; auto it = m_connectionResults.find(nncDataType); @@ -389,9 +388,9 @@ std::vector< std::vector >* RigNNCData::generatedConnectionScalarResult( //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -std::vector* RigNNCData::generatedConnectionScalarResult(size_t scalarResultIndex, size_t timeStep) +std::vector* RigNNCData::generatedConnectionScalarResult(const RigEclipseResultAddress& resVarAddr, size_t timeStep) { - QString nncDataType = getNNCDataTypeFromScalarResultIndex(scalarResultIndex); + QString nncDataType = getNNCDataTypeFromScalarResultIndex(resVarAddr); if (nncDataType.isNull()) return nullptr; auto it = m_connectionResults.find(nncDataType); @@ -493,17 +492,17 @@ std::vector RigNNCData::availableProperties(NNCResultType resultType) c //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RigNNCData::setScalarResultIndex(const QString& nncDataType, size_t scalarResultIndex) +void RigNNCData::setEclResultAddress(const QString& nncDataType, const RigEclipseResultAddress& resVarAddr) { - m_resultIndexToNNCDataType[scalarResultIndex] = nncDataType; + m_resultAddrToNNCDataType[resVarAddr] = nncDataType; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -bool RigNNCData::hasScalarValues(size_t scalarResultIndex) +bool RigNNCData::hasScalarValues(const RigEclipseResultAddress& resVarAddr) { - QString nncDataType = getNNCDataTypeFromScalarResultIndex(scalarResultIndex); + QString nncDataType = getNNCDataTypeFromScalarResultIndex(resVarAddr); if (nncDataType.isNull()) return false; auto it = m_connectionResults.find(nncDataType); @@ -513,10 +512,10 @@ bool RigNNCData::hasScalarValues(size_t scalarResultIndex) //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -const QString RigNNCData::getNNCDataTypeFromScalarResultIndex(size_t scalarResultIndex) const +const QString RigNNCData::getNNCDataTypeFromScalarResultIndex(const RigEclipseResultAddress& resVarAddr) const { - auto it = m_resultIndexToNNCDataType.find(scalarResultIndex); - if (it != m_resultIndexToNNCDataType.end()) + auto it = m_resultAddrToNNCDataType.find(resVarAddr); + if (it != m_resultAddrToNNCDataType.end()) { return it->second; } diff --git a/ApplicationCode/ReservoirDataModel/RigNNCData.h b/ApplicationCode/ReservoirDataModel/RigNNCData.h index 49816a6147..b19aa3c6ff 100644 --- a/ApplicationCode/ReservoirDataModel/RigNNCData.h +++ b/ApplicationCode/ReservoirDataModel/RigNNCData.h @@ -31,7 +31,7 @@ class RigMainGrid; class RigCell; - +class RigEclipseResultAddress; class RigConnection { @@ -88,20 +88,20 @@ class RigNNCData : public cvf::Object const std::vector& connections() const { return m_connections; } std::vector& makeStaticConnectionScalarResult(QString nncDataType); - const std::vector* staticConnectionScalarResult(size_t scalarResultIndex) const; + const std::vector* staticConnectionScalarResult(const RigEclipseResultAddress& resVarAddr) const; const std::vector* staticConnectionScalarResultByName(const QString& nncDataType) const; std::vector< std::vector >& makeDynamicConnectionScalarResult(QString nncDataType, size_t timeStepCount); - const std::vector< std::vector >* dynamicConnectionScalarResult(size_t scalarResultIndex) const; - const std::vector* dynamicConnectionScalarResult(size_t scalarResultIndex, size_t timeStep) const; + const std::vector< std::vector >* dynamicConnectionScalarResult(const RigEclipseResultAddress& resVarAddr) const; + const std::vector* dynamicConnectionScalarResult(const RigEclipseResultAddress& resVarAddr, size_t timeStep) const; const std::vector< std::vector >* dynamicConnectionScalarResultByName(const QString& nncDataType) const; const std::vector* dynamicConnectionScalarResultByName(const QString& nncDataType, size_t timeStep) const; std::vector< std::vector >& makeGeneratedConnectionScalarResult(QString nncDataType, size_t timeStepCount); - const std::vector< std::vector >* generatedConnectionScalarResult(size_t scalarResultIndex) const; - const std::vector* generatedConnectionScalarResult(size_t scalarResultIndex, size_t timeStep) const; - std::vector< std::vector >* generatedConnectionScalarResult(size_t scalarResultIndex); - std::vector* generatedConnectionScalarResult(size_t scalarResultIndex, size_t timeStep); + const std::vector< std::vector >* generatedConnectionScalarResult(const RigEclipseResultAddress& resVarAddr) const; + const std::vector* generatedConnectionScalarResult(const RigEclipseResultAddress& resVarAddr, size_t timeStep) const; + std::vector< std::vector >* generatedConnectionScalarResult(const RigEclipseResultAddress& resVarAddr); + std::vector* generatedConnectionScalarResult(const RigEclipseResultAddress& resVarAddr, size_t timeStep); const std::vector< std::vector >* generatedConnectionScalarResultByName(const QString& nncDataType) const; const std::vector* generatedConnectionScalarResultByName(const QString& nncDataType, size_t timeStep) const; std::vector< std::vector >* generatedConnectionScalarResultByName(const QString& nncDataType); @@ -109,16 +109,16 @@ class RigNNCData : public cvf::Object std::vector availableProperties(NNCResultType resultType) const; - void setScalarResultIndex(const QString& nncDataType, size_t scalarResultIndex); + void setEclResultAddress(const QString& nncDataType, const RigEclipseResultAddress& resVarAddr); - bool hasScalarValues(size_t scalarResultIndex); + bool hasScalarValues(const RigEclipseResultAddress& resVarAddr); private: - const QString getNNCDataTypeFromScalarResultIndex(size_t scalarResultIndex) const; + const QString getNNCDataTypeFromScalarResultIndex(const RigEclipseResultAddress& resVarAddr) const; bool isNative(QString nncDataType) const; private: std::vector m_connections; std::map > > m_connectionResults; - std::map m_resultIndexToNNCDataType; + std::map m_resultAddrToNNCDataType; }; diff --git a/ApplicationCode/ReservoirDataModel/RigNumberOfFloodedPoreVolumesCalculator.cpp b/ApplicationCode/ReservoirDataModel/RigNumberOfFloodedPoreVolumesCalculator.cpp index a59ca86f3a..536cdc8c98 100644 --- a/ApplicationCode/ReservoirDataModel/RigNumberOfFloodedPoreVolumesCalculator.cpp +++ b/ApplicationCode/ReservoirDataModel/RigNumberOfFloodedPoreVolumesCalculator.cpp @@ -68,21 +68,28 @@ RigNumberOfFloodedPoreVolumesCalculator::RigNumberOfFloodedPoreVolumesCalculator swcrResults = RigCaseCellResultsData::getResultIndexableStaticResult(actCellInfo, gridCellResults, "SWCR", porvActiveCellsResultStorage); progress.incrementProgress(); - std::vector scalarResultIndexTracers; + std::vector tracerResAddrs; for (QString tracerName : tracerNames) { - scalarResultIndexTracers.push_back(gridCellResults->findOrLoadScalarResult(RiaDefines::DYNAMIC_NATIVE, tracerName)); + RigEclipseResultAddress tracerResAddr(RiaDefines::DYNAMIC_NATIVE, tracerName); + if (gridCellResults->ensureKnownResultLoaded(tracerResAddr) ) + { + tracerResAddrs.push_back(tracerResAddr); + } progress.incrementProgress(); } std::vector > summedTracersAtAllTimesteps; //TODO: Option for Oil and Gas instead of water + RigEclipseResultAddress flrWatIAddr(RiaDefines::DYNAMIC_NATIVE, "FLRWATI+"); + RigEclipseResultAddress flrWatJAddr(RiaDefines::DYNAMIC_NATIVE, "FLRWATJ+"); + RigEclipseResultAddress flrWatKAddr(RiaDefines::DYNAMIC_NATIVE, "FLRWATK+"); - size_t scalarResultIndexFlowrateI = gridCellResults->findOrLoadScalarResult(RiaDefines::DYNAMIC_NATIVE, "FLRWATI+"); + bool hasFlowrateI = gridCellResults->ensureKnownResultLoaded(flrWatIAddr); progress.incrementProgress(); - size_t scalarResultIndexFlowrateJ = gridCellResults->findOrLoadScalarResult(RiaDefines::DYNAMIC_NATIVE, "FLRWATJ+"); + bool hasFlowrateJ = gridCellResults->ensureKnownResultLoaded(flrWatJAddr); progress.incrementProgress(); - size_t scalarResultIndexFlowrateK = gridCellResults->findOrLoadScalarResult(RiaDefines::DYNAMIC_NATIVE, "FLRWATK+"); + bool hasFlowrateK = gridCellResults->ensureKnownResultLoaded(flrWatKAddr); progress.incrementProgress(); std::vector* > flowrateIatAllTimeSteps; @@ -107,27 +114,27 @@ RigNumberOfFloodedPoreVolumesCalculator::RigNumberOfFloodedPoreVolumesCalculator for (size_t timeStep = 0; timeStep < daysSinceSimulationStart.size(); timeStep++) { const std::vector* flowrateI = nullptr; - if (scalarResultIndexFlowrateI != cvf::UNDEFINED_SIZE_T) + if (hasFlowrateI) { - flowrateI = &(eclipseCaseData->results(RiaDefines::MATRIX_MODEL)->cellScalarResults(scalarResultIndexFlowrateI, + flowrateI = &(eclipseCaseData->results(RiaDefines::MATRIX_MODEL)->cellScalarResults(flrWatIAddr, timeStep)); } flowrateIatAllTimeSteps.push_back(flowrateI); const std::vector* flowrateJ = nullptr; - if (scalarResultIndexFlowrateJ != cvf::UNDEFINED_SIZE_T) + if (hasFlowrateJ) { - flowrateJ = &(eclipseCaseData->results(RiaDefines::MATRIX_MODEL)->cellScalarResults(scalarResultIndexFlowrateJ, + flowrateJ = &(eclipseCaseData->results(RiaDefines::MATRIX_MODEL)->cellScalarResults(flrWatJAddr, timeStep)); } flowrateJatAllTimeSteps.push_back(flowrateJ); const std::vector* flowrateK = nullptr; - if (scalarResultIndexFlowrateK != cvf::UNDEFINED_SIZE_T) + if (hasFlowrateK) { - flowrateK = &(eclipseCaseData->results(RiaDefines::MATRIX_MODEL)->cellScalarResults(scalarResultIndexFlowrateK, + flowrateK = &(eclipseCaseData->results(RiaDefines::MATRIX_MODEL)->cellScalarResults(flrWatKAddr, timeStep)); } flowrateKatAllTimeSteps.push_back(flowrateK); @@ -140,16 +147,13 @@ RigNumberOfFloodedPoreVolumesCalculator::RigNumberOfFloodedPoreVolumesCalculator //sum all tracers at current timestep std::vector summedTracerValues(resultCellCount); - for (size_t tracerIndex : scalarResultIndexTracers) + for (const RigEclipseResultAddress& tracerResAddr : tracerResAddrs) { - if (tracerIndex != cvf::UNDEFINED_SIZE_T) - { - const std::vector* tracerResult = &(eclipseCaseData->results(RiaDefines::MATRIX_MODEL)->cellScalarResults(tracerIndex, timeStep)); + const std::vector* tracerResult = &(eclipseCaseData->results(RiaDefines::MATRIX_MODEL)->cellScalarResults(tracerResAddr, timeStep)); - for (size_t i = 0; i < summedTracerValues.size(); i++) - { - summedTracerValues[i] += tracerResult->at(i); - } + for ( size_t i = 0; i < summedTracerValues.size(); i++ ) + { + summedTracerValues[i] += tracerResult->at(i); } } summedTracersAtAllTimesteps.push_back(summedTracerValues); diff --git a/ApplicationCode/ReservoirDataModel/RigObservedData.cpp b/ApplicationCode/ReservoirDataModel/RigObservedData.cpp deleted file mode 100644 index 5c4176d4f4..0000000000 --- a/ApplicationCode/ReservoirDataModel/RigObservedData.cpp +++ /dev/null @@ -1,46 +0,0 @@ -///////////////////////////////////////////////////////////////////////////////// -// -// Copyright (C) 2017- Statoil ASA -// -// ResInsight 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 3 of the License, or -// (at your option) any later version. -// -// ResInsight 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 at -// for more details. -// -///////////////////////////////////////////////////////////////////////////////// - -#include "RigObservedData.h" - -#include -#include - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -RigObservedData::RigObservedData(const QString& observedDataFileName) -{ - openOrReloadCase(observedDataFileName); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -RigObservedData::~RigObservedData() -{ - -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RigObservedData::openOrReloadCase(const QString& observedDataFileName) -{ - -} diff --git a/ApplicationCode/ReservoirDataModel/RigObservedData.h b/ApplicationCode/ReservoirDataModel/RigObservedData.h deleted file mode 100644 index 6d23c53e7b..0000000000 --- a/ApplicationCode/ReservoirDataModel/RigObservedData.h +++ /dev/null @@ -1,35 +0,0 @@ -///////////////////////////////////////////////////////////////////////////////// -// -// Copyright (C) 2017- Statoil ASA -// -// ResInsight 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 3 of the License, or -// (at your option) any later version. -// -// ResInsight 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 at -// for more details. -// -///////////////////////////////////////////////////////////////////////////////// - -#pragma once - -#include "cvfBase.h" -#include "cvfObject.h" - -class QString; - -class RigObservedData: public cvf::Object -{ -public: - explicit RigObservedData(const QString& observedDataFileName ); - ~RigObservedData() override; - - void openOrReloadCase(const QString& observedDataFileName); - -private: -}; diff --git a/ApplicationCode/ReservoirDataModel/RigPolyLinesData.cpp b/ApplicationCode/ReservoirDataModel/RigPolyLinesData.cpp new file mode 100644 index 0000000000..fe108f1ec5 --- /dev/null +++ b/ApplicationCode/ReservoirDataModel/RigPolyLinesData.cpp @@ -0,0 +1,37 @@ +#include "RigPolyLinesData.h" +#include "RigPolyLinesData.h" +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2018- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// +#include "RigPolyLinesData.h" + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RigPolyLinesData::RigPolyLinesData() +{ + +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RigPolyLinesData::~RigPolyLinesData() +{ + +} diff --git a/ApplicationCode/ReservoirDataModel/RigPolyLinesData.h b/ApplicationCode/ReservoirDataModel/RigPolyLinesData.h new file mode 100644 index 0000000000..b5fbcc56c8 --- /dev/null +++ b/ApplicationCode/ReservoirDataModel/RigPolyLinesData.h @@ -0,0 +1,43 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2018 equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "cvfBase.h" +#include "cvfObject.h" +#include "cvfVector3.h" + +#include + +//================================================================================================== +/// +/// +//================================================================================================== +class RigPolyLinesData : public cvf::Object +{ +public: + RigPolyLinesData(); + ~RigPolyLinesData() override; + + const std::vector >& polyLines() const { return m_polylines;} + void setPolyLines(const std::vector >& polyLines) { m_polylines = polyLines;} + +private: + std::vector > m_polylines; +}; + diff --git a/ApplicationCode/ReservoirDataModel/RigReservoirBuilderMock.cpp b/ApplicationCode/ReservoirDataModel/RigReservoirBuilderMock.cpp index 24dcf8ffa7..5490e86a0a 100644 --- a/ApplicationCode/ReservoirDataModel/RigReservoirBuilderMock.cpp +++ b/ApplicationCode/ReservoirDataModel/RigReservoirBuilderMock.cpp @@ -27,9 +27,9 @@ #include "RigSimWellData.h" /* rand example: guess the number */ -#include -#include -#include +#include +#include +#include //-------------------------------------------------------------------------------------------------- /// diff --git a/ApplicationCode/ReservoirDataModel/RigResultAccessorFactory.cpp b/ApplicationCode/ReservoirDataModel/RigResultAccessorFactory.cpp index 696d70be35..c0aceb7c4d 100644 --- a/ApplicationCode/ReservoirDataModel/RigResultAccessorFactory.cpp +++ b/ApplicationCode/ReservoirDataModel/RigResultAccessorFactory.cpp @@ -34,65 +34,8 @@ #include "RimEclipseResultDefinition.h" #include "RimFlowDiagSolution.h" -#include +#include -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -cvf::ref RigResultAccessorFactory::createFromUiResultName(const RigEclipseCaseData* eclipseCase, - size_t gridIndex, - RiaDefines::PorosityModelType porosityModel, - size_t timeStepIndex, - const QString& uiResultName) -{ - cvf::ref derivedCandidate = createDerivedResultAccessor(eclipseCase, - gridIndex, - porosityModel, - timeStepIndex, - uiResultName); - - if (derivedCandidate.notNull()) return derivedCandidate; - - return RigResultAccessorFactory::createNativeFromUiResultName(eclipseCase, gridIndex, porosityModel, timeStepIndex, uiResultName); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -cvf::ref RigResultAccessorFactory::createFromNameAndType(const RigEclipseCaseData* eclipseCase, - size_t gridIndex, - RiaDefines::PorosityModelType porosityModel, - size_t timeStepIndex, - const QString& uiResultName, - RiaDefines::ResultCatType resultType) -{ - if (!eclipseCase || !eclipseCase->results(porosityModel) || !eclipseCase->activeCellInfo(porosityModel)) - { - return nullptr; - } - - size_t scalarSetIndex = eclipseCase->results(porosityModel)->findScalarResultIndex(resultType, uiResultName); - if (scalarSetIndex == cvf::UNDEFINED_SIZE_T) - { - return nullptr; - } - - cvf::ref derivedCandidate = createDerivedResultAccessor(eclipseCase, - gridIndex, - porosityModel, - timeStepIndex, - uiResultName); - - if (derivedCandidate.notNull()) return derivedCandidate; - - size_t adjustedTimeStepIndex = timeStepIndex; - if (resultType == RiaDefines::STATIC_NATIVE) - { - adjustedTimeStepIndex = 0; - } - - return createFromResultIdx(eclipseCase, gridIndex, porosityModel, adjustedTimeStepIndex, scalarSetIndex); -} //-------------------------------------------------------------------------------------------------- /// @@ -119,177 +62,213 @@ cvf::ref RigResultAccessorFactory::createFromResultDefinition } else { - size_t adjustedTimeStepIndex = timeStepIndex; - if ( resultDefinition->hasStaticResult() ) - { - adjustedTimeStepIndex = 0; - } - - return RigResultAccessorFactory::createFromNameAndType(eclipseCase, + return RigResultAccessorFactory::createFromResultAddress(eclipseCase, gridIndex, resultDefinition->porosityModel(), - adjustedTimeStepIndex, - resultDefinition->resultVariable(), - resultDefinition->resultType()); + timeStepIndex, + resultDefinition->eclipseResultAddress()); } } //-------------------------------------------------------------------------------------------------- -/// This function must be harmonized with RigResultModifierFactory::createResultModifier() +/// //-------------------------------------------------------------------------------------------------- -cvf::ref RigResultAccessorFactory::createNativeFromUiResultName(const RigEclipseCaseData* eclipseCase, - size_t gridIndex, - RiaDefines::PorosityModelType porosityModel, - size_t timeStepIndex, - const QString& uiResultName) +cvf::ref RigResultAccessorFactory::createFromResultAddress(const RigEclipseCaseData* eclipseCase, + size_t gridIndex, + RiaDefines::PorosityModelType porosityModel, + size_t timeStepIndex, + const RigEclipseResultAddress& resVarAddr) { if (!eclipseCase || !eclipseCase->results(porosityModel) || !eclipseCase->activeCellInfo(porosityModel)) { return nullptr; } - size_t scalarSetIndex = eclipseCase->results(porosityModel)->findScalarResultIndex(uiResultName); - if (scalarSetIndex == cvf::UNDEFINED_SIZE_T) + if (!eclipseCase->results(porosityModel)->hasResultEntry(resVarAddr)) { return nullptr; } - return createFromResultIdx(eclipseCase, gridIndex, porosityModel, timeStepIndex, scalarSetIndex); + size_t adjustedTimeStepIndex = timeStepIndex; + if (resVarAddr.m_resultCatType == RiaDefines::STATIC_NATIVE) + { + adjustedTimeStepIndex = 0; + } + + cvf::ref derivedCandidate = createCombinedResultAccessor(eclipseCase, + gridIndex, + porosityModel, + adjustedTimeStepIndex, + resVarAddr); + + if (derivedCandidate.notNull()) return derivedCandidate; + + + return createNativeFromResultAddress(eclipseCase, gridIndex, porosityModel, adjustedTimeStepIndex, resVarAddr); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -cvf::ref RigResultAccessorFactory::createDerivedResultAccessor(const RigEclipseCaseData* eclipseCase, +cvf::ref RigResultAccessorFactory::createCombinedResultAccessor(const RigEclipseCaseData* eclipseCase, size_t gridIndex, RiaDefines::PorosityModelType porosityModel, size_t timeStepIndex, - const QString& uiResultName) + const RigEclipseResultAddress& resVarAddr) { CVF_ASSERT(gridIndex < eclipseCase->gridCount()); CVF_ASSERT(eclipseCase); CVF_ASSERT(eclipseCase->results(porosityModel)); CVF_ASSERT(eclipseCase->activeCellInfo(porosityModel)); + RigEclipseResultAddress nativeAddr(resVarAddr); const RigGridBase* grid = eclipseCase->grid(gridIndex); - if (uiResultName == RiaDefines::combinedTransmissibilityResultName()) + if (resVarAddr.m_resultName == RiaDefines::combinedTransmissibilityResultName()) { CVF_ASSERT(timeStepIndex == 0); // Static result, only data for first time step cvf::ref cellFaceAccessObject = new RigCombTransResultAccessor(grid); - - cvf::ref xTransAccessor = RigResultAccessorFactory::createNativeFromUiResultName(eclipseCase, gridIndex, porosityModel, timeStepIndex, "TRANX"); - cvf::ref yTransAccessor = RigResultAccessorFactory::createNativeFromUiResultName(eclipseCase, gridIndex, porosityModel, timeStepIndex, "TRANY"); - cvf::ref zTransAccessor = RigResultAccessorFactory::createNativeFromUiResultName(eclipseCase, gridIndex, porosityModel, timeStepIndex, "TRANZ"); + nativeAddr.m_resultName = "TRANX"; + cvf::ref xTransAccessor = RigResultAccessorFactory::createNativeFromResultAddress(eclipseCase, gridIndex, porosityModel, timeStepIndex, nativeAddr); + nativeAddr.m_resultName ="TRANY"; + cvf::ref yTransAccessor = RigResultAccessorFactory::createNativeFromResultAddress(eclipseCase, gridIndex, porosityModel, timeStepIndex, nativeAddr); + nativeAddr.m_resultName = "TRANZ"; + cvf::ref zTransAccessor = RigResultAccessorFactory::createNativeFromResultAddress(eclipseCase, gridIndex, porosityModel, timeStepIndex, nativeAddr); cellFaceAccessObject->setTransResultAccessors(xTransAccessor.p(), yTransAccessor.p(), zTransAccessor.p()); return cellFaceAccessObject; } - else if (uiResultName == RiaDefines::combinedMultResultName()) + else if (resVarAddr.m_resultName == RiaDefines::combinedMultResultName()) { CVF_ASSERT(timeStepIndex == 0); // Static result, only data for first time step cvf::ref cellFaceAccessObject = new RigCombMultResultAccessor(grid); - cvf::ref multXPos = RigResultAccessorFactory::createNativeFromUiResultName(eclipseCase, gridIndex, porosityModel, timeStepIndex, "MULTX"); - cvf::ref multXNeg = RigResultAccessorFactory::createNativeFromUiResultName(eclipseCase, gridIndex, porosityModel, timeStepIndex, "MULTX-"); - cvf::ref multYPos = RigResultAccessorFactory::createNativeFromUiResultName(eclipseCase, gridIndex, porosityModel, timeStepIndex, "MULTY"); - cvf::ref multYNeg = RigResultAccessorFactory::createNativeFromUiResultName(eclipseCase, gridIndex, porosityModel, timeStepIndex, "MULTY-"); - cvf::ref multZPos = RigResultAccessorFactory::createNativeFromUiResultName(eclipseCase, gridIndex, porosityModel, timeStepIndex, "MULTZ"); - cvf::ref multZNeg = RigResultAccessorFactory::createNativeFromUiResultName(eclipseCase, gridIndex, porosityModel, timeStepIndex, "MULTZ-"); + nativeAddr.m_resultName = "MULTX" ; + cvf::ref multXPos = RigResultAccessorFactory::createNativeFromResultAddress(eclipseCase, gridIndex, porosityModel, timeStepIndex, nativeAddr); + nativeAddr.m_resultName = "MULTX-"; + cvf::ref multXNeg = RigResultAccessorFactory::createNativeFromResultAddress(eclipseCase, gridIndex, porosityModel, timeStepIndex, nativeAddr); + nativeAddr.m_resultName = "MULTY" ; + cvf::ref multYPos = RigResultAccessorFactory::createNativeFromResultAddress(eclipseCase, gridIndex, porosityModel, timeStepIndex, nativeAddr); + nativeAddr.m_resultName = "MULTY-"; + cvf::ref multYNeg = RigResultAccessorFactory::createNativeFromResultAddress(eclipseCase, gridIndex, porosityModel, timeStepIndex, nativeAddr); + nativeAddr.m_resultName = "MULTZ" ; + cvf::ref multZPos = RigResultAccessorFactory::createNativeFromResultAddress(eclipseCase, gridIndex, porosityModel, timeStepIndex, nativeAddr); + nativeAddr.m_resultName = "MULTZ-"; + cvf::ref multZNeg = RigResultAccessorFactory::createNativeFromResultAddress(eclipseCase, gridIndex, porosityModel, timeStepIndex, nativeAddr); cellFaceAccessObject->setMultResultAccessors(multXPos.p(), multXNeg.p(), multYPos.p(), multYNeg.p(), multZPos.p(), multZNeg.p()); return cellFaceAccessObject; } - else if (uiResultName == RiaDefines::combinedRiTranResultName()) + else if (resVarAddr.m_resultName == RiaDefines::combinedRiTranResultName()) { CVF_ASSERT(timeStepIndex == 0); // Static result, only data for first time step cvf::ref cellFaceAccessObject = new RigCombTransResultAccessor(grid); - cvf::ref xTransAccessor = RigResultAccessorFactory::createNativeFromUiResultName(eclipseCase, gridIndex, porosityModel, timeStepIndex, RiaDefines::riTranXResultName()); - cvf::ref yTransAccessor = RigResultAccessorFactory::createNativeFromUiResultName(eclipseCase, gridIndex, porosityModel, timeStepIndex, RiaDefines::riTranYResultName()); - cvf::ref zTransAccessor = RigResultAccessorFactory::createNativeFromUiResultName(eclipseCase, gridIndex, porosityModel, timeStepIndex, RiaDefines::riTranZResultName()); + nativeAddr.m_resultName = RiaDefines::riTranXResultName() ; + cvf::ref xTransAccessor = RigResultAccessorFactory::createNativeFromResultAddress(eclipseCase, gridIndex, porosityModel, timeStepIndex, nativeAddr); + nativeAddr.m_resultName = RiaDefines::riTranYResultName() ; + cvf::ref yTransAccessor = RigResultAccessorFactory::createNativeFromResultAddress(eclipseCase, gridIndex, porosityModel, timeStepIndex, nativeAddr); + nativeAddr.m_resultName = RiaDefines::riTranZResultName() ; + cvf::ref zTransAccessor = RigResultAccessorFactory::createNativeFromResultAddress(eclipseCase, gridIndex, porosityModel, timeStepIndex, nativeAddr); cellFaceAccessObject->setTransResultAccessors(xTransAccessor.p(), yTransAccessor.p(), zTransAccessor.p()); return cellFaceAccessObject; } - else if (uiResultName == RiaDefines::combinedRiMultResultName()) + else if (resVarAddr.m_resultName == RiaDefines::combinedRiMultResultName()) { CVF_ASSERT(timeStepIndex == 0); // Static result, only data for first time step cvf::ref cellFaceAccessObject = new RigCombTransResultAccessor(grid); - - cvf::ref xRiMultAccessor = RigResultAccessorFactory::createNativeFromUiResultName(eclipseCase, gridIndex, porosityModel, timeStepIndex, RiaDefines::riMultXResultName()); - cvf::ref yRiMultAccessor = RigResultAccessorFactory::createNativeFromUiResultName(eclipseCase, gridIndex, porosityModel, timeStepIndex, RiaDefines::riMultYResultName()); - cvf::ref zRiMultAccessor = RigResultAccessorFactory::createNativeFromUiResultName(eclipseCase, gridIndex, porosityModel, timeStepIndex, RiaDefines::riMultZResultName()); + nativeAddr.m_resultName = RiaDefines::riMultXResultName(); + cvf::ref xRiMultAccessor = RigResultAccessorFactory::createNativeFromResultAddress(eclipseCase, gridIndex, porosityModel, timeStepIndex, nativeAddr); + nativeAddr.m_resultName = RiaDefines::riMultYResultName(); + cvf::ref yRiMultAccessor = RigResultAccessorFactory::createNativeFromResultAddress(eclipseCase, gridIndex, porosityModel, timeStepIndex, nativeAddr); + nativeAddr.m_resultName = RiaDefines::riMultZResultName(); + cvf::ref zRiMultAccessor = RigResultAccessorFactory::createNativeFromResultAddress(eclipseCase, gridIndex, porosityModel, timeStepIndex, nativeAddr); cellFaceAccessObject->setTransResultAccessors(xRiMultAccessor.p(), yRiMultAccessor.p(), zRiMultAccessor.p()); return cellFaceAccessObject; } - else if (uiResultName == RiaDefines::combinedRiAreaNormTranResultName()) + else if (resVarAddr.m_resultName == RiaDefines::combinedRiAreaNormTranResultName()) { CVF_ASSERT(timeStepIndex == 0); // Static result, only data for first time step cvf::ref cellFaceAccessObject = new RigCombTransResultAccessor(grid); - cvf::ref xRiAreaNormTransAccessor = RigResultAccessorFactory::createNativeFromUiResultName(eclipseCase, gridIndex, porosityModel, timeStepIndex, RiaDefines::riAreaNormTranXResultName()); - cvf::ref yRiAreaNormTransAccessor = RigResultAccessorFactory::createNativeFromUiResultName(eclipseCase, gridIndex, porosityModel, timeStepIndex, RiaDefines::riAreaNormTranYResultName()); - cvf::ref zRiAreaNormTransAccessor = RigResultAccessorFactory::createNativeFromUiResultName(eclipseCase, gridIndex, porosityModel, timeStepIndex, RiaDefines::riAreaNormTranZResultName()); + nativeAddr.m_resultName = RiaDefines::riAreaNormTranXResultName(); + cvf::ref xRiAreaNormTransAccessor = RigResultAccessorFactory::createNativeFromResultAddress(eclipseCase, gridIndex, porosityModel, timeStepIndex, nativeAddr); + nativeAddr.m_resultName = RiaDefines::riAreaNormTranYResultName(); + cvf::ref yRiAreaNormTransAccessor = RigResultAccessorFactory::createNativeFromResultAddress(eclipseCase, gridIndex, porosityModel, timeStepIndex, nativeAddr); + nativeAddr.m_resultName = RiaDefines::riAreaNormTranZResultName(); + cvf::ref zRiAreaNormTransAccessor = RigResultAccessorFactory::createNativeFromResultAddress(eclipseCase, gridIndex, porosityModel, timeStepIndex, nativeAddr); cellFaceAccessObject->setTransResultAccessors(xRiAreaNormTransAccessor.p(), yRiAreaNormTransAccessor.p(), zRiAreaNormTransAccessor.p()); return cellFaceAccessObject; } - else if (uiResultName == RiaDefines::combinedWaterFluxResultName()) + else if (resVarAddr.m_resultName == RiaDefines::combinedWaterFluxResultName()) { cvf::ref cellFaceAccessObject = new RigCombTransResultAccessor(grid); - - cvf::ref xRiAreaNormTransAccessor = RigResultAccessorFactory::createNativeFromUiResultName(eclipseCase, gridIndex, porosityModel, timeStepIndex, "FLRWATI+"); - cvf::ref yRiAreaNormTransAccessor = RigResultAccessorFactory::createNativeFromUiResultName(eclipseCase, gridIndex, porosityModel, timeStepIndex, "FLRWATJ+"); - cvf::ref zRiAreaNormTransAccessor = RigResultAccessorFactory::createNativeFromUiResultName(eclipseCase, gridIndex, porosityModel, timeStepIndex, "FLRWATK+"); + + nativeAddr.m_resultName = "FLRWATI+"; + cvf::ref xRiAreaNormTransAccessor = RigResultAccessorFactory::createNativeFromResultAddress(eclipseCase, gridIndex, porosityModel, timeStepIndex, nativeAddr); + nativeAddr.m_resultName = "FLRWATJ+"; + cvf::ref yRiAreaNormTransAccessor = RigResultAccessorFactory::createNativeFromResultAddress(eclipseCase, gridIndex, porosityModel, timeStepIndex, nativeAddr); + nativeAddr.m_resultName = "FLRWATK+"; + cvf::ref zRiAreaNormTransAccessor = RigResultAccessorFactory::createNativeFromResultAddress(eclipseCase, gridIndex, porosityModel, timeStepIndex, nativeAddr); cellFaceAccessObject->setTransResultAccessors(xRiAreaNormTransAccessor.p(), yRiAreaNormTransAccessor.p(), zRiAreaNormTransAccessor.p()); return cellFaceAccessObject; } - else if (uiResultName == RiaDefines::combinedOilFluxResultName()) + else if (resVarAddr.m_resultName == RiaDefines::combinedOilFluxResultName()) { cvf::ref cellFaceAccessObject = new RigCombTransResultAccessor(grid); - cvf::ref xRiAreaNormTransAccessor = RigResultAccessorFactory::createNativeFromUiResultName(eclipseCase, gridIndex, porosityModel, timeStepIndex, "FLROILI+"); - cvf::ref yRiAreaNormTransAccessor = RigResultAccessorFactory::createNativeFromUiResultName(eclipseCase, gridIndex, porosityModel, timeStepIndex, "FLROILJ+"); - cvf::ref zRiAreaNormTransAccessor = RigResultAccessorFactory::createNativeFromUiResultName(eclipseCase, gridIndex, porosityModel, timeStepIndex, "FLROILK+"); + nativeAddr.m_resultName = "FLROILI+"; + cvf::ref xRiAreaNormTransAccessor = RigResultAccessorFactory::createNativeFromResultAddress(eclipseCase, gridIndex, porosityModel, timeStepIndex, nativeAddr); + nativeAddr.m_resultName = "FLROILJ+"; + cvf::ref yRiAreaNormTransAccessor = RigResultAccessorFactory::createNativeFromResultAddress(eclipseCase, gridIndex, porosityModel, timeStepIndex, nativeAddr); + nativeAddr.m_resultName = "FLROILK+"; + cvf::ref zRiAreaNormTransAccessor = RigResultAccessorFactory::createNativeFromResultAddress(eclipseCase, gridIndex, porosityModel, timeStepIndex, nativeAddr); cellFaceAccessObject->setTransResultAccessors(xRiAreaNormTransAccessor.p(), yRiAreaNormTransAccessor.p(), zRiAreaNormTransAccessor.p()); return cellFaceAccessObject; } - else if (uiResultName == RiaDefines::combinedGasFluxResultName()) + else if (resVarAddr.m_resultName == RiaDefines::combinedGasFluxResultName()) { cvf::ref cellFaceAccessObject = new RigCombTransResultAccessor(grid); - cvf::ref xRiAreaNormTransAccessor = RigResultAccessorFactory::createNativeFromUiResultName(eclipseCase, gridIndex, porosityModel, timeStepIndex, "FLRGASI+"); - cvf::ref yRiAreaNormTransAccessor = RigResultAccessorFactory::createNativeFromUiResultName(eclipseCase, gridIndex, porosityModel, timeStepIndex, "FLRGASJ+"); - cvf::ref zRiAreaNormTransAccessor = RigResultAccessorFactory::createNativeFromUiResultName(eclipseCase, gridIndex, porosityModel, timeStepIndex, "FLRGASK+"); + nativeAddr.m_resultName = "FLRGASI+"; + cvf::ref xRiAreaNormTransAccessor = RigResultAccessorFactory::createNativeFromResultAddress(eclipseCase, gridIndex, porosityModel, timeStepIndex, nativeAddr); + nativeAddr.m_resultName = "FLRGASJ+"; + cvf::ref yRiAreaNormTransAccessor = RigResultAccessorFactory::createNativeFromResultAddress(eclipseCase, gridIndex, porosityModel, timeStepIndex, nativeAddr); + nativeAddr.m_resultName = "FLRGASK+"; + cvf::ref zRiAreaNormTransAccessor = RigResultAccessorFactory::createNativeFromResultAddress(eclipseCase, gridIndex, porosityModel, timeStepIndex, nativeAddr); cellFaceAccessObject->setTransResultAccessors(xRiAreaNormTransAccessor.p(), yRiAreaNormTransAccessor.p(), zRiAreaNormTransAccessor.p()); return cellFaceAccessObject; } - else if (uiResultName.endsWith("IJK")) + else if (resVarAddr.m_resultName.endsWith("IJK")) { cvf::ref cellFaceAccessObject = new RigCombTransResultAccessor(grid); - QString baseName = uiResultName.left(uiResultName.size() - 3); - - cvf::ref iAccessor = RigResultAccessorFactory::createNativeFromUiResultName(eclipseCase, gridIndex, porosityModel, timeStepIndex, QString("%1I").arg(baseName)); - cvf::ref jAccessor = RigResultAccessorFactory::createNativeFromUiResultName(eclipseCase, gridIndex, porosityModel, timeStepIndex, QString("%1J").arg(baseName)); - cvf::ref kAccessor = RigResultAccessorFactory::createNativeFromUiResultName(eclipseCase, gridIndex, porosityModel, timeStepIndex, QString("%1K").arg(baseName)); + QString baseName = resVarAddr.m_resultName.left(resVarAddr.m_resultName.size() - 3); + + nativeAddr.m_resultName = QString("%1I").arg(baseName); + cvf::ref iAccessor = RigResultAccessorFactory::createNativeFromResultAddress(eclipseCase, gridIndex, porosityModel, timeStepIndex, nativeAddr); + nativeAddr.m_resultName = QString("%1J").arg(baseName); + cvf::ref jAccessor = RigResultAccessorFactory::createNativeFromResultAddress(eclipseCase, gridIndex, porosityModel, timeStepIndex, nativeAddr); + nativeAddr.m_resultName = QString("%1K").arg(baseName); + cvf::ref kAccessor = RigResultAccessorFactory::createNativeFromResultAddress(eclipseCase, gridIndex, porosityModel, timeStepIndex, nativeAddr); cellFaceAccessObject->setTransResultAccessors(iAccessor.p(), jAccessor.p(), kAccessor.p()); @@ -302,23 +281,34 @@ cvf::ref RigResultAccessorFactory::createDerivedResultAccesso //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -cvf::ref RigResultAccessorFactory::createFromResultIdx(const RigEclipseCaseData* eclipseCase, - size_t gridIndex, - RiaDefines::PorosityModelType porosityModel, - size_t timeStepIndex, - size_t resultIndex) +cvf::ref RigResultAccessorFactory::createNativeFromResultAddress(const RigEclipseCaseData* eclipseCase, + size_t gridIndex, + RiaDefines::PorosityModelType porosityModel, + size_t timeStepIndex, + const RigEclipseResultAddress& resultAddress) { - if ( resultIndex == cvf::UNDEFINED_SIZE_T ) + if (!eclipseCase || !eclipseCase->results(porosityModel) || !eclipseCase->activeCellInfo(porosityModel)) { - return new RigHugeValResultAccessor; + return nullptr; + } + + if (!eclipseCase->results(porosityModel)->hasResultEntry(resultAddress)) + { + return nullptr; } - if (!eclipseCase) return nullptr; + if ( !resultAddress.isValid() ) + { + return nullptr; + } const RigGridBase* grid = eclipseCase->grid(gridIndex); - if (!grid) return nullptr; + if (!grid) + { + return nullptr; + } - const std::vector< std::vector >& scalarSetResults = eclipseCase->results(porosityModel)->cellScalarResults(resultIndex); + const std::vector< std::vector >& scalarSetResults = eclipseCase->results(porosityModel)->cellScalarResults(resultAddress); if (timeStepIndex >= scalarSetResults.size()) { @@ -336,7 +326,7 @@ cvf::ref RigResultAccessorFactory::createFromResultIdx(const return new RigHugeValResultAccessor; } - bool useGlobalActiveIndex = eclipseCase->results(porosityModel)->isUsingGlobalActiveIndex(resultIndex); + bool useGlobalActiveIndex = eclipseCase->results(porosityModel)->isUsingGlobalActiveIndex(resultAddress); if (useGlobalActiveIndex) { cvf::ref object = new RigActiveCellsResultAccessor(grid, resultValues, eclipseCase->activeCellInfo(porosityModel)); diff --git a/ApplicationCode/ReservoirDataModel/RigResultAccessorFactory.h b/ApplicationCode/ReservoirDataModel/RigResultAccessorFactory.h index 19d1b4fd8a..212ecad96d 100644 --- a/ApplicationCode/ReservoirDataModel/RigResultAccessorFactory.h +++ b/ApplicationCode/ReservoirDataModel/RigResultAccessorFactory.h @@ -28,6 +28,7 @@ class RigActiveCellInfo; class RigGridBase; class RimEclipseResultDefinition; +class RigEclipseResultAddress; class RigResultAccessorFactory { @@ -39,42 +40,26 @@ class RigResultAccessorFactory RimEclipseResultDefinition* resultDefinition); static cvf::ref - createFromUiResultName(const RigEclipseCaseData* eclipseCase, - size_t gridIndex, - RiaDefines::PorosityModelType porosityModel, - size_t timeStepIndex, - const QString& uiResultName); - - static cvf::ref - createFromNameAndType(const RigEclipseCaseData* eclipseCase, - size_t gridIndex, - RiaDefines::PorosityModelType porosityModel, - size_t timeStepIndex, - const QString& uiResultName, - RiaDefines::ResultCatType resultType); - - static cvf::ref - createFromResultIdx(const RigEclipseCaseData* eclipseCase, - size_t gridIndex, - RiaDefines::PorosityModelType porosityModel, - size_t timeStepIndex, - size_t resultIndex); - - + createFromResultAddress(const RigEclipseCaseData* eclipseCase, + size_t gridIndex, + RiaDefines::PorosityModelType porosityModel, + size_t timeStepIndex, + const RigEclipseResultAddress& resVarAddr); private: - static cvf::ref - createNativeFromUiResultName(const RigEclipseCaseData* eclipseCase, - size_t gridIndex, - RiaDefines::PorosityModelType porosityModel, - size_t timeStepIndex, - const QString& resultName); static cvf::ref - createDerivedResultAccessor(const RigEclipseCaseData* eclipseCase, + createCombinedResultAccessor(const RigEclipseCaseData* eclipseCase, size_t gridIndex, RiaDefines::PorosityModelType porosityModel, size_t timeStepIndex, - const QString& uiResultName); + const RigEclipseResultAddress& resVarAddr); + + static cvf::ref + createNativeFromResultAddress(const RigEclipseCaseData* eclipseCase, + size_t gridIndex, + RiaDefines::PorosityModelType porosityModel, + size_t timeStepIndex, + const RigEclipseResultAddress& resVarAddr); }; diff --git a/ApplicationCode/ReservoirDataModel/RigResultModifierFactory.cpp b/ApplicationCode/ReservoirDataModel/RigResultModifierFactory.cpp index de4c947115..01f4b09866 100644 --- a/ApplicationCode/ReservoirDataModel/RigResultModifierFactory.cpp +++ b/ApplicationCode/ReservoirDataModel/RigResultModifierFactory.cpp @@ -23,29 +23,7 @@ #include "RigEclipseCaseData.h" #include "RigResultModifier.h" -#include - - -//-------------------------------------------------------------------------------------------------- -/// This function must be harmonized with RigResultAccessorFactory::createNativeResultAccessor() -//-------------------------------------------------------------------------------------------------- -cvf::ref RigResultModifierFactory::createResultModifier(RigEclipseCaseData* eclipseCase, - size_t gridIndex, - RiaDefines::PorosityModelType porosityModel, - size_t timeStepIndex, - QString& uiResultName) -{ - if (!eclipseCase) return nullptr; - - if (!eclipseCase->results(porosityModel) || !eclipseCase->activeCellInfo(porosityModel)) - { - return nullptr; - } - - size_t scalarSetIndex = eclipseCase->results(porosityModel)->findScalarResultIndex(uiResultName); - - return createResultModifier(eclipseCase, gridIndex, porosityModel, timeStepIndex, scalarSetIndex); -} +#include //-------------------------------------------------------------------------------------------------- @@ -54,7 +32,8 @@ cvf::ref RigResultModifierFactory::createResultModifier(RigEc cvf::ref RigResultModifierFactory::createResultModifier(RigEclipseCaseData* eclipseCase, size_t gridIndex, RiaDefines::PorosityModelType porosityModel, - size_t timeStepIndex, size_t scalarResultIndex) + size_t timeStepIndex, + const RigEclipseResultAddress& resVarAddr) { if ( !eclipseCase ) return nullptr; @@ -63,7 +42,7 @@ cvf::ref RigResultModifierFactory::createResultModifier(RigEc return nullptr; } - if (scalarResultIndex == cvf::UNDEFINED_SIZE_T) + if (!resVarAddr.isValid()) { return nullptr; } @@ -74,7 +53,7 @@ cvf::ref RigResultModifierFactory::createResultModifier(RigEc return nullptr; } - std::vector< std::vector >& scalarSetResults = eclipseCase->results(porosityModel)->cellScalarResults(scalarResultIndex); + std::vector< std::vector >& scalarSetResults = eclipseCase->results(porosityModel)->modifiableCellScalarResultTimesteps(resVarAddr); if (timeStepIndex >= scalarSetResults.size()) { @@ -87,7 +66,7 @@ cvf::ref RigResultModifierFactory::createResultModifier(RigEc resultValues = &(scalarSetResults[timeStepIndex]); } - bool useGlobalActiveIndex = eclipseCase->results(porosityModel)->isUsingGlobalActiveIndex(scalarResultIndex); + bool useGlobalActiveIndex = eclipseCase->results(porosityModel)->isUsingGlobalActiveIndex(resVarAddr); if (useGlobalActiveIndex) { cvf::ref object = new RigActiveCellsResultModifier(grid, eclipseCase->activeCellInfo(porosityModel), resultValues); diff --git a/ApplicationCode/ReservoirDataModel/RigResultModifierFactory.h b/ApplicationCode/ReservoirDataModel/RigResultModifierFactory.h index 9de9a938c1..e9a0a1f68b 100644 --- a/ApplicationCode/ReservoirDataModel/RigResultModifierFactory.h +++ b/ApplicationCode/ReservoirDataModel/RigResultModifierFactory.h @@ -23,23 +23,18 @@ class RigEclipseCaseData; class RigResultModifier; +class RigEclipseResultAddress; class RigResultModifierFactory { public: + static cvf::ref createResultModifier(RigEclipseCaseData* eclipseCase, size_t gridIndex, RiaDefines::PorosityModelType porosityModel, size_t timeStepIndex, - QString& uiResultName); - - static cvf::ref - createResultModifier(RigEclipseCaseData* eclipseCase, - size_t gridIndex, - RiaDefines::PorosityModelType porosityModel, - size_t timeStepIndex, - size_t scalarResultIndex); + const RigEclipseResultAddress& resVarAddr); }; diff --git a/ApplicationCode/ReservoirDataModel/RigSimWellData.cpp b/ApplicationCode/ReservoirDataModel/RigSimWellData.cpp index 1b3072a523..b95406aac6 100644 --- a/ApplicationCode/ReservoirDataModel/RigSimWellData.cpp +++ b/ApplicationCode/ReservoirDataModel/RigSimWellData.cpp @@ -354,7 +354,30 @@ bool RigSimWellData::isOpen(size_t resultTimeStepIndex) const //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -const RigWellResultPoint* RigWellResultFrame::findResultCell(size_t gridIndex, size_t gridCellIndex) const +const RigWellResultPoint* RigWellResultFrame::findResultCellWellHeadIncluded(size_t gridIndex, size_t gridCellIndex) const +{ + const RigWellResultPoint* wellResultPoint = findResultCellWellHeadExcluded(gridIndex, gridCellIndex); + if (wellResultPoint) return wellResultPoint; + + // If we could not find the cell among the real connections, we try the wellhead. + // The wellhead does however not have a real connection state, and is rendering using pipe color + // https://github.com/OPM/ResInsight/issues/4328 + + // This behavior was different prior to release 2019.04 and was rendered as a closed connection (gray) + // https://github.com/OPM/ResInsight/issues/712 + + if (m_wellHead.m_gridCellIndex == gridCellIndex && m_wellHead.m_gridIndex == gridIndex ) + { + return &m_wellHead; + } + + return nullptr; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +const RigWellResultPoint* RigWellResultFrame::findResultCellWellHeadExcluded(size_t gridIndex, size_t gridCellIndex) const { CVF_ASSERT(gridIndex != cvf::UNDEFINED_SIZE_T && gridCellIndex != cvf::UNDEFINED_SIZE_T); @@ -362,23 +385,14 @@ const RigWellResultPoint* RigWellResultFrame::findResultCell(size_t gridIndex, s { for (size_t wc = 0; wc < m_wellResultBranches[wb].m_branchResultPoints.size(); ++wc) { - if ( m_wellResultBranches[wb].m_branchResultPoints[wc].m_gridCellIndex == gridCellIndex - && m_wellResultBranches[wb].m_branchResultPoints[wc].m_gridIndex == gridIndex ) + if (m_wellResultBranches[wb].m_branchResultPoints[wc].m_gridCellIndex == gridCellIndex && + m_wellResultBranches[wb].m_branchResultPoints[wc].m_gridIndex == gridIndex) { return &(m_wellResultBranches[wb].m_branchResultPoints[wc]); } } } - // If we could not find the cell among the real connections, we try the wellhead. - // The wellhead does however not have a real connection state, and is thereby always rendered as closed - // If we have a real connection in the wellhead, we should not end here. See Github issue #712 - - if (m_wellHead.m_gridCellIndex == gridCellIndex && m_wellHead.m_gridIndex == gridIndex ) - { - return &m_wellHead; - } - return nullptr; } diff --git a/ApplicationCode/ReservoirDataModel/RigWellPathGeometryTools.cpp b/ApplicationCode/ReservoirDataModel/RigWellPathGeometryTools.cpp index c4cdbabbd2..188ec95d92 100644 --- a/ApplicationCode/ReservoirDataModel/RigWellPathGeometryTools.cpp +++ b/ApplicationCode/ReservoirDataModel/RigWellPathGeometryTools.cpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018- Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by diff --git a/ApplicationCode/ReservoirDataModel/RigWellPathGeometryTools.h b/ApplicationCode/ReservoirDataModel/RigWellPathGeometryTools.h index 658605280b..838ba966ec 100644 --- a/ApplicationCode/ReservoirDataModel/RigWellPathGeometryTools.h +++ b/ApplicationCode/ReservoirDataModel/RigWellPathGeometryTools.h @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018- Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by diff --git a/ApplicationCode/ReservoirDataModel/RigWellResultPoint.h b/ApplicationCode/ReservoirDataModel/RigWellResultPoint.h index 8cfe5255c1..f4afe01fa2 100644 --- a/ApplicationCode/ReservoirDataModel/RigWellResultPoint.h +++ b/ApplicationCode/ReservoirDataModel/RigWellResultPoint.h @@ -101,7 +101,9 @@ class RigWellResultFrame { } - const RigWellResultPoint* findResultCell(size_t gridIndex, size_t gridCellIndex) const; + const RigWellResultPoint* findResultCellWellHeadIncluded(size_t gridIndex, size_t gridCellIndex) const; + const RigWellResultPoint* findResultCellWellHeadExcluded(size_t gridIndex, size_t gridCellIndex) const; + RigWellResultPoint wellHeadOrStartCell() const; WellProductionType m_productionType; diff --git a/ApplicationCode/ReservoirDataModel/cvfGeometryTools.cpp b/ApplicationCode/ReservoirDataModel/cvfGeometryTools.cpp index 1214a187cd..5a485bf05a 100644 --- a/ApplicationCode/ReservoirDataModel/cvfGeometryTools.cpp +++ b/ApplicationCode/ReservoirDataModel/cvfGeometryTools.cpp @@ -104,7 +104,7 @@ double GeometryTools::getAngle(const cvf::Vec3d& positiveNormalAxis, const cvf:: bool isOk = false; cvf::Vec3d v1N = v1.getNormalized(&isOk); if (!isOk) return 0; - cvf::Vec3d v2N = v2.getNormalized(); + cvf::Vec3d v2N = v2.getNormalized(&isOk); if (!isOk) return 0; double cosAng = v1N * v2N; @@ -156,6 +156,26 @@ double GeometryTools::getAngle(const cvf::Vec3d& v1, const cvf::Vec3d& v2) return angle; } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +double GeometryTools::signedAreaPlanarPolygon(const cvf::Vec3d& planeNormal, const std::vector& polygon) +{ + int Z = findClosestAxis(planeNormal); + int X = (Z + 1) % 3; + int Y = (Z + 2) % 3; + + // Use Shoelace formula to calculate signed area. + // https://en.wikipedia.org/wiki/Shoelace_formula + double signedArea = 0.0; + for (size_t i = 0; i < polygon.size(); ++i) + { + signedArea += (polygon[(i + 1) % polygon.size()][X] - polygon[i][X]) * + (polygon[(i + 1) % polygon.size()][Y] + polygon[i][Y]); + } + return signedArea; +} + /* Determine the intersection point of two line segments From Paul Bourke, but modified to really handle coincident lines @@ -178,7 +198,7 @@ GeometryTools::IntersectionStatus inPlaneLineIntersect( numera = (x4-x3) * (y1-y3) - (y4-y3) * (x1-x3); numerb = (x2-x1) * (y1-y3) - (y2-y1) * (x1-x3); - double EPS = 1e-40; + double EPS = 1e-40; // Are the line coincident? if (fabs(numera) < EPS && fabs(numerb) < EPS && fabs(denom) < EPS) @@ -199,7 +219,7 @@ GeometryTools::IntersectionStatus inPlaneLineIntersect( // Check if the p1 p2 line is a point - if (length12 < EPS ) + if (length12 < EPS) { *x = x1; *y = y1; diff --git a/ApplicationCode/ReservoirDataModel/cvfGeometryTools.h b/ApplicationCode/ReservoirDataModel/cvfGeometryTools.h index a96c366e0b..44c3d36485 100644 --- a/ApplicationCode/ReservoirDataModel/cvfGeometryTools.h +++ b/ApplicationCode/ReservoirDataModel/cvfGeometryTools.h @@ -58,6 +58,8 @@ class GeometryTools static double getAngle(const cvf::Vec3d& positiveNormalAxis, const cvf::Vec3d& v1, const cvf::Vec3d& v2); static double getAngle(const cvf::Vec3d& v1, const cvf::Vec3d& v2); + static double signedAreaPlanarPolygon(const cvf::Vec3d& planeNormal, const std::vector& polygon); + static cvf::Vec3d polygonAreaNormal3D(const std::vector& polygon); enum IntersectionStatus diff --git a/ApplicationCode/Resources/2DMapProjection16x16.png b/ApplicationCode/Resources/2DMapProjection16x16.png new file mode 100644 index 0000000000..3b65d04aa8 Binary files /dev/null and b/ApplicationCode/Resources/2DMapProjection16x16.png differ diff --git a/ApplicationCode/Resources/Annotations16x16.png b/ApplicationCode/Resources/Annotations16x16.png new file mode 100644 index 0000000000..d64916e1b2 Binary files /dev/null and b/ApplicationCode/Resources/Annotations16x16.png differ diff --git a/ApplicationCode/Resources/GeoMechCase24x24.png b/ApplicationCode/Resources/GeoMechCase24x24.png new file mode 100644 index 0000000000..7e09ccd497 Binary files /dev/null and b/ApplicationCode/Resources/GeoMechCase24x24.png differ diff --git a/ApplicationCode/Resources/GeoMechCasePropTable24x24.png b/ApplicationCode/Resources/GeoMechCasePropTable24x24.png new file mode 100644 index 0000000000..df34644385 Binary files /dev/null and b/ApplicationCode/Resources/GeoMechCasePropTable24x24.png differ diff --git a/ApplicationCode/Resources/GeoMechCaseTime24x24.png b/ApplicationCode/Resources/GeoMechCaseTime24x24.png new file mode 100644 index 0000000000..88560b9d6b Binary files /dev/null and b/ApplicationCode/Resources/GeoMechCaseTime24x24.png differ diff --git a/ApplicationCode/Resources/HoloLensConnect24x24.png b/ApplicationCode/Resources/HoloLensConnect24x24.png new file mode 100644 index 0000000000..984dcd6d7d Binary files /dev/null and b/ApplicationCode/Resources/HoloLensConnect24x24.png differ diff --git a/ApplicationCode/Resources/HoloLensDisconnect24x24.png b/ApplicationCode/Resources/HoloLensDisconnect24x24.png new file mode 100644 index 0000000000..91f2ba545e Binary files /dev/null and b/ApplicationCode/Resources/HoloLensDisconnect24x24.png differ diff --git a/ApplicationCode/Resources/HoloLensSendContinously24x24.png b/ApplicationCode/Resources/HoloLensSendContinously24x24.png new file mode 100644 index 0000000000..5dd8178072 Binary files /dev/null and b/ApplicationCode/Resources/HoloLensSendContinously24x24.png differ diff --git a/ApplicationCode/Resources/HoloLensSendOnce24x24.png b/ApplicationCode/Resources/HoloLensSendOnce24x24.png new file mode 100644 index 0000000000..bea4f9a12a Binary files /dev/null and b/ApplicationCode/Resources/HoloLensSendOnce24x24.png differ diff --git a/ApplicationCode/Resources/PlotWindow24x24.png b/ApplicationCode/Resources/PlotWindow24x24.png index 555a43eff1..17a955d2f3 100644 Binary files a/ApplicationCode/Resources/PlotWindow24x24.png and b/ApplicationCode/Resources/PlotWindow24x24.png differ diff --git a/ApplicationCode/Resources/PolylinesFromFile16x16.png b/ApplicationCode/Resources/PolylinesFromFile16x16.png new file mode 100644 index 0000000000..c12ea53d35 Binary files /dev/null and b/ApplicationCode/Resources/PolylinesFromFile16x16.png differ diff --git a/ApplicationCode/Resources/ReachCircle16x16.png b/ApplicationCode/Resources/ReachCircle16x16.png new file mode 100644 index 0000000000..a67fb959f8 Binary files /dev/null and b/ApplicationCode/Resources/ReachCircle16x16.png differ diff --git a/ApplicationCode/Resources/ResInsight.qrc b/ApplicationCode/Resources/ResInsight.qrc index c0353f52ce..ceb002417f 100644 --- a/ApplicationCode/Resources/ResInsight.qrc +++ b/ApplicationCode/Resources/ResInsight.qrc @@ -28,6 +28,7 @@ Cases16x16.png SummaryCases16x16.png SummaryEnsemble16x16.png + SummaryEnsemble24x24.png SummaryGroup16x16.png CreateGridCaseGroup16x16.png GridCaseGroup16x16.png @@ -51,6 +52,9 @@ draw_style_surface_w_fault_mesh_24x24.png InfoBox16x16.png GeoMechCase48x48.png + GeoMechCase24x24.png + GeoMechCaseTime24x24.png + GeoMechCasePropTable24x24.png GeoMechCases48x48.png chain.png TileWindows24x24.png @@ -122,10 +126,10 @@ statistics.png WellTargetPoint16x16.png WellTargetPointTangent16x16.png - hololens.png - minus-sign-red.png - plus-sign-green.png - arrow-right-green.png + HoloLensConnect24x24.png + HoloLensDisconnect24x24.png + HoloLensSendContinously24x24.png + HoloLensSendOnce24x24.png 2DMap16x16.png 2DMaps16x16.png AICDValve16x16.png @@ -142,6 +146,14 @@ ExportCompletionsSymbol16x16.png StepUpDown16x16.png StepUpDownCorner16x16.png + TextAnnotation16x16.png + Annotations16x16.png + PolylinesFromFile16x16.png + ReachCircle16x16.png + 2DMapProjection16x16.png + Ruler24x24.png + RulerPoly24x24.png + Swap.png fs_CellFace.glsl diff --git a/ApplicationCode/Resources/Ruler16x16.png b/ApplicationCode/Resources/Ruler16x16.png new file mode 100644 index 0000000000..cea54428d0 Binary files /dev/null and b/ApplicationCode/Resources/Ruler16x16.png differ diff --git a/ApplicationCode/Resources/Ruler24x24.png b/ApplicationCode/Resources/Ruler24x24.png new file mode 100644 index 0000000000..7c198ffdf0 Binary files /dev/null and b/ApplicationCode/Resources/Ruler24x24.png differ diff --git a/ApplicationCode/Resources/RulerPoly24x24.png b/ApplicationCode/Resources/RulerPoly24x24.png new file mode 100644 index 0000000000..03a183c15f Binary files /dev/null and b/ApplicationCode/Resources/RulerPoly24x24.png differ diff --git a/ApplicationCode/Resources/Save.png b/ApplicationCode/Resources/Save.png index 367a79bdb6..5cd752f143 100644 Binary files a/ApplicationCode/Resources/Save.png and b/ApplicationCode/Resources/Save.png differ diff --git a/ApplicationCode/Resources/SummaryEnsemble16x16.png b/ApplicationCode/Resources/SummaryEnsemble16x16.png index 27c94b8490..3de8ab7c81 100644 Binary files a/ApplicationCode/Resources/SummaryEnsemble16x16.png and b/ApplicationCode/Resources/SummaryEnsemble16x16.png differ diff --git a/ApplicationCode/Resources/SummaryEnsemble24x24.png b/ApplicationCode/Resources/SummaryEnsemble24x24.png new file mode 100644 index 0000000000..589a02045a Binary files /dev/null and b/ApplicationCode/Resources/SummaryEnsemble24x24.png differ diff --git a/ApplicationCode/Resources/Swap.png b/ApplicationCode/Resources/Swap.png new file mode 100644 index 0000000000..5b87cfd9a6 Binary files /dev/null and b/ApplicationCode/Resources/Swap.png differ diff --git a/ApplicationCode/Resources/TextAnnotation16x16.png b/ApplicationCode/Resources/TextAnnotation16x16.png new file mode 100644 index 0000000000..01c5364749 Binary files /dev/null and b/ApplicationCode/Resources/TextAnnotation16x16.png differ diff --git a/ApplicationCode/Resources/arrow-right-green.png b/ApplicationCode/Resources/arrow-right-green.png deleted file mode 100644 index cc9f9b22b8..0000000000 Binary files a/ApplicationCode/Resources/arrow-right-green.png and /dev/null differ diff --git a/ApplicationCode/Resources/hololens.png b/ApplicationCode/Resources/hololens.png deleted file mode 100644 index a30781563e..0000000000 Binary files a/ApplicationCode/Resources/hololens.png and /dev/null differ diff --git a/ApplicationCode/Resources/minus-sign-red.png b/ApplicationCode/Resources/minus-sign-red.png deleted file mode 100644 index 2c1fc25e08..0000000000 Binary files a/ApplicationCode/Resources/minus-sign-red.png and /dev/null differ diff --git a/ApplicationCode/Resources/plus-sign-green.png b/ApplicationCode/Resources/plus-sign-green.png deleted file mode 100644 index f0f33c46a6..0000000000 Binary files a/ApplicationCode/Resources/plus-sign-green.png and /dev/null differ diff --git a/ApplicationCode/ResultStatisticsCache/CMakeLists.txt b/ApplicationCode/ResultStatisticsCache/CMakeLists.txt index d3385421c2..4483d67227 100644 --- a/ApplicationCode/ResultStatisticsCache/CMakeLists.txt +++ b/ApplicationCode/ResultStatisticsCache/CMakeLists.txt @@ -23,3 +23,8 @@ target_include_directories(${PROJECT_NAME} target_link_libraries(${PROJECT_NAME} LibCore) source_group("" FILES ${PROJECT_FILES}) + +# cotire +if (COMMAND caf_apply_cotire) + caf_apply_cotire("${PROJECT_NAME}") +endif() diff --git a/ApplicationCode/ResultStatisticsCache/RigStatisticsMath.cpp b/ApplicationCode/ResultStatisticsCache/RigStatisticsMath.cpp index 08c16ad958..4e2505d6bd 100644 --- a/ApplicationCode/ResultStatisticsCache/RigStatisticsMath.cpp +++ b/ApplicationCode/ResultStatisticsCache/RigStatisticsMath.cpp @@ -17,11 +17,13 @@ ///////////////////////////////////////////////////////////////////////////////// #include "RigStatisticsMath.h" + +#include "cvfBase.h" +#include "cvfMath.h" + #include #include #include -#include "cvfBase.h" -#include "cvfMath.h" //-------------------------------------------------------------------------------------------------- /// A function to do basic statistical calculations @@ -254,7 +256,12 @@ double RigHistogramCalculator::calculatePercentil(double pVal) { double domainValueAtEndOfBin = m_min + (binIdx+1) * binWidth; double unusedFractionOfLastBin = (double)(accObsCount - pValObservationCount)/binObsCount; - return domainValueAtEndOfBin - unusedFractionOfLastBin*binWidth; + + double histogramBasedEstimate = domainValueAtEndOfBin - unusedFractionOfLastBin*binWidth; + + // See https://resinsight.org/docs/casegroupsandstatistics/#percentile-methods for details + + return histogramBasedEstimate; } } assert(false); diff --git a/ApplicationCode/SocketInterface/RiaCaseInfoCommands.cpp b/ApplicationCode/SocketInterface/RiaCaseInfoCommands.cpp index 24ab4caf6b..d65594fdff 100644 --- a/ApplicationCode/SocketInterface/RiaCaseInfoCommands.cpp +++ b/ApplicationCode/SocketInterface/RiaCaseInfoCommands.cpp @@ -46,7 +46,7 @@ #include "RimReservoirCellResultsStorage.h" #include "RimSimWellInViewCollection.h" -#include "RiuSelectionManager.h" +#include "Riu3dSelectionManager.h" #include @@ -419,11 +419,11 @@ class RiaGetTimeStepDates : public RiaSocketCommand canFetchData = false; } - size_t scalarIndexWithMaxTimeStepCount = cvf::UNDEFINED_SIZE_T; + RigEclipseResultAddress addrToMaxTimeStepCountResult; if (rimCase && rimCase->eclipseCaseData()) { - rimCase->eclipseCaseData()->results(RiaDefines::MATRIX_MODEL)->maxTimeStepCount(&scalarIndexWithMaxTimeStepCount); - if (scalarIndexWithMaxTimeStepCount == cvf::UNDEFINED_SIZE_T) + rimCase->eclipseCaseData()->results(RiaDefines::MATRIX_MODEL)->maxTimeStepCount(&addrToMaxTimeStepCountResult); + if ( !addrToMaxTimeStepCountResult.isValid()) { canFetchData = false; } @@ -441,7 +441,7 @@ class RiaGetTimeStepDates : public RiaSocketCommand return true; } - std::vector timeStepDates = rimCase->eclipseCaseData()->results(RiaDefines::MATRIX_MODEL)->timeStepDates(scalarIndexWithMaxTimeStepCount); + std::vector timeStepDates = rimCase->eclipseCaseData()->results(RiaDefines::MATRIX_MODEL)->timeStepDates(RigEclipseResultAddress(addrToMaxTimeStepCountResult)); quint64 timeStepCount = timeStepDates.size(); quint64 byteCount = sizeof(quint64) + 6 * timeStepCount * sizeof(qint32); @@ -506,11 +506,11 @@ class RiaGetTimeStepDays : public RiaSocketCommand canFetchData = false; } - size_t scalarIndexWithMaxTimeStepCount = cvf::UNDEFINED_SIZE_T; + RigEclipseResultAddress addrToMaxTimeStepCountResult; if (rimCase && rimCase->eclipseCaseData()) { - rimCase->eclipseCaseData()->results(RiaDefines::MATRIX_MODEL)->maxTimeStepCount(&scalarIndexWithMaxTimeStepCount); - if (scalarIndexWithMaxTimeStepCount == cvf::UNDEFINED_SIZE_T) + rimCase->eclipseCaseData()->results(RiaDefines::MATRIX_MODEL)->maxTimeStepCount(&addrToMaxTimeStepCountResult); + if (!addrToMaxTimeStepCountResult.isValid() ) { canFetchData = false; } @@ -528,7 +528,7 @@ class RiaGetTimeStepDays : public RiaSocketCommand return true; } - std::vector daysSinceSimulationStart = rimCase->eclipseCaseData()->results(RiaDefines::MATRIX_MODEL)->daysSinceSimulationStart(scalarIndexWithMaxTimeStepCount); + std::vector daysSinceSimulationStart = rimCase->eclipseCaseData()->results(RiaDefines::MATRIX_MODEL)->daysSinceSimulationStart(addrToMaxTimeStepCountResult); quint64 timeStepCount = daysSinceSimulationStart.size(); quint64 byteCount = sizeof(quint64) + timeStepCount * sizeof(qint32); @@ -599,7 +599,7 @@ class RiaGetSelectedCells: public RiaSocketCommand std::vector& cellK) { std::vector items; - RiuSelectionManager::instance()->selectedItems(items); + Riu3dSelectionManager::instance()->selectedItems(items); for (const RiuSelectionItem* item : items) { diff --git a/ApplicationCode/SocketInterface/RiaNNCCommands.cpp b/ApplicationCode/SocketInterface/RiaNNCCommands.cpp index 1948c05051..49f8d6236a 100644 --- a/ApplicationCode/SocketInterface/RiaNNCCommands.cpp +++ b/ApplicationCode/SocketInterface/RiaNNCCommands.cpp @@ -44,7 +44,6 @@ #include "RimSimWellInViewCollection.h" #include -#include //-------------------------------------------------------------------------------------------------- /// @@ -148,7 +147,7 @@ class RiaGetDynamicNNCValues: public RiaSocketCommand if (timeStepReadError) { - server->errorMessageDialog()->showMessage(RiaSocketServer::tr("ResInsight SocketServer: riGetDynamicNNCValues : \n") + RiaSocketServer::tr("An error occurred while interpreting the requested time steps.")); + server->showErrorMessage(RiaSocketServer::tr("ResInsight SocketServer: riGetDynamicNNCValues : \n") + RiaSocketServer::tr("An error occurred while interpreting the requested time steps.")); } } else @@ -299,7 +298,7 @@ class RiaSetNNCProperty: public RiaSocketCommand public: RiaSetNNCProperty() : m_currentReservoir(nullptr), - m_currentScalarIndex(cvf::UNDEFINED_SIZE_T), + m_currentEclResultAddress(), m_timeStepCountToRead(0), m_bytesPerTimeStepToRead(0), m_currentTimeStepNumberToRead(0), @@ -319,7 +318,7 @@ class RiaSetNNCProperty: public RiaSocketCommand if (!(rimCase && rimCase->eclipseCaseData() && rimCase->eclipseCaseData()->mainGrid())) { QString caseId = args[1]; - server->errorMessageDialog()->showMessage(RiaSocketServer::tr("ResInsight SocketServer: \n") + RiaSocketServer::tr("Could not find case with id %1").arg(caseId)); + server->showErrorMessage(RiaSocketServer::tr("ResInsight SocketServer: \n") + RiaSocketServer::tr("Could not find case with id %1").arg(caseId)); return true; } @@ -347,11 +346,12 @@ class RiaSetNNCProperty: public RiaSocketCommand bool ok = createIJKCellResults(rimCase->results(m_porosityModelEnum), propertyName); if (!ok) { - server->errorMessageDialog()->showMessage(RiaSocketServer::tr("ResInsight SocketServer: \n") + RiaSocketServer::tr("Could not find the property named: \"%2\"").arg(propertyName)); + server->showErrorMessage(RiaSocketServer::tr("ResInsight SocketServer: \n") + RiaSocketServer::tr("Could not find the property named: \"%2\"").arg(propertyName)); return true; } - size_t scalarResultIndex = rimCase->results(m_porosityModelEnum)->findOrLoadScalarResult(QString("%1IJK").arg(propertyName)); - nncData->setScalarResultIndex(propertyName, scalarResultIndex); + RigEclipseResultAddress resAddr(QString("%1IJK").arg(propertyName)); + rimCase->results(m_porosityModelEnum)->ensureKnownResultLoaded(resAddr); + nncData->setEclResultAddress(propertyName, resAddr); } // Create a list of all the requested time steps @@ -385,7 +385,7 @@ class RiaSetNNCProperty: public RiaSocketCommand if (timeStepReadError) { - server->errorMessageDialog()->showMessage(RiaSocketServer::tr("ResInsight SocketServer: riSetNNCProperty : \n") + + server->showErrorMessage(RiaSocketServer::tr("ResInsight SocketServer: riSetNNCProperty : \n") + RiaSocketServer::tr("An error occurred while interpreting the requested time steps.")); } @@ -393,7 +393,7 @@ class RiaSetNNCProperty: public RiaSocketCommand if (! m_requestedTimesteps.size()) { - server->errorMessageDialog()->showMessage(RiaSocketServer::tr("ResInsight SocketServer: \n") + RiaSocketServer::tr("No time steps specified")); + server->showErrorMessage(RiaSocketServer::tr("ResInsight SocketServer: \n") + RiaSocketServer::tr("No time steps specified")); return true; } @@ -408,7 +408,7 @@ class RiaSetNNCProperty: public RiaSocketCommand return false; } - +private: static bool createIJKCellResults(RigCaseCellResultsData* results, QString propertyName) { bool ok; @@ -425,24 +425,21 @@ class RiaSetNNCProperty: public RiaSocketCommand static bool scalarResultExistsOrCreate(RigCaseCellResultsData* results, QString propertyName) { - size_t scalarResultIndex = results->findOrLoadScalarResult(propertyName); - if (scalarResultIndex == cvf::UNDEFINED_SIZE_T) - { - scalarResultIndex = results->findOrCreateScalarResultIndex(RiaDefines::GENERATED, propertyName, true); - } - - if (scalarResultIndex != cvf::UNDEFINED_SIZE_T) + RigEclipseResultAddress resAddr(RiaDefines::GENERATED, propertyName); + + if ( !results->ensureKnownResultLoaded(resAddr) ) { - std::vector< std::vector >* scalarResultFrames = nullptr; - scalarResultFrames = &(results->cellScalarResults(scalarResultIndex)); - size_t timeStepCount = results->maxTimeStepCount(); - scalarResultFrames->resize(timeStepCount); - return true; + results->createResultEntry(resAddr, true); } - return false; - } + std::vector< std::vector >* scalarResultFrames = nullptr; + scalarResultFrames = &(results->modifiableCellScalarResultTimesteps(resAddr)); + size_t timeStepCount = results->maxTimeStepCount(); + scalarResultFrames->resize(timeStepCount); + return true; + } +public: bool interpretMore(RiaSocketServer* server, QTcpSocket* currentClient) override { if (m_invalidConnectionCountDetected) return true; @@ -468,7 +465,7 @@ class RiaSetNNCProperty: public RiaSocketCommand if (connectionCountFromOctave != connectionCount) { - server->errorMessageDialog()->showMessage(RiaSocketServer::tr("ResInsight SocketServer: \n") + + server->showErrorMessage(RiaSocketServer::tr("ResInsight SocketServer: \n") + RiaSocketServer::tr("The number of connections in the data coming from octave does not match the case: '%1'\n").arg(m_currentReservoir->caseUserDescription()) + RiaSocketServer::tr(" Octave: %1\n").arg(connectionCountFromOctave) + RiaSocketServer::tr(" %1: Connection count: %2").arg(m_currentReservoir->caseUserDescription()).arg(connectionCount)); @@ -501,7 +498,7 @@ class RiaSetNNCProperty: public RiaSocketCommand { for (int i = 0; i < errorMessages.size(); i++) { - server->errorMessageDialog()->showMessage(errorMessages[i]); + server->showErrorMessage(errorMessages[i]); } currentClient->abort(); @@ -534,11 +531,11 @@ class RiaSetNNCProperty: public RiaSocketCommand inputProperty->resolvedState = RimEclipseInputProperty::RESOLVED_NOT_SAVED; } - if( m_currentScalarIndex != cvf::UNDEFINED_SIZE_T && + if( m_currentEclResultAddress.isValid() && // Will never be valid because it is never set. What is correct behaviour ? m_currentReservoir->eclipseCaseData() && m_currentReservoir->eclipseCaseData()->results(m_porosityModelEnum) ) { - m_currentReservoir->eclipseCaseData()->results(m_porosityModelEnum)->recalculateStatistics(m_currentScalarIndex); + m_currentReservoir->eclipseCaseData()->results(m_porosityModelEnum)->recalculateStatistics(m_currentEclResultAddress); } for (size_t i = 0; i < m_currentReservoir->reservoirViews.size(); ++i) @@ -565,7 +562,7 @@ class RiaSetNNCProperty: public RiaSocketCommand private: RimEclipseCase* m_currentReservoir; - size_t m_currentScalarIndex; + RigEclipseResultAddress m_currentEclResultAddress; QString m_currentPropertyName; std::vector m_requestedTimesteps; RiaDefines::PorosityModelType m_porosityModelEnum; diff --git a/ApplicationCode/SocketInterface/RiaPropertyDataCommands.cpp b/ApplicationCode/SocketInterface/RiaPropertyDataCommands.cpp index 7dae447c82..163c9a2b00 100644 --- a/ApplicationCode/SocketInterface/RiaPropertyDataCommands.cpp +++ b/ApplicationCode/SocketInterface/RiaPropertyDataCommands.cpp @@ -45,9 +45,7 @@ #include "RiuMainWindow.h" #include "RiuProcessMonitor.h" -#include "RiuSelectionManager.h" - -#include +#include "Riu3dSelectionManager.h" //-------------------------------------------------------------------------------------------------- @@ -73,23 +71,19 @@ class RiaGetActiveCellProperty: public RiaSocketCommand // Find the requested data - size_t scalarResultIndex = cvf::UNDEFINED_SIZE_T; std::vector< std::vector >* scalarResultFrames = nullptr; if (rimCase && rimCase->results(porosityModelEnum)) { - scalarResultIndex = rimCase->results(porosityModelEnum)->findOrLoadScalarResult(propertyName); - - if (scalarResultIndex != cvf::UNDEFINED_SIZE_T) + if (rimCase->results(porosityModelEnum)->ensureKnownResultLoaded(RigEclipseResultAddress(propertyName))) { - scalarResultFrames = &(rimCase->results(porosityModelEnum)->cellScalarResults(scalarResultIndex)); + scalarResultFrames = &(rimCase->results(porosityModelEnum)->modifiableCellScalarResultTimesteps(RigEclipseResultAddress(propertyName))); } - } if (scalarResultFrames == nullptr) { - server->errorMessageDialog()->showMessage(RiaSocketServer::tr("ResInsight SocketServer: \n") + server->showErrorMessage(RiaSocketServer::tr("ResInsight SocketServer: \n") + RiaSocketServer::tr("Could not find the %1 model property named: \"%2\"").arg(porosityModelName).arg(propertyName)); } @@ -134,7 +128,7 @@ class RiaGetActiveCellProperty: public RiaSocketCommand if (timeStepReadError) { - server->errorMessageDialog()->showMessage(RiaSocketServer::tr("ResInsight SocketServer: riGetActiveCellProperty : \n") + RiaSocketServer::tr("An error occured while interpreting the requested timesteps.")); + server->showErrorMessage(RiaSocketServer::tr("ResInsight SocketServer: riGetActiveCellProperty : \n") + RiaSocketServer::tr("An error occured while interpreting the requested timesteps.")); } } @@ -232,7 +226,7 @@ class RiaGetGridProperty: public RiaSocketCommand RimEclipseCase*rimCase = server->findReservoir(caseId); if (rimCase == nullptr) { - server->errorMessageDialog()->showMessage(RiaSocketServer::tr("ResInsight SocketServer: \n") + RiaSocketServer::tr("Could not find the case with ID: \"%1\"").arg(caseId)); + server->showErrorMessage(RiaSocketServer::tr("ResInsight SocketServer: \n") + RiaSocketServer::tr("Could not find the case with ID: \"%1\"").arg(caseId)); // No data available socketStream << (quint64)0 << (quint64)0 << (quint64)0 << (quint64)0 ; @@ -245,11 +239,13 @@ class RiaGetGridProperty: public RiaSocketCommand porosityModelEnum = RiaDefines::FRACTURE_MODEL; } - size_t scalarResultIndex = cvf::UNDEFINED_SIZE_T; + bool isResultsLoaded = false; + + RigEclipseResultAddress resVarAddr(propertyName); if (gridIdx < 0 || rimCase->eclipseCaseData()->gridCount() <= (size_t)gridIdx) { - server->errorMessageDialog()->showMessage("ResInsight SocketServer: riGetGridProperty : \n" + server->showErrorMessage("ResInsight SocketServer: riGetGridProperty : \n" "The gridIndex \"" + QString::number(gridIdx) + "\" does not point to an existing grid." ); } else @@ -257,13 +253,13 @@ class RiaGetGridProperty: public RiaSocketCommand // Find the requested data if (rimCase && rimCase->results(porosityModelEnum)) { - scalarResultIndex = rimCase->results(porosityModelEnum)->findOrLoadScalarResult(propertyName); + isResultsLoaded = rimCase->results(porosityModelEnum)->ensureKnownResultLoaded(resVarAddr); } } - if (scalarResultIndex == cvf::UNDEFINED_SIZE_T) + if (!isResultsLoaded) { - server->errorMessageDialog()->showMessage(RiaSocketServer::tr("ResInsight SocketServer: \n") + RiaSocketServer::tr("Could not find the %1 model property named: \"%2\"").arg(porosityModelName).arg(propertyName)); + server->showErrorMessage(RiaSocketServer::tr("ResInsight SocketServer: \n") + RiaSocketServer::tr("Could not find the %1 model property named: \"%2\"").arg(porosityModelName).arg(propertyName)); // No data available socketStream << (quint64)0 << (quint64)0 << (quint64)0 << (quint64)0 ; @@ -278,7 +274,7 @@ class RiaGetGridProperty: public RiaSocketCommand if (args.size() <= 5) { // Select all - for (size_t tsIdx = 0; tsIdx < rimCase->results(porosityModelEnum)->timeStepCount(scalarResultIndex); ++tsIdx) + for (size_t tsIdx = 0; tsIdx < rimCase->results(porosityModelEnum)->timeStepCount(resVarAddr); ++tsIdx) { requestedTimesteps.push_back(tsIdx); } @@ -303,7 +299,7 @@ class RiaGetGridProperty: public RiaSocketCommand if (timeStepReadError) { - server->errorMessageDialog()->showMessage(RiaSocketServer::tr("ResInsight SocketServer: riGetGridProperty : \n") + server->showErrorMessage(RiaSocketServer::tr("ResInsight SocketServer: riGetGridProperty : \n") + RiaSocketServer::tr("An error occured while interpreting the requested timesteps.")); } @@ -327,7 +323,7 @@ class RiaGetGridProperty: public RiaSocketCommand for (size_t tsIdx = 0; tsIdx < timestepCount; tsIdx++) { - cvf::ref resultAccessor = RigResultAccessorFactory::createFromUiResultName(rimCase->eclipseCaseData(), gridIdx, porosityModelEnum, requestedTimesteps[tsIdx], propertyName); + cvf::ref resultAccessor = RigResultAccessorFactory::createFromResultAddress(rimCase->eclipseCaseData(), gridIdx, porosityModelEnum, requestedTimesteps[tsIdx], RigEclipseResultAddress(propertyName)); if (resultAccessor.isNull()) { @@ -384,7 +380,7 @@ class RiaSetActiveCellProperty: public RiaSocketCommand RiaSetActiveCellProperty() : m_currentReservoir(nullptr), m_scalarResultsToAdd(nullptr), - m_currentScalarIndex(cvf::UNDEFINED_SIZE_T), + m_currentEclResultAddress(), m_timeStepCountToRead(0), m_bytesPerTimeStepToRead(0), m_currentTimeStepNumberToRead(0), @@ -408,37 +404,33 @@ class RiaSetActiveCellProperty: public RiaSocketCommand // Find the requested data, Or create a set if we are setting data and it is not found - size_t scalarResultIndex = cvf::UNDEFINED_SIZE_T; std::vector< std::vector >* scalarResultFrames = nullptr; if (rimCase && rimCase->results(m_porosityModelEnum)) { - scalarResultIndex = rimCase->results(m_porosityModelEnum)->findOrLoadScalarResult(RiaDefines::GENERATED, propertyName); + RigEclipseResultAddress eclResAddr(RiaDefines::GENERATED, propertyName); - if (scalarResultIndex == cvf::UNDEFINED_SIZE_T) + if (!rimCase->results(m_porosityModelEnum)->ensureKnownResultLoaded(eclResAddr)) { - scalarResultIndex = rimCase->results(m_porosityModelEnum)->findOrCreateScalarResultIndex(RiaDefines::GENERATED, propertyName, true); + rimCase->results(m_porosityModelEnum)->createResultEntry(eclResAddr, true); - size_t scalarResWithMostTimeSteps = cvf::UNDEFINED_SIZE_T; - rimCase->results(m_porosityModelEnum)->maxTimeStepCount(&scalarResWithMostTimeSteps); - const std::vector timeStepInfos = rimCase->results(m_porosityModelEnum)->timeStepInfos(scalarResWithMostTimeSteps); - rimCase->results(m_porosityModelEnum)->setTimeStepInfos(scalarResultIndex, timeStepInfos); + RigEclipseResultAddress addrToMaxTimeStepCountResult; + rimCase->results(m_porosityModelEnum)->maxTimeStepCount(&addrToMaxTimeStepCountResult); + const std::vector timeStepInfos = rimCase->results(m_porosityModelEnum)->timeStepInfos(addrToMaxTimeStepCountResult); + rimCase->results(m_porosityModelEnum)->setTimeStepInfos(eclResAddr, timeStepInfos); } - if (scalarResultIndex != cvf::UNDEFINED_SIZE_T) - { - scalarResultFrames = &(rimCase->results(m_porosityModelEnum)->cellScalarResults(scalarResultIndex)); - size_t timeStepCount = rimCase->results(m_porosityModelEnum)->maxTimeStepCount(); - scalarResultFrames->resize(timeStepCount); + scalarResultFrames = &(rimCase->results(m_porosityModelEnum)->modifiableCellScalarResultTimesteps(eclResAddr)); + size_t timeStepCount = rimCase->results(m_porosityModelEnum)->maxTimeStepCount(); + scalarResultFrames->resize(timeStepCount); - m_currentScalarIndex = scalarResultIndex; - m_currentPropertyName = propertyName; - } + m_currentEclResultAddress = eclResAddr; + m_currentPropertyName = propertyName; } if (scalarResultFrames == nullptr) { - server->errorMessageDialog()->showMessage(RiaSocketServer::tr("ResInsight SocketServer: \n") + RiaSocketServer::tr("Could not find the %1 model property named: \"%2\"").arg(porosityModelName).arg(propertyName)); + server->showErrorMessage(RiaSocketServer::tr("ResInsight SocketServer: \n") + RiaSocketServer::tr("Could not find the %1 model property named: \"%2\"").arg(porosityModelName).arg(propertyName)); return true; } @@ -487,14 +479,14 @@ class RiaSetActiveCellProperty: public RiaSocketCommand if (timeStepReadError) { - server->errorMessageDialog()->showMessage(RiaSocketServer::tr("ResInsight SocketServer: riGetActiveCellProperty : \n") + RiaSocketServer::tr("An error occured while interpreting the requested timesteps.")); + server->showErrorMessage(RiaSocketServer::tr("ResInsight SocketServer: riGetActiveCellProperty : \n") + RiaSocketServer::tr("An error occured while interpreting the requested timesteps.")); } } if (! m_requestedTimesteps.size()) { - server->errorMessageDialog()->showMessage(RiaSocketServer::tr("ResInsight SocketServer: \n") + RiaSocketServer::tr("No time steps specified").arg(porosityModelName).arg(propertyName)); + server->showErrorMessage(RiaSocketServer::tr("ResInsight SocketServer: \n") + RiaSocketServer::tr("No time steps specified").arg(porosityModelName).arg(propertyName)); return true; } @@ -542,7 +534,7 @@ class RiaSetActiveCellProperty: public RiaSocketCommand if (cellCountFromOctave != activeCellCountReservoir ) { - server->errorMessageDialog()->showMessage(RiaSocketServer::tr("ResInsight SocketServer: \n") + + server->showErrorMessage(RiaSocketServer::tr("ResInsight SocketServer: \n") + RiaSocketServer::tr("The number of cells in the data coming from octave does not match the case") + ":\"" + m_currentReservoir->caseUserDescription() + "\"\n" " Octave: " + QString::number(cellCountFromOctave) + "\n" " " + m_currentReservoir->caseUserDescription() + ": Active cell count: " + QString::number(activeCellCountReservoir) + " Total cell count: " + QString::number(totalCellCount)) ; @@ -606,7 +598,7 @@ class RiaSetActiveCellProperty: public RiaSocketCommand { for (int i = 0; i < errorMessages.size(); i++) { - server->errorMessageDialog()->showMessage(errorMessages[i]); + server->showErrorMessage(errorMessages[i]); } currentClient->abort(); @@ -654,15 +646,15 @@ class RiaSetActiveCellProperty: public RiaSocketCommand inputProperty->resolvedState = RimEclipseInputProperty::RESOLVED_NOT_SAVED; } - if( m_currentScalarIndex != cvf::UNDEFINED_SIZE_T && + if( m_currentEclResultAddress.isValid() && m_currentReservoir->eclipseCaseData() && m_currentReservoir->eclipseCaseData()->results(m_porosityModelEnum) ) { // Adjust the result data if only one time step is requested so the result behaves like a static result - if (m_requestedTimesteps.size() == 1 && m_currentScalarIndex != cvf::UNDEFINED_SIZE_T) + if (m_requestedTimesteps.size() == 1 && m_currentEclResultAddress.isValid()) { std::vector< std::vector >* scalarResultFrames = nullptr; - scalarResultFrames = &(m_currentReservoir->results(m_porosityModelEnum)->cellScalarResults(m_currentScalarIndex)); + scalarResultFrames = &(m_currentReservoir->results(m_porosityModelEnum)->modifiableCellScalarResultTimesteps(m_currentEclResultAddress)); size_t lastIndexWithDataPresent = cvf::UNDEFINED_SIZE_T; for (size_t i = 0; i < scalarResultFrames->size(); i++) { @@ -678,7 +670,7 @@ class RiaSetActiveCellProperty: public RiaSocketCommand } } - m_currentReservoir->eclipseCaseData()->results(m_porosityModelEnum)->recalculateStatistics(m_currentScalarIndex); + m_currentReservoir->eclipseCaseData()->results(m_porosityModelEnum)->recalculateStatistics(m_currentEclResultAddress); } for (size_t i = 0; i < m_currentReservoir->reservoirViews.size(); ++i) @@ -706,7 +698,7 @@ class RiaSetActiveCellProperty: public RiaSocketCommand private: RimEclipseCase* m_currentReservoir; std::vector< std::vector >* m_scalarResultsToAdd; - size_t m_currentScalarIndex; + RigEclipseResultAddress m_currentEclResultAddress; QString m_currentPropertyName; std::vector m_requestedTimesteps; RiaDefines::PorosityModelType m_porosityModelEnum; @@ -731,7 +723,6 @@ class RiaSetGridProperty : public RiaSocketCommand m_currentReservoir(nullptr), m_scalarResultsToAdd(nullptr), m_currentGridIndex(cvf::UNDEFINED_SIZE_T), - m_currentScalarIndex(cvf::UNDEFINED_SIZE_T), m_timeStepCountToRead(0), m_bytesPerTimeStepToRead(0), m_currentTimeStepNumberToRead(0), @@ -747,7 +738,7 @@ class RiaSetGridProperty : public RiaSocketCommand RimEclipseCase* rimCase = server->findReservoir(caseId); if (!rimCase) { - server->errorMessageDialog()->showMessage(RiaSocketServer::tr("ResInsight SocketServer: \n") + RiaSocketServer::tr("Could not find the case with ID : \"%1\"").arg(caseId)); + server->showErrorMessage(RiaSocketServer::tr("ResInsight SocketServer: \n") + RiaSocketServer::tr("Could not find the case with ID : \"%1\"").arg(caseId)); return true; } @@ -764,7 +755,7 @@ class RiaSetGridProperty : public RiaSocketCommand RigGridBase* grid = rimCase->eclipseCaseData()->grid(m_currentGridIndex); if (!grid) { - server->errorMessageDialog()->showMessage(RiaSocketServer::tr("ResInsight SocketServer: \n") + RiaSocketServer::tr("Could not find the grid index : %1").arg(m_currentGridIndex)); + server->showErrorMessage(RiaSocketServer::tr("ResInsight SocketServer: \n") + RiaSocketServer::tr("Could not find the grid index : %1").arg(m_currentGridIndex)); return true; } @@ -786,7 +777,7 @@ class RiaSetGridProperty : public RiaSocketCommand grid->cellCountJ() != cellCountJ || grid->cellCountK() != cellCountK) { - server->errorMessageDialog()->showMessage(RiaSocketServer::tr("ResInsight SocketServer: \n") + RiaSocketServer::tr("Destination grid size do not match incoming grid size for grid index : %1").arg(m_currentGridIndex)); + server->showErrorMessage(RiaSocketServer::tr("ResInsight SocketServer: \n") + RiaSocketServer::tr("Destination grid size do not match incoming grid size for grid index : %1").arg(m_currentGridIndex)); return true; } @@ -795,39 +786,35 @@ class RiaSetGridProperty : public RiaSocketCommand if (m_timeStepCountToRead == 0 || m_bytesPerTimeStepToRead == 0) { - server->errorMessageDialog()->showMessage(RiaSocketServer::tr("ResInsight SocketServer: \n") + + server->showErrorMessage(RiaSocketServer::tr("ResInsight SocketServer: \n") + RiaSocketServer::tr("Zero data to read for ") + ":\"" + m_currentReservoir->caseUserDescription() + "\"\n"); return true; } - size_t scalarResultIndex = cvf::UNDEFINED_SIZE_T; std::vector< std::vector >* scalarResultFrames = nullptr; if (rimCase && rimCase->results(m_porosityModelEnum)) { - scalarResultIndex = rimCase->results(m_porosityModelEnum)->findOrLoadScalarResult(RiaDefines::GENERATED, propertyName); + RigEclipseResultAddress resAddr(RiaDefines::GENERATED, propertyName); - if (scalarResultIndex == cvf::UNDEFINED_SIZE_T) + if ( !rimCase->results(m_porosityModelEnum)->ensureKnownResultLoaded(resAddr)) { - scalarResultIndex = rimCase->results(m_porosityModelEnum)->findOrCreateScalarResultIndex(RiaDefines::GENERATED, propertyName, true); + rimCase->results(m_porosityModelEnum)->createResultEntry(resAddr, true); } - if (scalarResultIndex != cvf::UNDEFINED_SIZE_T) - { - scalarResultFrames = &(rimCase->results(m_porosityModelEnum)->cellScalarResults(scalarResultIndex)); - size_t timeStepCount = rimCase->results(m_porosityModelEnum)->maxTimeStepCount(); - scalarResultFrames->resize(timeStepCount); + m_currentResultAddress = resAddr; + scalarResultFrames = &(rimCase->results(m_porosityModelEnum)->modifiableCellScalarResultTimesteps(m_currentResultAddress)); + size_t timeStepCount = rimCase->results(m_porosityModelEnum)->maxTimeStepCount(); + scalarResultFrames->resize(timeStepCount); - m_currentScalarIndex = scalarResultIndex; - m_currentPropertyName = propertyName; - } + m_currentPropertyName = propertyName; } if (scalarResultFrames == nullptr) { - server->errorMessageDialog()->showMessage(RiaSocketServer::tr("ResInsight SocketServer: \n") + RiaSocketServer::tr("Could not find the %1 model property named: \"%2\"").arg(porosityModelName).arg(propertyName)); + server->showErrorMessage(RiaSocketServer::tr("ResInsight SocketServer: \n") + RiaSocketServer::tr("Could not find the %1 model property named: \"%2\"").arg(porosityModelName).arg(propertyName)); return true; } @@ -863,7 +850,7 @@ class RiaSetGridProperty : public RiaSocketCommand if (timeStepReadError) { - server->errorMessageDialog()->showMessage(RiaSocketServer::tr("ResInsight SocketServer: riGetActiveCellProperty : \n") + RiaSocketServer::tr("An error occured while interpreting the requested timesteps.")); + server->showErrorMessage(RiaSocketServer::tr("ResInsight SocketServer: riGetActiveCellProperty : \n") + RiaSocketServer::tr("An error occured while interpreting the requested timesteps.")); return true; } @@ -871,7 +858,7 @@ class RiaSetGridProperty : public RiaSocketCommand if (! m_requestedTimesteps.size()) { - server->errorMessageDialog()->showMessage(RiaSocketServer::tr("ResInsight SocketServer: \n") + RiaSocketServer::tr("No time steps specified").arg(porosityModelName).arg(propertyName)); + server->showErrorMessage(RiaSocketServer::tr("ResInsight SocketServer: \n") + RiaSocketServer::tr("No time steps specified").arg(porosityModelName).arg(propertyName)); return true; } @@ -904,7 +891,7 @@ class RiaSetGridProperty : public RiaSocketCommand RigGridBase* grid = m_currentReservoir->eclipseCaseData()->grid(m_currentGridIndex); if (!grid) { - server->errorMessageDialog()->showMessage(RiaSocketServer::tr("ResInsight SocketServer: \n") + + server->showErrorMessage(RiaSocketServer::tr("ResInsight SocketServer: \n") + RiaSocketServer::tr("No grid found") + ":\"" + m_currentReservoir->caseUserDescription() + "\"\n"); m_invalidDataDetected = true; @@ -925,7 +912,7 @@ class RiaSetGridProperty : public RiaSocketCommand if (cellCountFromOctave != grid->cellCount()) { - server->errorMessageDialog()->showMessage(RiaSocketServer::tr("ResInsight SocketServer: \n") + + server->showErrorMessage(RiaSocketServer::tr("ResInsight SocketServer: \n") + RiaSocketServer::tr("Mismatch between expected and received data. Expected : %1, Received : %2").arg(grid->cellCount()).arg(cellCountFromOctave)); m_invalidDataDetected = true; @@ -976,14 +963,18 @@ class RiaSetGridProperty : public RiaSocketCommand { for (int i = 0; i < errorMessages.size(); i++) { - server->errorMessageDialog()->showMessage(errorMessages[i]); + server->showErrorMessage(errorMessages[i]); } currentClient->abort(); return true; } - cvf::ref resultModifier = RigResultModifierFactory::createResultModifier(m_currentReservoir->eclipseCaseData(), grid->gridIndex(), m_porosityModelEnum, m_requestedTimesteps[m_currentTimeStepNumberToRead], m_currentScalarIndex); + cvf::ref resultModifier = RigResultModifierFactory::createResultModifier(m_currentReservoir->eclipseCaseData(), + grid->gridIndex(), + m_porosityModelEnum, + m_requestedTimesteps[m_currentTimeStepNumberToRead], + m_currentResultAddress); if (!resultModifier.isNull()) { for (size_t cellIdx = 0; static_cast(cellIdx) < cellCountFromOctave; cellIdx++) @@ -1018,15 +1009,15 @@ class RiaSetGridProperty : public RiaSocketCommand inputProperty->resolvedState = RimEclipseInputProperty::RESOLVED_NOT_SAVED; } - if( m_currentScalarIndex != cvf::UNDEFINED_SIZE_T && + if( m_currentResultAddress.isValid() && m_currentReservoir->eclipseCaseData() && m_currentReservoir->eclipseCaseData()->results(m_porosityModelEnum) ) { // Adjust the result data if only one time step is requested so the result behaves like a static result - if (m_requestedTimesteps.size() == 1 && m_currentScalarIndex != cvf::UNDEFINED_SIZE_T) + if (m_requestedTimesteps.size() == 1 && m_currentResultAddress.isValid()) { std::vector< std::vector >* scalarResultFrames = nullptr; - scalarResultFrames = &(m_currentReservoir->results(m_porosityModelEnum)->cellScalarResults(m_currentScalarIndex)); + scalarResultFrames = &(m_currentReservoir->results(m_porosityModelEnum)->modifiableCellScalarResultTimesteps(RigEclipseResultAddress(m_currentResultAddress))); size_t lastIndexWithDataPresent = cvf::UNDEFINED_SIZE_T; for (size_t i = 0; i < scalarResultFrames->size(); i++) { @@ -1042,7 +1033,7 @@ class RiaSetGridProperty : public RiaSocketCommand } } - m_currentReservoir->eclipseCaseData()->results(m_porosityModelEnum)->recalculateStatistics(m_currentScalarIndex); + m_currentReservoir->eclipseCaseData()->results(m_porosityModelEnum)->recalculateStatistics(RigEclipseResultAddress(m_currentResultAddress)); } for (size_t i = 0; i < m_currentReservoir->reservoirViews.size(); ++i) @@ -1072,7 +1063,7 @@ class RiaSetGridProperty : public RiaSocketCommand RimEclipseCase* m_currentReservoir; std::vector< std::vector >* m_scalarResultsToAdd; size_t m_currentGridIndex; - size_t m_currentScalarIndex; + RigEclipseResultAddress m_currentResultAddress; QString m_currentPropertyName; std::vector m_requestedTimesteps; RiaDefines::PorosityModelType m_porosityModelEnum; @@ -1100,7 +1091,7 @@ class RiaGetPropertyNames : public RiaSocketCommand RimEclipseCase* rimCase = server->findReservoir(caseId); if (!rimCase) { - server->errorMessageDialog()->showMessage(RiaSocketServer::tr("ResInsight SocketServer: \n") + RiaSocketServer::tr("Could not find the case with ID : \"%1\"").arg(caseId)); + server->showErrorMessage(RiaSocketServer::tr("ResInsight SocketServer: \n") + RiaSocketServer::tr("Could not find the case with ID : \"%1\"").arg(caseId)); return true; } @@ -1198,17 +1189,16 @@ class RiaGetGridPropertyForSelectedCells: public RiaSocketCommand } } - size_t scalarResultIndex = cvf::UNDEFINED_SIZE_T; if (rimCase && rimCase->results(porosityModel)) { - scalarResultIndex = rimCase->results(porosityModel)->findOrLoadScalarResult(propertyName); + rimCase->results(porosityModel)->ensureKnownResultLoaded(RigEclipseResultAddress( propertyName) ); } std::vector requestedTimesteps; if (args.size() < 5) { // Select all - for (size_t tsIdx = 0; tsIdx < rimCase->results(porosityModel)->timeStepCount(scalarResultIndex); ++tsIdx) + for (size_t tsIdx = 0; tsIdx < rimCase->results(porosityModel)->timeStepCount(RigEclipseResultAddress(propertyName)); ++tsIdx) { requestedTimesteps.push_back(tsIdx); } @@ -1233,7 +1223,7 @@ class RiaGetGridPropertyForSelectedCells: public RiaSocketCommand if (timeStepReadError) { - server->errorMessageDialog()->showMessage(RiaSocketServer::tr("ResInsight SocketServer: riGetGridProperty : \n") + server->showErrorMessage(RiaSocketServer::tr("ResInsight SocketServer: riGetGridProperty : \n") + RiaSocketServer::tr("An error occurred while interpreting the requested time steps.")); } @@ -1263,7 +1253,7 @@ class RiaGetGridPropertyForSelectedCells: public RiaSocketCommand { for (const std::pair selectedCell : selectedCells) { - cvf::ref resultAccessor = RigResultAccessorFactory::createFromUiResultName(rimCase->eclipseCaseData(), selectedCell.first, porosityModel, timeStep, propertyName); + cvf::ref resultAccessor = RigResultAccessorFactory::createFromResultAddress(rimCase->eclipseCaseData(), selectedCell.first, porosityModel, timeStep, RigEclipseResultAddress(propertyName)); if (resultAccessor.isNull()) { return false; @@ -1296,7 +1286,7 @@ class RiaGetGridPropertyForSelectedCells: public RiaSocketCommand static std::vector< std::pair > getSelectedCellsForCase(const RimCase* reservoirCase) { std::vector items; - RiuSelectionManager::instance()->selectedItems(items); + Riu3dSelectionManager::instance()->selectedItems(items); std::vector< std::pair > selectedCells; diff --git a/ApplicationCode/SocketInterface/RiaSocketServer.cpp b/ApplicationCode/SocketInterface/RiaSocketServer.cpp index 9a75a92faa..bbe4097f3a 100644 --- a/ApplicationCode/SocketInterface/RiaSocketServer.cpp +++ b/ApplicationCode/SocketInterface/RiaSocketServer.cpp @@ -22,6 +22,8 @@ #include "RiaSocketCommand.h" #include "RiaApplication.h" +#include "RiaLogging.h" +#include "RiaPreferences.h" #include "RimEclipseCase.h" #include "RimEclipseView.h" @@ -33,10 +35,14 @@ #include "cafFactory.h" +#if QT_VERSION >= 0x050000 +#include +#else #include +#endif #include -#include +#include //-------------------------------------------------------------------------------------------------- @@ -50,8 +56,6 @@ RiaSocketServer::RiaSocketServer(QObject* parent) m_currentCommand(nullptr), m_currentCaseId(-1) { - m_errorMessageDialog = new QErrorMessage(RiuMainWindow::instance()); - // TCP server setup m_tcpServer = new QTcpServer(this); @@ -60,16 +64,18 @@ RiaSocketServer::RiaSocketServer(QObject* parent) m_nextPendingConnectionTimer->setInterval(100); m_nextPendingConnectionTimer->setSingleShot(true); - if (!m_tcpServer->listen(QHostAddress::LocalHost, 40001)) + if (!m_tcpServer->listen(QHostAddress::LocalHost, 40001)) { - m_errorMessageDialog->showMessage("Octave communication disabled :\n" - "\n" - "This instance of ResInsight could not start the Socket Server enabling octave to get and set data.\n" - "This is probably because you already have a running ResInsight process.\n" - "Octave can only communicate with one ResInsight process at a time, so the Octave\n" - "communication in this ResInsight instance will be disabled.\n" - "\n" - + tr("The error from the socket system is: %1.").arg(m_tcpServer->errorString())); + QString txt; + txt = "This instance of ResInsight could not start the Socket Server enabling octave to get and set data.\n " + "This is probably because you already have a running ResInsight process.\n" + "Octave can only communicate with one ResInsight process at a time, so the Octave\n" + "communication in this ResInsight instance will be disabled.\n" + "\n" + + tr("The error from the socket system is: %1.").arg(m_tcpServer->errorString()); + + RiaLogging::error(txt); + return; } @@ -116,7 +122,10 @@ void RiaSocketServer::slotNewClientConnection() if (!isFinshed) { - m_errorMessageDialog->showMessage(tr("ResInsight SocketServer: \n") + tr("Warning : The command did not finish up correctly at the presence of a new one.")); + QString txt; + txt = "ResInsight SocketServer : The command did not finish up correctly at the presence of a new one."; + + RiaLogging::error(txt); } } @@ -227,7 +236,10 @@ bool RiaSocketServer::readCommandFromOctave() } else { - m_errorMessageDialog->showMessage(tr("ResInsight SocketServer: \n") + tr("Unknown command: %1").arg(args[0].data())); + QString txt; + txt = QString("ResInsight SocketServer: Unknown command: %1").arg(args[0].data()); + + RiaLogging::error(txt); return true; } } @@ -245,7 +257,10 @@ void RiaSocketServer::slotCurrentClientDisconnected() if (!isFinished) { - m_errorMessageDialog->showMessage(tr("ResInsight SocketServer: \n") + tr("Warning : The command was interrupted and did not finish because the connection to octave disconnected.")); + QString txt; + txt = QString("ResInsight SocketServer: The command was interrupted and did not finish because the connection to octave disconnected."); + + RiaLogging::error(txt); } } @@ -292,6 +307,14 @@ int RiaSocketServer::currentCaseId() const return m_currentCaseId; } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiaSocketServer::showErrorMessage(const QString& message) const +{ + RiaLogging::error(message); +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/SocketInterface/RiaSocketServer.h b/ApplicationCode/SocketInterface/RiaSocketServer.h index 5a76ed119d..fd4c3c563e 100644 --- a/ApplicationCode/SocketInterface/RiaSocketServer.h +++ b/ApplicationCode/SocketInterface/RiaSocketServer.h @@ -31,7 +31,6 @@ class QPushButton; class QTcpServer; class QTcpSocket; class QNetworkSession; -class QErrorMessage; class QTimer; class RimEclipseCase; class RiaSocketCommand; @@ -51,13 +50,14 @@ class RiaSocketServer : public QObject ~RiaSocketServer() override; unsigned short serverPort(); - RimEclipseCase* findReservoir(int caseId); - QErrorMessage* errorMessageDialog() { return m_errorMessageDialog; } + RimEclipseCase* findReservoir(int caseId); QTcpSocket* currentClient() { return m_currentClient; } void setCurrentCaseId(int caseId); int currentCaseId() const; + void showErrorMessage(const QString& message) const; + private slots: void slotNewClientConnection(); void slotCurrentClientDisconnected(); @@ -70,7 +70,6 @@ private slots: private: QTcpServer* m_tcpServer; - QErrorMessage* m_errorMessageDialog; QTcpSocket* m_currentClient; qint64 m_currentCommandSize; ///< The size in bytes of the command we are currently reading. diff --git a/ApplicationCode/SocketInterface/RiaSocketServerDefines.h b/ApplicationCode/SocketInterface/RiaSocketServerDefines.h index 542bf47484..e54ceeb047 100644 --- a/ApplicationCode/SocketInterface/RiaSocketServerDefines.h +++ b/ApplicationCode/SocketInterface/RiaSocketServerDefines.h @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018 Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by diff --git a/ApplicationCode/SocketInterface/RiaSocketTools.cpp b/ApplicationCode/SocketInterface/RiaSocketTools.cpp index fb4e68d822..54fec4968d 100644 --- a/ApplicationCode/SocketInterface/RiaSocketTools.cpp +++ b/ApplicationCode/SocketInterface/RiaSocketTools.cpp @@ -41,7 +41,6 @@ #include "cvfTimer.h" -#include #include //-------------------------------------------------------------------------------------------------- @@ -61,7 +60,7 @@ RimEclipseCase* RiaSocketTools::findCaseFromArgs(RiaSocketServer* server, const if (rimCase == nullptr) { // TODO: Display error message a different place to avoid socket comm to be halted. - //server->errorMessageDialog()->showMessage(RiaSocketServer::tr("ResInsight SocketServer: \n") + RiaSocketServer::tr("Could not find the Case with CaseId : \"%1\"").arg(caseId)); + //server->showMessage(RiaSocketServer::tr("ResInsight SocketServer: \n") + RiaSocketServer::tr("Could not find the Case with CaseId : \"%1\"").arg(caseId)); } return rimCase; @@ -131,13 +130,13 @@ bool RiaSocketTools::writeBlockData(RiaSocketServer* server, QTcpSocket* socket, { for (int i = 0; i < errorMessages.size(); i++) { - server->errorMessageDialog()->showMessage(errorMessages[i]); + server->showErrorMessage(errorMessages[i]); } // double totalTimeMS = timer.time() * 1000.0; // QString resultInfo = QString("Total time '%1 ms'").arg(totalTimeMS); // -// server->errorMessageDialog()->showMessage(resultInfo); +// server->showMessage(resultInfo); } return writeSucceded; diff --git a/ApplicationCode/SocketInterface/RiaWellDataCommands.cpp b/ApplicationCode/SocketInterface/RiaWellDataCommands.cpp index 747004997f..3a31655902 100644 --- a/ApplicationCode/SocketInterface/RiaWellDataCommands.cpp +++ b/ApplicationCode/SocketInterface/RiaWellDataCommands.cpp @@ -30,7 +30,6 @@ #include "cvfCollection.h" -#include #include @@ -48,7 +47,7 @@ class RiaGetWellNames : public RiaSocketCommand RimEclipseCase* rimCase = server->findReservoir(caseId); if (!rimCase) { - server->errorMessageDialog()->showMessage(RiaSocketServer::tr("ResInsight SocketServer: \n") + RiaSocketServer::tr("Could not find the case with ID : \"%1\"").arg(caseId)); + server->showErrorMessage(RiaSocketServer::tr("ResInsight SocketServer: \n") + RiaSocketServer::tr("Could not find the case with ID : \"%1\"").arg(caseId)); return true; } @@ -102,7 +101,7 @@ class RiaGetWellStatus : public RiaSocketCommand RimEclipseCase* rimCase = server->findReservoir(caseId); if (!rimCase) { - server->errorMessageDialog()->showMessage(RiaSocketServer::tr("ResInsight SocketServer: \n") + RiaSocketServer::tr("Could not find the case with ID : \"%1\"").arg(caseId)); + server->showErrorMessage(RiaSocketServer::tr("ResInsight SocketServer: \n") + RiaSocketServer::tr("Could not find the case with ID : \"%1\"").arg(caseId)); return true; } @@ -125,7 +124,7 @@ class RiaGetWellStatus : public RiaSocketCommand if (currentWellResult.isNull()) { - server->errorMessageDialog()->showMessage( + server->showErrorMessage( RiaSocketServer::tr("ResInsight SocketServer: \n") + RiaSocketServer::tr("Could not find the well with name : \"%1\"").arg(wellName)); return true; @@ -161,7 +160,7 @@ class RiaGetWellStatus : public RiaSocketCommand if (timeStepReadError) { - server->errorMessageDialog()->showMessage(RiaSocketServer::tr("ResInsight SocketServer: riGetGridProperty : \n") + server->showErrorMessage(RiaSocketServer::tr("ResInsight SocketServer: riGetGridProperty : \n") + RiaSocketServer::tr("An error occured while interpreting the requested timesteps.")); } } @@ -241,7 +240,7 @@ class RiaGetWellCells : public RiaSocketCommand RimEclipseCase* rimCase = server->findReservoir(caseId); if (!rimCase) { - server->errorMessageDialog()->showMessage(RiaSocketServer::tr("ResInsight SocketServer: \n") + RiaSocketServer::tr("Could not find the case with ID : \"%1\"").arg(caseId)); + server->showErrorMessage(RiaSocketServer::tr("ResInsight SocketServer: \n") + RiaSocketServer::tr("Could not find the case with ID : \"%1\"").arg(caseId)); socketStream << (quint64)0; return true; @@ -260,7 +259,7 @@ class RiaGetWellCells : public RiaSocketCommand if (currentWellResult.isNull()) { - server->errorMessageDialog()->showMessage( + server->showErrorMessage( RiaSocketServer::tr("ResInsight SocketServer: \n") + RiaSocketServer::tr("Could not find the well with name : \"%1\"").arg(wellName)); socketStream << (quint64)0; diff --git a/ApplicationCode/UnitTests/CMakeLists_files.cmake b/ApplicationCode/UnitTests/CMakeLists_files.cmake index e9b22f7853..596414f93a 100644 --- a/ApplicationCode/UnitTests/CMakeLists_files.cmake +++ b/ApplicationCode/UnitTests/CMakeLists_files.cmake @@ -52,6 +52,9 @@ ${CMAKE_CURRENT_LIST_DIR}/RiaWeightedGeometricMeanCalculator-Test.cpp ${CMAKE_CURRENT_LIST_DIR}/RiaWeightedHarmonicMeanCalculator-Test.cpp ${CMAKE_CURRENT_LIST_DIR}/RiaCellDividingTools-Test.cpp ${CMAKE_CURRENT_LIST_DIR}/Intersect-Test.cpp +${CMAKE_CURRENT_LIST_DIR}/RifPerforationIntervalReader-Test.cpp +${CMAKE_CURRENT_LIST_DIR}/RimWellPathCompletions-Test.cpp +${CMAKE_CURRENT_LIST_DIR}/RimSummaryCaseCollection-Test.cpp ) list(APPEND CODE_HEADER_FILES diff --git a/ApplicationCode/UnitTests/ObservedDataParser-Test.cpp b/ApplicationCode/UnitTests/ObservedDataParser-Test.cpp index 6b54ae4087..92a58e9f39 100644 --- a/ApplicationCode/UnitTests/ObservedDataParser-Test.cpp +++ b/ApplicationCode/UnitTests/ObservedDataParser-Test.cpp @@ -837,3 +837,80 @@ TEST(RifColumnBasedRsmspecParserTest, HasOnlyValidDoubleValues) EXPECT_FALSE(RifEclipseUserDataParserTools::hasOnlyValidDoubleValues(words, &doubleValues)); } } + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +TEST(RifColumnBasedRsmspecParserTest, TestParsingOfDateString) +{ + { + QString txt = "22.12.1900"; + RicPasteAsciiDataToSummaryPlotFeatureUi::DateFormat df = RicPasteAsciiDataToSummaryPlotFeatureUi::dateFormatFromString(txt); + + EXPECT_EQ(RicPasteAsciiDataToSummaryPlotFeatureUi::DateFormat::DATE_DDMMYYYY_DOT_SEPARATED, df); + } + + { + QString txt = "22-12-1900"; + RicPasteAsciiDataToSummaryPlotFeatureUi::DateFormat df = + RicPasteAsciiDataToSummaryPlotFeatureUi::dateFormatFromString(txt); + + EXPECT_EQ(RicPasteAsciiDataToSummaryPlotFeatureUi::DateFormat::DATE_DDMMYYYY_DASH_SEPARATED, df); + } + + { + QString txt = "22/12/1900"; + RicPasteAsciiDataToSummaryPlotFeatureUi::DateFormat df = + RicPasteAsciiDataToSummaryPlotFeatureUi::dateFormatFromString(txt); + + EXPECT_EQ(RicPasteAsciiDataToSummaryPlotFeatureUi::DateFormat::DATE_DDMMYYYY_SLASH_SEPARATED, df); + } + + { + QString txt = "1900.12.24"; + RicPasteAsciiDataToSummaryPlotFeatureUi::DateFormat df = + RicPasteAsciiDataToSummaryPlotFeatureUi::dateFormatFromString(txt); + + EXPECT_EQ(RicPasteAsciiDataToSummaryPlotFeatureUi::DateFormat::DATE_YYYYMMDD_DOT_SEPARATED, df); + } + + { + QString txt = "1900-12-24"; + RicPasteAsciiDataToSummaryPlotFeatureUi::DateFormat df = + RicPasteAsciiDataToSummaryPlotFeatureUi::dateFormatFromString(txt); + + EXPECT_EQ(RicPasteAsciiDataToSummaryPlotFeatureUi::DateFormat::DATE_YYYYMMDD_DASH_SEPARATED, df); + } + + { + QString txt = "1900/12/24"; + RicPasteAsciiDataToSummaryPlotFeatureUi::DateFormat df = + RicPasteAsciiDataToSummaryPlotFeatureUi::dateFormatFromString(txt); + + EXPECT_EQ(RicPasteAsciiDataToSummaryPlotFeatureUi::DateFormat::DATE_YYYYMMDD_SLASH_SEPARATED, df); + } + + { + QString txt = "12/22/1900"; + RicPasteAsciiDataToSummaryPlotFeatureUi::DateFormat df = + RicPasteAsciiDataToSummaryPlotFeatureUi::dateFormatFromString(txt); + + EXPECT_EQ(RicPasteAsciiDataToSummaryPlotFeatureUi::DateFormat::DATE_MMDDYYYY_SLASH_SEPARATED, df); + } + + { + QString txt = "22/12/1900"; + RicPasteAsciiDataToSummaryPlotFeatureUi::DateFormat df = + RicPasteAsciiDataToSummaryPlotFeatureUi::dateFormatFromString(txt); + + EXPECT_EQ(RicPasteAsciiDataToSummaryPlotFeatureUi::DateFormat::DATE_DDMMYYYY_SLASH_SEPARATED, df); + } + + { + QString txt = "12/22/30"; + RicPasteAsciiDataToSummaryPlotFeatureUi::DateFormat df = + RicPasteAsciiDataToSummaryPlotFeatureUi::dateFormatFromString(txt); + + EXPECT_EQ(RicPasteAsciiDataToSummaryPlotFeatureUi::DateFormat::DATE_MMDDYY_SLASH_SEPARATED, df); + } +} diff --git a/ApplicationCode/UnitTests/RiaTestDataDirectory.h.cmake b/ApplicationCode/UnitTests/RiaTestDataDirectory.h.cmake index cc9abc663e..89de75ac64 100644 --- a/ApplicationCode/UnitTests/RiaTestDataDirectory.h.cmake +++ b/ApplicationCode/UnitTests/RiaTestDataDirectory.h.cmake @@ -1,3 +1,4 @@ // Test data directory used by unit tests #define TEST_DATA_DIR "${CMAKE_CURRENT_LIST_DIR}/TestData" +#define TEST_MODEL_DIR "${CMAKE_CURRENT_LIST_DIR}/../../TestModels" \ No newline at end of file diff --git a/ApplicationCode/UnitTests/RifCaseRealizationParametersReader-Test.cpp b/ApplicationCode/UnitTests/RifCaseRealizationParametersReader-Test.cpp index 7488094fb4..5ca5fedf0c 100644 --- a/ApplicationCode/UnitTests/RifCaseRealizationParametersReader-Test.cpp +++ b/ApplicationCode/UnitTests/RifCaseRealizationParametersReader-Test.cpp @@ -9,15 +9,15 @@ #include -static const QString TEST_DATA_DIRECTORY = QString("%1/RifCaseRealizationParametersReader/").arg(TEST_DATA_DIR); +static const QString CASE_REAL_TEST_DATA_DIRECTORY = QString("%1/RifCaseRealizationParametersReader/").arg(TEST_DATA_DIR); //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- TEST(RifCaseRealizationParametersReaderTest, LocatorTestSuccess) { - QString file = RifCaseRealizationParametersFileLocator::locate(TEST_DATA_DIRECTORY + "4/3/2"); - QString expected = TEST_DATA_DIRECTORY + "parameters.txt"; + QString file = RifCaseRealizationParametersFileLocator::locate(CASE_REAL_TEST_DATA_DIRECTORY + "4/3/2"); + QString expected = CASE_REAL_TEST_DATA_DIRECTORY + "parameters.txt"; EXPECT_EQ(expected.toStdString(), file.toStdString()); } @@ -26,7 +26,7 @@ TEST(RifCaseRealizationParametersReaderTest, LocatorTestSuccess) //-------------------------------------------------------------------------------------------------- TEST(RifCaseRealizationParametersReaderTest, LocatorTestFailure) { - QString file = RifCaseRealizationParametersFileLocator::locate(TEST_DATA_DIRECTORY + "4/3/2/1"); + QString file = RifCaseRealizationParametersFileLocator::locate(CASE_REAL_TEST_DATA_DIRECTORY + "4/3/2/1"); QString expected = ""; EXPECT_EQ(expected.toStdString(), file.toStdString()); } @@ -36,7 +36,7 @@ TEST(RifCaseRealizationParametersReaderTest, LocatorTestFailure) //-------------------------------------------------------------------------------------------------- TEST(RifCaseRealizationParametersReaderTest, SuccessfulParsing) { - RifCaseRealizationParametersReader reader(TEST_DATA_DIRECTORY + "parameters.txt"); + RifCaseRealizationParametersReader reader(CASE_REAL_TEST_DATA_DIRECTORY + "parameters.txt"); try { @@ -68,7 +68,7 @@ TEST(RifCaseRealizationParametersReaderTest, SuccessfulParsing) //-------------------------------------------------------------------------------------------------- TEST(RifCaseRealizationParametersReaderTest, ParseFailed_InvalidFormat) { - RifCaseRealizationParametersReader reader(TEST_DATA_DIRECTORY + "parameters_invalid_format.txt"); + RifCaseRealizationParametersReader reader(CASE_REAL_TEST_DATA_DIRECTORY + "parameters_invalid_format.txt"); try { @@ -91,7 +91,7 @@ TEST(RifCaseRealizationParametersReaderTest, ParseFailed_InvalidFormat) //-------------------------------------------------------------------------------------------------- TEST(RifCaseRealizationParametersReaderTest, ParseFailed_InvalidNumberFormat) { - RifCaseRealizationParametersReader reader(TEST_DATA_DIRECTORY + "parameters_invalid_number_format.txt"); + RifCaseRealizationParametersReader reader(CASE_REAL_TEST_DATA_DIRECTORY + "parameters_invalid_number_format.txt"); try { diff --git a/ApplicationCode/UnitTests/RifEclipseDataTableFormatter-Test.cpp b/ApplicationCode/UnitTests/RifEclipseDataTableFormatter-Test.cpp index c26b592a2a..7e9a14f375 100644 --- a/ApplicationCode/UnitTests/RifEclipseDataTableFormatter-Test.cpp +++ b/ApplicationCode/UnitTests/RifEclipseDataTableFormatter-Test.cpp @@ -2,6 +2,9 @@ #include "RifEclipseDataTableFormatter.h" +#include +#include + TEST(RifEclipseDataTableFormatter, BasicUsage) { QString tableText; @@ -73,3 +76,142 @@ TEST(RifEclipseDataTableFormatter, NoPrefix) std::cout << tableText.toStdString(); } + +TEST(RifEclipseDataTableFormatter, LongLine) +{ + QString tableText; + QTextStream stream(&tableText); + RifEclipseDataTableFormatter formatter(stream); + + std::vector header = { + RifEclipseOutputTableColumn("50 Character Well Name"), + RifEclipseOutputTableColumn("10 Int #1", RifEclipseOutputTableDoubleFormatting(), RIGHT), + RifEclipseOutputTableColumn("10 Int #2", RifEclipseOutputTableDoubleFormatting(), RIGHT), + RifEclipseOutputTableColumn("10 Int #3", RifEclipseOutputTableDoubleFormatting(), RIGHT), + RifEclipseOutputTableColumn("10 Int #4", RifEclipseOutputTableDoubleFormatting(), RIGHT), + RifEclipseOutputTableColumn("10 Int #5", RifEclipseOutputTableDoubleFormatting(), RIGHT), + RifEclipseOutputTableColumn("10 Int #6", RifEclipseOutputTableDoubleFormatting(), RIGHT), + RifEclipseOutputTableColumn("10 Int #7", RifEclipseOutputTableDoubleFormatting(), RIGHT), + RifEclipseOutputTableColumn("10 Int #8", RifEclipseOutputTableDoubleFormatting(), RIGHT), + }; + + formatter.header(header); + QString fiftyCharacterWellName = "01234567890123456789012345678901234567890123456789"; + formatter.add(fiftyCharacterWellName); + for (int i = 0; i < 8; ++i) + { + formatter.add(std::numeric_limits::max()); // 10 characters + } + int fullLineLength = formatter.tableRowPrependText().length() + 9 * formatter.columnSpacing() + + 50 + 8 * 10 + formatter.tableRowAppendText().length(); + int tableWidth = formatter.tableWidth(); + EXPECT_EQ(tableWidth, fullLineLength); + EXPECT_GT(tableWidth, formatter.maxDataRowWidth()); + + formatter.rowCompleted(); + formatter.tableCompleted(); + + QStringList tableLines = tableText.split(QRegExp("[\r\n]"), QString::SkipEmptyParts); + for (QString line : tableLines) + { + std::cout << QString("Line: \"%1\"").arg(line).toStdString() << std::endl; + if (!line.startsWith(formatter.commentPrefix())) + { + EXPECT_LE(line.length(), formatter.maxDataRowWidth()); + } + } +} + +TEST(RifEclipseDataTableFormatter, LongLine132) +{ + QString tableText; + QTextStream stream(&tableText); + RifEclipseDataTableFormatter formatter(stream); + + std::vector header = { + RifEclipseOutputTableColumn("10 Char"), + RifEclipseOutputTableColumn("10 Int #1", RifEclipseOutputTableDoubleFormatting(), RIGHT), + RifEclipseOutputTableColumn("10 Int #2", RifEclipseOutputTableDoubleFormatting(), RIGHT), + RifEclipseOutputTableColumn("10 Int #3", RifEclipseOutputTableDoubleFormatting(), RIGHT), + RifEclipseOutputTableColumn("10 Int #4", RifEclipseOutputTableDoubleFormatting(), RIGHT), + RifEclipseOutputTableColumn("10 Int #5", RifEclipseOutputTableDoubleFormatting(), RIGHT), + RifEclipseOutputTableColumn("10 Int #6", RifEclipseOutputTableDoubleFormatting(), RIGHT), + RifEclipseOutputTableColumn("10 Int #7", RifEclipseOutputTableDoubleFormatting(), RIGHT), + RifEclipseOutputTableColumn("I", RifEclipseOutputTableDoubleFormatting(), RIGHT), + }; + + formatter.header(header); + QString tenCharacterWellName = "0123456789"; + formatter.add(tenCharacterWellName); + for (int i = 0; i < 7; ++i) + { + formatter.add(std::numeric_limits::max()); // 10 characters + } + formatter.add(11); + + int fullLineLength = formatter.tableRowPrependText().length() + 9 * formatter.columnSpacing() + 10 + 7 * 10 + 2 + + formatter.tableRowAppendText().length(); + int tableWidth = formatter.tableWidth(); + EXPECT_GE(tableWidth, fullLineLength); + EXPECT_EQ(formatter.maxDataRowWidth(), fullLineLength); + + formatter.rowCompleted(); + formatter.tableCompleted(); + + QStringList tableLines = tableText.split(QRegExp("[\r\n]"), QString::SkipEmptyParts); + for (QString line : tableLines) + { + std::cout << QString("Line: \"%1\"").arg(line).toStdString() << std::endl; + if (line.startsWith("0")) + { + EXPECT_EQ(line.length(), formatter.maxDataRowWidth()); + } + } +} + +TEST(RifEclipseDataTableFormatter, LongLine133) +{ + QString tableText; + QTextStream stream(&tableText); + RifEclipseDataTableFormatter formatter(stream); + + std::vector header = { + RifEclipseOutputTableColumn("10 Char"), + RifEclipseOutputTableColumn("10 Int #1", RifEclipseOutputTableDoubleFormatting(), RIGHT), + RifEclipseOutputTableColumn("10 Int #2", RifEclipseOutputTableDoubleFormatting(), RIGHT), + RifEclipseOutputTableColumn("10 Int #3", RifEclipseOutputTableDoubleFormatting(), RIGHT), + RifEclipseOutputTableColumn("10 Int #4", RifEclipseOutputTableDoubleFormatting(), RIGHT), + RifEclipseOutputTableColumn("10 Int #5", RifEclipseOutputTableDoubleFormatting(), RIGHT), + RifEclipseOutputTableColumn("10 Int #6", RifEclipseOutputTableDoubleFormatting(), RIGHT), + RifEclipseOutputTableColumn("10 Int #7", RifEclipseOutputTableDoubleFormatting(), RIGHT), + RifEclipseOutputTableColumn("I", RifEclipseOutputTableDoubleFormatting(), RIGHT), + }; + + formatter.header(header); + QString fiftyCharacterWellName = "0123456789"; + formatter.add(fiftyCharacterWellName); + for (int i = 0; i < 7; ++i) + { + formatter.add(std::numeric_limits::max()); // 10 characters + } + formatter.add(111); + + int fullLineLength = formatter.tableRowPrependText().length() + 9 * formatter.columnSpacing() + 10 + 7 * 10 + 3 + + formatter.tableRowAppendText().length(); + int tableWidth = formatter.tableWidth(); + EXPECT_GE(tableWidth, fullLineLength); + EXPECT_LT(formatter.maxDataRowWidth(), fullLineLength); + + formatter.rowCompleted(); + formatter.tableCompleted(); + + QStringList tableLines = tableText.split(QRegExp("[\r\n]"), QString::SkipEmptyParts); + for (QString line : tableLines) + { + std::cout << QString("Line: \"%1\"").arg(line).toStdString() << std::endl; + if (line.startsWith("0")) + { + EXPECT_LE(line.length(), formatter.maxDataRowWidth()); + } + } +} \ No newline at end of file diff --git a/ApplicationCode/UnitTests/RifEclipseInputFileTools-Test.cpp b/ApplicationCode/UnitTests/RifEclipseInputFileTools-Test.cpp index d4f0cf9d3e..743b07b37c 100644 --- a/ApplicationCode/UnitTests/RifEclipseInputFileTools-Test.cpp +++ b/ApplicationCode/UnitTests/RifEclipseInputFileTools-Test.cpp @@ -1,44 +1,28 @@ #include "gtest/gtest.h" -#include "RigEclipseCaseData.h" - +#include "RiaTestDataDirectory.h" #include "RifEclipseInputFileTools.h" +#include "RigEclipseCaseData.h" +#include "RigEquil.h" #include +#include //-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -/* -TEST(RifEclipseInputFileToolsTest, PathsKeyword) -{ - QString filename = "d:/Models/Statoil/troll_Ref2014/T07-4A-W2014-06.DATA"; - //QString filename = "d:/Models/Statoil/!myTestWithWellLog/TEST10K_FLT_LGR_NNC.DATA"; - - std::vector> pathEntries; - - RifEclipseInputFileTools::parseAndReadPathAliasKeyword(filename, &pathEntries); - - for (auto entry : pathEntries) - { - qDebug() << entry.first << " " << entry.second; - } - - std::vector filenamesWithFaults; - cvf::Collection faults; - RifEclipseInputFileTools::readFaultsInGridSection(filename, &faults, &filenamesWithFaults); - -} -*/ - -//-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- TEST(RifEclipseInputFileToolsTest, FaultFaces) { { QStringList faceTexts; - faceTexts << "X" << "X+" << "I" << "I+" << "x" << "x+" << "i" << "i+"; + faceTexts << "X" + << "X+" + << "I" + << "I+" + << "x" + << "x+" + << "i" + << "i+"; cvf::StructGridInterface::FaceEnum faceType; foreach (QString text, faceTexts) @@ -50,10 +34,13 @@ TEST(RifEclipseInputFileToolsTest, FaultFaces) { QStringList faceTexts; - faceTexts << "X-" << "I-" << "x-" << "i-"; + faceTexts << "X-" + << "I-" + << "x-" + << "i-"; cvf::StructGridInterface::FaceEnum faceType; - foreach(QString text, faceTexts) + foreach (QString text, faceTexts) { faceType = RifEclipseInputFileTools::faceEnumFromText(text); EXPECT_EQ(cvf::StructGridInterface::NEG_I, faceType); @@ -62,10 +49,17 @@ TEST(RifEclipseInputFileToolsTest, FaultFaces) { QStringList faceTexts; - faceTexts << "Y" << "Y+" << "J" << "J+" << "y" << "y+" << "j" << "j+"; + faceTexts << "Y" + << "Y+" + << "J" + << "J+" + << "y" + << "y+" + << "j" + << "j+"; cvf::StructGridInterface::FaceEnum faceType; - foreach(QString text, faceTexts) + foreach (QString text, faceTexts) { faceType = RifEclipseInputFileTools::faceEnumFromText(text); EXPECT_EQ(cvf::StructGridInterface::POS_J, faceType); @@ -74,10 +68,13 @@ TEST(RifEclipseInputFileToolsTest, FaultFaces) { QStringList faceTexts; - faceTexts << "Y-" << "J-" << "y-" << "j-"; + faceTexts << "Y-" + << "J-" + << "y-" + << "j-"; cvf::StructGridInterface::FaceEnum faceType; - foreach(QString text, faceTexts) + foreach (QString text, faceTexts) { faceType = RifEclipseInputFileTools::faceEnumFromText(text); EXPECT_EQ(cvf::StructGridInterface::NEG_J, faceType); @@ -86,10 +83,17 @@ TEST(RifEclipseInputFileToolsTest, FaultFaces) { QStringList faceTexts; - faceTexts << "Z" << "Z+" << "K" << "k+" << "z" << "z+" << "k" << "k+"; + faceTexts << "Z" + << "Z+" + << "K" + << "k+" + << "z" + << "z+" + << "k" + << "k+"; cvf::StructGridInterface::FaceEnum faceType; - foreach(QString text, faceTexts) + foreach (QString text, faceTexts) { faceType = RifEclipseInputFileTools::faceEnumFromText(text); EXPECT_EQ(cvf::StructGridInterface::POS_K, faceType); @@ -98,37 +102,44 @@ TEST(RifEclipseInputFileToolsTest, FaultFaces) { QStringList faceTexts; - faceTexts << "Z-" << "K-" << "z-" << "k-"; + faceTexts << "Z-" + << "K-" + << "z-" + << "k-"; cvf::StructGridInterface::FaceEnum faceType; - foreach(QString text, faceTexts) + foreach (QString text, faceTexts) { faceType = RifEclipseInputFileTools::faceEnumFromText(text); EXPECT_EQ(cvf::StructGridInterface::NEG_K, faceType); } } - // Improved parsing handling some special cases { QStringList faceTexts; - faceTexts << "Z--" << "z--" << "z/" << " y /"; + faceTexts << "Z--" + << "z--" + << "z/" + << " y /"; cvf::StructGridInterface::FaceEnum faceType; - foreach(QString text, faceTexts) + foreach (QString text, faceTexts) { faceType = RifEclipseInputFileTools::faceEnumFromText(text); EXPECT_NE(cvf::StructGridInterface::NO_FACE, faceType); } } - //Invalid faces + // Invalid faces { QStringList faceTexts; - faceTexts << "-k-" << " -k " << " +k- "; + faceTexts << "-k-" + << " -k " + << " +k- "; cvf::StructGridInterface::FaceEnum faceType; - foreach(QString text, faceTexts) + foreach (QString text, faceTexts) { faceType = RifEclipseInputFileTools::faceEnumFromText(text); EXPECT_EQ(cvf::StructGridInterface::NO_FACE, faceType); @@ -138,14 +149,172 @@ TEST(RifEclipseInputFileToolsTest, FaultFaces) // Valid cases with whitespace { QStringList faceTexts; - faceTexts << " X" << " X+ " << " I " << " i+ "; + faceTexts << " X" + << " X+ " + << " I " + << " i+ "; cvf::StructGridInterface::FaceEnum faceType; - foreach(QString text, faceTexts) + foreach (QString text, faceTexts) { faceType = RifEclipseInputFileTools::faceEnumFromText(text); EXPECT_EQ(cvf::StructGridInterface::POS_I, faceType); } } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +TEST(RifEclipseInputFileToolsTest, EquilData) +{ + static const QString testDataRootFolder = QString("%1/ParsingOfDataKeywords/").arg(TEST_DATA_DIR); + + { + QString fileName = testDataRootFolder + "simulation/MY_CASE.DATA"; + + QFile data(fileName); + if (!data.open(QFile::ReadOnly)) + { + return; + } + + std::vector> pathAliasDefinitions; + RifEclipseInputFileTools::parseAndReadPathAliasKeyword(fileName, &pathAliasDefinitions); + + const QString keyword("EQUIL"); + const QString keywordToStopParsing; + const qint64 startPositionInFile = 0; + QStringList keywordContent; + std::vector fileNamesContainingKeyword; + bool isStopParsingKeywordDetected = false; + const QString includeStatementAbsolutePathPrefix; + + RifEclipseInputFileTools::readKeywordAndParseIncludeStatementsRecursively(keyword, + keywordToStopParsing, + data, + startPositionInFile, + pathAliasDefinitions, + &keywordContent, + &fileNamesContainingKeyword, + &isStopParsingKeywordDetected, + includeStatementAbsolutePathPrefix); + EXPECT_EQ((int)10, keywordContent.size()); + for (const auto& s : keywordContent) + { + RigEquil equilRec = RigEquil::parseString(s); + // qDebug() << s; + } + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +TEST(RifEclipseInputFileToolsTest, FaultData) +{ + static const QString testDataRootFolder = QString("%1/ParsingOfDataKeywords/").arg(TEST_DATA_DIR); + + { + QString fileName = testDataRootFolder + "simulation/MY_CASE.DATA"; + + QFile data(fileName); + if (!data.open(QFile::ReadOnly)) + { + return; + } + + std::vector> pathAliasDefinitions; + RifEclipseInputFileTools::parseAndReadPathAliasKeyword(fileName, &pathAliasDefinitions); + + const QString keyword("FAULTS"); + const QString keywordToStopParsing; + const qint64 startPositionInFile = 0; + QStringList keywordContent; + std::vector fileNamesContainingKeyword; + bool isStopParsingKeywordDetected = false; + const QString includeStatementAbsolutePathPrefix; + + RifEclipseInputFileTools::readKeywordAndParseIncludeStatementsRecursively(keyword, + keywordToStopParsing, + data, + startPositionInFile, + pathAliasDefinitions, + &keywordContent, + &fileNamesContainingKeyword, + &isStopParsingKeywordDetected, + includeStatementAbsolutePathPrefix); + + EXPECT_EQ((int)1041, keywordContent.size()); + + /* + for (const auto& s : keywordContent) + { + qDebug() << s; + } + */ + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +TEST(RifEclipseInputFileToolsTest, StopAtKeyword) +{ + static const QString testDataRootFolder = QString("%1/ParsingOfDataKeywords/").arg(TEST_DATA_DIR); + QString fileName = testDataRootFolder + "simulation/MY_CASE_2.DATA"; + + QFile data(fileName); + if (!data.open(QFile::ReadOnly)) + { + return; + } + + { + const QString keyword("FAULTS"); + const QString keywordToStopParsing("EDIT"); + const qint64 startPositionInFile = 0; + std::vector> pathAliasDefinitions; + QStringList keywordContent; + std::vector fileNamesContainingKeyword; + bool isStopParsingKeywordDetected = false; + const QString includeStatementAbsolutePathPrefix; + + RifEclipseInputFileTools::readKeywordAndParseIncludeStatementsRecursively(keyword, + keywordToStopParsing, + data, + startPositionInFile, + pathAliasDefinitions, + &keywordContent, + &fileNamesContainingKeyword, + &isStopParsingKeywordDetected, + includeStatementAbsolutePathPrefix); + + EXPECT_TRUE(isStopParsingKeywordDetected); + EXPECT_TRUE(keywordContent.isEmpty()); + } + + { + const QString keyword("EQUIL"); + const QString keywordToStopParsing("SCHEDULE"); + const qint64 startPositionInFile = 0; + std::vector> pathAliasDefinitions; + QStringList keywordContent; + std::vector fileNamesContainingKeyword; + bool isStopParsingKeywordDetected = false; + const QString includeStatementAbsolutePathPrefix; + + RifEclipseInputFileTools::readKeywordAndParseIncludeStatementsRecursively(keyword, + keywordToStopParsing, + data, + startPositionInFile, + pathAliasDefinitions, + &keywordContent, + &fileNamesContainingKeyword, + &isStopParsingKeywordDetected, + includeStatementAbsolutePathPrefix); + EXPECT_TRUE(isStopParsingKeywordDetected); + EXPECT_TRUE(keywordContent.isEmpty()); + } } diff --git a/ApplicationCode/UnitTests/RifElementPropertyTableReader-Test.cpp b/ApplicationCode/UnitTests/RifElementPropertyTableReader-Test.cpp index 0683e25451..8a99951549 100644 --- a/ApplicationCode/UnitTests/RifElementPropertyTableReader-Test.cpp +++ b/ApplicationCode/UnitTests/RifElementPropertyTableReader-Test.cpp @@ -9,14 +9,14 @@ #include -static const QString TEST_DATA_DIRECTORY = QString("%1/RifElementPropertyTableReader/").arg(TEST_DATA_DIR); +static const QString ELEM_PROP_TEST_DATA_DIRECTORY = QString("%1/RifElementPropertyTableReader/").arg(TEST_DATA_DIR); //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- TEST(RicElementPropertyTableReaderTest, BasicUsage) { - RifElementPropertyMetadata metadata = RifElementPropertyTableReader::readMetadata(TEST_DATA_DIRECTORY + "ELASTIC_TABLE.inp"); + RifElementPropertyMetadata metadata = RifElementPropertyTableReader::readMetadata(ELEM_PROP_TEST_DATA_DIRECTORY + "ELASTIC_TABLE.inp"); RifElementPropertyTable table; RifElementPropertyTableReader::readData(&metadata, &table); @@ -40,7 +40,7 @@ TEST(RicElementPropertyTableReaderTest, ParseFailed) { try { - RifElementPropertyMetadata metadata = RifElementPropertyTableReader::readMetadata(TEST_DATA_DIRECTORY + "ELASTIC_TABLE_error.inp"); + RifElementPropertyMetadata metadata = RifElementPropertyTableReader::readMetadata(ELEM_PROP_TEST_DATA_DIRECTORY + "ELASTIC_TABLE_error.inp"); RifElementPropertyTable table; RifElementPropertyTableReader::readData(&metadata, &table); diff --git a/ApplicationCode/UnitTests/RifPerforationIntervalReader-Test.cpp b/ApplicationCode/UnitTests/RifPerforationIntervalReader-Test.cpp new file mode 100644 index 0000000000..cf15c0ca3b --- /dev/null +++ b/ApplicationCode/UnitTests/RifPerforationIntervalReader-Test.cpp @@ -0,0 +1,21 @@ +#include "gtest/gtest.h" + +#include "RiaTestDataDirectory.h" + +#include "RifPerforationIntervalReader.h" + +#include // Needed for HUGE_VAL on Linux +#include + +static const QString PERFORATION_TEST_DATA_DIRECTORY = QString("%1/RifPerforationIntervalReader/").arg(TEST_DATA_DIR); + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +TEST(RifPerforationIntervalReaderTest, SpacesInWellNameHandledSuccessfully) +{ + std::map > + perforationIntervals = RifPerforationIntervalReader::readPerforationIntervals(PERFORATION_TEST_DATA_DIRECTORY + "perforations_with_space_after_well_name.ev"); + + EXPECT_EQ(size_t(10), perforationIntervals["A1_RI_HZX"].size()); +} diff --git a/ApplicationCode/UnitTests/RifReaderEclipseOutput-Test.cpp b/ApplicationCode/UnitTests/RifReaderEclipseOutput-Test.cpp index a7b2e38b9f..5e36e4d141 100644 --- a/ApplicationCode/UnitTests/RifReaderEclipseOutput-Test.cpp +++ b/ApplicationCode/UnitTests/RifReaderEclipseOutput-Test.cpp @@ -25,27 +25,91 @@ #include #include "ert/ecl/ecl_kw_magic.h" +#include "RiaStringEncodingTools.h" +#include "RiaTestDataDirectory.h" #include "RifReaderEclipseOutput.h" #include "RifEclipseOutputFileTools.h" +#include "RigEclipseCaseData.h" #include "RigCaseCellResultsData.h" #include "RifEclipseUnifiedRestartFileAccess.h" #include "RifReaderSettings.h" +#include "RimEclipseResultCase.h" #include +#include + +#include +using namespace RiaDefines; //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -TEST(RigReservoirTest, BasicTest) +TEST(RigReservoirTest, BasicTest10k) +{ + QDir baseFolder(TEST_MODEL_DIR); + bool subFolderExists = baseFolder.cd("TEST10K_FLT_LGR_NNC"); + EXPECT_TRUE(subFolderExists); + QString filename("TEST10K_FLT_LGR_NNC.EGRID"); + QString filePath = baseFolder.absoluteFilePath(filename); + EXPECT_TRUE(QFile::exists(filePath)); + + std::unique_ptr resultCase(new RimEclipseResultCase); + cvf::ref reservoir = new RigEclipseCaseData(resultCase.get()); + + { + RigCaseCellResultsData* cellData = reservoir->results(MATRIX_MODEL); + + QStringList staticResults = cellData->resultNames(STATIC_NATIVE); + EXPECT_EQ(0, staticResults.size()); + //qDebug() << "Static results\n" << staticResults; + + QStringList dynamicResults = cellData->resultNames(DYNAMIC_NATIVE); + EXPECT_EQ(0, dynamicResults.size()); + //qDebug() << "Dynamic results\n" << dynamicResults; + + int numTimeSteps = static_cast(cellData->maxTimeStepCount()); + EXPECT_EQ(0, numTimeSteps); + + } + + { + cvf::ref readerInterfaceEcl = new RifReaderEclipseOutput; + bool result = readerInterfaceEcl->open(filePath, reservoir.p()); + EXPECT_TRUE(result); + int numTimeSteps = static_cast(readerInterfaceEcl->allTimeSteps().size()); + EXPECT_EQ(9, numTimeSteps); + } + + { + RigCaseCellResultsData* cellData = reservoir->results(MATRIX_MODEL); + + QStringList staticResults = cellData->resultNames(STATIC_NATIVE); + EXPECT_EQ(44, staticResults.size()); + //qDebug() << "Static results\n" << staticResults; + + QStringList dynamicResults = cellData->resultNames(DYNAMIC_NATIVE); + EXPECT_EQ(23, dynamicResults.size()); + //qDebug() << "Dynamic results\n" << dynamicResults; + + int numTimeSteps = static_cast(cellData->maxTimeStepCount()); + EXPECT_EQ(9, numTimeSteps); + } +} + +TEST(RigReservoirTest, BasicTest10kRestart) { RifEclipseUnifiedRestartFileAccess unrstAccess; -/* - QStringList filenames; - //filenames << "d:/Models/Statoil/testcase_juli_2011/data/TEST10K_FLT_LGR_NNC.UNRST"; - filenames << "d:/Models/MRST/simple/SIMPLE.UNRST"; + QDir baseFolder(TEST_MODEL_DIR); + bool subFolderExists = baseFolder.cd("TEST10K_FLT_LGR_NNC"); + EXPECT_TRUE(subFolderExists); + QString filename("TEST10K_FLT_LGR_NNC.UNRST"); + QString filePath = baseFolder.absoluteFilePath(filename); + EXPECT_TRUE(QFile::exists(filePath)); + QStringList filenames; + filenames << filePath; unrstAccess.setRestartFiles(filenames); @@ -54,70 +118,106 @@ TEST(RigReservoirTest, BasicTest) unrstAccess.resultNames(&resultNames, &dataItemCount); - for (size_t i = 0; i < resultNames.size(); i++) + EXPECT_EQ(resultNames.size(), (int) dataItemCount.size()); + EXPECT_EQ(83, resultNames.size()); + + /* for (int i = 0; i < resultNames.size(); i++) { qDebug() << resultNames[i] << "\t" << dataItemCount[i]; - } + } */ auto reportNums = unrstAccess.reportNumbers(); - for (auto reportNum : reportNums) + EXPECT_EQ((size_t) 9, reportNums.size()); + + /* for (auto reportNum : reportNums) { qDebug() << reportNum; - } -*/ - -/* - cvf::ref readerInterfaceEcl = new RifReaderEclipseOutput; - cvf::ref reservoir = new RigCaseData; + } */ +} - // Location of test dataset received from Håkon Høgstøl in July 2011 with 10k active cells -#ifdef WIN32 +TEST(RigReservoirTest, BasicTest10k_NativeECL) +{ + QDir baseFolder(TEST_MODEL_DIR); + bool subFolderExists = baseFolder.cd("TEST10K_FLT_LGR_NNC"); + EXPECT_TRUE(subFolderExists); QString filename("TEST10K_FLT_LGR_NNC.EGRID"); + QString filePath = baseFolder.absoluteFilePath(filename); + EXPECT_TRUE(QFile::exists(filePath)); + + ecl_grid_type* grid = ecl_grid_alloc(RiaStringEncodingTools::toNativeEncoded(filePath).data()); + EXPECT_TRUE(grid); + + QString subDir("RifReaderEclipseOutput"); + QDir dataDir(TEST_DATA_DIR); + dataDir.mkdir(subDir); + dataDir.cd(subDir); + QString outFilePath = dataDir.absoluteFilePath("TEST10K_FLT_LGR_NNC_OUT.GRDECL"); + +#ifdef _MSC_VER +#pragma warning (push) +#pragma warning(disable : 4996) +#endif + FILE* filePtr = fopen(RiaStringEncodingTools::toNativeEncoded(outFilePath).data(), "w"); + EXPECT_TRUE(filePtr != nullptr); + ecl_grid_fprintf_grdecl(grid, filePtr); + fclose(filePtr); + EXPECT_TRUE(QFile::exists(outFilePath)); + +#ifdef _WIN32 + QString expectedMd5(QByteArray::fromHex("e993b85140568f13f4c3849604700a0f")); #else - QString filename("/mnt/hgfs/Statoil/testcase_juli_2011/data/TEST10K_FLT_LGR_NNC.EGRID"); + QString expectedMd5(QByteArray::fromHex("274e44fe51299c1f9ca6645c384e237d")); #endif + QByteArray generatedMd5 = RifEclipseOutputFileTools::md5sum(outFilePath); - bool result = readerInterfaceEcl->open(filename, reservoir.p()); - EXPECT_TRUE(result); + // Enable to produce text string so expectedMd5 can be updated + // Qt4 doesn't take a parameter for toHex() + //qDebug() << expectedMd5.toLatin1().toHex(0) << " " << generatedMd5.toHex(0); + EXPECT_TRUE(generatedMd5 == expectedMd5); - { - QStringList staticResults = readerInterfaceEcl->staticResults(); - EXPECT_EQ(42, staticResults.size()); - qDebug() << "Static results\n" << staticResults; - - QStringList dynamicResults = readerInterfaceEcl->dynamicResults(); - EXPECT_EQ(23, dynamicResults.size()); - qDebug() << "Dynamic results\n" << dynamicResults; +#ifdef _MSC_VER +#pragma warning(pop) +#endif +} - int numTimeSteps = static_cast(readerInterfaceEcl->numTimeSteps()); - EXPECT_EQ(9, numTimeSteps); - QStringList timeStepText = readerInterfaceEcl->timeStepText(); - EXPECT_EQ(numTimeSteps, timeStepText.size()); - qDebug() << "Time step texts\n" << timeStepText; - } +TEST(RigReservoirTest, Test10k_ReadThenWriteToECL) +{ + QDir baseFolder(TEST_MODEL_DIR); + bool subFolderExists = baseFolder.cd("TEST10K_FLT_LGR_NNC"); + EXPECT_TRUE(subFolderExists); + QString filename("TEST10K_FLT_LGR_NNC.EGRID"); + QString filePath = baseFolder.absoluteFilePath(filename); + EXPECT_TRUE(QFile::exists(filePath)); + std::unique_ptr resultCase(new RimEclipseResultCase); + resultCase->setGridFileName(filePath); + resultCase->importGridAndResultMetaData(false); - readerInterfaceEcl->close(); + QString subDir("RifReaderEclipseOutput"); + QDir dataDir(TEST_DATA_DIR); + dataDir.mkdir(subDir); + dataDir.cd(subDir); + QString outFilePath = dataDir.absoluteFilePath("TEST10K_FLT_LGR_NNC_OUT_FROM_RES.GRDECL"); - { - QStringList staticResults = readerInterfaceEcl->staticResults(); - EXPECT_EQ(0, staticResults.size()); + /* bool worked = RifReaderEclipseOutput::saveEclipseGrid(outFilePath, resultCase->eclipseCaseData()); + EXPECT_TRUE(worked); + EXPECT_TRUE(QFile::exists(outFilePath)); - QStringList dynamicResults = readerInterfaceEcl->dynamicResults(); - EXPECT_EQ(0, dynamicResults.size()); + QString dataFilePath = dataDir.absoluteFilePath("TEST10K_FLT_LGR_NNC_OUT_FROM_RES.VARS"); - int numTimeSteps = static_cast(readerInterfaceEcl->numTimeSteps()); - EXPECT_EQ(0, numTimeSteps); + QStringList allStaticResults = resultCase->eclipseCaseData()->results(MATRIX_MODEL)->resultNames(RiaDefines::STATIC_NATIVE); - QStringList timeStepText = readerInterfaceEcl->timeStepText(); - EXPECT_EQ(numTimeSteps, timeStepText.size()); + std::vector keywords; + for (QString keyword : allStaticResults) + { + keywords.push_back(keyword); } -*/ + worked = RifReaderEclipseOutput::saveEclipseResults(dataFilePath, resultCase->eclipseCaseData(), keywords); + EXPECT_TRUE(worked); + EXPECT_TRUE(QFile::exists(dataFilePath)); */ } - - #if 0 diff --git a/ApplicationCode/UnitTests/RifReaderEclipseSummary-Test.cpp b/ApplicationCode/UnitTests/RifReaderEclipseSummary-Test.cpp index 9c06a46a9a..fa6003ad70 100644 --- a/ApplicationCode/UnitTests/RifReaderEclipseSummary-Test.cpp +++ b/ApplicationCode/UnitTests/RifReaderEclipseSummary-Test.cpp @@ -1,669 +1,724 @@ -///////////////////////////////////////////////////////////////////////////////// -// -// Copyright (C) Statoil ASA -// -// ResInsight 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 3 of the License, or -// (at your option) any later version. -// -// ResInsight 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 at -// for more details. -// -///////////////////////////////////////////////////////////////////////////////// - -#include "gtest/gtest.h" - -#include "RifReaderEclipseSummary.h" -#include "RifEclipseSummaryTools.h" - -//#include "stringlist.h" - -#include -#include - -#include - - -/* -void printDateAndValues(const std::vector& dates, const std::vector& values) -{ - EXPECT_TRUE(dates.size() == values.size()); - - for (size_t i = 0; i < values.size(); i++) - { - std::string dateStr = dates[i].toString("dd/MMM/yyyy").toStdString(); - - std::cout << dateStr << " " << values[i] << std::endl; - } -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -TEST(RifEclipseSummaryTest, SummaryToolsFindSummaryFiles) -{ - { -// std::string filename = "g:\\Models\\Statoil\\MultipleRealisations\\Case_without_p9\\Real10\\BRUGGE_0010"; - std::string filename = "g:\\Models\\Statoil\\testcase_juli_2011\\data\\TEST10K_FLT_LGR_NNC"; - - { - std::string headerFile; - bool isFormatted = false; - RifEclipseSummaryTools::findSummaryHeaderFile(filename, &headerFile, &isFormatted); - - EXPECT_FALSE(isFormatted); - EXPECT_FALSE(headerFile.empty()); - - std::vector dataFiles = RifEclipseSummaryTools::findSummaryDataFiles(filename); - EXPECT_TRUE(dataFiles.size() > 0); - - std::unique_ptr eclSummary = std::unique_ptr(new RifReaderEclipseSummary); - eclSummary->open(headerFile, dataFiles); - - RifEclipseSummaryTools::dumpMetaData(eclSummary.get()); - - // Create a vector of summary addresses based on type, item name and variable name, and compare the resulting - // resultAddressString to the original string - - std::vector addresses = eclSummary->allResultAddresses(); - std::vector myAddresses; - for (size_t i = 0; i < addresses.size(); i++) - { - RifEclipseSummaryAddress adr(addresses[i].category(), addresses[i].simulationItemName(), addresses[i].quantityName()); - myAddresses.push_back(adr); - } - - for (size_t i = 0; i < addresses.size(); i++) - { - EXPECT_TRUE(addresses[i].ertSummaryVarId().compare(myAddresses[i].ertSummaryVarId()) == 0); - } - } - } -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -TEST(RifEclipseSummaryTest, SummaryToolsFindSummaryFiles) -{ - { - std::string filename = "g:\\Models\\Statoil\\MultipleRealisations\\Case_without_p9\\Real10\\BRUGGE_0010"; - - { - std::string headerFile; - bool isFormatted = false; - RifEclipseSummaryTools::findSummaryHeaderFile(filename, &headerFile, &isFormatted); - - EXPECT_FALSE(isFormatted); - EXPECT_FALSE(headerFile.empty()); - - std::vector dataFiles = RifEclipseSummaryTools::findSummaryDataFiles(filename); - EXPECT_TRUE(dataFiles.size() > 0); - } - } - - { - std::string filename = "g:\\Models\\Statoil\\testcase_juli_2011\\data\\TEST10K_FLT_LGR_NNC"; - - { - std::string headerFile; - bool isFormatted = false; - RifEclipseSummaryTools::findSummaryHeaderFile(filename, &headerFile, &isFormatted); - - EXPECT_FALSE(isFormatted); - EXPECT_FALSE(headerFile.empty()); - - std::vector dataFiles = RifEclipseSummaryTools::findSummaryDataFiles(filename); - EXPECT_TRUE(dataFiles.size() > 0); - - std::unique_ptr eclSummary = std::unique_ptr(new RifReaderEclipseSummary); - eclSummary->open(headerFile, dataFiles); - - RifEclipseSummaryTools::dumpMetaData(eclSummary.get()); - } - } - - { - // MSJ TODO: Formatted output does not work now, should be reported? -/ * - std::string filename = "g:\\Models\\Statoil\\Brillig\\BRILLIG_FMTOUT"; - - { - std::string headerFile; - bool isFormatted = false; - RifEclipseSummaryTools::findSummaryHeaderFile(filename, &headerFile, &isFormatted); - - EXPECT_FALSE(isFormatted); - EXPECT_FALSE(headerFile.empty()); - - std::vector dataFiles = RifEclipseSummaryTools::findSummaryDataFiles(filename); - EXPECT_TRUE(dataFiles.size() > 0); - - std::unique_ptr eclSummary = std::unique_ptr(new RifReaderEclipseSummary); - eclSummary->open(headerFile, dataFiles); - - RifEclipseSummaryTools::dumpMetaData(eclSummary.get()); - } -* / - } - -/ * - { - std::string path; - std::string base; - bool isFormatted = false; - RifEclipseSummaryTools::findSummaryHeaderFile(filename, &path, &base, &isFormatted); - - } -* / - -} - - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -TEST(RifEclipseSummaryTest, BasicReadKeywordTest) -{ - std::unique_ptr eclSummary = std::unique_ptr(new RifReaderEclipseSummary); - - std::string filename = "g:\\Models\\Statoil\\testcase_juli_2011\\data\\TEST10K_FLT_LGR_NNC"; - - std::string headerFileName; - RifEclipseSummaryTools::findSummaryHeaderFile(filename, &headerFileName, NULL); - - std::vector dataFileNames = RifEclipseSummaryTools::findSummaryDataFiles(filename); - - eclSummary->open(headerFileName, dataFileNames); - - RifEclipseSummaryTools::dumpMetaData(eclSummary.get()); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -TEST(RifEclipseSummaryTest, DISABLE_BasicReadKeywordTest) -{ - std::unique_ptr eclSummary = std::unique_ptr(new RifReaderEclipseSummary); - - std::string filename = "g:\\Models\\Statoil\\MultipleRealisations\\Case_without_p9\\Real10\\BRUGGE_0010.SMSPEC"; - std::vector dataFileNames; - dataFileNames.push_back("g:\\Models\\Statoil\\MultipleRealisations\\Case_without_p9\\Real10\\BRUGGE_0010.S0001"); - dataFileNames.push_back("g:\\Models\\Statoil\\MultipleRealisations\\Case_without_p9\\Real10\\BRUGGE_0010.S0002"); - dataFileNames.push_back("g:\\Models\\Statoil\\MultipleRealisations\\Case_without_p9\\Real10\\BRUGGE_0010.S0003"); - eclSummary->open(filename, dataFileNames); - - std::cout << " -- Well names --" << std::endl; - { - std::vector names = eclSummary->wellNames(); - - for (size_t i = 0; i < names.size(); i++) - { - std::cout << names[i] << std::endl; - } - } - - std::cout << " -- Well variable names --" << std::endl; - { - std::vector names = eclSummary->wellVariableNames(); - - for (size_t i = 0; i < names.size(); i++) - { - std::cout << names[i] << std::endl; - } - } - - std::cout << " -- Group names --" << std::endl; - { - std::vector names = eclSummary->wellGroupNames(); - - for (size_t i = 0; i < names.size(); i++) - { - std::cout << names[i] << std::endl; - } - } - -} - - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -TEST(RifEclipseSummaryTest, BasicReadDataTest) -{ - std::unique_ptr eclSummary = std::unique_ptr(new RifReaderEclipseSummary); - - std::string filename = "g:\\Models\\Statoil\\MultipleRealisations\\Case_without_p9\\Real10\\BRUGGE_0010.SMSPEC"; - std::vector dataFileNames; - dataFileNames.push_back("g:\\Models\\Statoil\\MultipleRealisations\\Case_without_p9\\Real10\\BRUGGE_0010.S0001"); - dataFileNames.push_back("g:\\Models\\Statoil\\MultipleRealisations\\Case_without_p9\\Real10\\BRUGGE_0010.S0012"); - dataFileNames.push_back("g:\\Models\\Statoil\\MultipleRealisations\\Case_without_p9\\Real10\\BRUGGE_0010.S0023"); - eclSummary->open(filename, dataFileNames); - - std::vector dateTimes; - { - std::vector times = eclSummary->timeSteps(); - dateTimes = RifReaderEclipseSummary::fromTimeT(times); - } - - { - std::string keyword = "YEARS"; - std::cout << std::endl << keyword << std::endl; - - std::vector values; - eclSummary->values(keyword, &values); - printDateAndValues(dateTimes, values); - } - - { - std::string keyword = "WWPR:P20"; - std::cout << std::endl << keyword << std::endl; - - std::vector values; - eclSummary->values(keyword, &values); - printDateAndValues(dateTimes, values); - } - - -} - - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -TEST(RifEclipseSummaryTest, DISABLED_StringlistSelectMatchingFiles) -{ - std::string currentFolderName = "g:\\Models\\Statoil\\MultipleRealisations\\Case_without_p9\\Real10"; - //QDir::setCurrent(currentFolderName); - - //std::string filename = ""; - //std::string filepattern = "BRUGGE_0010.S[0-9][0-9][0-9][0-9]"; - std::string filepattern = "BRUGGE_0010.S*"; - //std::string filepattern = "*"; - - stringlist_type* names = stringlist_alloc_new(); - - stringlist_select_matching_files(names, currentFolderName.data(), filepattern.data()); - - for (int i = 0; i < stringlist_get_size(names); i++) - { - std::cout << stringlist_iget(names, i) << std::endl; - } - - stringlist_free(names); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -TEST(RifEclipseSummaryTest, DISABLED_StringlistSelectMatchingFilesQuestion) -{ - std::string currentFolderName = "g:\\Models\\Statoil\\MultipleRealisations\\Case_without_p9\\Real10"; - std::string filepattern = "BRUGGE_0010.S????"; - - stringlist_type* names = stringlist_alloc_new(); - - stringlist_select_matching_files(names, currentFolderName.data(), filepattern.data()); - - for (int i = 0; i < stringlist_get_size(names); i++) - { - std::cout << stringlist_iget(names, i) << std::endl; - } - - stringlist_free(names); -} - - - -/ * -WBHP:I01-01 -WBHP:I01-02 -WBHP:I01-03 -WBHP:I02 -WBHP:I02-01 -WBHP:I02-02 -WBHP:I02-03 -WBHP:I03 -WBHP:I03-01 -WBHP:I03-02 -WBHP:I03-03 -WBHP:I04 -WBHP:I04-01 -WBHP:I04-02 -WBHP:I04-03 -WBHP:I05 -WBHP:I05-01 -WBHP:I05-02 -WBHP:I05-03 -WBHP:I06 -WBHP:I06-01 -WBHP:I06-02 -WBHP:I06-03 -WBHP:I07 -WBHP:I07-01 -WBHP:I07-02 -WBHP:I07-03 -WBHP:I08 -WBHP:I08-01 -WBHP:I08-02 -WBHP:I08-03 -WBHP:I09 -WBHP:I09-01 -WBHP:I09-02 -WBHP:I09-03 -WBHP:I10 -WBHP:I10-01 -WBHP:I10-02 -WBHP:I10-03 -WBHP:P01 -WBHP:P01-01 -WBHP:P01-02 -WBHP:P01-03 -WBHP:P02 -WBHP:P02-01 -WBHP:P02-02 -WBHP:P02-03 -WBHP:P03 -WBHP:P03-01 -WBHP:P03-02 -WBHP:P03-03 -WBHP:P04 -WBHP:P04-01 -WBHP:P04-02 -WBHP:P04-03 -WBHP:P05 -WBHP:P05-01 -WBHP:P05-02 -WBHP:P06 -WBHP:P06-01 -WBHP:P06-02 -WBHP:P07 -WBHP:P07-01 -WBHP:P07-02 -WBHP:P07-03 -WBHP:P08 -WBHP:P08-01 -WBHP:P08-02 -WBHP:P08-03 -WBHP:P09 -WBHP:P09-01 -WBHP:P10 -WBHP:P10-01 -WBHP:P10-02 -WBHP:P11 -WBHP:P11-01 -WBHP:P11-02 -WBHP:P11-03 -WBHP:P12 -WBHP:P12-01 -WBHP:P12-02 -WBHP:P12-03 -WBHP:P13 -WBHP:P13-01 -WBHP:P13-02 -WBHP:P13-03 -WBHP:P14 -WBHP:P14-01 -WBHP:P14-02 -WBHP:P15 -WBHP:P15-01 -WBHP:P15-02 -WBHP:P16 -WBHP:P16-01 -WBHP:P16-02 -WBHP:P16-03 -WBHP:P17 -WBHP:P17-01 -WBHP:P17-02 -WBHP:P17-03 -WBHP:P18 -WBHP:P18-01 -WBHP:P18-02 -WBHP:P18-03 -WBHP:P19 -WBHP:P19-01 -WBHP:P19-02 -WBHP:P19-03 -WBHP:P20 -WBHP:P20-01 -WBHP:P20-02 -WBHP:P20-03 -WOPR:P01 -WOPR:P01-01 -WOPR:P01-02 -WOPR:P01-03 -WOPR:P02 -WOPR:P02-01 -WOPR:P02-02 -WOPR:P02-03 -WOPR:P03 -WOPR:P03-01 -WOPR:P03-02 -WOPR:P03-03 -WOPR:P04 -WOPR:P04-01 -WOPR:P04-02 -WOPR:P04-03 -WOPR:P05 -WOPR:P05-01 -WOPR:P05-02 -WOPR:P06 -WOPR:P06-01 -WOPR:P06-02 -WOPR:P07 -WOPR:P07-01 -WOPR:P07-02 -WOPR:P07-03 -WOPR:P08 -WOPR:P08-01 -WOPR:P08-02 -WOPR:P08-03 -WOPR:P09 -WOPR:P09-01 -WOPR:P10 -WOPR:P10-01 -WOPR:P10-02 -WOPR:P11 -WOPR:P11-01 -WOPR:P11-02 -WOPR:P11-03 -WOPR:P12 -WOPR:P12-01 -WOPR:P12-02 -WOPR:P12-03 -WOPR:P13 -WOPR:P13-01 -WOPR:P13-02 -WOPR:P13-03 -WOPR:P14 -WOPR:P14-01 -WOPR:P14-02 -WOPR:P15 -WOPR:P15-01 -WOPR:P15-02 -WOPR:P16 -WOPR:P16-01 -WOPR:P16-02 -WOPR:P16-03 -WOPR:P17 -WOPR:P17-01 -WOPR:P17-02 -WOPR:P17-03 -WOPR:P18 -WOPR:P18-01 -WOPR:P18-02 -WOPR:P18-03 -WOPR:P19 -WOPR:P19-01 -WOPR:P19-02 -WOPR:P19-03 -WOPR:P20 -WOPR:P20-01 -WOPR:P20-02 -WOPR:P20-03 -WWIR:I01 -WWIR:I01-01 -WWIR:I01-02 -WWIR:I01-03 -WWIR:I02 -WWIR:I02-01 -WWIR:I02-02 -WWIR:I02-03 -WWIR:I03 -WWIR:I03-01 -WWIR:I03-02 -WWIR:I03-03 -WWIR:I04 -WWIR:I04-01 -WWIR:I04-02 -WWIR:I04-03 -WWIR:I05 -WWIR:I05-01 -WWIR:I05-02 -WWIR:I05-03 -WWIR:I06 -WWIR:I06-01 -WWIR:I06-02 -WWIR:I06-03 -WWIR:I07 -WWIR:I07-01 -WWIR:I07-02 -WWIR:I07-03 -WWIR:I08 -WWIR:I08-01 -WWIR:I08-02 -WWIR:I08-03 -WWIR:I09 -WWIR:I09-01 -WWIR:I09-02 -WWIR:I09-03 -WWIR:I10 -WWIR:I10-01 -WWIR:I10-02 -WWIR:I10-03 -WWPR:P01 -WWPR:P01-01 -WWPR:P01-02 -WWPR:P01-03 -WWPR:P02 -WWPR:P02-01 -WWPR:P02-02 -WWPR:P02-03 -WWPR:P03 -WWPR:P03-01 -WWPR:P03-02 -WWPR:P03-03 -WWPR:P04 -WWPR:P04-01 -WWPR:P04-02 -WWPR:P04-03 -WWPR:P05 -WWPR:P05-01 -WWPR:P05-02 -WWPR:P06 -WWPR:P06-01 -WWPR:P06-02 -WWPR:P07 -WWPR:P07-01 -WWPR:P07-02 -WWPR:P07-03 -WWPR:P08 -WWPR:P08-01 -WWPR:P08-02 -WWPR:P08-03 -WWPR:P09 -WWPR:P09-01 -WWPR:P10 -WWPR:P10-01 -WWPR:P10-02 -WWPR:P11 -WWPR:P11-01 -WWPR:P11-02 -WWPR:P11-03 -WWPR:P12 -WWPR:P12-01 -WWPR:P12-02 -WWPR:P12-03 -WWPR:P13 -WWPR:P13-01 -WWPR:P13-02 -WWPR:P13-03 -WWPR:P14 -WWPR:P14-01 -WWPR:P14-02 -WWPR:P15 -WWPR:P15-01 -WWPR:P15-02 -WWPR:P16 -WWPR:P16-01 -WWPR:P16-02 -WWPR:P16-03 -WWPR:P17 -WWPR:P17-01 -WWPR:P17-02 -WWPR:P17-03 -WWPR:P18 -WWPR:P18-01 -WWPR:P18-02 -WWPR:P18-03 -WWPR:P19 -WWPR:P19-01 -WWPR:P19-02 -WWPR:P19-03 -WWPR:P20 -WWPR:P20-01 -WWPR:P20-02 -WWPR:P20-03 -YEARS -* / - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -TEST(RifEclipseSummaryTest, DISABLED_BasicTestSetCurrentFolder) -{ -/ * - std::unique_ptr eclSummary = std::unique_ptr(new RifReaderEclipseSummary); - - QString currentFolderName = "g:\\Models\\Statoil\\MultipleRealisations\\Case_without_p9\\Real10"; - QDir::setCurrent(currentFolderName); - - std::string filename = "BRUGGE_0010"; - eclSummary->open(filename); - - std::vector keywords; - eclSummary->keywords(&keywords); - - for (size_t i = 0; i < keywords.size(); i++) - { - std::cout << keywords[i] << std::endl; - } -* / -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -TEST(RifEclipseSummaryTest, DISABLED_BasicTest) -{ -/ * - std::unique_ptr eclSummary = std::unique_ptr(new RifReaderEclipseSummary); - - std::string filename = "g:\\Models\\Statoil\\MultipleRealisations\\Case_without_p9\\Real10\\BRUGGE_0010"; - eclSummary->open(filename); - - std::vector keywords; - eclSummary->keywords(&keywords); - - for (size_t i = 0; i < keywords.size(); i++) - { - std::cout << keywords[i] << std::endl; - } -* / -} -*/ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) Statoil ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "gtest/gtest.h" + +#include "RiaTestDataDirectory.h" + +#include "RifEclipseSummaryTools.h" +#include "RifReaderEclipseSummary.h" + +#include +#include + +#include + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +TEST(RifEclipseSummaryTest, BasicTestSetCurrentFolder) +{ + RifReaderEclipseSummary eclSummary; + + static const QString testDataRootFolder = QString("%1/SummaryData/Reek/").arg(TEST_DATA_DIR); + + QString summaryFileName = testDataRootFolder + "3_R001_REEK-1.SMSPEC"; + + bool hasWarning = false; + std::vector originFileInfos = eclSummary.getRestartFiles(summaryFileName, &hasWarning); + EXPECT_TRUE(originFileInfos.empty()); +} + +/* +void printDateAndValues(const std::vector& dates, const std::vector& values) +{ + EXPECT_TRUE(dates.size() == values.size()); + + for (size_t i = 0; i < values.size(); i++) + { + std::string dateStr = dates[i].toString("dd/MMM/yyyy").toStdString(); + + std::cout << dateStr << " " << values[i] << std::endl; + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +TEST(RifEclipseSummaryTest, SummaryToolsFindSummaryFiles) +{ + { +// std::string filename = "g:\\Models\\Statoil\\MultipleRealisations\\Case_without_p9\\Real10\\BRUGGE_0010"; + std::string filename = "g:\\Models\\Statoil\\testcase_juli_2011\\data\\TEST10K_FLT_LGR_NNC"; + + { + std::string headerFile; + bool isFormatted = false; + RifEclipseSummaryTools::findSummaryHeaderFile(filename, &headerFile, &isFormatted); + + EXPECT_FALSE(isFormatted); + EXPECT_FALSE(headerFile.empty()); + + std::vector dataFiles = RifEclipseSummaryTools::findSummaryDataFiles(filename); + EXPECT_TRUE(dataFiles.size() > 0); + + std::unique_ptr eclSummary = std::unique_ptr(new +RifReaderEclipseSummary); eclSummary->open(headerFile, dataFiles); + + RifEclipseSummaryTools::dumpMetaData(eclSummary.get()); + + // Create a vector of summary addresses based on type, item name and variable name, and compare the resulting + // resultAddressString to the original string + + std::vector addresses = eclSummary->allResultAddresses(); + std::vector myAddresses; + for (size_t i = 0; i < addresses.size(); i++) + { + RifEclipseSummaryAddress adr(addresses[i].category(), addresses[i].simulationItemName(), +addresses[i].quantityName()); myAddresses.push_back(adr); + } + + for (size_t i = 0; i < addresses.size(); i++) + { + EXPECT_TRUE(addresses[i].ertSummaryVarId().compare(myAddresses[i].ertSummaryVarId()) == 0); + } + } + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +TEST(RifEclipseSummaryTest, SummaryToolsFindSummaryFiles) +{ + { + std::string filename = "g:\\Models\\Statoil\\MultipleRealisations\\Case_without_p9\\Real10\\BRUGGE_0010"; + + { + std::string headerFile; + bool isFormatted = false; + RifEclipseSummaryTools::findSummaryHeaderFile(filename, &headerFile, &isFormatted); + + EXPECT_FALSE(isFormatted); + EXPECT_FALSE(headerFile.empty()); + + std::vector dataFiles = RifEclipseSummaryTools::findSummaryDataFiles(filename); + EXPECT_TRUE(dataFiles.size() > 0); + } + } + + { + std::string filename = "g:\\Models\\Statoil\\testcase_juli_2011\\data\\TEST10K_FLT_LGR_NNC"; + + { + std::string headerFile; + bool isFormatted = false; + RifEclipseSummaryTools::findSummaryHeaderFile(filename, &headerFile, &isFormatted); + + EXPECT_FALSE(isFormatted); + EXPECT_FALSE(headerFile.empty()); + + std::vector dataFiles = RifEclipseSummaryTools::findSummaryDataFiles(filename); + EXPECT_TRUE(dataFiles.size() > 0); + + std::unique_ptr eclSummary = std::unique_ptr(new +RifReaderEclipseSummary); eclSummary->open(headerFile, dataFiles); + + RifEclipseSummaryTools::dumpMetaData(eclSummary.get()); + } + } + + + + + + { + // MSJ TODO: Formatted output does not work now, should be reported? +/ * + std::string filename = "g:\\Models\\Statoil\\Brillig\\BRILLIG_FMTOUT"; + + { + std::string headerFile; + bool isFormatted = false; + RifEclipseSummaryTools::findSummaryHeaderFile(filename, &headerFile, &isFormatted); + + EXPECT_FALSE(isFormatted); + EXPECT_FALSE(headerFile.empty()); + + std::vector dataFiles = RifEclipseSummaryTools::findSummaryDataFiles(filename); + EXPECT_TRUE(dataFiles.size() > 0); + + std::unique_ptr eclSummary = std::unique_ptr(new +RifReaderEclipseSummary); eclSummary->open(headerFile, dataFiles); + + RifEclipseSummaryTools::dumpMetaData(eclSummary.get()); + } +* / + } + + + + + +/ * + { + std::string path; + std::string base; + bool isFormatted = false; + RifEclipseSummaryTools::findSummaryHeaderFile(filename, &path, &base, &isFormatted); + + } +* / + +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +TEST(RifEclipseSummaryTest, BasicReadKeywordTest) +{ + std::unique_ptr eclSummary = std::unique_ptr(new RifReaderEclipseSummary); + + + + + + std::string filename = "g:\\Models\\Statoil\\testcase_juli_2011\\data\\TEST10K_FLT_LGR_NNC"; + + std::string headerFileName; + RifEclipseSummaryTools::findSummaryHeaderFile(filename, &headerFileName, NULL); + + std::vector dataFileNames = RifEclipseSummaryTools::findSummaryDataFiles(filename); + + + + + + eclSummary->open(headerFileName, dataFileNames); + + RifEclipseSummaryTools::dumpMetaData(eclSummary.get()); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +TEST(RifEclipseSummaryTest, DISABLE_BasicReadKeywordTest) +{ + std::unique_ptr eclSummary = std::unique_ptr(new RifReaderEclipseSummary); + + + + + + std::string filename = "g:\\Models\\Statoil\\MultipleRealisations\\Case_without_p9\\Real10\\BRUGGE_0010.SMSPEC"; + std::vector dataFileNames; + dataFileNames.push_back("g:\\Models\\Statoil\\MultipleRealisations\\Case_without_p9\\Real10\\BRUGGE_0010.S0001"); + dataFileNames.push_back("g:\\Models\\Statoil\\MultipleRealisations\\Case_without_p9\\Real10\\BRUGGE_0010.S0002"); + dataFileNames.push_back("g:\\Models\\Statoil\\MultipleRealisations\\Case_without_p9\\Real10\\BRUGGE_0010.S0003"); + eclSummary->open(filename, dataFileNames); + + std::cout << " -- Well names --" << std::endl; + { + std::vector names = eclSummary->wellNames(); + + for (size_t i = 0; i < names.size(); i++) + { + std::cout << names[i] << std::endl; + } + } + + std::cout << " -- Well variable names --" << std::endl; + { + std::vector names = eclSummary->wellVariableNames(); + + for (size_t i = 0; i < names.size(); i++) + { + std::cout << names[i] << std::endl; + } + } + + std::cout << " -- Group names --" << std::endl; + { + std::vector names = eclSummary->wellGroupNames(); + + for (size_t i = 0; i < names.size(); i++) + { + std::cout << names[i] << std::endl; + } + } + +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +TEST(RifEclipseSummaryTest, BasicReadDataTest) +{ + std::unique_ptr eclSummary = std::unique_ptr(new RifReaderEclipseSummary); + + + + + + std::string filename = "g:\\Models\\Statoil\\MultipleRealisations\\Case_without_p9\\Real10\\BRUGGE_0010.SMSPEC"; + std::vector dataFileNames; + dataFileNames.push_back("g:\\Models\\Statoil\\MultipleRealisations\\Case_without_p9\\Real10\\BRUGGE_0010.S0001"); + dataFileNames.push_back("g:\\Models\\Statoil\\MultipleRealisations\\Case_without_p9\\Real10\\BRUGGE_0010.S0012"); + dataFileNames.push_back("g:\\Models\\Statoil\\MultipleRealisations\\Case_without_p9\\Real10\\BRUGGE_0010.S0023"); + eclSummary->open(filename, dataFileNames); + + std::vector dateTimes; + { + std::vector times = eclSummary->timeSteps(); + dateTimes = RifReaderEclipseSummary::fromTimeT(times); + } + + { + std::string keyword = "YEARS"; + std::cout << std::endl << keyword << std::endl; + + std::vector values; + eclSummary->values(keyword, &values); + printDateAndValues(dateTimes, values); + } + + { + std::string keyword = "WWPR:P20"; + std::cout << std::endl << keyword << std::endl; + + std::vector values; + eclSummary->values(keyword, &values); + printDateAndValues(dateTimes, values); + } + + + + + + +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +TEST(RifEclipseSummaryTest, DISABLED_StringlistSelectMatchingFiles) +{ + std::string currentFolderName = "g:\\Models\\Statoil\\MultipleRealisations\\Case_without_p9\\Real10"; + //QDir::setCurrent(currentFolderName); + + //std::string filename = ""; + //std::string filepattern = "BRUGGE_0010.S[0-9][0-9][0-9][0-9]"; + std::string filepattern = "BRUGGE_0010.S*"; + //std::string filepattern = "*"; + + stringlist_type* names = stringlist_alloc_new(); + + stringlist_select_matching_files(names, currentFolderName.data(), filepattern.data()); + + for (int i = 0; i < stringlist_get_size(names); i++) + { + std::cout << stringlist_iget(names, i) << std::endl; + } + + stringlist_free(names); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +TEST(RifEclipseSummaryTest, DISABLED_StringlistSelectMatchingFilesQuestion) +{ + std::string currentFolderName = "g:\\Models\\Statoil\\MultipleRealisations\\Case_without_p9\\Real10"; + std::string filepattern = "BRUGGE_0010.S????"; + + stringlist_type* names = stringlist_alloc_new(); + + stringlist_select_matching_files(names, currentFolderName.data(), filepattern.data()); + + for (int i = 0; i < stringlist_get_size(names); i++) + { + std::cout << stringlist_iget(names, i) << std::endl; + } + + stringlist_free(names); +} + + + +/ * +WBHP:I01-01 +WBHP:I01-02 +WBHP:I01-03 +WBHP:I02 +WBHP:I02-01 +WBHP:I02-02 +WBHP:I02-03 +WBHP:I03 +WBHP:I03-01 +WBHP:I03-02 +WBHP:I03-03 +WBHP:I04 +WBHP:I04-01 +WBHP:I04-02 +WBHP:I04-03 +WBHP:I05 +WBHP:I05-01 +WBHP:I05-02 +WBHP:I05-03 +WBHP:I06 +WBHP:I06-01 +WBHP:I06-02 +WBHP:I06-03 +WBHP:I07 +WBHP:I07-01 +WBHP:I07-02 +WBHP:I07-03 +WBHP:I08 +WBHP:I08-01 +WBHP:I08-02 +WBHP:I08-03 +WBHP:I09 +WBHP:I09-01 +WBHP:I09-02 +WBHP:I09-03 +WBHP:I10 +WBHP:I10-01 +WBHP:I10-02 +WBHP:I10-03 +WBHP:P01 +WBHP:P01-01 +WBHP:P01-02 +WBHP:P01-03 +WBHP:P02 +WBHP:P02-01 +WBHP:P02-02 +WBHP:P02-03 +WBHP:P03 +WBHP:P03-01 +WBHP:P03-02 +WBHP:P03-03 +WBHP:P04 +WBHP:P04-01 +WBHP:P04-02 +WBHP:P04-03 +WBHP:P05 +WBHP:P05-01 +WBHP:P05-02 +WBHP:P06 +WBHP:P06-01 +WBHP:P06-02 +WBHP:P07 +WBHP:P07-01 +WBHP:P07-02 +WBHP:P07-03 +WBHP:P08 +WBHP:P08-01 +WBHP:P08-02 +WBHP:P08-03 +WBHP:P09 +WBHP:P09-01 +WBHP:P10 +WBHP:P10-01 +WBHP:P10-02 +WBHP:P11 +WBHP:P11-01 +WBHP:P11-02 +WBHP:P11-03 +WBHP:P12 +WBHP:P12-01 +WBHP:P12-02 +WBHP:P12-03 +WBHP:P13 +WBHP:P13-01 +WBHP:P13-02 +WBHP:P13-03 +WBHP:P14 +WBHP:P14-01 +WBHP:P14-02 +WBHP:P15 +WBHP:P15-01 +WBHP:P15-02 +WBHP:P16 +WBHP:P16-01 +WBHP:P16-02 +WBHP:P16-03 +WBHP:P17 +WBHP:P17-01 +WBHP:P17-02 +WBHP:P17-03 +WBHP:P18 +WBHP:P18-01 +WBHP:P18-02 +WBHP:P18-03 +WBHP:P19 +WBHP:P19-01 +WBHP:P19-02 +WBHP:P19-03 +WBHP:P20 +WBHP:P20-01 +WBHP:P20-02 +WBHP:P20-03 +WOPR:P01 +WOPR:P01-01 +WOPR:P01-02 +WOPR:P01-03 +WOPR:P02 +WOPR:P02-01 +WOPR:P02-02 +WOPR:P02-03 +WOPR:P03 +WOPR:P03-01 +WOPR:P03-02 +WOPR:P03-03 +WOPR:P04 +WOPR:P04-01 +WOPR:P04-02 +WOPR:P04-03 +WOPR:P05 +WOPR:P05-01 +WOPR:P05-02 +WOPR:P06 +WOPR:P06-01 +WOPR:P06-02 +WOPR:P07 +WOPR:P07-01 +WOPR:P07-02 +WOPR:P07-03 +WOPR:P08 +WOPR:P08-01 +WOPR:P08-02 +WOPR:P08-03 +WOPR:P09 +WOPR:P09-01 +WOPR:P10 +WOPR:P10-01 +WOPR:P10-02 +WOPR:P11 +WOPR:P11-01 +WOPR:P11-02 +WOPR:P11-03 +WOPR:P12 +WOPR:P12-01 +WOPR:P12-02 +WOPR:P12-03 +WOPR:P13 +WOPR:P13-01 +WOPR:P13-02 +WOPR:P13-03 +WOPR:P14 +WOPR:P14-01 +WOPR:P14-02 +WOPR:P15 +WOPR:P15-01 +WOPR:P15-02 +WOPR:P16 +WOPR:P16-01 +WOPR:P16-02 +WOPR:P16-03 +WOPR:P17 +WOPR:P17-01 +WOPR:P17-02 +WOPR:P17-03 +WOPR:P18 +WOPR:P18-01 +WOPR:P18-02 +WOPR:P18-03 +WOPR:P19 +WOPR:P19-01 +WOPR:P19-02 +WOPR:P19-03 +WOPR:P20 +WOPR:P20-01 +WOPR:P20-02 +WOPR:P20-03 +WWIR:I01 +WWIR:I01-01 +WWIR:I01-02 +WWIR:I01-03 +WWIR:I02 +WWIR:I02-01 +WWIR:I02-02 +WWIR:I02-03 +WWIR:I03 +WWIR:I03-01 +WWIR:I03-02 +WWIR:I03-03 +WWIR:I04 +WWIR:I04-01 +WWIR:I04-02 +WWIR:I04-03 +WWIR:I05 +WWIR:I05-01 +WWIR:I05-02 +WWIR:I05-03 +WWIR:I06 +WWIR:I06-01 +WWIR:I06-02 +WWIR:I06-03 +WWIR:I07 +WWIR:I07-01 +WWIR:I07-02 +WWIR:I07-03 +WWIR:I08 +WWIR:I08-01 +WWIR:I08-02 +WWIR:I08-03 +WWIR:I09 +WWIR:I09-01 +WWIR:I09-02 +WWIR:I09-03 +WWIR:I10 +WWIR:I10-01 +WWIR:I10-02 +WWIR:I10-03 +WWPR:P01 +WWPR:P01-01 +WWPR:P01-02 +WWPR:P01-03 +WWPR:P02 +WWPR:P02-01 +WWPR:P02-02 +WWPR:P02-03 +WWPR:P03 +WWPR:P03-01 +WWPR:P03-02 +WWPR:P03-03 +WWPR:P04 +WWPR:P04-01 +WWPR:P04-02 +WWPR:P04-03 +WWPR:P05 +WWPR:P05-01 +WWPR:P05-02 +WWPR:P06 +WWPR:P06-01 +WWPR:P06-02 +WWPR:P07 +WWPR:P07-01 +WWPR:P07-02 +WWPR:P07-03 +WWPR:P08 +WWPR:P08-01 +WWPR:P08-02 +WWPR:P08-03 +WWPR:P09 +WWPR:P09-01 +WWPR:P10 +WWPR:P10-01 +WWPR:P10-02 +WWPR:P11 +WWPR:P11-01 +WWPR:P11-02 +WWPR:P11-03 +WWPR:P12 +WWPR:P12-01 +WWPR:P12-02 +WWPR:P12-03 +WWPR:P13 +WWPR:P13-01 +WWPR:P13-02 +WWPR:P13-03 +WWPR:P14 +WWPR:P14-01 +WWPR:P14-02 +WWPR:P15 +WWPR:P15-01 +WWPR:P15-02 +WWPR:P16 +WWPR:P16-01 +WWPR:P16-02 +WWPR:P16-03 +WWPR:P17 +WWPR:P17-01 +WWPR:P17-02 +WWPR:P17-03 +WWPR:P18 +WWPR:P18-01 +WWPR:P18-02 +WWPR:P18-03 +WWPR:P19 +WWPR:P19-01 +WWPR:P19-02 +WWPR:P19-03 +WWPR:P20 +WWPR:P20-01 +WWPR:P20-02 +WWPR:P20-03 +YEARS +* / + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +TEST(RifEclipseSummaryTest, DISABLED_BasicTestSetCurrentFolder) +{ +/ * + std::unique_ptr eclSummary = std::unique_ptr(new RifReaderEclipseSummary); + + + + + + QString currentFolderName = "g:\\Models\\Statoil\\MultipleRealisations\\Case_without_p9\\Real10"; + QDir::setCurrent(currentFolderName); + + std::string filename = "BRUGGE_0010"; + eclSummary->open(filename); + + std::vector keywords; + eclSummary->keywords(&keywords); + + for (size_t i = 0; i < keywords.size(); i++) + { + std::cout << keywords[i] << std::endl; + } +* / +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +TEST(RifEclipseSummaryTest, DISABLED_BasicTest) +{ +/ * + std::unique_ptr eclSummary = std::unique_ptr(new RifReaderEclipseSummary); + + + + + + std::string filename = "g:\\Models\\Statoil\\MultipleRealisations\\Case_without_p9\\Real10\\BRUGGE_0010"; + eclSummary->open(filename); + + + + + + std::vector keywords; + eclSummary->keywords(&keywords); + + for (size_t i = 0; i < keywords.size(); i++) + { + std::cout << keywords[i] << std::endl; + } +* / +} +*/ diff --git a/ApplicationCode/UnitTests/RigCellGeometryTools-Test.cpp b/ApplicationCode/UnitTests/RigCellGeometryTools-Test.cpp index 3ec9fbdc24..0ea6a45d7b 100644 --- a/ApplicationCode/UnitTests/RigCellGeometryTools-Test.cpp +++ b/ApplicationCode/UnitTests/RigCellGeometryTools-Test.cpp @@ -46,7 +46,8 @@ TEST(RigCellGeometryTools, calculateCellVolumeTest) // The overlap with the original bounding box should just yield the original bounding box cvf::BoundingBox overlapBoundingBox; - std::array overlapVertices = RigCellGeometryTools::estimateHexOverlapWithBoundingBox(cornerVertices, bbox, &overlapBoundingBox); + std::array overlapVertices; + RigCellGeometryTools::estimateHexOverlapWithBoundingBox(cornerVertices, bbox, &overlapVertices, &overlapBoundingBox); EXPECT_DOUBLE_EQ(bboxVolume, RigCellGeometryTools::calculateCellVolume(overlapVertices)); @@ -64,7 +65,8 @@ TEST(RigCellGeometryTools, calculateCellVolumeTest) corner.x() += 0.5 * bbox.extent().x(); tetrahedronBBox.add(corner); } - overlapVertices = RigCellGeometryTools::estimateHexOverlapWithBoundingBox(cornerVertices, tetrahedronBBox, &overlapBoundingBox); + overlapVertices; + RigCellGeometryTools::estimateHexOverlapWithBoundingBox(cornerVertices, tetrahedronBBox, &overlapVertices, &overlapBoundingBox); EXPECT_DOUBLE_EQ(bboxVolume * 0.5 + extraVolume, RigCellGeometryTools::calculateCellVolume(overlapVertices)); @@ -76,13 +78,13 @@ TEST(RigCellGeometryTools, calculateCellVolumeTest) corner.x() += 0.5 * bbox.extent().x(); tetrahedronBBox.add(corner); } - overlapVertices = RigCellGeometryTools::estimateHexOverlapWithBoundingBox(cornerVertices, tetrahedronBBox, &overlapBoundingBox); + RigCellGeometryTools::estimateHexOverlapWithBoundingBox(cornerVertices, tetrahedronBBox, &overlapVertices, &overlapBoundingBox); EXPECT_DOUBLE_EQ(extraVolume, RigCellGeometryTools::calculateCellVolume(overlapVertices)); // Expand original bounding box to be much larger than the hex bbox.expand(2000); - overlapVertices = RigCellGeometryTools::estimateHexOverlapWithBoundingBox(cornerVertices, bbox, &overlapBoundingBox); + RigCellGeometryTools::estimateHexOverlapWithBoundingBox(cornerVertices, bbox, &overlapVertices, &overlapBoundingBox); EXPECT_DOUBLE_EQ(bboxVolume + extraVolume, RigCellGeometryTools::calculateCellVolume(overlapVertices)); } @@ -105,20 +107,21 @@ TEST(RigCellGeometryTools, calculateCellVolumeTest2) double expectedOverlap = 50 * 50 * 25 + 0.5 * 50 * 50 * 50; cvf::BoundingBox overlapBoundingBox; - std::array overlapVertices = RigCellGeometryTools::estimateHexOverlapWithBoundingBox(cornerVertices, innerBBox, &overlapBoundingBox); + std::array overlapVertices; + RigCellGeometryTools::estimateHexOverlapWithBoundingBox(cornerVertices, innerBBox, &overlapVertices, &overlapBoundingBox); EXPECT_DOUBLE_EQ(expectedOverlap, RigCellGeometryTools::calculateCellVolume(overlapVertices)); cvf::BoundingBox smallerInnerBBox(cvf::Vec3d(25.0, 25.0, -10.0), cvf::Vec3d(75.0, 75.0, 25.0)); - overlapVertices = RigCellGeometryTools::estimateHexOverlapWithBoundingBox(cornerVertices, smallerInnerBBox, &overlapBoundingBox); + RigCellGeometryTools::estimateHexOverlapWithBoundingBox(cornerVertices, smallerInnerBBox, &overlapVertices, &overlapBoundingBox); EXPECT_DOUBLE_EQ(50 * 50 * 25, RigCellGeometryTools::calculateCellVolume(overlapVertices)); cvf::BoundingBox smallerBBox(cvf::Vec3d(50.0, 50.0, 0.0), cvf::Vec3d(100.0, 100.0, 100.0)); - overlapVertices = RigCellGeometryTools::estimateHexOverlapWithBoundingBox(cornerVertices, smallerBBox, &overlapBoundingBox); + RigCellGeometryTools::estimateHexOverlapWithBoundingBox(cornerVertices, smallerBBox, &overlapVertices, &overlapBoundingBox); double tipVolume = 50 * 50 * 50 * 0.5; EXPECT_DOUBLE_EQ(tipVolume, RigCellGeometryTools::calculateCellVolume(overlapVertices)); cvf::BoundingBox smallerBBox2(cvf::Vec3d(0.0, 0.0, 0.0), cvf::Vec3d(50.0, 50.0, 100.0)); - overlapVertices = RigCellGeometryTools::estimateHexOverlapWithBoundingBox(cornerVertices, smallerBBox2, &overlapBoundingBox); + RigCellGeometryTools::estimateHexOverlapWithBoundingBox(cornerVertices, smallerBBox2, &overlapVertices, &overlapBoundingBox); double expectedVolume = (totalCellVolume - 2*tipVolume) * 0.5; EXPECT_DOUBLE_EQ(expectedVolume, RigCellGeometryTools::calculateCellVolume(overlapVertices)); } diff --git a/ApplicationCode/UnitTests/RigWellLogExtractor-Test.cpp b/ApplicationCode/UnitTests/RigWellLogExtractor-Test.cpp index 86abb48003..99fb54f62f 100644 --- a/ApplicationCode/UnitTests/RigWellLogExtractor-Test.cpp +++ b/ApplicationCode/UnitTests/RigWellLogExtractor-Test.cpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018 Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by diff --git a/ApplicationCode/UnitTests/RimSummaryCaseCollection-Test.cpp b/ApplicationCode/UnitTests/RimSummaryCaseCollection-Test.cpp new file mode 100644 index 0000000000..5d57fd2425 --- /dev/null +++ b/ApplicationCode/UnitTests/RimSummaryCaseCollection-Test.cpp @@ -0,0 +1,59 @@ +#include "gtest/gtest.h" + +#include "RimSummaryCaseCollection.h" + +#include + +#include + +TEST(RimSummaryCaseCollection, EnsembleParameter) +{ + std::random_device rd; + std::mt19937 gen(rd()); + std::uniform_real_distribution meanDistribution(-10000.0, 10000.0); + std::uniform_real_distribution variationDistribution(0.0, 5000.0); + std::uniform_int_distribution countDistribution(1u, 1000u); + size_t N = 1000; + + std::vector parameters; + for (size_t i = 0; i < N; ++i) + { + EnsembleParameter param; + param.type = EnsembleParameter::TYPE_NUMERIC; + + size_t valueCount = countDistribution(gen); + double meanValue = meanDistribution(gen); + double range = variationDistribution(gen); + std::uniform_real_distribution valueDistribution(meanValue - range, meanValue + range); + double maxValue = -std::numeric_limits::max(); + double minValue = std::numeric_limits::max(); + for (size_t j = 0; j < valueCount; ++j) + { + double value = valueDistribution(gen); + maxValue = std::max(maxValue, value); + minValue = std::min(minValue, value); + param.values.push_back(QVariant(value)); + } + + param.minValue = minValue; + param.maxValue = maxValue; + + double normStdDev = param.normalizedStdDeviation(); + EXPECT_GE(normStdDev, 0.0); + EXPECT_LE(normStdDev, std::sqrt(2.0)); + parameters.push_back(std::make_pair(QString("%1").arg(i), param)); + } + size_t previousSize = parameters.size(); + EnsembleParameter::sortByBinnedVariation(parameters); + size_t currentSize = parameters.size(); + EXPECT_EQ(previousSize, currentSize); + + int currentVariation = (int)EnsembleParameter::HIGH_VARIATION; + for (const EnsembleParameter::NameParameterPair& nameParamPair : parameters) + { + EXPECT_GE(nameParamPair.second.variationBin, (int) EnsembleParameter::LOW_VARIATION); + EXPECT_LE(nameParamPair.second.variationBin, (int) EnsembleParameter::HIGH_VARIATION); + EXPECT_LE(nameParamPair.second.variationBin, currentVariation); + currentVariation = nameParamPair.second.variationBin; + } +} diff --git a/ApplicationCode/UnitTests/RimWellPathCompletions-Test.cpp b/ApplicationCode/UnitTests/RimWellPathCompletions-Test.cpp new file mode 100644 index 0000000000..a7529b9f39 --- /dev/null +++ b/ApplicationCode/UnitTests/RimWellPathCompletions-Test.cpp @@ -0,0 +1,50 @@ +#include "gtest/gtest.h" + +#include "RimWellPathCompletions.h" + +#include +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +TEST(RimWellPathCompletions, WellNameRegExp) +{ + std::vector validNames = { "RASASD", "gf0sdf", "sd-ASD12", "1-AA_b" }; + std::vector invalidNames = { ".AdSD", "+gf0sdf", "sd ASD12", "ABCDEFGHIJKL" }; + + QRegExp rx = RimWellPathCompletions::wellNameForExportRegExp(); + EXPECT_TRUE(rx.isValid()); + + for (QString validName : validNames) + { + EXPECT_TRUE(rx.exactMatch(validName)); + } + for (QString invalidName : invalidNames) + { + EXPECT_FALSE(rx.exactMatch(invalidName)); + } +} + +TEST(RimWellPathCompletions, WellNameRegExpValidator) +{ + std::vector validNames = {"RASASD", "gf0sdf", "sd-ASD12", "1-AA_b"}; + std::vector invalidNames = {".AdSD", "+gf0sdf", "sd ASD12", "ABCDEFGHIJKL"}; + QString emptyString = ""; + + QRegExp rx = RimWellPathCompletions::wellNameForExportRegExp(); + QRegExpValidator validator (nullptr); + validator.setRegExp(rx); + + for (QString validName : validNames) + { + int dummyPos; + EXPECT_EQ(QValidator::Acceptable, validator.validate(validName, dummyPos)); + } + for (QString invalidName : invalidNames) + { + int dummyPos; + EXPECT_EQ(QValidator::Invalid, validator.validate(invalidName, dummyPos)); + } + + int dummyPos; + EXPECT_EQ(QValidator::Intermediate, validator.validate(emptyString, dummyPos)); +} \ No newline at end of file diff --git a/ApplicationCode/UnitTests/SolveSpaceSolver-Test.cpp b/ApplicationCode/UnitTests/SolveSpaceSolver-Test.cpp index d0fc148554..b2a9cebb95 100644 --- a/ApplicationCode/UnitTests/SolveSpaceSolver-Test.cpp +++ b/ApplicationCode/UnitTests/SolveSpaceSolver-Test.cpp @@ -622,7 +622,7 @@ TEST(RiaArcCurveCalculator, Basic) { RiaArcCurveCalculator calc({ 0,0,0 }, 0, 0, { 0, 0,-1000 }); - EXPECT_TRUE(calc.curveStatus() == RiaJCurveCalculator::OK_STRAIGHT_LINE); + EXPECT_TRUE(calc.curveStatus() == RiaArcCurveCalculator::OK_STRAIGHT_LINE); cvf::Vec3d te = calc.endTangent(); EXPECT_NEAR(0, te.x(), 1e-5); diff --git a/ApplicationCode/UnitTests/TestData/.gitignore b/ApplicationCode/UnitTests/TestData/.gitignore new file mode 100644 index 0000000000..8c274c7837 --- /dev/null +++ b/ApplicationCode/UnitTests/TestData/.gitignore @@ -0,0 +1,2 @@ +RifReaderEclipseOutput/TEST10K_FLT_LGR_NNC_OUT.GRDECL +RifReaderEclipseOutput/TEST10K_FLT_LGR_NNC_OUT_FROM_RES.GRDECL \ No newline at end of file diff --git a/ApplicationCode/UnitTests/TestData/ParsingOfDataKeywords/include/grid/FAULT_JUN_05.INC b/ApplicationCode/UnitTests/TestData/ParsingOfDataKeywords/include/grid/FAULT_JUN_05.INC new file mode 100644 index 0000000000..4f2047b8ed --- /dev/null +++ b/ApplicationCode/UnitTests/TestData/ParsingOfDataKeywords/include/grid/FAULT_JUN_05.INC @@ -0,0 +1,1062 @@ +-- This reservoir simulation deck is made available under the Open Database +-- License: http://opendatacommons.org/licenses/odbl/1.0/. Any rights in +-- individual contents of the database are licensed under the Database Contents +-- License: http://opendatacommons.org/licenses/dbcl/1.0/ + +-- Copyright (C) 2015 Statoil + + +FAULTS +-- NAME IX1 IX2 IY1 IY2 IZ1 IZ2 FACE + +'m_west' 5 5 3 3 1 22 'X' / +'m_west' 5 5 4 4 1 22 'X' / +'m_west' 5 5 5 5 1 22 'X' / +'m_west' 5 5 6 6 1 22 'X' / +'m_west' 5 5 7 7 1 22 'X' / +'m_west' 5 5 8 8 1 22 'X' / +'m_west' 5 5 9 9 1 22 'X' / +'m_west' 5 5 10 10 1 22 'X' / +'m_west' 5 5 11 11 1 22 'X' / +'m_west' 5 5 12 12 1 22 'X' / +'m_west' 5 5 13 13 1 22 'X' / +'m_west' 5 5 14 14 1 22 'X' / +'m_west' 5 5 15 15 1 22 'X' / +'m_west' 5 5 16 16 1 22 'X' / +'m_west' 5 5 17 17 1 22 'X' / +'m_west' 5 5 18 18 1 22 'X' / +'m_west' 5 5 19 19 1 22 'X' / +'m_west' 5 5 20 20 1 22 'X' / +'m_west' 5 5 21 21 1 22 'X' / +'m_west' 5 5 22 22 1 22 'X' / +'m_west' 5 5 23 23 1 22 'X' / +'m_west' 5 5 24 24 1 22 'X' / +'m_west' 5 5 25 25 1 22 'X' / +'m_west' 5 5 26 26 1 22 'X' / +'m_west' 5 5 27 27 1 22 'X' / +'m_west' 5 5 28 28 1 22 'X' / +'m_west' 5 5 29 29 1 22 'X' / +'m_west' 5 5 30 30 1 22 'X' / +'m_west' 5 5 31 31 1 22 'X' / +'m_west' 5 5 32 32 1 22 'X' / +'m_west' 5 5 33 33 1 22 'X' / +'m_west' 5 5 34 34 1 22 'X' / +'m_west' 5 5 35 35 1 22 'X' / +'m_west' 5 5 36 36 1 22 'X' / +'m_west' 5 5 37 37 1 22 'X' / +'m_west' 5 5 38 38 1 22 'X' / +'m_west' 5 5 39 39 1 22 'X' / +'m_west' 5 5 40 40 1 22 'X' / +'m_west' 5 5 41 41 1 22 'X' / +'m_west' 5 5 42 42 1 22 'X' / +'m_west' 5 5 43 43 1 22 'X' / +'m_west' 5 5 44 44 1 22 'X' / +'m_west' 5 5 45 45 1 22 'X' / +'m_west' 5 5 46 46 1 22 'X' / +'m_west' 5 5 47 47 1 22 'X' / +'m_west' 5 5 48 48 1 22 'X' / +'m_west' 5 5 49 49 1 22 'X' / +'m_west' 5 5 50 50 1 22 'X' / +'m_west' 5 5 51 51 1 22 'X' / +'m_west' 5 5 52 52 1 22 'X' / +'m_west' 5 5 53 53 1 22 'X' / +'m_west' 5 5 54 54 1 22 'X' / +'m_west' 5 5 55 55 1 22 'X' / +'m_west' 5 5 56 56 1 22 'X' / +'m_west' 5 5 57 57 1 22 'X' / +'m_west' 5 5 58 58 1 22 'X' / +'m_west' 5 5 59 59 1 22 'X' / +'m_west' 5 5 60 60 1 22 'X' / +'m_west' 5 5 61 61 1 22 'X' / +'m_west' 5 5 62 62 1 22 'X' / +'m_west' 5 5 63 63 1 22 'X' / +'m_west' 5 5 64 64 1 22 'X' / +'m_west' 5 5 65 65 1 22 'X' / +'m_west' 5 5 66 66 1 22 'X' / +'m_west' 5 5 67 67 1 22 'X' / +'m_west' 5 5 68 68 1 22 'X' / +'m_west' 5 5 69 69 1 22 'X' / +'m_west' 5 5 70 70 1 22 'X' / +'m_west' 5 5 71 71 1 22 'X' / +'m_west' 5 5 72 72 1 22 'X' / +'m_west' 5 5 73 73 1 22 'X' / +'m_west' 5 5 74 74 1 22 'X' / +'m_west' 5 5 75 75 1 22 'X' / +'m_west' 5 5 76 76 1 22 'X' / +'m_west' 5 5 77 77 1 22 'X' / +'m_west' 5 5 78 78 1 22 'X' / +'m_west' 5 5 79 79 1 22 'X' / +'m_west' 5 5 80 80 1 22 'X' / +'m_west' 5 5 81 81 1 22 'X' / +'m_west' 5 5 82 82 1 22 'X' / +'m_west' 5 5 83 83 1 22 'X' / +'m_west' 5 5 84 84 1 22 'X' / +'m_west' 5 5 85 85 1 22 'X' / +'m_west' 5 5 86 86 1 22 'X' / +'m_west' 5 5 87 87 1 22 'X' / +'m_west' 5 5 88 88 1 22 'X' / + +'BC' 43 43 8 8 1 22 'Y' / +'BC' 42 42 9 9 1 22 'X' / +'BC' 44 44 8 8 1 22 'Y' / +'BC' 45 45 8 8 1 22 'Y' / +'BC' 46 46 8 8 1 22 'Y' / +'BC' 31 31 9 9 1 22 'Y' / +'BC' 30 30 10 10 1 22 'X' / +'BC' 32 32 9 9 1 22 'Y' / +'BC' 33 33 9 9 1 22 'Y' / +'BC' 34 34 9 9 1 22 'Y' / +'BC' 35 35 9 9 1 22 'Y' / +'BC' 36 36 9 9 1 22 'Y' / +'BC' 37 37 9 9 1 22 'Y' / +'BC' 38 38 9 9 1 22 'Y' / +'BC' 39 39 9 9 1 22 'Y' / +'BC' 40 40 9 9 1 22 'Y' / +'BC' 41 41 9 9 1 22 'Y' / +'BC' 42 42 9 9 1 22 'Y' / +'BC' 6 6 10 10 1 22 'Y' / +'BC' 7 7 10 10 1 22 'Y' / +'BC' 8 8 10 10 1 22 'Y' / +'BC' 9 9 10 10 1 22 'Y' / +'BC' 10 10 10 10 1 22 'Y' / +'BC' 11 11 10 10 1 22 'Y' / +'BC' 12 12 10 10 1 22 'Y' / +'BC' 13 13 10 10 1 22 'Y' / +'BC' 14 14 10 10 1 22 'Y' / +'BC' 15 15 10 10 1 22 'Y' / +'BC' 16 16 10 10 1 22 'Y' / +'BC' 17 17 10 10 1 22 'Y' / +'BC' 18 18 10 10 1 22 'Y' / +'BC' 19 19 10 10 1 22 'Y' / +'BC' 20 20 10 10 1 22 'Y' / +'BC' 21 21 10 10 1 22 'Y' / +'BC' 22 22 10 10 1 22 'Y' / +'BC' 23 23 10 10 1 22 'Y' / +'BC' 24 24 10 10 1 22 'Y' / +'BC' 25 25 10 10 1 22 'Y' / +'BC' 26 26 10 10 1 22 'Y' / +'BC' 27 27 10 10 1 22 'Y' / +'BC' 28 28 10 10 1 22 'Y' / +'BC' 29 29 10 10 1 22 'Y' / +'BC' 30 30 10 10 1 22 'Y' / + +'m_north' 6 6 89 89 1 22 'Y' / +'m_north' 5 5 89 89 1 22 'X' / +'m_north' 7 7 90 90 1 22 'Y' / +'m_north' 6 6 90 90 1 22 'X' / +'m_north' 8 8 91 91 1 22 'Y' / +'m_north' 7 7 91 91 1 22 'X' / +'m_north' 9 9 92 92 1 22 'Y' / +'m_north' 8 8 92 92 1 22 'X' / +'m_north' 9 9 93 93 1 22 'X' / +'m_north' 10 10 94 94 1 22 'Y' / +'m_north' 9 9 94 94 1 22 'X' / +'m_north' 11 11 94 94 1 22 'Y' / +'m_north' 11 11 95 95 1 22 'X' / +'m_north' 12 12 96 96 1 22 'Y' / +'m_north' 11 11 96 96 1 22 'X' / +'m_north' 13 13 97 97 1 22 'Y' / +'m_north' 12 12 97 97 1 22 'X' / +'m_north' 13 13 98 98 1 22 'X' / +'m_north' 14 14 99 99 1 22 'Y' / +'m_north' 13 13 99 99 1 22 'X' / +'m_north' 15 15 100 100 1 22 'Y' / +'m_north' 14 14 100 100 1 22 'X' / +'m_north' 16 16 100 100 1 22 'Y' / +'m_north' 17 17 100 100 1 22 'Y' / +'m_north' 18 18 101 101 1 22 'Y' / +'m_north' 17 17 101 101 1 22 'X' / +'m_north' 19 19 101 101 1 22 'Y' / +'m_north' 20 20 102 102 1 22 'Y' / +'m_north' 19 19 102 102 1 22 'X' / +'m_north' 21 21 102 102 1 22 'Y' / +'m_north' 22 22 103 103 1 22 'Y' / +'m_north' 21 21 103 103 1 22 'X' / +'m_north' 23 23 103 103 1 22 'Y' / +'m_north' 24 24 104 104 1 22 'Y' / +'m_north' 23 23 104 104 1 22 'X' / +'m_north' 25 25 104 104 1 22 'Y' / +'m_north' 26 26 105 105 1 22 'Y' / +'m_north' 25 25 105 105 1 22 'X' / +'m_north' 27 27 105 105 1 22 'Y' / +'m_north' 28 28 106 106 1 22 'Y' / +'m_north' 27 27 106 106 1 22 'X' / +'m_north' 29 29 107 107 1 22 'Y' / +'m_north' 28 28 107 107 1 22 'X' / +'m_north' 30 30 107 107 1 22 'Y' / +'m_north' 31 31 108 108 1 22 'Y' / +'m_north' 30 30 108 108 1 22 'X' / +'m_north' 32 32 108 108 1 22 'Y' / +'m_north' 33 33 109 109 1 22 'Y' / +'m_north' 32 32 109 109 1 22 'X' / +'m_north' 34 34 109 109 1 22 'Y' / +'m_north' 35 35 109 109 1 22 'Y' / +'m_north' 35 35 110 110 1 22 'X' / +'m_north' 35 35 110 110 1 22 'Y' / +'m_north' 34 34 111 111 1 22 'X' / +'m_north' 34 34 112 112 1 22 'X' / + +'EF' 7 7 79 79 1 22 'X' / +'EF' 7 7 80 80 1 22 'X' / +'EF' 8 8 81 81 1 22 'Y' / +'EF' 7 7 81 81 1 22 'X' / +'EF' 8 8 82 82 1 22 'X' / +'EF' 8 8 82 82 1 22 'Y' / +'EF' 8 8 83 83 1 22 'Y' / +'EF' 7 7 83 83 1 22 'X' / +'EF' 8 8 84 84 1 22 'X' / +'EF' 9 9 85 85 1 22 'Y' / +'EF' 8 8 85 85 1 22 'X' / +'EF' 9 9 86 86 1 22 'X' / +'EF' 9 9 87 87 1 22 'X' / +'EF' 9 9 88 88 1 22 'X' / +'EF' 9 9 89 89 1 22 'X' / +'EF' 9 9 90 90 1 22 'X' / +'EF' 9 9 91 91 1 22 'X' / +'EF' 9 9 92 92 1 22 'X' / + +--simopt +'DE_0' 8 8 49 49 1 22 'Y' / +'DE_0' 7 7 49 49 1 22 'X' / +'DE_0' 7 7 48 48 1 22 'X' / +'DE_0' 6 7 47 47 1 22 'Y' / + +'DE_B3' 9 9 49 49 1 22 'Y' / +'DE_B3' 9 9 50 50 1 22 'X' / +'DE_B3' 9 9 51 51 1 22 'X' / +'DE_B3' 9 9 52 52 1 22 'X' / +'DE_B3' 9 9 53 53 1 22 'X' / +'DE_B3' 10 10 53 53 1 22 'Y' / + +'DE_1' 10 10 54 54 1 15 'X' / +'DE_1' 11 11 54 54 1 15 'Y' / +'DE_1' 11 11 55 55 1 15 'X' / +'DE_1' 11 11 56 56 1 15 'X' / +'DE_1' 12 12 56 56 1 15 'Y' / +'DE_1' 12 12 57 57 1 15 'X' / +'DE_1' 12 12 58 58 1 15 'X' / +'DE_1' 12 12 59 59 1 15 'X' / +'DE_1' 13 13 59 59 1 15 'Y' / +'DE_1' 13 13 60 60 1 15 'X' / +'DE_1' 13 13 61 61 1 15 'X' / +'DE_1' 13 13 62 62 1 15 'X' / +'DE_1' 14 14 62 62 1 15 'Y' / +'DE_1' 14 14 63 63 1 15 'X' / +'DE_1' 14 14 64 64 1 15 'X' / +'DE_1' 14 14 65 65 1 15 'X' / +'DE_1' 15 15 65 65 1 15 'Y' / +'DE_1' 15 15 66 66 1 15 'X' / +'DE_1' 15 15 67 67 1 15 'X' / +'DE_1' 15 15 68 68 1 15 'X' / +'DE_1' 15 15 69 69 1 15 'X' / +'DE_1' 16 16 69 69 1 15 'Y' / + +'DE_1_LTo' 10 10 54 54 16 22 'X' / +'DE_1_LTo' 11 11 54 54 16 22 'Y' / +'DE_1_LTo' 11 11 55 55 16 22 'X' / +'DE_1_LTo' 11 11 56 56 16 22 'X' / +'DE_1_LTo' 12 12 56 56 16 22 'Y' / +'DE_1_LTo' 12 12 57 57 16 22 'X' / +'DE_1_LTo' 12 12 58 58 16 22 'X' / +'DE_1_LTo' 12 12 59 59 16 22 'X' / +'DE_1_LTo' 13 13 59 59 16 22 'Y' / +'DE_1_LTo' 13 13 60 60 16 22 'X' / +'DE_1_LTo' 13 13 61 61 16 22 'X' / +'DE_1_LTo' 13 13 62 62 16 22 'X' / +'DE_1_LTo' 14 14 62 62 16 22 'Y' / +'DE_1_LTo' 14 14 63 63 16 22 'X' / +'DE_1_LTo' 14 14 64 64 16 22 'X' / +'DE_1_LTo' 14 14 65 65 16 22 'X' / +'DE_1_LTo' 15 15 65 65 16 22 'Y' / +'DE_1_LTo' 15 15 66 66 16 22 'X' / +'DE_1_LTo' 15 15 67 67 16 22 'X' / +'DE_1_LTo' 15 15 68 68 16 22 'X' / +'DE_1_LTo' 15 15 69 69 16 22 'X' / +'DE_1_LTo' 16 16 69 69 16 22 'Y' / + +'DE_2' 16 16 70 70 1 22 'X' / +'DE_2' 16 16 71 71 1 22 'X' / +'DE_2' 16 16 72 72 1 22 'X' / +'DE_2' 16 16 73 73 1 22 'X' / +'DE_2' 16 16 74 74 1 22 'X' / +'DE_2' 16 16 75 75 1 22 'X' / +'DE_2' 16 16 76 76 1 22 'X' / +'DE_2' 16 16 77 77 1 22 'X' / +'DE_2' 16 16 78 78 1 22 'X' / +'DE_2' 16 16 79 79 1 22 'X' / +'DE_2' 16 16 80 80 1 22 'X' / +'DE_2' 16 16 81 81 1 22 'X' / +'DE_2' 16 16 82 82 1 22 'X' / +'DE_2' 16 16 83 83 1 22 'X' / +'DE_2' 16 16 84 84 1 22 'X' / +'DE_2' 16 16 85 85 1 22 'X' / +'DE_2' 16 16 86 86 1 22 'X' / +'DE_2' 16 16 87 87 1 22 'X' / +'DE_2' 16 16 88 88 1 22 'X' / +'DE_2' 16 16 89 89 1 22 'X' / +'DE_2' 16 16 90 90 1 22 'X' / +'DE_2' 16 16 91 91 1 22 'X' / +'DE_2' 16 16 92 92 1 22 'X' / +'DE_2' 16 16 93 93 1 22 'X' / +'DE_2' 16 16 94 94 1 22 'X' / +'DE_2' 16 16 95 95 1 22 'X' / +'DE_2' 16 16 96 96 1 22 'X' / +'DE_2' 16 16 97 97 1 22 'X' / +'DE_2' 16 16 98 98 1 22 'X' / +'DE_2' 16 16 99 99 1 22 'X' / +'DE_2' 16 16 100 100 1 22 'X' / + +'DI_S' 19 19 45 45 1 22 'X' / +'DI_S' 19 19 46 46 1 22 'X' / +'DI_S' 19 19 47 47 1 22 'X' / + +'DI' 19 19 48 48 1 22 'X' / +'DI' 19 19 49 49 1 22 'X' / +'DI' 19 19 50 50 1 22 'X' / +'DI' 19 19 51 51 1 22 'X' / +'DI' 19 19 52 52 1 22 'X' / +'DI' 19 19 53 53 1 22 'X' / +'DI' 19 19 54 54 1 22 'X' / +'DI' 19 19 55 55 1 22 'X' / +'DI' 19 19 56 56 1 22 'X' / +'DI' 19 19 57 57 1 22 'X' / +'DI' 19 19 58 58 1 22 'X' / +'DI' 19 19 59 59 1 22 'X' / +'DI' 19 19 60 60 1 22 'X' / +'DI' 19 19 61 61 1 22 'X' / +'DI' 19 19 62 62 1 22 'X' / +'DI' 19 19 63 63 1 22 'X' / +'DI' 19 19 64 64 1 22 'X' / +'DI' 19 19 65 65 1 22 'X' / +'DI' 19 19 66 66 1 22 'X' / +'DI' 19 19 67 67 1 22 'X' / +'DI' 19 19 68 68 1 22 'X' / +'DI' 19 19 69 69 1 22 'X' / +'DI' 19 19 70 70 1 22 'X' / +'DI' 19 19 71 71 1 22 'X' / +'DI' 19 19 72 72 1 22 'X' / +'DI' 19 19 73 73 1 22 'X' / +'DI' 19 19 74 74 1 22 'X' / +'DI' 19 19 75 75 1 22 'X' / +'DI' 19 19 76 76 1 22 'X' / +'DI' 19 19 77 77 1 22 'X' / +'DI' 19 19 78 78 1 22 'X' / +'DI' 19 19 79 79 1 22 'X' / +'DI' 19 19 80 80 1 22 'X' / +'DI' 19 19 81 81 1 22 'X' / +'DI' 19 19 82 82 1 22 'X' / +'DI' 19 19 83 83 1 22 'X' / +'DI' 19 19 84 84 1 22 'X' / +'DI' 19 19 85 85 1 22 'X' / +'DI' 19 19 86 86 1 22 'X' / +'DI' 19 19 87 87 1 22 'X' / +'DI' 19 19 88 88 1 22 'X' / + +-- simopt +'CD_0' 6 7 39 39 1 22 'Y' / + +'CD_B3' 7 7 39 39 1 22 'X' / +'CD_B3' 8 8 40 40 1 22 'Y' / +'CD_B3' 7 7 40 40 1 22 'X' / +'CD_B3' 9 9 41 41 1 22 'Y' / +'CD_B3' 8 8 41 41 1 22 'X' / +'CD_B3' 9 9 42 42 1 22 'X' / +'CD_B3' 10 10 43 43 1 22 'Y' / +'CD_B3' 9 9 43 43 1 22 'X' / +'CD_B3' 11 11 44 44 1 22 'Y' / +'CD_B3' 10 10 44 44 1 22 'X' / + +'CD' 12 12 45 45 1 11 'Y' / +'CD' 11 11 45 45 1 11 'X' / +'CD' 12 12 46 46 1 11 'X' / +'CD' 13 13 47 47 1 11 'Y' / +'CD' 12 12 47 47 1 11 'X' / +'CD' 14 14 48 48 1 11 'Y' / +'CD' 13 13 48 48 1 11 'X' / +'CD' 14 14 49 49 1 11 'X' / +'CD' 15 15 50 50 1 11 'Y' / +'CD' 14 14 50 50 1 11 'X' / +'CD' 16 16 51 51 1 11 'Y' / +'CD' 15 15 51 51 1 11 'X' / +'CD' 16 16 52 52 1 11 'X' / +'CD_To' 12 12 45 45 12 22 'Y' / +'CD_To' 11 11 45 45 12 22 'X' / +'CD_To' 12 12 46 46 12 22 'X' / +'CD_To' 13 13 47 47 12 22 'Y' / +'CD_To' 12 12 47 47 12 22 'X' / +'CD_To' 14 14 48 48 12 22 'Y' / +'CD_To' 13 13 48 48 12 22 'X' / +'CD_To' 14 14 49 49 12 22 'X' / +'CD_To' 15 15 50 50 12 22 'Y' / +'CD_To' 14 14 50 50 12 22 'X' / +'CD_To' 16 16 51 51 12 22 'Y' / +'CD_To' 15 15 51 51 12 22 'X' / +'CD_To' 16 16 52 52 12 22 'X' / +-- simopt +'CD_1' 16 16 53 53 1 22 'X' / +'CD_1' 17 17 53 53 1 22 'Y' / +'CD_1' 17 17 54 54 1 22 'X' / +'CD_1' 18 19 54 54 1 22 'Y' / + +'m_east' 29 29 2 2 1 22 'Y' / +'m_east' 29 29 3 3 1 22 'X' / +'m_east' 29 29 4 4 1 22 'X' / +'m_east' 29 29 5 5 1 22 'X' / +'m_east' 29 29 6 6 1 22 'X' / +'m_east' 29 29 7 7 1 22 'X' / +'m_east' 29 29 8 8 1 22 'X' / +'m_east' 29 29 9 9 1 22 'X' / +'m_east' 29 29 10 10 1 22 'X' / +'m_east' 29 29 11 11 1 22 'X' / +'m_east' 29 29 12 12 1 22 'X' / +'m_east' 29 29 13 13 1 22 'X' / +'m_east' 29 29 14 14 1 22 'X' / +'m_east' 29 29 15 15 1 22 'X' / +'m_east' 29 29 16 16 1 22 'X' / +'m_east' 29 29 17 17 1 22 'X' / +'m_east' 29 29 18 18 1 22 'X' / +'m_east' 29 29 19 19 1 22 'X' / +'m_east' 29 29 20 20 1 22 'X' / +'m_east' 29 29 21 21 1 22 'X' / +'m_east' 29 29 22 22 1 22 'X' / +'m_east' 29 29 23 23 1 22 'X' / +'m_east' 29 29 24 24 1 22 'X' / +'m_east' 29 29 25 25 1 22 'X' / +'m_east' 29 29 26 26 1 22 'X' / +'m_east' 29 29 27 27 1 22 'X' / +'m_east' 29 29 28 28 1 22 'X' / +'m_east' 29 29 29 29 1 22 'X' / +'m_east' 29 29 30 30 1 22 'X' / +'m_east' 29 29 31 31 1 22 'X' / +'m_east' 29 29 32 32 1 22 'X' / +'m_east' 29 29 33 33 1 22 'X' / +'m_east' 29 29 34 34 1 22 'X' / +'m_east' 29 29 35 35 1 22 'X' / +'m_east' 29 29 36 36 1 22 'X' / +'m_east' 29 29 37 37 1 22 'X' / +'m_east' 29 29 38 38 1 22 'X' / +'m_east' 29 29 39 39 1 22 'X' / +'m_east' 29 29 40 40 1 22 'X' / +'m_east' 29 29 41 41 1 22 'X' / +'m_east' 29 29 42 42 1 22 'X' / +'m_east' 29 29 43 43 1 22 'X' / +'m_east' 29 29 44 44 1 22 'X' / +'m_east' 29 29 45 45 1 22 'X' / +'m_east' 29 29 46 46 1 22 'X' / +'m_east' 29 29 47 47 1 22 'X' / +'m_east' 29 29 48 48 1 22 'X' / +'m_east' 29 29 49 49 1 22 'X' / +'m_east' 30 30 49 49 1 22 'Y' / +'m_east' 30 30 50 50 1 22 'X' / +'m_east' 30 30 51 51 1 22 'X' / +'m_east' 31 31 51 51 1 22 'Y' / +'m_east' 31 31 52 52 1 22 'X' / +'m_east' 32 32 52 52 1 22 'Y' / +'m_east' 32 32 53 53 1 22 'X' / +'m_east' 33 33 53 53 1 22 'Y' / +'m_east' 33 33 54 54 1 22 'X' / +'m_east' 33 33 55 55 1 22 'X' / +'m_east' 34 34 55 55 1 22 'Y' / +'m_east' 34 34 56 56 1 22 'X' / +'m_east' 34 34 57 57 1 22 'X' / +'m_east' 35 35 57 57 1 22 'Y' / +'m_east' 35 35 58 58 1 22 'X' / +'m_east' 36 36 58 58 1 22 'Y' / +'m_east' 36 36 59 59 1 22 'X' / +'m_east' 37 37 59 59 1 22 'Y' / +'m_east' 37 37 60 60 1 22 'X' / +'m_east' 38 38 60 60 1 22 'Y' / +'m_east' 38 38 61 61 1 22 'X' / +'m_east' 38 38 62 62 1 22 'X' / +'m_east' 39 39 62 62 1 22 'Y' / +'m_east' 39 39 63 63 1 22 'X' / +'m_east' 40 40 63 63 1 22 'Y' / +'m_east' 40 40 64 64 1 22 'X' / +'m_east' 41 41 64 64 1 22 'Y' / +'m_east' 41 41 65 65 1 22 'X' / +'m_east' 41 41 66 66 1 22 'X' / +'m_east' 41 41 67 67 1 22 'X' / +'m_east' 41 41 68 68 1 22 'X' / +'m_east' 41 41 69 69 1 22 'X' / +'m_east' 41 41 70 70 1 22 'X' / +'m_east' 41 41 71 71 1 22 'X' / +'m_east' 41 41 72 72 1 22 'X' / +'m_east' 41 41 73 73 1 22 'X' / +'m_east' 41 41 74 74 1 22 'X' / +'m_east' 41 41 75 75 1 22 'X' / +'m_east' 41 41 76 76 1 22 'X' / +'m_east' 41 41 77 77 1 22 'X' / +'m_east' 41 41 78 78 1 22 'X' / +'m_east' 41 41 79 79 1 22 'X' / +'m_east' 41 41 80 80 1 22 'X' / +'m_east' 41 41 81 81 1 22 'X' / +'m_east' 41 41 82 82 1 22 'X' / +'m_east' 41 41 83 83 1 22 'X' / +'m_east' 41 41 84 84 1 22 'X' / +'m_east' 41 41 85 85 1 22 'X' / +'m_east' 41 41 86 86 1 22 'X' / +'m_east' 41 41 87 87 1 22 'X' / +'m_east' 41 41 88 88 1 22 'X' / +'m_east' 41 41 89 89 1 22 'X' / +'m_east' 41 41 90 90 1 22 'X' / +'m_east' 41 41 91 91 1 22 'X' / +'m_east' 41 41 92 92 1 22 'X' / +'m_east' 41 41 93 93 1 22 'X' / +'m_east' 41 41 94 94 1 22 'X' / +'m_east' 41 41 95 95 1 22 'X' / +'m_east' 41 41 96 96 1 22 'X' / +'m_east' 41 41 97 97 1 22 'X' / +'m_east' 41 41 98 98 1 22 'X' / +'m_east' 41 41 99 99 1 22 'X' / +'m_east' 41 41 100 100 1 22 'X' / +'m_east' 41 41 101 101 1 22 'X' / +'m_east' 41 41 102 102 1 22 'X' / +'m_east' 41 41 103 103 1 22 'X' / +'m_east' 41 41 104 104 1 22 'X' / + +'B2' 23 23 6 6 1 22 'Y' / +'B2' 24 24 6 6 1 22 'Y' / +'B2' 25 25 6 6 1 22 'Y' / +'B2' 26 26 6 6 1 22 'Y' / +'B2' 27 27 6 6 1 22 'Y' / +'B2' 28 28 6 6 1 22 'Y' / +'B2' 29 29 6 6 1 22 'Y' / +'B2' 19 19 7 7 1 22 'Y' / +'B2' 20 20 7 7 1 22 'Y' / +'B2' 21 21 7 7 1 22 'Y' / +'B2' 22 22 7 7 1 22 'Y' / +'B2' 22 22 7 7 1 22 'X' / + +'D_05' 18 18 56 56 1 22 'X' / +'D_05' 18 18 57 57 1 22 'X' / +'D_05' 18 18 58 58 1 22 'X' / +'D_05' 18 18 59 59 1 22 'X' / +'D_05' 18 18 60 60 1 22 'X' / +'D_05' 18 18 61 61 1 22 'X' / +'D_05' 18 18 62 62 1 22 'X' / +'D_05' 18 18 63 63 1 22 'X' / +'D_05' 18 18 64 64 1 22 'X' / +'D_05' 18 18 64 64 1 22 'Y' / +'D_05' 17 17 65 65 1 22 'X' / + +'IH' 29 29 71 71 1 22 'Y' / +'IH' 28 28 72 72 1 22 'X' / +'IH' 28 28 73 73 1 22 'X' / +'IH' 28 28 73 73 1 22 'Y' / +'IH' 27 27 74 74 1 22 'X' / +'IH' 27 27 75 75 1 22 'X' / +'IH' 27 27 76 76 1 22 'X' / +'IH' 27 27 76 76 1 22 'Y' / +'IH' 26 26 77 77 1 22 'X' / +'IH' 26 26 78 78 1 22 'X' / +'IH' 26 26 79 79 1 22 'X' / +'IH' 26 26 80 80 1 22 'X' / +'IH' 26 26 81 81 1 22 'X' / +'IH' 26 26 82 82 1 22 'X' / +'IH' 26 26 83 83 1 22 'X' / +'IH' 26 26 83 83 1 22 'Y' / +'IH' 25 25 84 84 1 22 'X' / +'IH' 25 25 85 85 1 22 'X' / +'IH' 25 25 86 86 1 22 'X' / +'IH' 25 25 86 86 1 22 'Y' / +'IH' 24 24 87 87 1 22 'X' / +'IH' 24 24 88 88 1 22 'X' / +'IH' 24 24 89 89 1 22 'X' / +'IH' 24 24 90 90 1 22 'X' / +'IH' 24 24 91 91 1 22 'X' / +'IH' 24 24 92 92 1 22 'X' / +'IH' 24 24 93 93 1 22 'X' / +'IH' 24 24 94 94 1 22 'X' / +'IH' 24 24 95 95 1 22 'X' / +'IH' 24 24 96 96 1 22 'X' / +'IH' 24 24 97 97 1 22 'X' / +'IH' 24 24 98 98 1 22 'X' / +'IH' 24 24 99 99 1 22 'X' / +'IH' 24 24 100 100 1 22 'X' / +'IH' 24 24 101 101 1 22 'X' / + +'GH' 29 29 54 54 1 22 'Y' / +'GH' 28 28 54 54 1 22 'X' / +'GH' 29 29 55 55 1 22 'X' / +'GH' 29 29 56 56 1 22 'X' / +'GH' 29 29 57 57 1 22 'X' / +'GH' 29 29 58 58 1 22 'X' / +'GH' 29 29 59 59 1 22 'X' / +'GH' 29 29 60 60 1 22 'X' / +'GH' 29 29 61 61 1 22 'X' / +'GH' 29 29 62 62 1 22 'X' / +'GH' 29 29 63 63 1 22 'X' / +'GH' 29 29 64 64 1 22 'X' / +'GH' 29 29 65 65 1 22 'X' / +'GH' 29 29 66 66 1 22 'X' / +'GH' 29 29 67 67 1 22 'X' / +'GH' 29 29 68 68 1 22 'X' / +'GH' 29 29 69 69 1 22 'X' / +'GH' 29 29 70 70 1 22 'X' / +'GH' 29 29 71 71 1 22 'X' / +'GH' 29 29 72 72 1 22 'X' / +'GH' 29 29 73 73 1 22 'X' / +'GH' 29 29 74 74 1 22 'X' / +'GH' 29 29 75 75 1 22 'X' / +'GH' 29 29 76 76 1 22 'X' / +'GH' 29 29 77 77 1 22 'X' / +'GH' 29 29 78 78 1 22 'X' / +'GH' 29 29 79 79 1 22 'X' / +'GH' 29 29 80 80 1 22 'X' / +'GH' 29 29 81 81 1 22 'X' / +'GH' 29 29 82 82 1 22 'X' / +'GH' 29 29 83 83 1 22 'X' / +'GH' 29 29 84 84 1 22 'X' / +'GH' 29 29 85 85 1 22 'X' / +'GH' 29 29 86 86 1 22 'X' / +'GH' 29 29 87 87 1 22 'X' / +'GH' 29 29 88 88 1 22 'X' / +'GH' 29 29 89 89 1 22 'X' / +'GH' 29 29 90 90 1 22 'X' / +'GH' 29 29 91 91 1 22 'X' / +'GH' 29 29 92 92 1 22 'X' / +'GH' 30 30 93 93 1 22 'Y' / +'GH' 29 29 93 93 1 22 'X' / +'GH' 30 30 94 94 1 22 'X' / +'GH' 31 31 95 95 1 22 'Y' / +'GH' 30 30 95 95 1 22 'X' / +'GH' 32 32 95 95 1 22 'Y' / +'GH' 33 33 96 96 1 22 'Y' / +'GH' 32 32 96 96 1 22 'X' / +'GH' 34 34 97 97 1 22 'Y' / +'GH' 33 33 97 97 1 22 'X' / +'GH' 35 35 98 98 1 22 'Y' / +'GH' 34 34 98 98 1 22 'X' / +'GH' 36 36 99 99 1 22 'Y' / +'GH' 35 35 99 99 1 22 'X' / +'GH' 37 37 99 99 1 22 'Y' / +'GH' 38 38 100 100 1 22 'Y' / +'GH' 37 37 100 100 1 22 'X' / +'GH' 38 38 101 101 1 22 'X' / +'GH' 38 38 102 102 1 22 'X' / +'GH' 38 38 103 103 1 22 'X' / +'GH' 38 38 103 103 1 22 'Y' / + +'C_01' 27 27 14 14 1 22 'X' / +'C_01' 27 27 15 15 1 22 'X' / +'C_01' 27 27 16 16 1 22 'X' / +'C_01' 27 27 17 17 1 22 'X' / +'C_01' 27 27 18 18 1 22 'X' / +'C_01' 27 27 19 19 1 22 'X' / +'C_01' 27 27 20 20 1 22 'X' / +'C_01' 27 27 21 21 1 22 'X' / +'C_01' 27 27 22 22 1 22 'X' / +'C_01' 27 27 23 23 1 22 'X' / +'C_01' 27 27 24 24 1 22 'X' / +'C_01' 27 27 25 25 1 22 'X' / +'C_01' 27 27 26 26 1 22 'X' / +'C_01' 27 27 27 27 1 22 'X' / +'C_01' 27 27 28 28 1 22 'X' / +'C_01' 27 27 29 29 1 22 'X' / +'C_01' 27 27 30 30 1 22 'X' / +'C_01' 27 27 31 31 1 22 'X' / +'C_01' 27 27 32 32 1 22 'X' / +'C_01' 27 27 33 33 1 22 'X' / +'C_01' 27 27 34 34 1 22 'X' / +'C_01' 27 27 35 35 1 22 'X' / +'C_01' 27 27 36 36 1 22 'X' / +'C_01' 27 27 37 37 1 22 'X' / +'C_01' 27 27 38 38 1 22 'X' / +'C_01' 27 27 39 39 1 22 'X' / +'C_01' 27 27 40 40 1 22 'X' / +'C_01' 27 27 41 41 1 22 'X' / +'C_01' 27 27 42 42 1 22 'X' / +'C_01' 27 27 43 43 1 18 'X' / +'C_01' 27 27 44 44 1 18 'X' / +'C_01' 27 27 45 45 1 18 'X' / +'C_01' 27 27 46 46 1 18 'X' / +'C_01' 27 27 47 47 1 18 'X' / +'C_01' 27 27 48 48 1 18 'X' / + +'C_01_Ti' 27 27 43 43 19 22 'X' / +'C_01_Ti' 27 27 44 44 19 22 'X' / +'C_01_Ti' 27 27 45 45 19 22 'X' / +'C_01_Ti' 27 27 46 46 19 22 'X' / +'C_01_Ti' 27 27 47 47 19 22 'X' / +'C_01_Ti' 27 27 48 48 19 22 'X' / + +'m_northe' 43 43 105 105 1 22 'Y' / +'m_northe' 39 39 106 106 1 22 'Y' / +'m_northe' 40 40 106 106 1 22 'Y' / +'m_northe' 41 41 106 106 1 22 'Y' / +'m_northe' 42 42 106 106 1 22 'Y' / +'m_northe' 42 42 106 106 1 22 'X' / +'m_northe' 34 34 107 107 1 22 'Y' / +'m_northe' 35 35 107 107 1 22 'Y' / +'m_northe' 36 36 107 107 1 22 'Y' / +'m_northe' 37 37 107 107 1 22 'Y' / +'m_northe' 38 38 107 107 1 22 'Y' / +'m_northe' 38 38 107 107 1 22 'X' / +'m_northe' 33 33 108 108 1 22 'Y' / +'m_northe' 33 33 108 108 1 22 'X' / + +'m_east_2' 44 44 100 100 1 22 'Y' / +'m_east_2' 44 44 100 100 1 22 'X' / +'m_east_2' 43 43 101 101 1 22 'X' / +'m_east_2' 43 43 102 102 1 22 'X' / +'m_east_2' 43 43 103 103 1 22 'X' / +'m_east_2' 43 43 104 104 1 22 'X' / +'m_east_2' 43 43 105 105 1 22 'X' / + +'C_02' 7 7 19 19 1 22 'X' / +'C_02' 7 7 20 20 1 22 'X' / +'C_02' 7 7 20 20 1 22 'Y' / +'C_02' 6 6 21 21 1 22 'X' / +'C_02' 6 6 22 22 1 22 'X' / + +'C_04' 24 24 26 26 1 22 'X' / +'C_04' 24 24 27 27 1 22 'X' / +'C_04' 24 24 28 28 1 22 'X' / +'C_04' 25 25 28 28 1 22 'Y' / +'C_04' 25 25 29 29 1 22 'X' / +'C_04' 25 25 30 30 1 22 'X' / +'C_04' 25 25 31 31 1 22 'X' / +'C_04' 25 25 32 32 1 22 'X' / +'C_04' 25 25 33 33 1 22 'X' / +'C_04' 25 25 34 34 1 22 'X' / +'C_04' 25 25 35 35 1 22 'Y' / +'C_04' 25 25 35 35 1 22 'X' / + +'C_05' 13 13 42 42 1 22 'X' / +'C_05' 14 14 43 43 1 22 'Y' / +'C_05' 13 13 43 43 1 22 'X' / +'C_05' 14 14 44 44 1 22 'X' / + +'C_06' 17 17 48 48 1 22 'X' / +'C_06' 17 17 49 49 1 22 'X' / +'C_06' 18 18 50 50 1 22 'Y' / +'C_06' 17 17 50 50 1 22 'X' / +'C_06' 18 18 51 51 1 22 'X' / +'C_06' 18 18 52 52 1 22 'X' / +'C_06' 18 18 52 52 1 22 'X' / +'C_06' 19 19 52 52 1 22 'Y' / -- utvidelse for simopt + +'C_09' 22 22 49 49 1 22 'Y' / +'C_09' 22 22 50 50 1 22 'X' / +'C_09' 22 22 51 51 1 22 'X' / +'C_09' 22 22 52 52 1 22 'X' / +'C_09' 23 23 53 53 1 22 'Y' / +'C_09' 22 22 53 53 1 22 'X' / +'C_09' 23 23 54 54 1 22 'X' / +'C_09' 23 23 55 55 1 22 'X' / +'C_09' 23 23 56 56 1 22 'X' / +'C_09' 24 24 57 57 1 22 'Y' / +'C_09' 23 23 57 57 1 22 'X' / +'C_09' 24 24 58 58 1 22 'X' / +'C_09' 25 25 59 59 1 22 'Y' / +'C_09' 24 24 59 59 1 22 'X' / +'C_09' 25 25 60 60 1 22 'X' / +'C_09' 25 25 61 61 1 22 'X' / +'C_09' 25 25 62 62 1 22 'X' / +'C_09' 25 25 63 63 1 22 'X' / +'C_09' 25 25 64 64 1 22 'X' / +'C_09' 25 25 65 65 1 22 'X' / +'C_09' 25 25 66 66 1 22 'X' / +'C_09' 25 25 67 67 1 22 'X' / +'C_09' 25 25 68 68 1 22 'X' / + +'C_10' 12 12 21 21 1 22 'Y' / +'C_10' 11 11 22 22 1 22 'X' / +'C_10' 13 13 21 21 1 22 'Y' / +'C_10' 14 14 21 21 1 22 'Y' / +'C_10' 15 15 21 21 1 22 'Y' / +'C_10' 16 16 21 21 1 22 'Y' / +'C_10' 17 17 21 21 1 22 'Y' / +'C_10' 18 18 21 21 1 22 'Y' / +'C_10' 7 7 22 22 1 22 'Y' / +'C_10' 8 8 22 22 1 22 'Y' / +'C_10' 9 9 22 22 1 22 'Y' / +'C_10' 10 10 22 22 1 22 'Y' / +'C_10' 11 11 22 22 1 22 'Y' / + +'C_12' 26 26 52 52 1 22 'X' / +'C_12' 26 26 53 53 1 22 'X' / +'C_12' 26 26 54 54 1 22 'X' / +'C_12' 26 26 55 55 1 22 'X' / +'C_12' 26 26 56 56 1 22 'X' / +'C_12' 26 26 57 57 1 22 'X' / + +'C_21' 13 13 13 13 1 17 'X' / +'C_21' 13 13 14 14 1 17 'X' / +'C_21' 13 13 15 15 1 17 'X' / +'C_21' 13 13 16 16 1 17 'X' / +'C_21' 13 13 17 17 1 17 'Y' / +'C_21' 13 13 17 17 1 17 'X' / +'C_21' 12 12 18 18 1 17 'X' / +'C_21' 12 12 19 19 1 17 'X' / +'C_21' 12 12 20 20 1 17 'X' / +'C_21' 12 12 21 21 1 17 'X' / +'C_21' 12 12 22 22 1 17 'X' / +'C_21' 12 12 23 23 1 17 'X' / +'C_21' 12 12 24 24 1 17 'X' / + +'C_21_Ti' 13 13 13 13 18 22 'X' / +'C_21_Ti' 13 13 14 14 18 22 'X' / +'C_21_Ti' 13 13 15 15 18 22 'X' / +'C_21_Ti' 13 13 16 16 18 22 'X' / +'C_21_Ti' 13 13 17 17 18 22 'Y' / +'C_21_Ti' 13 13 17 17 18 22 'X' / +'C_21_Ti' 12 12 18 18 18 22 'X' / +'C_21_Ti' 12 12 19 19 18 22 'X' / +'C_21_Ti' 12 12 20 20 18 22 'X' / +'C_21_Ti' 12 12 21 21 18 22 'X' / +'C_21_Ti' 12 12 22 22 18 22 'X' / +'C_21_Ti' 12 12 23 23 18 22 'X' / +'C_21_Ti' 12 12 24 24 18 22 'X' / + +'C_22' 14 14 15 15 1 22 'X' / +'C_22' 14 14 16 16 1 22 'X' / +'C_22' 14 14 16 16 1 22 'Y' / +'C_22' 13 13 17 17 1 22 'X' / +'C_22' 13 13 18 18 1 22 'X' / + +'C_23' 20 20 20 20 1 22 'Y' / +'C_23' 21 21 20 20 1 22 'Y' / +'C_23' 22 22 20 20 1 22 'Y' / + +'C_24' 18 18 26 26 1 22 'Y' / +'C_24' 17 17 27 27 1 22 'X' / + +'C_25' 22 22 25 25 1 22 'X' / +'C_25' 22 22 25 25 1 22 'Y' / +'C_25' 21 21 26 26 1 22 'X' / +'C_25' 21 21 27 27 1 22 'X' / +'C_25' 21 21 28 28 1 22 'X' / +'C_25' 21 21 29 29 1 22 'X' / +'C_25' 21 21 30 30 1 22 'X' / + +'C_26' 9 9 28 28 1 22 'X' / +'C_26' 9 9 29 29 1 22 'X' / +'C_26' 9 9 30 30 1 22 'X' / +'C_26' 9 9 31 31 1 22 'X' / +'C_26' 9 9 32 32 1 22 'Y' / +'C_26' 9 9 32 32 1 22 'X' / +'C_26' 8 8 33 33 1 22 'X' / +'C_26' 8 8 34 34 1 22 'X' / +'C_26' 8 8 35 35 1 22 'X' / +'C_26' 8 8 36 36 1 22 'Y' / +'C_26' 8 8 36 36 1 22 'X' / + +'C_26N' 7 7 37 37 1 22 'X' / +'C_26N' 7 7 38 38 1 22 'X' / +'C_26N' 7 7 39 39 1 22 'X' / +'C_26N' 7 7 40 40 1 22 'X' / +'C_26N' 7 7 41 41 1 22 'X' / +'C_26N' 7 7 42 42 1 22 'X' / +'C_26N' 7 7 43 43 1 22 'X' / +'C_26N' 8 8 43 43 1 22 'Y' / +'C_26N' 8 8 44 44 1 22 'X' / + +'C_27' 10 10 30 30 1 22 'Y' / +'C_27' 10 10 31 31 1 22 'X' / +'C_27' 10 10 32 32 1 22 'X' / +'C_27' 10 10 33 33 1 22 'X' / +'C_27' 10 10 34 34 1 22 'X' / +'C_27' 10 10 35 35 1 22 'X' / +'C_27' 10 10 36 36 1 22 'X' / +'C_27' 10 10 37 37 1 22 'X' / +'C_27' 10 10 38 38 1 22 'X' / + +'C_28' 16 16 39 39 1 22 'Y' / +'C_28' 16 16 39 39 1 22 'X' / +'C_28' 15 15 40 40 1 22 'X' / + +'C_29' 15 15 44 44 1 22 'X' / +'C_29' 15 15 45 45 1 22 'X' / +'C_29' 16 16 46 46 1 22 'Y' / +'C_29' 15 15 46 46 1 22 'X' / +'C_29' 16 16 47 47 1 22 'X' / + +'C_08_S' 25 25 41 41 1 19 'X' / +'C_08_S' 25 25 42 42 1 19 'X' / +'C_08_S' 25 25 43 43 1 19 'X' / +'C_08_S' 25 25 44 44 1 19 'X' / +'C_08_S' 25 25 45 45 1 19 'X' / + +'C_08' 25 25 46 46 11 19 'X' / +'C_08' 25 25 47 47 11 19 'X' / +'C_08' 25 25 48 48 11 19 'X' / +'C_08' 25 25 49 49 11 19 'X' / +'C_08' 25 25 50 50 11 19 'X' / +'C_08' 25 25 51 51 11 19 'X' / +'C_08' 25 25 52 52 11 19 'X' / + +'C_08_Ile' 25 25 46 46 1 10 'X' / +'C_08_Ile' 25 25 47 47 1 10 'X' / +'C_08_Ile' 25 25 48 48 1 10 'X' / +'C_08_Ile' 25 25 49 49 1 10 'X' / +'C_08_Ile' 25 25 50 50 1 10 'X' / +'C_08_Ile' 25 25 51 51 1 10 'X' / +'C_08_Ile' 25 25 52 52 1 10 'X' / + + +'C_08_S_Ti' 25 25 41 41 20 22 'X' / +'C_08_S_Ti' 25 25 42 42 20 22 'X' / +'C_08_S_Ti' 25 25 43 43 20 22 'X' / +'C_08_S_Ti' 25 25 44 44 20 22 'X' / +'C_08_S_Ti' 25 25 45 45 20 22 'X' / + +'C_08_Ti' 25 25 46 46 20 22 'X' / +'C_08_Ti' 25 25 47 47 20 22 'X' / +'C_08_Ti' 25 25 48 48 20 22 'X' / +'C_08_Ti' 25 25 49 49 20 22 'X' / +'C_08_Ti' 25 25 50 50 20 22 'X' / +'C_08_Ti' 25 25 51 51 20 22 'X' / +'C_08_Ti' 25 25 52 52 20 22 'X' / + +'C_20' 24 24 36 36 1 15 'Y' / +'C_20' 23 23 37 37 1 15 'X' / +'C_20' 23 23 38 38 1 15 'X' / +'C_20' 23 23 38 38 1 15 'Y' / +'C_20' 22 22 39 39 1 15 'X' / + +'C_20_LTo' 24 24 36 36 16 22 'Y' / +'C_20_LTo' 23 23 37 37 16 22 'X' / +'C_20_LTo' 23 23 38 38 16 22 'X' / +'C_20_LTo' 23 23 38 38 16 22 'Y' / +'C_20_LTo' 22 22 39 39 16 22 'X' / + +--'E_01_2' 7 7 54 54 1 22 'X' / +--'E_01_2' 7 7 55 55 1 22 'X' / +--'E_01_2' 8 8 56 56 1 22 'Y' / +--'E_01_2' 7 7 56 56 1 22 'X' / +'E_01_F3' 8 8 57 57 1 22 'X' / +'E_01_F3' 8 8 58 58 1 22 'X' / +'E_01_F3' 8 8 59 59 1 22 'X' / +'E_01_F3' 8 8 60 60 1 22 'X' / +'E_01_F3' 9 9 61 61 1 22 'Y' / +'E_01_F3' 8 8 61 61 1 22 'X' / + +'E_01' 9 9 62 62 1 22 'X' / +'E_01' 9 9 63 63 1 22 'X' / + +'E_01' 9 9 64 64 1 22 'X' / +'E_01' 9 9 65 65 1 22 'X' / +'E_01' 10 10 66 66 1 22 'Y' / +'E_01' 9 9 66 66 1 22 'X' / +'E_01' 10 10 67 67 1 22 'X' / +'E_01' 10 10 68 68 1 22 'X' / +'E_01' 10 10 69 69 1 22 'X' / +'E_01' 11 11 70 70 1 22 'Y' / +'E_01' 10 10 70 70 1 22 'X' / +'E_01' 11 11 71 71 1 22 'X' / +'E_01' 11 11 72 72 1 22 'X' / +'E_01' 12 12 73 73 1 22 'Y' / +'E_01' 11 11 73 73 1 22 'X' / + +'E_01' 12 12 74 74 1 22 'X' / +'E_01' 12 12 75 75 1 22 'X' / +'E_01' 12 12 76 76 1 22 'X' / +'E_01' 13 13 77 77 1 22 'Y' / +'E_01' 12 12 77 77 1 22 'X' / +'E_01' 13 13 78 78 1 22 'X' / +'E_01' 13 13 79 79 1 22 'X' / +'E_01' 14 14 80 80 1 22 'Y' / +'E_01' 13 13 80 80 1 22 'X' / +'E_01' 14 14 81 81 1 22 'X' / + +-- simopt +'E_01' 15 16 81 81 1 22 'Y' / + +'G_01' 33 33 72 72 1 22 'Y' / +'G_01' 32 32 72 72 1 22 'X' / +'G_01' 33 33 73 73 1 22 'X' / +'G_01' 33 33 74 74 1 22 'X' / +'G_01' 33 33 75 75 1 22 'X' / +'G_01' 33 33 76 76 1 22 'X' / +'G_01' 33 33 77 77 1 22 'X' / +'G_01' 33 33 78 78 1 22 'X' / +'G_01' 33 33 79 79 1 22 'X' / +'G_01' 33 33 80 80 1 22 'X' / +'G_01' 33 33 81 81 1 22 'X' / +'G_01' 33 33 81 81 1 22 'Y' / +'G_01' 32 32 82 82 1 22 'X' / +'G_01' 32 32 83 83 1 22 'X' / +'G_01' 32 32 84 84 1 22 'X' / +'G_01' 32 32 84 84 1 22 'Y' / +'G_01' 31 31 85 85 1 22 'X' / +'G_01' 31 31 85 85 1 22 'Y' / +'G_01' 30 30 86 86 1 22 'X' / + +'G_02' 35 35 73 73 1 22 'X' / +'G_02' 36 36 74 74 1 22 'Y' / +'G_02' 35 35 74 74 1 22 'X' / +'G_02' 36 36 75 75 1 22 'X' / + +'G_03' 34 34 70 70 1 22 'Y' / +'G_03' 35 35 70 70 1 22 'Y' / +'G_03' 36 36 70 70 1 22 'Y' / +'G_03' 37 37 70 70 1 22 'Y' / + +'G_05' 34 34 62 62 1 22 'Y' / +'G_05' 35 35 62 62 1 22 'Y' / +'G_05' 35 35 62 62 1 22 'X' / +'G_05' 33 33 63 63 1 22 'Y' / +'G_05' 33 33 63 63 1 22 'X' / +'G_05' 32 32 64 64 1 22 'Y' / +'G_05' 32 32 64 64 1 22 'X' / +'G_05' 31 31 65 65 1 22 'X' / + +'G_07' 37 37 80 80 1 22 'Y' / +'G_07' 36 36 81 81 1 22 'X' / +'G_07' 36 36 82 82 1 22 'X' / +'G_07' 36 36 83 83 1 22 'X' / +'G_07' 36 36 84 84 1 22 'X' / +'G_07' 36 36 84 84 1 22 'Y' / +'G_07' 35 35 85 85 1 22 'X' / +'G_07' 35 35 85 85 1 22 'Y' / +'G_07' 34 34 86 86 1 22 'X' / +'G_07' 34 34 86 86 1 22 'Y' / +'G_07' 33 33 87 87 1 22 'X' / +'G_07' 33 33 87 87 1 22 'Y' / +'G_07' 32 32 88 88 1 22 'X' / +'G_07' 32 32 88 88 1 22 'Y' / +'G_07' 31 31 89 89 1 22 'X' / +'G_07' 31 31 90 90 1 22 'X' / +'G_07' 31 31 91 91 1 22 'X' / +'G_07' 31 31 92 92 1 22 'X' / + +'G_08' 34 34 105 105 1 22 'X' / +'G_08' 34 34 106 106 1 22 'X' / +'G_08' 34 34 107 107 1 22 'X' / + +'G_09' 36 36 67 67 1 22 'Y' / +'G_09' 35 35 68 68 1 22 'X' / +'G_09' 37 37 67 67 1 22 'Y' / +'G_09' 34 34 68 68 1 22 'Y' / +'G_09' 33 33 69 69 1 22 'X' / +'G_09' 35 35 68 68 1 22 'Y' / +'G_09' 32 32 69 69 1 22 'Y' / +'G_09' 31 31 70 70 1 22 'X' / +'G_09' 33 33 69 69 1 22 'Y' / +'G_09' 31 31 70 70 1 22 'Y' / + +'G_13' 36 36 65 65 1 22 'X' / +'G_13' 37 37 65 65 1 22 'Y' / +'G_13' 38 38 65 65 1 22 'Y' / +'G_13' 38 38 66 66 1 22 'X' / +'G_13' 38 38 67 67 1 22 'X' / +'G_13' 39 39 67 67 1 22 'Y' / +'G_13' 39 39 68 68 1 22 'X' / +'G_13' 40 40 68 68 1 22 'Y' / +'G_13' 40 40 69 69 1 22 'X' / + +'H_03' 21 21 96 96 1 22 'X' / +'H_03' 21 21 97 97 1 22 'X' / +'H_03' 22 22 97 97 1 22 'Y' / +'H_03' 22 22 98 98 1 22 'X' / +'H_03' 22 22 99 99 1 22 'X' / +'H_03' 22 22 100 100 1 22 'X' / +'H_03' 23 23 100 100 1 22 'Y' / +'H_03' 23 23 101 101 1 22 'X' / +'H_03' 23 23 102 102 1 22 'X' / +'H_03' 24 24 102 102 1 22 'Y' / + +/ +-- MFSEGS should be set to at least 891 +-- in the FAULTDIM keyword in RUNSPEC section diff --git a/ApplicationCode/UnitTests/TestData/ParsingOfDataKeywords/include/solution/equilibiration.inc b/ApplicationCode/UnitTests/TestData/ParsingOfDataKeywords/include/solution/equilibiration.inc new file mode 100644 index 0000000000..206a2df308 --- /dev/null +++ b/ApplicationCode/UnitTests/TestData/ParsingOfDataKeywords/include/solution/equilibiration.inc @@ -0,0 +1,13 @@ +EQUIL +-- Datum P-datum WOC Pcwoc GOC Pcgoc RSVD RSVD + 1950 634.8 1940 0.00 3904 0.00 1 1 / asdf + 1950 634.8 1944 0.00 3904 0.00 2 2 / asdf + 1950 634.8 1898.5 0.00 3898.5 0.00 3 3 / sdfsdfsdf + 1950 634 2020 0.00 4020 0.00 4 4 / ssss + 1821.94 629.35 1883 0.00 3000 0.00 5 5 20/ sdfsdf + 1821.94 629.35 1877 0.00 3000 0.00 6 6 / abab + 1950 634.8 1944 0.00 3650 0.00 7 7 / aaa + 1950 634.8 1944 0.00 3650 0.00 8 8 / bbb + 1950 634.8 1820.5 0.00 3811 0.00 9 9 / ddd + 1950 634.8 1892 0.00 3821 0.00 10 10 / sdf +-- 1950 634.8 1913 0.00 3871 0.00 11 11 / sdf diff --git a/ApplicationCode/UnitTests/TestData/ParsingOfDataKeywords/simulation/MY_CASE.DATA b/ApplicationCode/UnitTests/TestData/ParsingOfDataKeywords/simulation/MY_CASE.DATA new file mode 100644 index 0000000000..f6fdc5e427 --- /dev/null +++ b/ApplicationCode/UnitTests/TestData/ParsingOfDataKeywords/simulation/MY_CASE.DATA @@ -0,0 +1,6 @@ +INCLUDE + '../include/solution/equilibiration.inc' / + + INCLUDE +'../include/grid/FAULT_JUN_05.INC'/ + diff --git a/ApplicationCode/UnitTests/TestData/ParsingOfDataKeywords/simulation/MY_CASE_2.DATA b/ApplicationCode/UnitTests/TestData/ParsingOfDataKeywords/simulation/MY_CASE_2.DATA new file mode 100644 index 0000000000..6b5742dc20 --- /dev/null +++ b/ApplicationCode/UnitTests/TestData/ParsingOfDataKeywords/simulation/MY_CASE_2.DATA @@ -0,0 +1,12 @@ + + +EDIT +-- searching for faults stops when EDIT keyword is detected + INCLUDE +'../include/grid/FAULT_JUN_05.INC'/ + +SCHEDULE + +-- searching for EQUIL stops when SCHEDULE keyword is detected +INCLUDE + '../include/solution/equilibiration.inc' / diff --git a/ApplicationCode/UnitTests/TestData/RifPerforationIntervalReader/perforations_with_space_after_well_name.ev b/ApplicationCode/UnitTests/TestData/RifPerforationIntervalReader/perforations_with_space_after_well_name.ev new file mode 100644 index 0000000000..1b2d940749 --- /dev/null +++ b/ApplicationCode/UnitTests/TestData/RifPerforationIntervalReader/perforations_with_space_after_well_name.ev @@ -0,0 +1,12 @@ +UNITS METRIC +WELLNAME A1_RI_HZX +"SOH" perforation 2010 2060 0.212 0 +"SOH" perforation 2080 2130 0.212 0 +"SOH" perforation 2150 2200 0.212 0 +"SOH" perforation 2220 2270 0.212 0 +"SOH" perforation 2290 2340 0.212 0 +"SOH" perforation 2360 2410 0.212 0 +"SOH" perforation 2430 2480 0.212 0 +"SOH" perforation 2500 2550 0.212 0 +"SOH" perforation 2570 2620 0.212 0 +"SOH" perforation 2640 2690 0.212 0 diff --git a/ApplicationCode/UnitTests/TestData/SummaryData/Reek/3_R001_REEK-1.SMSPEC b/ApplicationCode/UnitTests/TestData/SummaryData/Reek/3_R001_REEK-1.SMSPEC new file mode 100644 index 0000000000..3999d1be59 Binary files /dev/null and b/ApplicationCode/UnitTests/TestData/SummaryData/Reek/3_R001_REEK-1.SMSPEC differ diff --git a/ApplicationCode/UnitTests/TestData/SummaryData/Reek/3_R001_REEK-1.UNSMRY b/ApplicationCode/UnitTests/TestData/SummaryData/Reek/3_R001_REEK-1.UNSMRY new file mode 100644 index 0000000000..93baae94ac Binary files /dev/null and b/ApplicationCode/UnitTests/TestData/SummaryData/Reek/3_R001_REEK-1.UNSMRY differ diff --git a/ApplicationCode/UnitTests/cvfGeometryTools-Test.cpp b/ApplicationCode/UnitTests/cvfGeometryTools-Test.cpp index 606f8cba8c..614994e932 100644 --- a/ApplicationCode/UnitTests/cvfGeometryTools-Test.cpp +++ b/ApplicationCode/UnitTests/cvfGeometryTools-Test.cpp @@ -2,17 +2,17 @@ // // Copyright (C) Statoil ASA // Copyright (C) Ceetron Solutions AS -// +// // ResInsight 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 3 of the License, or // (at your option) any later version. -// +// // ResInsight 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 at +// +// See the GNU General Public License at // for more details. // ///////////////////////////////////////////////////////////////////////////////// @@ -20,15 +20,15 @@ #include "gtest/gtest.h" #include "cvfLibCore.h" -#include "cvfLibViewing.h" -#include "cvfLibRender.h" #include "cvfLibGeometry.h" +#include "cvfLibRender.h" +#include "cvfLibViewing.h" -#include "cvfArrayWrapperToEdit.h" #include "cvfArrayWrapperConst.h" +#include "cvfArrayWrapperToEdit.h" -#include "cvfGeometryTools.h" #include "cvfBoundingBoxTree.h" +#include "cvfGeometryTools.h" #include @@ -86,23 +86,22 @@ void ControlVolume::calculateCubeFaceStatus(const cvf::Vec3dArray& nodeCoords, d } #endif - -template -NodeType quadNormal (ArrayWrapperConst nodeCoords, - const IndexType cubeFaceIndices[4] ) +template +NodeType quadNormal(ArrayWrapperConst nodeCoords, const IndexType cubeFaceIndices[4]) { - return ( nodeCoords[cubeFaceIndices[2]] - nodeCoords[cubeFaceIndices[0]]) ^ - ( nodeCoords[cubeFaceIndices[3]] - nodeCoords[cubeFaceIndices[1]]); + return (nodeCoords[cubeFaceIndices[2]] - nodeCoords[cubeFaceIndices[0]]) ^ + (nodeCoords[cubeFaceIndices[3]] - nodeCoords[cubeFaceIndices[1]]); } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- std::vector createVertices() { std::vector vxs; vxs.resize(14, cvf::Vec3d::ZERO); + // clang-format off vxs[ 0]= cvf::Vec3d( 0 , 0 , 0 ); vxs[ 1]= cvf::Vec3d( 1 , 0 , 0 ); vxs[ 2]= cvf::Vec3d( 1 , 1 , 0 ); @@ -117,26 +116,27 @@ std::vector createVertices() vxs[11]= cvf::Vec3d( 1.2 , 0.6 , 0.0 ); vxs[12]= cvf::Vec3d( 1.6 , 0.2 , 0.0 ); vxs[13]= cvf::Vec3d( 0.8 ,-0.6 , 0.0 ); - + // clang-format on + return vxs; } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- std::vector> getCubeFaces() { std::vector> cubeFaces; cubeFaces.resize(4); - cubeFaces[0] = { 0, 1, 2, 3 }; - cubeFaces[1] = { 4, 5, 6, 7 }; - cubeFaces[2] = { 5, 8, 9, 6 }; - cubeFaces[3] = { 10, 11, 12, 13 }; + cubeFaces[0] = {0, 1, 2, 3}; + cubeFaces[1] = {4, 5, 6, 7}; + cubeFaces[2] = {5, 8, 9, 6}; + cubeFaces[3] = {10, 11, 12, 13}; return cubeFaces; } -std::ostream& operator<< (std::ostream& stream, std::vector v) +std::ostream& operator<<(std::ostream& stream, std::vector v) { for (size_t i = 0; i < v.size(); ++i) { @@ -146,7 +146,7 @@ std::ostream& operator<< (std::ostream& stream, std::vector v) } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- TEST(CellFaceIntersectionTst, Intersection1) { @@ -154,187 +154,162 @@ TEST(CellFaceIntersectionTst, Intersection1) std::vector additionalVertices; - std::vector< std::vector > overlapPolygons; - auto faces = getCubeFaces(); + std::vector> overlapPolygons; + auto faces = getCubeFaces(); EdgeIntersectStorage edgeIntersectionStorage; edgeIntersectionStorage.setVertexCount(nodes.size()); { std::vector polygon; - bool isOk = GeometryTools::calculateOverlapPolygonOfTwoQuads( - &polygon, - &additionalVertices, - &edgeIntersectionStorage, - wrapArrayConst(&nodes), - faces[0].data(), - faces[1].data(), - 1e-6); - - EXPECT_EQ( (size_t)5, polygon.size()); - EXPECT_EQ( (size_t)2, additionalVertices.size()); + bool isOk = GeometryTools::calculateOverlapPolygonOfTwoQuads(&polygon, + &additionalVertices, + &edgeIntersectionStorage, + wrapArrayConst(&nodes), + faces[0].data(), + faces[1].data(), + 1e-6); + + EXPECT_EQ((size_t)5, polygon.size()); + EXPECT_EQ((size_t)2, additionalVertices.size()); EXPECT_TRUE(isOk); overlapPolygons.push_back(polygon); std::cout << polygon << std::endl; - } - + { std::vector polygon; - bool isOk = GeometryTools::calculateOverlapPolygonOfTwoQuads( - &polygon, - &additionalVertices, - &edgeIntersectionStorage, - wrapArrayConst(&nodes), - faces[0].data(), - faces[2].data(), - 1e-6); - - EXPECT_EQ( (size_t)5, polygon.size()); - EXPECT_EQ( (size_t)4, additionalVertices.size()); + bool isOk = GeometryTools::calculateOverlapPolygonOfTwoQuads(&polygon, + &additionalVertices, + &edgeIntersectionStorage, + wrapArrayConst(&nodes), + faces[0].data(), + faces[2].data(), + 1e-6); + + EXPECT_EQ((size_t)5, polygon.size()); + EXPECT_EQ((size_t)4, additionalVertices.size()); EXPECT_TRUE(isOk); overlapPolygons.push_back(polygon); std::cout << polygon << std::endl; - } { std::vector polygon; - bool isOk = GeometryTools::calculateOverlapPolygonOfTwoQuads( - &polygon, - &additionalVertices, - &edgeIntersectionStorage, - wrapArrayConst(&nodes), - faces[0].data(), - faces[3].data(), - 1e-6); - - EXPECT_EQ( (size_t)3, polygon.size()); - EXPECT_EQ( (size_t)6, additionalVertices.size()); + bool isOk = GeometryTools::calculateOverlapPolygonOfTwoQuads(&polygon, + &additionalVertices, + &edgeIntersectionStorage, + wrapArrayConst(&nodes), + faces[0].data(), + faces[3].data(), + 1e-6); + + EXPECT_EQ((size_t)3, polygon.size()); + EXPECT_EQ((size_t)6, additionalVertices.size()); EXPECT_TRUE(isOk); overlapPolygons.push_back(polygon); std::cout << polygon << std::endl; } - nodes.insert(nodes.end(), additionalVertices.begin(), additionalVertices.end()); - std::vector basePolygon; - basePolygon.insert(basePolygon.begin(), faces[0].data(), &(faces[0].data()[4])); - - for (cvf::uint vxIdx = 0; vxIdx < nodes.size(); ++vxIdx) - { - GeometryTools::insertVertexInPolygon( - &basePolygon, - wrapArrayConst(&nodes), - vxIdx, - 1e-6 - ); - } - - EXPECT_EQ( (size_t)8, basePolygon.size()); - std::cout << "Bp: " << basePolygon << std::endl; - - for (size_t pIdx = 0; pIdx < overlapPolygons.size(); ++pIdx) - { - for (cvf::uint vxIdx = 0; vxIdx < nodes.size(); ++vxIdx) - { - GeometryTools::insertVertexInPolygon( - &overlapPolygons[pIdx], - wrapArrayConst(&nodes), - vxIdx, - 1e-6 - ); - } - - if (pIdx == 0) - { - EXPECT_EQ((size_t)5, overlapPolygons[pIdx].size()); - } - if (pIdx == 1) - { - EXPECT_EQ((size_t)5, overlapPolygons[pIdx].size()); - } - if (pIdx == 2) - { - EXPECT_EQ((size_t)4, overlapPolygons[pIdx].size()); - } - - std::cout << "Op" << pIdx << ":" << overlapPolygons[pIdx] << std::endl; - } - - - Vec3d normal = quadNormal(wrapArrayConst(&nodes), faces[0].data()); - std::vector faceOverlapPolygonWindingSameAsCubeFaceFlags; - faceOverlapPolygonWindingSameAsCubeFaceFlags.resize(overlapPolygons.size(), true); - - { - std::vector freeFacePolygon; - bool hasHoles = false; - - std::vector< std::vector* > overlapPolygonPtrs; - for (size_t pIdx = 0; pIdx < overlapPolygons.size(); ++pIdx) - { - overlapPolygonPtrs.push_back(&(overlapPolygons[pIdx])); - } - - GeometryTools::calculatePartiallyFreeCubeFacePolygon( - wrapArrayConst(&nodes), - wrapArrayConst(&basePolygon), - normal, - overlapPolygonPtrs, - faceOverlapPolygonWindingSameAsCubeFaceFlags, - &freeFacePolygon, - &hasHoles - ); - - EXPECT_EQ( (size_t)4, freeFacePolygon.size()); - EXPECT_FALSE(hasHoles); - std::cout << "FF1: " << freeFacePolygon << std::endl; - } - - { - std::vector freeFacePolygon; - bool hasHoles = false; - - std::vector< std::vector* > overlapPolygonPtrs; - for (size_t pIdx = 0; pIdx < 1; ++pIdx) - { - overlapPolygonPtrs.push_back(&(overlapPolygons[pIdx])); - } - - GeometryTools::calculatePartiallyFreeCubeFacePolygon( - wrapArrayConst(&nodes), - wrapArrayConst(&basePolygon), - normal, - overlapPolygonPtrs, - faceOverlapPolygonWindingSameAsCubeFaceFlags, - &freeFacePolygon, - &hasHoles - ); - - EXPECT_EQ( (size_t)9, freeFacePolygon.size()); - EXPECT_FALSE(hasHoles); - - std::cout << "FF2: " << freeFacePolygon << std::endl; - - } + nodes.insert(nodes.end(), additionalVertices.begin(), additionalVertices.end()); + std::vector basePolygon; + basePolygon.insert(basePolygon.begin(), faces[0].data(), &(faces[0].data()[4])); + + for (cvf::uint vxIdx = 0; vxIdx < nodes.size(); ++vxIdx) + { + GeometryTools::insertVertexInPolygon(&basePolygon, wrapArrayConst(&nodes), vxIdx, 1e-6); + } + + EXPECT_EQ((size_t)8, basePolygon.size()); + std::cout << "Bp: " << basePolygon << std::endl; + for (size_t pIdx = 0; pIdx < overlapPolygons.size(); ++pIdx) + { + for (cvf::uint vxIdx = 0; vxIdx < nodes.size(); ++vxIdx) + { + GeometryTools::insertVertexInPolygon(&overlapPolygons[pIdx], wrapArrayConst(&nodes), vxIdx, 1e-6); + } + + if (pIdx == 0) + { + EXPECT_EQ((size_t)5, overlapPolygons[pIdx].size()); + } + if (pIdx == 1) + { + EXPECT_EQ((size_t)5, overlapPolygons[pIdx].size()); + } + if (pIdx == 2) + { + EXPECT_EQ((size_t)4, overlapPolygons[pIdx].size()); + } + + std::cout << "Op" << pIdx << ":" << overlapPolygons[pIdx] << std::endl; + } + + Vec3d normal = quadNormal(wrapArrayConst(&nodes), faces[0].data()); + std::vector faceOverlapPolygonWindingSameAsCubeFaceFlags; + faceOverlapPolygonWindingSameAsCubeFaceFlags.resize(overlapPolygons.size(), true); + + { + std::vector freeFacePolygon; + bool hasHoles = false; + + std::vector*> overlapPolygonPtrs; + for (size_t pIdx = 0; pIdx < overlapPolygons.size(); ++pIdx) + { + overlapPolygonPtrs.push_back(&(overlapPolygons[pIdx])); + } + + GeometryTools::calculatePartiallyFreeCubeFacePolygon(wrapArrayConst(&nodes), + wrapArrayConst(&basePolygon), + normal, + overlapPolygonPtrs, + faceOverlapPolygonWindingSameAsCubeFaceFlags, + &freeFacePolygon, + &hasHoles); + + EXPECT_EQ((size_t)4, freeFacePolygon.size()); + EXPECT_FALSE(hasHoles); + std::cout << "FF1: " << freeFacePolygon << std::endl; + } + + { + std::vector freeFacePolygon; + bool hasHoles = false; + std::vector*> overlapPolygonPtrs; + for (size_t pIdx = 0; pIdx < 1; ++pIdx) + { + overlapPolygonPtrs.push_back(&(overlapPolygons[pIdx])); + } + + GeometryTools::calculatePartiallyFreeCubeFacePolygon(wrapArrayConst(&nodes), + wrapArrayConst(&basePolygon), + normal, + overlapPolygonPtrs, + faceOverlapPolygonWindingSameAsCubeFaceFlags, + &freeFacePolygon, + &hasHoles); + + EXPECT_EQ((size_t)9, freeFacePolygon.size()); + EXPECT_FALSE(hasHoles); + + std::cout << "FF2: " << freeFacePolygon << std::endl; + } } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- TEST(CellFaceIntersectionTst, Intersection) { - std::vector additionalVertices; - cvf::Vec3dArray nodes; - std::vector polygon; + cvf::Vec3dArray nodes; + std::vector polygon; - cvf::Array ids; - size_t cv1CubeFaceIndices[4] = {0, 1, 2, 3}; - size_t cv2CubeFaceIndices[4] = {4, 5, 6, 7}; + size_t cv1CubeFaceIndices[4] = {0, 1, 2, 3}; + size_t cv2CubeFaceIndices[4] = {4, 5, 6, 7}; nodes.resize(8); nodes.setAll(cvf::Vec3d(0, 0, 0)); @@ -352,11 +327,15 @@ TEST(CellFaceIntersectionTst, Intersection) nodes[6] = cvf::Vec3d(1, 1, 0); nodes[7] = cvf::Vec3d(0, 1, 0); - - bool isOk = GeometryTools::calculateOverlapPolygonOfTwoQuads(&polygon, &additionalVertices, &edgeIntersectionStorage, - wrapArrayConst(&nodes), cv1CubeFaceIndices, cv2CubeFaceIndices, 1e-6); - EXPECT_EQ( (size_t)4, polygon.size()); - EXPECT_EQ( (size_t)0, additionalVertices.size()); + bool isOk = GeometryTools::calculateOverlapPolygonOfTwoQuads(&polygon, + &additionalVertices, + &edgeIntersectionStorage, + wrapArrayConst(&nodes), + cv1CubeFaceIndices, + cv2CubeFaceIndices, + 1e-6); + EXPECT_EQ((size_t)4, polygon.size()); + EXPECT_EQ((size_t)0, additionalVertices.size()); EXPECT_TRUE(isOk); // Face 1 @@ -371,31 +350,30 @@ TEST(CellFaceIntersectionTst, Intersection) nodes[7] = cvf::Vec3d(-0.25, 0.5, 0); polygon.clear(); - isOk = GeometryTools::calculateOverlapPolygonOfTwoQuads(&polygon, &additionalVertices, &edgeIntersectionStorage, - wrapArrayConst(&nodes), cv1CubeFaceIndices, cv2CubeFaceIndices, 1e-6); - EXPECT_EQ( (size_t)8, polygon.size()); - EXPECT_EQ( (size_t)8, additionalVertices.size()); + isOk = GeometryTools::calculateOverlapPolygonOfTwoQuads(&polygon, + &additionalVertices, + &edgeIntersectionStorage, + wrapArrayConst(&nodes), + cv1CubeFaceIndices, + cv2CubeFaceIndices, + 1e-6); + EXPECT_EQ((size_t)8, polygon.size()); + EXPECT_EQ((size_t)8, additionalVertices.size()); EXPECT_TRUE(isOk); - - - } - //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- TEST(CellFaceIntersectionTst, FreeFacePolygon) { - std::vector additionalVertices; - cvf::Vec3dArray nodes; - std::vector polygon; - + cvf::Vec3dArray nodes; + std::vector polygon; cvf::Array ids; - size_t cv1CubeFaceIndices[4] = {0, 1, 2, 3}; - size_t cv2CubeFaceIndices[4] = {4, 5, 6, 7}; + size_t cv1CubeFaceIndices[4] = {0, 1, 2, 3}; + size_t cv2CubeFaceIndices[4] = {4, 5, 6, 7}; nodes.resize(8); nodes.setAll(cvf::Vec3d(0, 0, 0)); @@ -413,28 +391,31 @@ TEST(CellFaceIntersectionTst, FreeFacePolygon) nodes[6] = cvf::Vec3d(1, 1, 0); nodes[7] = cvf::Vec3d(0, 1, 0); - - bool isOk = GeometryTools::calculateOverlapPolygonOfTwoQuads(&polygon, &additionalVertices, &edgeIntersectionStorage, - wrapArrayConst(&nodes), cv1CubeFaceIndices, cv2CubeFaceIndices, 1e-6); - EXPECT_EQ( (size_t)4, polygon.size()); - EXPECT_EQ( (size_t)0, additionalVertices.size()); + bool isOk = GeometryTools::calculateOverlapPolygonOfTwoQuads(&polygon, + &additionalVertices, + &edgeIntersectionStorage, + wrapArrayConst(&nodes), + cv1CubeFaceIndices, + cv2CubeFaceIndices, + 1e-6); + EXPECT_EQ((size_t)4, polygon.size()); + EXPECT_EQ((size_t)0, additionalVertices.size()); EXPECT_TRUE(isOk); - std::vector< bool > faceOverlapPolygonWinding; - std::vector< std::vector* > faceOverlapPolygons; + std::vector faceOverlapPolygonWinding; + std::vector*> faceOverlapPolygons; faceOverlapPolygons.push_back(&polygon); faceOverlapPolygonWinding.push_back(true); - std::vector partialFacePolygon; - bool hasHoles = false; - GeometryTools::calculatePartiallyFreeCubeFacePolygon( - wrapArrayConst(&nodes), - wrapArrayConst(cv1CubeFaceIndices, 4), - Vec3d(0,0,1), - faceOverlapPolygons, - faceOverlapPolygonWinding, - &partialFacePolygon, - &hasHoles); + std::vector partialFacePolygon; + bool hasHoles = false; + GeometryTools::calculatePartiallyFreeCubeFacePolygon(wrapArrayConst(&nodes), + wrapArrayConst(cv1CubeFaceIndices, 4), + Vec3d(0, 0, 1), + faceOverlapPolygons, + faceOverlapPolygonWinding, + &partialFacePolygon, + &hasHoles); // Face 1 nodes[0] = cvf::Vec3d(0, 0, 0); @@ -448,12 +429,105 @@ TEST(CellFaceIntersectionTst, FreeFacePolygon) nodes[7] = cvf::Vec3d(-0.25, 0.5, 0); polygon.clear(); - isOk = GeometryTools::calculateOverlapPolygonOfTwoQuads(&polygon, &additionalVertices, &edgeIntersectionStorage, - wrapArrayConst(&nodes), cv1CubeFaceIndices, cv2CubeFaceIndices, 1e-6); - EXPECT_EQ( (size_t)8, polygon.size()); - EXPECT_EQ( (size_t)8, additionalVertices.size()); + isOk = GeometryTools::calculateOverlapPolygonOfTwoQuads(&polygon, + &additionalVertices, + &edgeIntersectionStorage, + wrapArrayConst(&nodes), + cv1CubeFaceIndices, + cv2CubeFaceIndices, + 1e-6); + EXPECT_EQ((size_t)8, polygon.size()); + EXPECT_EQ((size_t)8, additionalVertices.size()); EXPECT_TRUE(isOk); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +TEST(CellFaceIntersectionTst, PolygonAreaNormal3D) +{ + // Test special cases with zero area + + { + std::vector vxs; + + cvf::Vec3d area = GeometryTools::polygonAreaNormal3D(vxs); + EXPECT_TRUE(area == cvf::Vec3d::ZERO); + } + + { + std::vector vxs; + vxs.push_back({0, 0, 0}); + + cvf::Vec3d area = GeometryTools::polygonAreaNormal3D(vxs); + EXPECT_TRUE(area == cvf::Vec3d::ZERO); + } + + { + std::vector vxs; + vxs.push_back({0, 0, 0}); + vxs.push_back({0, 0, 1}); + + cvf::Vec3d area = GeometryTools::polygonAreaNormal3D(vxs); + EXPECT_TRUE(area == cvf::Vec3d::ZERO); + } + + // Three points + + { + std::vector vxs; + vxs.push_back({0, 0, 0}); + vxs.push_back({0, 0, 1}); + vxs.push_back({0, 1, 1}); + + cvf::Vec3d area = GeometryTools::polygonAreaNormal3D(vxs); + EXPECT_DOUBLE_EQ(-0.5, area.x()); + EXPECT_DOUBLE_EQ(0.0, area.y()); + EXPECT_DOUBLE_EQ(0.0, area.z()); + } + + // four identical points + { + std::vector vxs; + vxs.push_back({0, 0, 0}); + vxs.push_back({0, 0, 0}); + vxs.push_back({0, 0, 0}); + vxs.push_back({0, 0, 0}); + + cvf::Vec3d area = GeometryTools::polygonAreaNormal3D(vxs); + EXPECT_TRUE(area == cvf::Vec3d::ZERO); + } + // Square of four points + { + std::vector vxs; + vxs.push_back({0, 0, 0}); + vxs.push_back({0, 0, 1}); + vxs.push_back({0, 1, 1}); + vxs.push_back({0, 1, 0}); + + cvf::Vec3d area = GeometryTools::polygonAreaNormal3D(vxs); + EXPECT_DOUBLE_EQ(-1.0, area.x()); + EXPECT_DOUBLE_EQ(0.0, area.y()); + EXPECT_DOUBLE_EQ(0.0, area.z()); + } + + // Square of four points + one point in center of square + + { + std::vector vxs; + vxs.push_back({0, 0, 0}); + vxs.push_back({0, 0, 1}); + vxs.push_back({0, 1, 1}); + vxs.push_back({0, 1, 0}); + + vxs.push_back({0, 0.5, 0.5}); // center of square + + cvf::Vec3d area = GeometryTools::polygonAreaNormal3D(vxs); + EXPECT_DOUBLE_EQ(-0.75, area.x()); + EXPECT_DOUBLE_EQ(0.0, area.y()); + EXPECT_DOUBLE_EQ(0.0, area.z()); + } } diff --git a/ApplicationCode/UserInterface/CMakeLists_files.cmake b/ApplicationCode/UserInterface/CMakeLists_files.cmake index 8999464694..c56cbeb05d 100644 --- a/ApplicationCode/UserInterface/CMakeLists_files.cmake +++ b/ApplicationCode/UserInterface/CMakeLists_files.cmake @@ -12,6 +12,7 @@ ${CMAKE_CURRENT_LIST_DIR}/RiuRimQwtPlotCurve.h ${CMAKE_CURRENT_LIST_DIR}/RiuPlotMainWindow.h ${CMAKE_CURRENT_LIST_DIR}/RiuMainWindow.h ${CMAKE_CURRENT_LIST_DIR}/RiuMainWindowBase.h +${CMAKE_CURRENT_LIST_DIR}/RiuMdiArea.h ${CMAKE_CURRENT_LIST_DIR}/RiuMdiSubWindow.h ${CMAKE_CURRENT_LIST_DIR}/RiuMultiCaseImportDialog.h ${CMAKE_CURRENT_LIST_DIR}/RiuProcessMonitor.h @@ -34,8 +35,11 @@ ${CMAKE_CURRENT_LIST_DIR}/RiuResultQwtPlot.h ${CMAKE_CURRENT_LIST_DIR}/RiuResultTextBuilder.h ${CMAKE_CURRENT_LIST_DIR}/RiuRmsNavigation.h ${CMAKE_CURRENT_LIST_DIR}/RiuSelectionChangedHandler.h -${CMAKE_CURRENT_LIST_DIR}/RiuSelectionManager.h +${CMAKE_CURRENT_LIST_DIR}/Riu3dSelectionManager.h ${CMAKE_CURRENT_LIST_DIR}/RiuSimpleHistogramWidget.h +${CMAKE_CURRENT_LIST_DIR}/RiuQwtPlot.h +${CMAKE_CURRENT_LIST_DIR}/RiuDockedQwtPlot.h +${CMAKE_CURRENT_LIST_DIR}/RiuGridCrossQwtPlot.h ${CMAKE_CURRENT_LIST_DIR}/RiuSummaryQwtPlot.h ${CMAKE_CURRENT_LIST_DIR}/RiuTextDialog.h ${CMAKE_CURRENT_LIST_DIR}/RiuTimeStepChangedHandler.h @@ -52,7 +56,7 @@ ${CMAKE_CURRENT_LIST_DIR}/RiuPlotAnnotationTool.h ${CMAKE_CURRENT_LIST_DIR}/RiuGeoMechXfTensorResultAccessor.h ${CMAKE_CURRENT_LIST_DIR}/RiuFemTimeHistoryResultAccessor.h ${CMAKE_CURRENT_LIST_DIR}/RiuEditPerforationCollectionWidget.h -${CMAKE_CURRENT_LIST_DIR}/RiuExportMultipleSnapshotsWidget.h +${CMAKE_CURRENT_LIST_DIR}/RiuAdvancedSnapshotExportWidget.h ${CMAKE_CURRENT_LIST_DIR}/RiuWellAllocationPlot.h ${CMAKE_CURRENT_LIST_DIR}/RiuWellRftPlot.h ${CMAKE_CURRENT_LIST_DIR}/RiuWellPltPlot.h @@ -75,7 +79,10 @@ ${CMAKE_CURRENT_LIST_DIR}/RiuPlotMainWindowTools.h ${CMAKE_CURRENT_LIST_DIR}/Riu3DMainWindowTools.h ${CMAKE_CURRENT_LIST_DIR}/RiuDockWidgetTools.h ${CMAKE_CURRENT_LIST_DIR}/RiuQwtPlotItemGroup.h +${CMAKE_CURRENT_LIST_DIR}/RiuQwtPlotTools.h ${CMAKE_CURRENT_LIST_DIR}/RiuWellPathComponentPlotItem.h +${CMAKE_CURRENT_LIST_DIR}/RiuMeasurementViewEventFilter.h +${CMAKE_CURRENT_LIST_DIR}/RiuDraggableOverlayFrame.h ) set (SOURCE_GROUP_SOURCE_FILES @@ -91,6 +98,7 @@ ${CMAKE_CURRENT_LIST_DIR}/RiuRimQwtPlotCurve.cpp ${CMAKE_CURRENT_LIST_DIR}/RiuPlotMainWindow.cpp ${CMAKE_CURRENT_LIST_DIR}/RiuMainWindow.cpp ${CMAKE_CURRENT_LIST_DIR}/RiuMainWindowBase.cpp +${CMAKE_CURRENT_LIST_DIR}/RiuMdiArea.cpp ${CMAKE_CURRENT_LIST_DIR}/RiuMdiSubWindow.cpp ${CMAKE_CURRENT_LIST_DIR}/RiuMultiCaseImportDialog.cpp ${CMAKE_CURRENT_LIST_DIR}/RiuProcessMonitor.cpp @@ -112,8 +120,11 @@ ${CMAKE_CURRENT_LIST_DIR}/RiuResultQwtPlot.cpp ${CMAKE_CURRENT_LIST_DIR}/RiuResultTextBuilder.cpp ${CMAKE_CURRENT_LIST_DIR}/RiuRmsNavigation.cpp ${CMAKE_CURRENT_LIST_DIR}/RiuSelectionChangedHandler.cpp -${CMAKE_CURRENT_LIST_DIR}/RiuSelectionManager.cpp +${CMAKE_CURRENT_LIST_DIR}/Riu3dSelectionManager.cpp ${CMAKE_CURRENT_LIST_DIR}/RiuSimpleHistogramWidget.cpp +${CMAKE_CURRENT_LIST_DIR}/RiuQwtPlot.cpp +${CMAKE_CURRENT_LIST_DIR}/RiuDockedQwtPlot.cpp +${CMAKE_CURRENT_LIST_DIR}/RiuGridCrossQwtPlot.cpp ${CMAKE_CURRENT_LIST_DIR}/RiuSummaryQwtPlot.cpp ${CMAKE_CURRENT_LIST_DIR}/RiuTextDialog.cpp ${CMAKE_CURRENT_LIST_DIR}/RiuTimeStepChangedHandler.cpp @@ -129,7 +140,7 @@ ${CMAKE_CURRENT_LIST_DIR}/RiuPlotAnnotationTool.cpp ${CMAKE_CURRENT_LIST_DIR}/RiuGeoMechXfTensorResultAccessor.cpp ${CMAKE_CURRENT_LIST_DIR}/RiuFemTimeHistoryResultAccessor.cpp ${CMAKE_CURRENT_LIST_DIR}/RiuEditPerforationCollectionWidget.cpp -${CMAKE_CURRENT_LIST_DIR}/RiuExportMultipleSnapshotsWidget.cpp +${CMAKE_CURRENT_LIST_DIR}/RiuAdvancedSnapshotExportWidget.cpp ${CMAKE_CURRENT_LIST_DIR}/RiuWellAllocationPlot.cpp ${CMAKE_CURRENT_LIST_DIR}/RiuWellRftPlot.cpp ${CMAKE_CURRENT_LIST_DIR}/RiuWellPltPlot.cpp @@ -151,7 +162,9 @@ ${CMAKE_CURRENT_LIST_DIR}/RiuPlotMainWindowTools.cpp ${CMAKE_CURRENT_LIST_DIR}/Riu3DMainWindowTools.cpp ${CMAKE_CURRENT_LIST_DIR}/RiuDockWidgetTools.cpp ${CMAKE_CURRENT_LIST_DIR}/RiuQwtPlotItemGroup.cpp +${CMAKE_CURRENT_LIST_DIR}/RiuQwtPlotTools.cpp ${CMAKE_CURRENT_LIST_DIR}/RiuWellPathComponentPlotItem.cpp +${CMAKE_CURRENT_LIST_DIR}/RiuDraggableOverlayFrame.cpp ) list(APPEND CODE_HEADER_FILES @@ -166,6 +179,8 @@ list(APPEND QT_MOC_HEADERS ${CMAKE_CURRENT_LIST_DIR}/RiuMainWindowBase.h ${CMAKE_CURRENT_LIST_DIR}/RiuMainWindow.h ${CMAKE_CURRENT_LIST_DIR}/RiuPlotMainWindow.h +${CMAKE_CURRENT_LIST_DIR}/RiuMdiArea.h +${CMAKE_CURRENT_LIST_DIR}/RiuMdiSubWindow.h ${CMAKE_CURRENT_LIST_DIR}/RiuPvtPlotPanel.h ${CMAKE_CURRENT_LIST_DIR}/RiuRelativePermeabilityPlotPanel.h ${CMAKE_CURRENT_LIST_DIR}/RiuResultInfoPanel.h @@ -179,6 +194,9 @@ ${CMAKE_CURRENT_LIST_DIR}/RiuTreeViewEventFilter.h ${CMAKE_CURRENT_LIST_DIR}/RiuWellLogPlot.h ${CMAKE_CURRENT_LIST_DIR}/RiuWellLogTrack.h ${CMAKE_CURRENT_LIST_DIR}/RiuRecentFileActionProvider.h +${CMAKE_CURRENT_LIST_DIR}/RiuQwtPlot.h +${CMAKE_CURRENT_LIST_DIR}/RiuDockedQwtPlot.h +${CMAKE_CURRENT_LIST_DIR}/RiuGridCrossQwtPlot.h ${CMAKE_CURRENT_LIST_DIR}/RiuSummaryQwtPlot.h ${CMAKE_CURRENT_LIST_DIR}/RiuTofAccumulatedPhaseFractionsPlot.h ${CMAKE_CURRENT_LIST_DIR}/RiuQwtScalePicker.h @@ -186,7 +204,7 @@ ${CMAKE_CURRENT_LIST_DIR}/RiuQwtPlotWheelZoomer.h ${CMAKE_CURRENT_LIST_DIR}/RiuWidgetDragger.h ${CMAKE_CURRENT_LIST_DIR}/RiuCvfOverlayItemWidget.h ${CMAKE_CURRENT_LIST_DIR}/RiuEditPerforationCollectionWidget.h -${CMAKE_CURRENT_LIST_DIR}/RiuExportMultipleSnapshotsWidget.h +${CMAKE_CURRENT_LIST_DIR}/RiuAdvancedSnapshotExportWidget.h ${CMAKE_CURRENT_LIST_DIR}/RiuWellAllocationPlot.h ${CMAKE_CURRENT_LIST_DIR}/RiuWellRftPlot.h ${CMAKE_CURRENT_LIST_DIR}/RiuWellPltPlot.h @@ -196,6 +214,7 @@ ${CMAKE_CURRENT_LIST_DIR}/RiuMessagePanel.h ${CMAKE_CURRENT_LIST_DIR}/RiuExpressionContextMenuManager.h ${CMAKE_CURRENT_LIST_DIR}/RiuCalculationsContextMenuManager.h ${CMAKE_CURRENT_LIST_DIR}/RiuMohrsCirclePlot.h +${CMAKE_CURRENT_LIST_DIR}/RiuDraggableOverlayFrame.h ) list(APPEND QT_UI_FILES diff --git a/ApplicationCode/UserInterface/Riu3DMainWindowTools.cpp b/ApplicationCode/UserInterface/Riu3DMainWindowTools.cpp index 6db4df1274..58b8c8f7ac 100644 --- a/ApplicationCode/UserInterface/Riu3DMainWindowTools.cpp +++ b/ApplicationCode/UserInterface/Riu3DMainWindowTools.cpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018- Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by diff --git a/ApplicationCode/UserInterface/Riu3DMainWindowTools.h b/ApplicationCode/UserInterface/Riu3DMainWindowTools.h index 5f4f4e4ca2..63fdce299d 100644 --- a/ApplicationCode/UserInterface/Riu3DMainWindowTools.h +++ b/ApplicationCode/UserInterface/Riu3DMainWindowTools.h @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018- Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by diff --git a/ApplicationCode/UserInterface/Riu3dSelectionManager.cpp b/ApplicationCode/UserInterface/Riu3dSelectionManager.cpp new file mode 100644 index 0000000000..93fb04d1bf --- /dev/null +++ b/ApplicationCode/UserInterface/Riu3dSelectionManager.cpp @@ -0,0 +1,292 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2015- Statoil ASA +// Copyright (C) 2015- Ceetron Solutions AS +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "Riu3dSelectionManager.h" + +#include "RimGridView.h" +#include "RimEclipseView.h" +#include "RimGeoMechView.h" +#include "RimSimWellInView.h" +#include "Rim2dIntersectionView.h" +#include "RimWellPath.h" + +#include "RivSimWellPipeSourceInfo.h" +#include "RivWellPathSourceInfo.h" + +#include "RiuSelectionChangedHandler.h" + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +Riu3dSelectionManager::Riu3dSelectionManager() + : m_notificationCenter(new RiuSelectionChangedHandler) +{ + m_selection.resize(2); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +Riu3dSelectionManager::~Riu3dSelectionManager() +{ + deleteAllItemsFromSelection(RUI_APPLICATION_GLOBAL); + deleteAllItemsFromSelection(RUI_TEMPORARY); + + delete m_notificationCenter; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +Riu3dSelectionManager* Riu3dSelectionManager::instance() +{ + static Riu3dSelectionManager* singleton = new Riu3dSelectionManager; + return singleton; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void Riu3dSelectionManager::selectedItems(std::vector& items, int role) const +{ + const std::vector& s = m_selection[role]; + + items = s; +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RiuSelectionItem* Riu3dSelectionManager::selectedItem(int role /*= RUI_APPLICATION_GLOBAL*/) const +{ + const std::vector& s = m_selection[role]; + + if (s.size() == 1) + { + if (s[0]) + { + return s[0]; + } + } + + return nullptr; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void Riu3dSelectionManager::appendItemToSelection(RiuSelectionItem* item, int role) +{ + std::vector& s = m_selection[role]; + + s.push_back(item); + + if (role == RUI_APPLICATION_GLOBAL) m_notificationCenter->handleItemAppended(item); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void Riu3dSelectionManager::setSelectedItem(RiuSelectionItem* item, int role) +{ + deleteAllItemsFromSelection(role); + + std::vector& s = m_selection[role]; + + s.push_back(item); + + if (role == RUI_APPLICATION_GLOBAL) m_notificationCenter->handleSetSelectedItem(item); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void Riu3dSelectionManager::deleteAllItems(int role) +{ + if (!isEmpty(role)) + { + deleteAllItemsFromSelection(role); + + if (role == RUI_APPLICATION_GLOBAL) m_notificationCenter->handleSelectionDeleted(); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool Riu3dSelectionManager::isEmpty(int role) const +{ + const std::vector& s = m_selection[role]; + + return s.size() == 0; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void Riu3dSelectionManager::deleteAllItemsFromSelection(int role) +{ + std::vector& s = m_selection[role]; + + for (RiuSelectionItem* item : s) + { + delete item; + } + + s.clear(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RiuEclipseSelectionItem::RiuEclipseSelectionItem(RimEclipseView* view, + size_t gridIndex, + size_t cellIndex, + size_t nncIndex, + cvf::Color3f color, + cvf::StructGridInterface::FaceType face, + const cvf::Vec3d& localIntersectionPointInDisplay) + : m_view(view), + m_gridIndex(gridIndex), + m_gridLocalCellIndex(cellIndex), + m_nncIndex(nncIndex), + m_color(color), + m_face(face), + m_localIntersectionPointInDisplay(localIntersectionPointInDisplay) +{ +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RiuGeoMechSelectionItem::RiuGeoMechSelectionItem(RimGeoMechView* view, + size_t gridIndex, + size_t cellIndex, + cvf::Color3f color, + int elementFace, + const cvf::Vec3d& localIntersectionPointInDisplay) + : m_view(view) + , m_gridIndex(gridIndex) + , m_cellIndex(cellIndex) + , m_color(color) + , m_elementFace(elementFace) + , m_hasIntersectionTriangle(false) + , m_localIntersectionPointInDisplay(localIntersectionPointInDisplay) +{ +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RiuGeoMechSelectionItem::RiuGeoMechSelectionItem(RimGeoMechView* view, + size_t gridIndex, + size_t cellIndex, + cvf::Color3f color, + int elementFace, + const cvf::Vec3d& localIntersectionPointInDisplay, + const std::array& intersectionTriangle) + : m_view(view) + , m_gridIndex(gridIndex) + , m_cellIndex(cellIndex) + , m_color(color) + , m_elementFace(elementFace) + , m_hasIntersectionTriangle(true) + , m_intersectionTriangle(intersectionTriangle) + , m_localIntersectionPointInDisplay(localIntersectionPointInDisplay) +{ +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +Riu2dIntersectionSelectionItem::Riu2dIntersectionSelectionItem(Rim2dIntersectionView* view, RiuSelectionItem *selItem) +{ + m_view = view; + m_eclipseSelItem = dynamic_cast(selItem); + m_geoMechSelItem = dynamic_cast(selItem); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +Riu2dIntersectionSelectionItem::~Riu2dIntersectionSelectionItem() +{ + if (m_eclipseSelItem) delete m_eclipseSelItem; + if (m_geoMechSelItem) delete m_geoMechSelItem; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +caf::PdmPointer Riu2dIntersectionSelectionItem::view() const +{ + return m_view; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RiuEclipseSelectionItem* Riu2dIntersectionSelectionItem::eclipseSelectionItem() const +{ + return m_eclipseSelItem; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RiuGeoMechSelectionItem* Riu2dIntersectionSelectionItem::geoMechSelectionItem() const +{ + return m_geoMechSelItem; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RiuWellPathSelectionItem::RiuWellPathSelectionItem(const RivWellPathSourceInfo* wellPathSourceInfo, + const cvf::Vec3d& pipeCenterLineIntersectionInDomainCoords, + double measuredDepth, + RimWellPathComponentInterface* component /*=nullptr*/) + : m_pipeCenterlineIntersectionInDomainCoords(pipeCenterLineIntersectionInDomainCoords) + , m_measuredDepth(measuredDepth) + , m_wellPathComponent(component) +{ + m_wellpath = wellPathSourceInfo->wellPath(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RiuSimWellSelectionItem::RiuSimWellSelectionItem(RimSimWellInView* simwell, + cvf::Vec3d m_domainCoord, + size_t m_branchIndex) + : m_simWell(simwell), + m_domainCoord(m_domainCoord), + m_branchIndex(m_branchIndex) +{ +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RiuGeneralSelectionItem::RiuGeneralSelectionItem(caf::PdmObject* object) + : m_object(object) +{ +} diff --git a/ApplicationCode/UserInterface/Riu3dSelectionManager.h b/ApplicationCode/UserInterface/Riu3dSelectionManager.h new file mode 100644 index 0000000000..82baebb509 --- /dev/null +++ b/ApplicationCode/UserInterface/Riu3dSelectionManager.h @@ -0,0 +1,304 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2015- Statoil ASA +// Copyright (C) 2015- Ceetron Solutions AS +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "cafPdmPointer.h" +#include "cafPdmObject.h" + +#include "cvfBase.h" +#include "cvfColor3.h" +#include "cvfStructGrid.h" + +#include +#include +#include +// #include "RivWellPathSourceInfo.h" +// #include "RivWellPipeSourceInfo.h" + +class RimGridView; +class RimEclipseView; +class RimGeoMechView; +class RimSimWellInView; +class Rim2dIntersectionView; +class RimWellPath; +class RimWellPathComponentInterface; +class RiuSelectionChangedHandler; +class RiuSelectionItem; +class RivSimWellPipeSourceInfo; +class RivWellPathSourceInfo; + +//================================================================================================== +// +// +// +//================================================================================================== +class Riu3dSelectionManager +{ +public: + enum SelectionRole + { + RUI_APPLICATION_GLOBAL, // Selection role intended to manage the cells selected by left mouse click in the 3D view + RUI_TEMPORARY // Selection role intended to manage the items selected by a right mouse click in the 3D view + }; + +public: + static Riu3dSelectionManager* instance(); + + // Returns selected items + // Selection manager owns the selection items + void selectedItems(std::vector& items, int role = RUI_APPLICATION_GLOBAL) const; + + // Returns selected items + // Selection manager owns the selection items + RiuSelectionItem* selectedItem(int role = RUI_APPLICATION_GLOBAL) const; + // PdmUiItem* selectedItem(int role = SelectionManager::APPLICATION_GLOBAL); + + + // Append item to selected items + // SelectionManager takes ownership of the item + void appendItemToSelection(RiuSelectionItem* item, int role = RUI_APPLICATION_GLOBAL); + + // Set one selected item + // SelectionManager takes ownership of the item + void setSelectedItem(RiuSelectionItem* item, int role = RUI_APPLICATION_GLOBAL); + + // Deletes all items in the SelectionManager + void deleteAllItems(int role = RUI_APPLICATION_GLOBAL); + + bool isEmpty(int role = RUI_APPLICATION_GLOBAL) const; + +private: + Riu3dSelectionManager(); + ~Riu3dSelectionManager(); + Riu3dSelectionManager(const Riu3dSelectionManager&) = delete; + + void deleteAllItemsFromSelection(int role); + +private: + std::vector< std::vector > m_selection; + + RiuSelectionChangedHandler* m_notificationCenter; +}; + + +//================================================================================================== +// +// +// +//================================================================================================== +class RiuSelectionItem +{ +public: + enum RiuSelectionType + { + ECLIPSE_SELECTION_OBJECT, + GEOMECH_SELECTION_OBJECT, + WELLPATH_SELECTION_OBJECT, + SIMWELL_SELECTION_OBJECT, + GENERAL_SELECTION_OBJECT, + INTERSECTION_SELECTION_OBJECT + }; + +public: + RiuSelectionItem() {} + virtual ~RiuSelectionItem() {}; + + virtual RiuSelectionType type() const = 0; +}; + + +//================================================================================================== +// +// +// +//================================================================================================== +class RiuEclipseSelectionItem : public RiuSelectionItem +{ +public: + explicit RiuEclipseSelectionItem(RimEclipseView* view, + size_t gridIndex, + size_t cellIndex, + size_t nncIndex, + cvf::Color3f color, + cvf::StructGridInterface::FaceType face, + const cvf::Vec3d& localIntersectionPointInDisplay); + + ~RiuEclipseSelectionItem() override {}; + + RiuSelectionType type() const override + { + return ECLIPSE_SELECTION_OBJECT; + } + +public: + caf::PdmPointer m_view; + size_t m_gridIndex; + size_t m_gridLocalCellIndex; + size_t m_nncIndex; + cvf::Color3f m_color; + cvf::StructGridInterface::FaceType m_face; + cvf::Vec3d m_localIntersectionPointInDisplay; +}; + + +//================================================================================================== +// +// +// +//================================================================================================== +class RiuGeoMechSelectionItem : public RiuSelectionItem +{ +public: + explicit RiuGeoMechSelectionItem(RimGeoMechView* view, + size_t gridIndex, + size_t cellIndex, + cvf::Color3f color, + int elementFace, + const cvf::Vec3d& localIntersectionPointInDisplay); + + explicit RiuGeoMechSelectionItem(RimGeoMechView* view, + size_t gridIndex, + size_t cellIndex, + cvf::Color3f color, + int elementFace, + const cvf::Vec3d& localIntersectionPointInDisplay, + const std::array& intersectionTriangle ); + ~RiuGeoMechSelectionItem() override {}; + + RiuSelectionType type() const override + { + return GEOMECH_SELECTION_OBJECT; + } + +public: + caf::PdmPointer m_view; + size_t m_gridIndex; + size_t m_cellIndex; + cvf::Color3f m_color; + int m_elementFace; + bool m_hasIntersectionTriangle; + std::array m_intersectionTriangle; + cvf::Vec3d m_localIntersectionPointInDisplay; +}; + + +//================================================================================================== +// +// +// +//================================================================================================== +class Riu2dIntersectionSelectionItem : public RiuSelectionItem +{ +public: + explicit Riu2dIntersectionSelectionItem(Rim2dIntersectionView* view, RiuSelectionItem *selItem); + + ~Riu2dIntersectionSelectionItem() override; + + RiuSelectionType type() const override + { + return INTERSECTION_SELECTION_OBJECT; + } + +public: + caf::PdmPointer view() const; + RiuEclipseSelectionItem* eclipseSelectionItem() const; + RiuGeoMechSelectionItem* geoMechSelectionItem() const; + +private: + caf::PdmPointer m_view; + RiuEclipseSelectionItem* m_eclipseSelItem; + RiuGeoMechSelectionItem* m_geoMechSelItem; +}; + + +//================================================================================================== +// +// +// +//================================================================================================== +class RiuWellPathSelectionItem : public RiuSelectionItem +{ +public: + explicit RiuWellPathSelectionItem(const RivWellPathSourceInfo* wellPathSourceInfo, + const cvf::Vec3d& pipeCenterLineIntersectionInDomainCoords, + double measuredDepth, + RimWellPathComponentInterface* wellPathComponent = nullptr); + + ~RiuWellPathSelectionItem() override {}; + + RiuSelectionType type() const override + { + return WELLPATH_SELECTION_OBJECT; + } + +public: + RimWellPath* m_wellpath; + cvf::Vec3d m_pipeCenterlineIntersectionInDomainCoords; + double m_measuredDepth; + RimWellPathComponentInterface* m_wellPathComponent; +}; + + + +//================================================================================================== +// +// +// +//================================================================================================== +class RiuSimWellSelectionItem : public RiuSelectionItem +{ +public: + explicit RiuSimWellSelectionItem(RimSimWellInView* simwell, cvf::Vec3d domainCoord, size_t branchIndex); + + + ~RiuSimWellSelectionItem() override {}; + + RiuSelectionType type() const override + { + return SIMWELL_SELECTION_OBJECT; + } + +public: + RimSimWellInView* m_simWell; + cvf::Vec3d m_domainCoord; + size_t m_branchIndex; +}; + + +//================================================================================================== +// +// +// +//================================================================================================== +class RiuGeneralSelectionItem : public RiuSelectionItem +{ +public: + RiuGeneralSelectionItem(caf::PdmObject* object); + + ~RiuGeneralSelectionItem() override {}; + + RiuSelectionType type() const override + { + return GENERAL_SELECTION_OBJECT; + } + +public: + caf::PdmObject* m_object; +}; diff --git a/ApplicationCode/UserInterface/RiuAdvancedSnapshotExportWidget.cpp b/ApplicationCode/UserInterface/RiuAdvancedSnapshotExportWidget.cpp new file mode 100644 index 0000000000..5c522a572d --- /dev/null +++ b/ApplicationCode/UserInterface/RiuAdvancedSnapshotExportWidget.cpp @@ -0,0 +1,259 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2016 Statoil ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "RiuAdvancedSnapshotExportWidget.h" + +#include "RiaApplication.h" + +#include "ExportCommands/RicAdvancedSnapshotExportFeature.h" + +#include "RimCase.h" +#include "RimEclipseCellColors.h" +#include "RimEclipseView.h" +#include "RimAdvancedSnapshotExportDefinition.h" +#include "RimProject.h" +#include "Rim3dView.h" + +#include "RiuTools.h" + +#include "cafCmdFeatureManager.h" +#include "cafPdmUiTableView.h" +#include "cafSelectionManager.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RiuAdvancedSnapshotExportWidget::RiuAdvancedSnapshotExportWidget(QWidget* parent, RimProject* project) + : QDialog(parent, RiuTools::defaultDialogFlags()), + m_rimProject(project) +{ + setWindowTitle("Advanced Snapshot Export"); + + int nWidth = 1000; + int nHeight = 300; + resize(nWidth, nHeight); + + QVBoxLayout* dialogLayout = new QVBoxLayout; + setLayout(dialogLayout); + + m_pdmTableView = new caf::PdmUiTableView(this); + m_pdmTableView->tableView()->setSelectionMode(QAbstractItemView::ExtendedSelection); + m_pdmTableView->tableView()->setContextMenuPolicy(Qt::CustomContextMenu); + m_pdmTableView->enableHeaderText(false); + + connect(m_pdmTableView->tableView(), SIGNAL(customContextMenuRequested(QPoint)), SLOT(customMenuRequested(QPoint))); + + m_pdmTableView->setChildArrayField(&(project->multiSnapshotDefinitions())); + + QHeaderView* verticalHeader = m_pdmTableView->tableView()->verticalHeader(); +#if QT_VERSION >= 0x050000 + verticalHeader->setSectionResizeMode(QHeaderView::Interactive); +#else + verticalHeader->setResizeMode(QHeaderView::Interactive); +#endif + m_pdmTableView->tableView()->resizeColumnsToContents(); + + // Set active child array to be able to use generic delete + caf::SelectionManager::instance()->setActiveChildArrayFieldHandle(&(project->multiSnapshotDefinitions())); + + dialogLayout->addWidget(m_pdmTableView); + + // Export folder + { + QHBoxLayout* layout = new QHBoxLayout; + + layout->addWidget(new QLabel("Export folder")); + + // Save images in snapshot catalog relative to project directory + QString snapshotFolderName = RiaApplication::instance()->createAbsolutePathFromProjectRelativePath("snapshots"); + + m_exportFolderLineEdit = new QLineEdit(snapshotFolderName); + + QToolButton* button = new QToolButton; + button->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred)); + button->setText(QLatin1String("...")); + + layout->addWidget(m_exportFolderLineEdit); + layout->addWidget(button); + + connect(button, SIGNAL(clicked()), this, SLOT(folderSelectionClicked())); + + dialogLayout->addLayout(layout); + } + + + // Buttons + QDialogButtonBox* buttonBox = new QDialogButtonBox(QDialogButtonBox::Close); + connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept())); + connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject())); + + QPushButton* exportButton = new QPushButton(tr("Export")); + exportButton->setDefault(true); + buttonBox->addButton(exportButton, QDialogButtonBox::ActionRole); + connect(exportButton, SIGNAL(clicked()), this, SLOT(exportSnapshots())); + + dialogLayout->addWidget(buttonBox); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RiuAdvancedSnapshotExportWidget::~RiuAdvancedSnapshotExportWidget() +{ + m_pdmTableView->setChildArrayField(nullptr); + + caf::SelectionManager::instance()->setActiveChildArrayFieldHandle(nullptr); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuAdvancedSnapshotExportWidget::addSnapshotItemFromActiveView() +{ + if (!m_rimProject) return; + + Rim3dView* activeView = RiaApplication::instance()->activeReservoirView(); + if (activeView) + { + RimAdvancedSnapshotExportDefinition* multiSnapshot = new RimAdvancedSnapshotExportDefinition(); + multiSnapshot->view = activeView; + + RimEclipseView* eclipseView = dynamic_cast(activeView); + if (eclipseView) + { + multiSnapshot->eclipseResultType = eclipseView->cellResult()->resultType(); + multiSnapshot->selectedEclipseResults.v().push_back(eclipseView->cellResult()->resultVariable()); + + } + multiSnapshot->timeStepStart = activeView->currentTimeStep(); + multiSnapshot->timeStepEnd = activeView->currentTimeStep(); + + RimCase* sourceCase = nullptr; + activeView->firstAncestorOrThisOfType(sourceCase); + if (sourceCase) + { + multiSnapshot->additionalCases().push_back(sourceCase); + } + + m_rimProject->multiSnapshotDefinitions.push_back(multiSnapshot); + m_rimProject->multiSnapshotDefinitions.uiCapability()->updateConnectedEditors(); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuAdvancedSnapshotExportWidget::addEmptySnapshotItems(size_t itemCount) +{ + if (!m_rimProject) return; + + for (size_t i = 0; i < itemCount; i++) + { + RimAdvancedSnapshotExportDefinition* multiSnapshot = new RimAdvancedSnapshotExportDefinition(); + multiSnapshot->isActive = false; + + m_rimProject->multiSnapshotDefinitions.push_back(multiSnapshot); + } + + m_rimProject->multiSnapshotDefinitions.uiCapability()->updateConnectedEditors(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuAdvancedSnapshotExportWidget::customMenuRequested(QPoint pos) +{ + caf::CmdFeatureManager* commandManager = caf::CmdFeatureManager::instance(); + + QMenu menu; + menu.addAction(commandManager->action("PdmListField_DeleteItem","Delete row")); + + QAction* newRowAction = new QAction("New row", this); + connect(newRowAction, SIGNAL(triggered()), SLOT(addSnapshotItem())); + menu.addAction(newRowAction); + + QAction* clearAllRows = new QAction("Clear", this); + connect(clearAllRows, SIGNAL(triggered()), SLOT(deleteAllSnapshotItems())); + menu.addAction(clearAllRows); + + + // Qt doc: QAbstractScrollArea and its subclasses that map the context menu event to coordinates of the viewport(). + QPoint globalPos = m_pdmTableView->tableView()->viewport()->mapToGlobal(pos); + + menu.exec(globalPos); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuAdvancedSnapshotExportWidget::deleteAllSnapshotItems() +{ + if (!m_rimProject) return; + + m_rimProject->multiSnapshotDefinitions.deleteAllChildObjects(); + + m_rimProject->multiSnapshotDefinitions.uiCapability()->updateConnectedEditors(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuAdvancedSnapshotExportWidget::exportSnapshots() +{ + RicAdvancedSnapshotExportFeature::exportMultipleSnapshots(m_exportFolderLineEdit->text(), m_rimProject); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuAdvancedSnapshotExportWidget::folderSelectionClicked() +{ + QString defaultPath = m_exportFolderLineEdit->text(); + + QString directoryPath = QFileDialog::getExistingDirectory(m_exportFolderLineEdit, + tr("Get existing directory"), + defaultPath, + QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks); + + if (!directoryPath.isEmpty()) + { + m_exportFolderLineEdit->setText(directoryPath); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuAdvancedSnapshotExportWidget::addSnapshotItem() +{ + addSnapshotItemFromActiveView(); +} diff --git a/ApplicationCode/UserInterface/RiuAdvancedSnapshotExportWidget.h b/ApplicationCode/UserInterface/RiuAdvancedSnapshotExportWidget.h new file mode 100644 index 0000000000..6f4a43b72c --- /dev/null +++ b/ApplicationCode/UserInterface/RiuAdvancedSnapshotExportWidget.h @@ -0,0 +1,54 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2016 Statoil ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include + +class RimProject; + +namespace caf { + class PdmUiTableView; +} + +class QWidget; +class QLineEdit; + +class RiuAdvancedSnapshotExportWidget : public QDialog +{ + Q_OBJECT +public: + RiuAdvancedSnapshotExportWidget(QWidget* parent, RimProject* project); + ~RiuAdvancedSnapshotExportWidget() override; + + void addSnapshotItemFromActiveView(); + void addEmptySnapshotItems(size_t itemCount); + +private slots: + void customMenuRequested(QPoint pos); + void addSnapshotItem(); + void deleteAllSnapshotItems(); + void exportSnapshots(); + + void folderSelectionClicked(); + +private: + RimProject* m_rimProject; + caf::PdmUiTableView* m_pdmTableView; + QLineEdit* m_exportFolderLineEdit; +}; diff --git a/ApplicationCode/UserInterface/RiuCadNavigation.cpp b/ApplicationCode/UserInterface/RiuCadNavigation.cpp index 26a5869a62..edea8f4cee 100644 --- a/ApplicationCode/UserInterface/RiuCadNavigation.cpp +++ b/ApplicationCode/UserInterface/RiuCadNavigation.cpp @@ -60,7 +60,7 @@ bool RiuCadNavigation::handleInputEvent(QInputEvent* inputEvent) cvfEventPos(me->x(), me->y(), &translatedMousePosX, &translatedMousePosY); if (me->button() == Qt::MidButton && me->modifiers() == Qt::NoModifier && isRotationEnabled()) - { + { cvf::HitItemCollection hic; bool hitSomething = m_viewer->rayPick( me->x(), me->y(), &hic); @@ -86,6 +86,7 @@ bool RiuCadNavigation::handleInputEvent(QInputEvent* inputEvent) m_hasMovedMouseDuringNavigation = false; isEventHandled = true; } + forcePointOfInterestUpdateDuringNextWheelZoom(); } break; case QEvent::MouseButtonRelease: @@ -103,6 +104,7 @@ bool RiuCadNavigation::handleInputEvent(QInputEvent* inputEvent) } } + forcePointOfInterestUpdateDuringNextWheelZoom(); } break; case QEvent::MouseMove: @@ -133,11 +135,12 @@ bool RiuCadNavigation::handleInputEvent(QInputEvent* inputEvent) { if (inputEvent->modifiers() == Qt::NoModifier) { - initializeRotationCenter(); + QWheelEvent* we = static_cast(inputEvent); + + updatePointOfInterestDuringZoomIfNecessary(we->x(), we->y()); + if (m_isRotCenterInitialized) { - QWheelEvent* we = static_cast ( inputEvent); - int translatedMousePosX, translatedMousePosY; cvfEventPos(we->x(), we->y(), &translatedMousePosX, &translatedMousePosY); diff --git a/ApplicationCode/UserInterface/RiuCalculationsContextMenuManager.h b/ApplicationCode/UserInterface/RiuCalculationsContextMenuManager.h index f12c64f7a4..b2de3a4091 100644 --- a/ApplicationCode/UserInterface/RiuCalculationsContextMenuManager.h +++ b/ApplicationCode/UserInterface/RiuCalculationsContextMenuManager.h @@ -41,7 +41,11 @@ class RiuCalculationsContextMenuManager : public QObject static const std::map> MENU_MAP; public: - RiuCalculationsContextMenuManager() { } + RiuCalculationsContextMenuManager() + : m_curveCalc(nullptr) + , m_textPosition(0) + { + } void attachWidget(QWidget* widget, RicSummaryCurveCalculator* curveCalc); diff --git a/ApplicationCode/UserInterface/RiuCursors.cpp b/ApplicationCode/UserInterface/RiuCursors.cpp index ea339eb817..07b9ae76ac 100644 --- a/ApplicationCode/UserInterface/RiuCursors.cpp +++ b/ApplicationCode/UserInterface/RiuCursors.cpp @@ -20,7 +20,7 @@ #include "RiuCursors.h" #include -#include +#include diff --git a/ApplicationCode/UserInterface/RiuCursors.h b/ApplicationCode/UserInterface/RiuCursors.h index bb0dff9b06..525491cf04 100644 --- a/ApplicationCode/UserInterface/RiuCursors.h +++ b/ApplicationCode/UserInterface/RiuCursors.h @@ -18,7 +18,7 @@ #pragma once -#include +#include diff --git a/ApplicationCode/UserInterface/RiuCvfOverlayItemWidget.cpp b/ApplicationCode/UserInterface/RiuCvfOverlayItemWidget.cpp index 46b015fd43..03ef42752b 100644 --- a/ApplicationCode/UserInterface/RiuCvfOverlayItemWidget.cpp +++ b/ApplicationCode/UserInterface/RiuCvfOverlayItemWidget.cpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018- Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -20,6 +20,7 @@ #include "RiaApplication.h" +#include "cafTitledOverlayFrame.h" #include "cafViewer.h" #include "cvfqtUtils.h" @@ -41,16 +42,11 @@ //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -RiuCvfOverlayItemWidget::RiuCvfOverlayItemWidget(QWidget* parent/*=0*/) -: QWidget(parent) +RiuCvfOverlayItemWidget::RiuCvfOverlayItemWidget(QWidget* parent/*=0*/, QWidget* widgetToSnapTo) +: RiuDraggableOverlayFrame(parent, widgetToSnapTo) { - auto hblayout = new QHBoxLayout(this); - hblayout->setMargin(0); - hblayout->setSpacing(0); - - this->setLayout(hblayout); - m_overlayItemLabel = new QLabel(this); - this->layout()->addWidget(m_overlayItemLabel); + this->layout()->setMargin(0); + this->layout()->setSpacing(0); } //-------------------------------------------------------------------------------------------------- @@ -64,16 +60,17 @@ RiuCvfOverlayItemWidget::~RiuCvfOverlayItemWidget() //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RiuCvfOverlayItemWidget::updateFromOverlyItem( cvf::OverlayItem * item) +void RiuCvfOverlayItemWidget::updateFromOverlayItem( caf::TitledOverlayFrame * item) { - // Use the render size of the overlayItem (sizeHint should be renamed) - - unsigned int width = item->sizeHint().x(); - unsigned int height = item->sizeHint().y(); + unsigned int width = item->renderSize().x(); + unsigned int height = item->renderSize().y(); QGLFormat glFormat; glFormat.setDirectRendering(RiaApplication::instance()->useShaders()); + // Enforce no border to avoid + item->setBackgroundFrameColor(cvf::Color4f(0, 0, 0, 0)); + caf::Viewer* viewer = new caf::Viewer(glFormat, nullptr); cvf::OpenGLContext* cvfOglContext = viewer->cvfOpenGLContext(); viewer->resize(width, height); @@ -126,7 +123,7 @@ void RiuCvfOverlayItemWidget::updateFromOverlyItem( cvf::OverlayItem * item) QPixmap pixmap = QPixmap::fromImage(image); delete viewer; - + m_overlayItemLabel->setPixmap(pixmap); this->setMinimumSize(QSize(width, height)); this->resize(QSize(width, height)); diff --git a/ApplicationCode/UserInterface/RiuCvfOverlayItemWidget.h b/ApplicationCode/UserInterface/RiuCvfOverlayItemWidget.h index fe9541873f..75b0013a23 100644 --- a/ApplicationCode/UserInterface/RiuCvfOverlayItemWidget.h +++ b/ApplicationCode/UserInterface/RiuCvfOverlayItemWidget.h @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018- Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -18,12 +18,14 @@ #pragma once +#include "RiuDraggableOverlayFrame.h" + #include class QLabel; -namespace cvf +namespace caf { - class OverlayItem; +class TitledOverlayFrame; } //================================================================================================== @@ -31,18 +33,15 @@ namespace cvf // // //================================================================================================== -class RiuCvfOverlayItemWidget : public QWidget +class RiuCvfOverlayItemWidget : public RiuDraggableOverlayFrame { Q_OBJECT public: - explicit RiuCvfOverlayItemWidget(QWidget* parent = nullptr); + explicit RiuCvfOverlayItemWidget(QWidget* parent = nullptr, QWidget* widgetToSnapTo = nullptr); ~RiuCvfOverlayItemWidget() override; - void updateFromOverlyItem( cvf::OverlayItem * item); + void updateFromOverlayItem( caf::TitledOverlayFrame* item); // virtual QSize sizeHint() const override; // virtual QSize minimumSizeHint() const override; - -protected: - QLabel* m_overlayItemLabel; }; diff --git a/ApplicationCode/UserInterface/RiuDockWidgetTools.cpp b/ApplicationCode/UserInterface/RiuDockWidgetTools.cpp index 4c12ac222b..6b3c9795ba 100644 --- a/ApplicationCode/UserInterface/RiuDockWidgetTools.cpp +++ b/ApplicationCode/UserInterface/RiuDockWidgetTools.cpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018 Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by diff --git a/ApplicationCode/UserInterface/RiuDockWidgetTools.h b/ApplicationCode/UserInterface/RiuDockWidgetTools.h index 7e071d67e4..7e59b3f798 100644 --- a/ApplicationCode/UserInterface/RiuDockWidgetTools.h +++ b/ApplicationCode/UserInterface/RiuDockWidgetTools.h @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018 Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by diff --git a/ApplicationCode/UserInterface/RiuDockedQwtPlot.cpp b/ApplicationCode/UserInterface/RiuDockedQwtPlot.cpp new file mode 100644 index 0000000000..ac83b3e4e6 --- /dev/null +++ b/ApplicationCode/UserInterface/RiuDockedQwtPlot.cpp @@ -0,0 +1,78 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2019- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// +#include "RiuDockedQwtPlot.h" + +#include "RiaApplication.h" +#include "RiaPreferences.h" + +#include "qwt_abstract_legend.h" +#include "qwt_text.h" + +#include +#include + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RiuDockedQwtPlot::RiuDockedQwtPlot(QWidget* parent /*= nullptr*/) + : QwtPlot(parent) +{ +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuDockedQwtPlot::applyFontSizes(bool replot /*= false*/) +{ + std::set allAxes = {QwtPlot::xBottom, QwtPlot::yLeft, QwtPlot::xTop, QwtPlot::yRight}; + + RiaFontCache::FontSize fontSizeEnum = RiaApplication::instance()->preferences()->defaultPlotFontSize(); + int fontPointSize = RiaFontCache::pointSizeFromFontSizeEnum(fontSizeEnum) - 1; + + for (QwtPlot::Axis axis : allAxes) + { + QwtText text = this->axisTitle(axis); + QFont font = text.font(); + font.setPointSize(fontPointSize); + text.setFont(font); + this->setAxisTitle(axis, text); + + QFont valuesFont = this->axisFont(axis); + valuesFont.setPointSize(fontPointSize); + this->setAxisFont(axis, valuesFont); + } + + if (legend()) + { + auto font = legend()->font(); + font.setPointSize(fontPointSize); + legend()->setFont(font); + } + + QwtText titleText = this->title(); + QFont font = titleText.font(); + + font.setPointSize(fontPointSize + 3); + titleText.setFont(font); + this->setTitle(titleText); + + if (replot) + { + this->replot(); + } +} diff --git a/ApplicationCode/UserInterface/RiuDockedQwtPlot.h b/ApplicationCode/UserInterface/RiuDockedQwtPlot.h new file mode 100644 index 0000000000..cc8dac2408 --- /dev/null +++ b/ApplicationCode/UserInterface/RiuDockedQwtPlot.h @@ -0,0 +1,30 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2019- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// +#pragma once + +#include "qwt_plot.h" + +class RiuDockedQwtPlot : public QwtPlot +{ + Q_OBJECT +public: + explicit RiuDockedQwtPlot(QWidget* parent = nullptr); + + void applyFontSizes(bool replot); +}; + diff --git a/ApplicationCode/UserInterface/RiuDraggableOverlayFrame.cpp b/ApplicationCode/UserInterface/RiuDraggableOverlayFrame.cpp new file mode 100644 index 0000000000..84fccaf442 --- /dev/null +++ b/ApplicationCode/UserInterface/RiuDraggableOverlayFrame.cpp @@ -0,0 +1,61 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2019- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// +#include "RiuDraggableOverlayFrame.h" +#include "RiuWidgetDragger.h" + +#include +#include +#include + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RiuDraggableOverlayFrame::RiuDraggableOverlayFrame(QWidget* parent, QWidget* widgetToSnapTo, const QColor& backgroundColor) + : QFrame(parent) +{ + RiuWidgetDragger* dragger = new RiuWidgetDragger(this, widgetToSnapTo); + + QPalette pal = this->palette(); + pal.setColor(QPalette::Background, backgroundColor); + setAutoFillBackground(true); + setPalette(pal); + setFrameShape(QFrame::Box); + QGraphicsDropShadowEffect* dropShadowEffect = new QGraphicsDropShadowEffect(this); + dropShadowEffect->setOffset(1.0, 1.0); + dropShadowEffect->setBlurRadius(3.0); + dropShadowEffect->setColor(QColor(100, 100, 100, 100)); + setGraphicsEffect(dropShadowEffect); + + auto hblayout = new QVBoxLayout(this); + this->setLayout(hblayout); + + m_overlayItemLabel = new QLabel(this); + hblayout->addWidget(m_overlayItemLabel); + m_overlayItemLabel->setObjectName("OverlayFrameLabel"); + m_overlayItemLabel->setGraphicsEffect(nullptr); + m_overlayItemLabel->setAlignment(Qt::AlignTop | Qt::AlignLeft); + dragger->addWidget(m_overlayItemLabel); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QLabel* RiuDraggableOverlayFrame::label() +{ + return m_overlayItemLabel; +} diff --git a/ApplicationCode/UserInterface/RiuDraggableOverlayFrame.h b/ApplicationCode/UserInterface/RiuDraggableOverlayFrame.h new file mode 100644 index 0000000000..cb735d3f81 --- /dev/null +++ b/ApplicationCode/UserInterface/RiuDraggableOverlayFrame.h @@ -0,0 +1,35 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2019- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// +#pragma once + +#include +#include + +class QColor; +class QLabel; + +class RiuDraggableOverlayFrame : public QFrame +{ + Q_OBJECT +public: + RiuDraggableOverlayFrame(QWidget* parent, QWidget* widgetToSnapTo = nullptr, const QColor& backgroundColor = QColor(255, 255, 255, 100)); + QLabel* label(); + +protected: + QPointer m_overlayItemLabel; +}; diff --git a/ApplicationCode/UserInterface/RiuEditPerforationCollectionWidget.cpp b/ApplicationCode/UserInterface/RiuEditPerforationCollectionWidget.cpp index 4c5498202c..91d7ffd004 100644 --- a/ApplicationCode/UserInterface/RiuEditPerforationCollectionWidget.cpp +++ b/ApplicationCode/UserInterface/RiuEditPerforationCollectionWidget.cpp @@ -57,8 +57,12 @@ RiuEditPerforationCollectionWidget::RiuEditPerforationCollectionWidget(QWidget* m_pdmTableView->setChildArrayField(&(m_perforationCollection->m_perforations)); QHeaderView* verticalHeader = m_pdmTableView->tableView()->verticalHeader(); - verticalHeader->setResizeMode(QHeaderView::Interactive); +#if QT_VERSION >= 0x050000 + verticalHeader->setSectionResizeMode(QHeaderView::Interactive); +#else + verticalHeader->setResizeMode(QHeaderView::Interactive); +#endif m_pdmTableView->tableView()->resizeColumnsToContents(); // Set active child array to be able to use generic delete diff --git a/ApplicationCode/UserInterface/RiuExportMultipleSnapshotsWidget.cpp b/ApplicationCode/UserInterface/RiuExportMultipleSnapshotsWidget.cpp deleted file mode 100644 index 0ebd106e78..0000000000 --- a/ApplicationCode/UserInterface/RiuExportMultipleSnapshotsWidget.cpp +++ /dev/null @@ -1,256 +0,0 @@ -///////////////////////////////////////////////////////////////////////////////// -// -// Copyright (C) 2016 Statoil ASA -// -// ResInsight 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 3 of the License, or -// (at your option) any later version. -// -// ResInsight 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 at -// for more details. -// -///////////////////////////////////////////////////////////////////////////////// - -#include "RiuExportMultipleSnapshotsWidget.h" - -#include "RiaApplication.h" - -#include "ExportCommands/RicExportMultipleSnapshotsFeature.h" - -#include "RimCase.h" -#include "RimEclipseCellColors.h" -#include "RimEclipseView.h" -#include "RimMultiSnapshotDefinition.h" -#include "RimProject.h" -#include "Rim3dView.h" - -#include "RiuTools.h" - -#include "cafCmdFeatureManager.h" -#include "cafPdmUiTableView.h" -#include "cafSelectionManager.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -RiuExportMultipleSnapshotsWidget::RiuExportMultipleSnapshotsWidget(QWidget* parent, RimProject* project) - : QDialog(parent, RiuTools::defaultDialogFlags()), - m_rimProject(project) -{ - setWindowTitle("Export Multiple Snapshots"); - - int nWidth = 1000; - int nHeight = 300; - resize(nWidth, nHeight); - - QVBoxLayout* dialogLayout = new QVBoxLayout; - setLayout(dialogLayout); - - m_pdmTableView = new caf::PdmUiTableView(this); - m_pdmTableView->tableView()->setSelectionMode(QAbstractItemView::ExtendedSelection); - m_pdmTableView->tableView()->setContextMenuPolicy(Qt::CustomContextMenu); - m_pdmTableView->enableHeaderText(false); - - connect(m_pdmTableView->tableView(), SIGNAL(customContextMenuRequested(QPoint)), SLOT(customMenuRequested(QPoint))); - - m_pdmTableView->setChildArrayField(&(project->multiSnapshotDefinitions())); - - QHeaderView* verticalHeader = m_pdmTableView->tableView()->verticalHeader(); - verticalHeader->setResizeMode(QHeaderView::Interactive); - - m_pdmTableView->tableView()->resizeColumnsToContents(); - - // Set active child array to be able to use generic delete - caf::SelectionManager::instance()->setActiveChildArrayFieldHandle(&(project->multiSnapshotDefinitions())); - - dialogLayout->addWidget(m_pdmTableView); - - // Export folder - { - QHBoxLayout* layout = new QHBoxLayout; - - layout->addWidget(new QLabel("Export folder")); - - // Save images in snapshot catalog relative to project directory - QString snapshotFolderName = RiaApplication::instance()->createAbsolutePathFromProjectRelativePath("snapshots"); - - m_exportFolderLineEdit = new QLineEdit(snapshotFolderName); - - QToolButton* button = new QToolButton; - button->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred)); - button->setText(QLatin1String("...")); - - layout->addWidget(m_exportFolderLineEdit); - layout->addWidget(button); - - connect(button, SIGNAL(clicked()), this, SLOT(folderSelectionClicked())); - - dialogLayout->addLayout(layout); - } - - - // Buttons - QDialogButtonBox* buttonBox = new QDialogButtonBox(QDialogButtonBox::Close); - connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept())); - connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject())); - - QPushButton* exportButton = new QPushButton(tr("Export")); - exportButton->setDefault(true); - buttonBox->addButton(exportButton, QDialogButtonBox::ActionRole); - connect(exportButton, SIGNAL(clicked()), this, SLOT(exportSnapshots())); - - dialogLayout->addWidget(buttonBox); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -RiuExportMultipleSnapshotsWidget::~RiuExportMultipleSnapshotsWidget() -{ - m_pdmTableView->setChildArrayField(nullptr); - - caf::SelectionManager::instance()->setActiveChildArrayFieldHandle(nullptr); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RiuExportMultipleSnapshotsWidget::addSnapshotItemFromActiveView() -{ - if (!m_rimProject) return; - - Rim3dView* activeView = RiaApplication::instance()->activeReservoirView(); - if (activeView) - { - RimMultiSnapshotDefinition* multiSnapshot = new RimMultiSnapshotDefinition(); - multiSnapshot->view = activeView; - - RimEclipseView* eclipseView = dynamic_cast(activeView); - if (eclipseView) - { - multiSnapshot->eclipseResultType = eclipseView->cellResult()->resultType(); - multiSnapshot->selectedEclipseResults.v().push_back(eclipseView->cellResult()->resultVariable()); - - } - multiSnapshot->timeStepStart = activeView->currentTimeStep(); - multiSnapshot->timeStepEnd = activeView->currentTimeStep(); - - RimCase* sourceCase = nullptr; - activeView->firstAncestorOrThisOfType(sourceCase); - if (sourceCase) - { - multiSnapshot->additionalCases().push_back(sourceCase); - } - - m_rimProject->multiSnapshotDefinitions.push_back(multiSnapshot); - m_rimProject->multiSnapshotDefinitions.uiCapability()->updateConnectedEditors(); - } -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RiuExportMultipleSnapshotsWidget::addEmptySnapshotItems(size_t itemCount) -{ - if (!m_rimProject) return; - - for (size_t i = 0; i < itemCount; i++) - { - RimMultiSnapshotDefinition* multiSnapshot = new RimMultiSnapshotDefinition(); - multiSnapshot->isActive = false; - - m_rimProject->multiSnapshotDefinitions.push_back(multiSnapshot); - } - - m_rimProject->multiSnapshotDefinitions.uiCapability()->updateConnectedEditors(); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RiuExportMultipleSnapshotsWidget::customMenuRequested(QPoint pos) -{ - caf::CmdFeatureManager* commandManager = caf::CmdFeatureManager::instance(); - - QMenu menu; - menu.addAction(commandManager->action("PdmListField_DeleteItem","Delete row")); - - QAction* newRowAction = new QAction("New row", this); - connect(newRowAction, SIGNAL(triggered()), SLOT(addSnapshotItem())); - menu.addAction(newRowAction); - - QAction* clearAllRows = new QAction("Clear", this); - connect(clearAllRows, SIGNAL(triggered()), SLOT(deleteAllSnapshotItems())); - menu.addAction(clearAllRows); - - - // Qt doc: QAbstractScrollArea and its subclasses that map the context menu event to coordinates of the viewport(). - QPoint globalPos = m_pdmTableView->tableView()->viewport()->mapToGlobal(pos); - - menu.exec(globalPos); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RiuExportMultipleSnapshotsWidget::deleteAllSnapshotItems() -{ - if (!m_rimProject) return; - - m_rimProject->multiSnapshotDefinitions.deleteAllChildObjects(); - - m_rimProject->multiSnapshotDefinitions.uiCapability()->updateConnectedEditors(); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RiuExportMultipleSnapshotsWidget::exportSnapshots() -{ - RicExportMultipleSnapshotsFeature::exportMultipleSnapshots(m_exportFolderLineEdit->text(), m_rimProject); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RiuExportMultipleSnapshotsWidget::folderSelectionClicked() -{ - QString defaultPath = m_exportFolderLineEdit->text(); - - QString directoryPath = QFileDialog::getExistingDirectory(m_exportFolderLineEdit, - tr("Get existing directory"), - defaultPath, - QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks); - - if (!directoryPath.isEmpty()) - { - m_exportFolderLineEdit->setText(directoryPath); - } -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RiuExportMultipleSnapshotsWidget::addSnapshotItem() -{ - addSnapshotItemFromActiveView(); -} diff --git a/ApplicationCode/UserInterface/RiuExportMultipleSnapshotsWidget.h b/ApplicationCode/UserInterface/RiuExportMultipleSnapshotsWidget.h deleted file mode 100644 index c45446faec..0000000000 --- a/ApplicationCode/UserInterface/RiuExportMultipleSnapshotsWidget.h +++ /dev/null @@ -1,54 +0,0 @@ -///////////////////////////////////////////////////////////////////////////////// -// -// Copyright (C) 2016 Statoil ASA -// -// ResInsight 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 3 of the License, or -// (at your option) any later version. -// -// ResInsight 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 at -// for more details. -// -///////////////////////////////////////////////////////////////////////////////// - -#pragma once - -#include - -class RimProject; - -namespace caf { - class PdmUiTableView; -} - -class QWidget; -class QLineEdit; - -class RiuExportMultipleSnapshotsWidget : public QDialog -{ - Q_OBJECT -public: - RiuExportMultipleSnapshotsWidget(QWidget* parent, RimProject* project); - ~RiuExportMultipleSnapshotsWidget() override; - - void addSnapshotItemFromActiveView(); - void addEmptySnapshotItems(size_t itemCount); - -private slots: - void customMenuRequested(QPoint pos); - void addSnapshotItem(); - void deleteAllSnapshotItems(); - void exportSnapshots(); - - void folderSelectionClicked(); - -private: - RimProject* m_rimProject; - caf::PdmUiTableView* m_pdmTableView; - QLineEdit* m_exportFolderLineEdit; -}; diff --git a/ApplicationCode/UserInterface/RiuExpressionContextMenuManager.h b/ApplicationCode/UserInterface/RiuExpressionContextMenuManager.h index be54ed5a46..17b74eb1cd 100644 --- a/ApplicationCode/UserInterface/RiuExpressionContextMenuManager.h +++ b/ApplicationCode/UserInterface/RiuExpressionContextMenuManager.h @@ -39,7 +39,10 @@ class RiuExpressionContextMenuManager : public QObject static const std::map> MENU_MAP; public: - RiuExpressionContextMenuManager() { } + RiuExpressionContextMenuManager() + : m_textPosition(0) + { + } void attachTextEdit(QTextEdit* textEdit); diff --git a/ApplicationCode/UserInterface/RiuFemTimeHistoryResultAccessor.cpp b/ApplicationCode/UserInterface/RiuFemTimeHistoryResultAccessor.cpp index 619847387a..73986eeca2 100644 --- a/ApplicationCode/UserInterface/RiuFemTimeHistoryResultAccessor.cpp +++ b/ApplicationCode/UserInterface/RiuFemTimeHistoryResultAccessor.cpp @@ -39,7 +39,7 @@ RiuFemTimeHistoryResultAccessor::RiuFemTimeHistoryResultAccessor(RigGeoMechCaseD int face, const cvf::Vec3d& intersectionPointInDomain) : m_geoMechCaseData(geomData), - m_femResultAddress(femResultAddress), + m_femResultAddress(new RigFemResultAddress(femResultAddress)), m_gridIndex(gridIndex), m_elementIndex(elementIndex), m_face(face), @@ -60,7 +60,7 @@ RiuFemTimeHistoryResultAccessor::RiuFemTimeHistoryResultAccessor(RigGeoMechCaseD const cvf::Vec3d& intersectionPointInDomain, const std::array& intersectionTriangle) : m_geoMechCaseData(geomData), - m_femResultAddress(femResultAddress), + m_femResultAddress(new RigFemResultAddress(femResultAddress)), m_gridIndex(gridIndex), m_elementIndex(elementIndex), m_face(face), @@ -115,6 +115,14 @@ std::vector RiuFemTimeHistoryResultAccessor::timeHistoryValues() const return m_timeHistoryValues; } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +int RiuFemTimeHistoryResultAccessor::closestNodeId() const +{ + return m_closestNodeId; +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -123,7 +131,7 @@ void RiuFemTimeHistoryResultAccessor::computeTimeHistoryData() m_timeHistoryValues.clear(); RigFemClosestResultIndexCalculator closestCalc(m_geoMechCaseData->femParts()->part(m_gridIndex), - m_femResultAddress.resultPosType, + m_femResultAddress->resultPosType, m_elementIndex, m_face, m_intersectionPointInDomain ); @@ -133,13 +141,13 @@ void RiuFemTimeHistoryResultAccessor::computeTimeHistoryData() RigFemPartResultsCollection* femPartResultsColl = m_geoMechCaseData->femPartResults(); - if (m_femResultAddress.resultPosType == RIG_ELEMENT_NODAL_FACE && m_hasIntersectionTriangle) + if (m_femResultAddress->resultPosType == RIG_ELEMENT_NODAL_FACE && m_hasIntersectionTriangle) { int closestElmNodeResIndex = closestCalc.closestElementNodeResIdx(); for ( int frameIdx = 0; frameIdx < femPartResultsColl->frameCount(); frameIdx++ ) { - RiuGeoMechXfTensorResultAccessor stressXfAccessor(femPartResultsColl, m_femResultAddress, frameIdx); + RiuGeoMechXfTensorResultAccessor stressXfAccessor(femPartResultsColl, *m_femResultAddress, frameIdx); float scalarValue = stressXfAccessor.calculateElmNodeValue(m_intersectionTriangle, closestElmNodeResIndex); m_timeHistoryValues.push_back(scalarValue); } @@ -150,7 +158,7 @@ void RiuFemTimeHistoryResultAccessor::computeTimeHistoryData() for ( int frameIdx = 0; frameIdx < femPartResultsColl->frameCount(); frameIdx++ ) { - const std::vector& scalarResults = m_geoMechCaseData->femPartResults()->resultValues(m_femResultAddress, static_cast(m_gridIndex), frameIdx); + const std::vector& scalarResults = m_geoMechCaseData->femPartResults()->resultValues(*m_femResultAddress, static_cast(m_gridIndex), frameIdx); if ( scalarResults.size() ) { float scalarValue = scalarResults[scalarResultIndex]; diff --git a/ApplicationCode/UserInterface/RiuFemTimeHistoryResultAccessor.h b/ApplicationCode/UserInterface/RiuFemTimeHistoryResultAccessor.h index b3f601fe6a..cefa1f943f 100644 --- a/ApplicationCode/UserInterface/RiuFemTimeHistoryResultAccessor.h +++ b/ApplicationCode/UserInterface/RiuFemTimeHistoryResultAccessor.h @@ -19,23 +19,26 @@ #pragma once -#include "RigFemResultAddress.h" - -#include "cvfStructGrid.h" +#include "cvfBase.h" #include "cvfVector3.h" + +#include + #include +#include +#include class RigGeoMechCaseData; - +class RigFemResultAddress; class RiuFemTimeHistoryResultAccessor { public: - RiuFemTimeHistoryResultAccessor(RigGeoMechCaseData* geomData, + RiuFemTimeHistoryResultAccessor(RigGeoMechCaseData* geomData, RigFemResultAddress femResultAddress, - size_t gridIndex, + size_t gridIndex, int elementIndex, - int face, + int face, const cvf::Vec3d& intersectionPointInDomain); RiuFemTimeHistoryResultAccessor(RigGeoMechCaseData* geomData, @@ -43,19 +46,20 @@ class RiuFemTimeHistoryResultAccessor size_t gridIndex, int elementIndex, int face, - const cvf::Vec3d& intersectionPointInDomain, + const cvf::Vec3d& intersectionPointInDomain, const std::array& m_intersectionTriangle); QString geometrySelectionText() const; std::vector timeHistoryValues() const; - int closestNodeId() const { return m_closestNodeId; } + + int closestNodeId() const; private: void computeTimeHistoryData(); private: - RigGeoMechCaseData* m_geoMechCaseData; - RigFemResultAddress m_femResultAddress; + RigGeoMechCaseData* m_geoMechCaseData; + std::unique_ptr m_femResultAddress; size_t m_gridIndex; int m_elementIndex; diff --git a/ApplicationCode/UserInterface/RiuFlowCharacteristicsPlot.cpp b/ApplicationCode/UserInterface/RiuFlowCharacteristicsPlot.cpp index a39964cf53..d98cfc4df4 100644 --- a/ApplicationCode/UserInterface/RiuFlowCharacteristicsPlot.cpp +++ b/ApplicationCode/UserInterface/RiuFlowCharacteristicsPlot.cpp @@ -26,7 +26,7 @@ #include "RiuQwtPlotWheelZoomer.h" #include "RiuQwtPlotZoomer.h" #include "RiuResultQwtPlot.h" -#include "RiuSummaryQwtPlot.h" +#include "RiuQwtPlotTools.h" #include "cvfBase.h" #include "cvfColor3.h" @@ -73,18 +73,18 @@ RiuFlowCharacteristicsPlot::RiuFlowCharacteristicsPlot(RimFlowCharacteristicsPlo mainLayout->addWidget(m_flowCapVsStorageCapPlot, 1, 0); mainLayout->addWidget(m_sweepEffPlot, 1, 1); - RiuSummaryQwtPlot::setCommonPlotBehaviour(m_lorenzPlot); + RiuQwtPlotTools::setCommonPlotBehaviour(m_lorenzPlot); new RiuQwtPlotWheelZoomer(m_lorenzPlot); addWindowZoom(m_lorenzPlot); - RiuSummaryQwtPlot::enableDateBasedBottomXAxis(m_lorenzPlot); + RiuQwtPlotTools::enableDateBasedBottomXAxis(m_lorenzPlot); m_lorenzPlot->setTitle("Lorenz Coefficient"); - RiuSummaryQwtPlot::setCommonPlotBehaviour(m_sweepEffPlot); + RiuQwtPlotTools::setCommonPlotBehaviour(m_sweepEffPlot); new RiuQwtPlotWheelZoomer(m_sweepEffPlot); addWindowZoom(m_sweepEffPlot); m_sweepEffPlot->setTitle("Sweep Efficiency"); - RiuSummaryQwtPlot::setCommonPlotBehaviour(m_flowCapVsStorageCapPlot); + RiuQwtPlotTools::setCommonPlotBehaviour(m_flowCapVsStorageCapPlot); new RiuQwtPlotWheelZoomer(m_flowCapVsStorageCapPlot); addWindowZoom(m_flowCapVsStorageCapPlot); m_flowCapVsStorageCapPlot->setTitle("Flow Capacity vs Storage Capacity"); @@ -106,10 +106,6 @@ void RiuFlowCharacteristicsPlot::addWindowZoom(QwtPlot* plot) //-------------------------------------------------------------------------------------------------- RiuFlowCharacteristicsPlot::~RiuFlowCharacteristicsPlot() { - if (m_plotDefinition) - { - m_plotDefinition->handleMdiWindowClosed(); - } } //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/UserInterface/RiuGeoQuestNavigation.cpp b/ApplicationCode/UserInterface/RiuGeoQuestNavigation.cpp index 25ead7cfba..41aa323e60 100644 --- a/ApplicationCode/UserInterface/RiuGeoQuestNavigation.cpp +++ b/ApplicationCode/UserInterface/RiuGeoQuestNavigation.cpp @@ -89,6 +89,7 @@ bool RiuGeoQuestNavigation::handleInputEvent(QInputEvent* inputEvent) isEventHandled = true; } } + forcePointOfInterestUpdateDuringNextWheelZoom(); } break; case QEvent::MouseButtonRelease: @@ -144,11 +145,12 @@ bool RiuGeoQuestNavigation::handleInputEvent(QInputEvent* inputEvent) { if (inputEvent->modifiers() == Qt::NoModifier) { - initializeRotationCenter(); + QWheelEvent* we = static_cast(inputEvent); + + updatePointOfInterestDuringZoomIfNecessary(we->x(), we->y()); + if (m_isRotCenterInitialized) { - QWheelEvent* we = static_cast(inputEvent); - int translatedMousePosX, translatedMousePosY; cvfEventPos(we->x(), we->y(), &translatedMousePosX, &translatedMousePosY); diff --git a/ApplicationCode/UserInterface/RiuGridCrossQwtPlot.cpp b/ApplicationCode/UserInterface/RiuGridCrossQwtPlot.cpp new file mode 100644 index 0000000000..8580aaddb5 --- /dev/null +++ b/ApplicationCode/UserInterface/RiuGridCrossQwtPlot.cpp @@ -0,0 +1,453 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2019- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// +#include "RiuGridCrossQwtPlot.h" + +#include "RiaFontCache.h" + +#include "RiuCvfOverlayItemWidget.h" +#include "RiuRimQwtPlotCurve.h" +#include "RiuQwtCurvePointTracker.h" +#include "RiuWidgetDragger.h" + +#include "RimGridCrossPlot.h" +#include "RimGridCrossPlotDataSet.h" +#include "RimGridCrossPlotCurve.h" +#include "RimRegularLegendConfig.h" + +#include "cafCmdFeatureMenuBuilder.h" +#include "cafFixedAtlasFont.h" +#include "cafSelectionManager.h" +#include "cafTitledOverlayFrame.h" + +#include "RimPlotAxisAnnotation.h" +#include "RimPlotAxisProperties.h" +#include "RiuPlotAnnotationTool.h" + +#include "qwt_text.h" +#include "qwt_text_engine.h" + +#include +#include +#include +#include + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RiuGridCrossQwtPlot::RiuGridCrossQwtPlot(RimViewWindow* ownerViewWindow, QWidget* parent /*= nullptr*/) + : RiuQwtPlot(ownerViewWindow, parent) +{ + m_annotationTool = std::unique_ptr(new RiuPlotAnnotationTool()); + m_infoBox = new RiuDraggableOverlayFrame(this, canvas()); + + m_selectedPointMarker = new QwtPlotMarker; + + // QwtPlotMarker takes ownership of the symbol, it is deleted in destructor of QwtPlotMarker + QwtSymbol* mySymbol = new QwtSymbol(QwtSymbol::Ellipse, QBrush(QColor(255, 255, 255, 50)), QPen(Qt::black, 2.0), QSize(10, 10)); + m_selectedPointMarker->setSymbol(mySymbol); + m_selectedPointMarker->setLabelAlignment(Qt::AlignRight | Qt::AlignVCenter); + m_selectedPointMarker->setSpacing(3); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RiuGridCrossQwtPlot::~RiuGridCrossQwtPlot() +{ + if (m_selectedPointMarker->plot()) + { + m_selectedPointMarker->detach(); + } + delete m_selectedPointMarker; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuGridCrossQwtPlot::addOrUpdateDataSetLegend(RimGridCrossPlotDataSet* dataSet) +{ + RiuCvfOverlayItemWidget* overlayWidget = nullptr; + + auto it = m_legendWidgets.find(dataSet); + if (it == m_legendWidgets.end() || it->second == nullptr) + { + overlayWidget = new RiuCvfOverlayItemWidget(this, canvas()); + m_legendWidgets[dataSet] = overlayWidget; + } + else + { + overlayWidget = it->second; + } + + if (overlayWidget) + { + caf::TitledOverlayFrame* overlayItem = dataSet->legendConfig()->titledOverlayFrame(); + applyFontSizeToOverlayItem(overlayItem); + resizeOverlayItemToFitPlot(overlayItem); + overlayWidget->updateFromOverlayItem(overlayItem); + } + this->updateLegendLayout(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuGridCrossQwtPlot::removeDataSetLegend(RimGridCrossPlotDataSet* dataSetToShowLegendFor) +{ + auto it = m_legendWidgets.find(dataSetToShowLegendFor); + if (it != m_legendWidgets.end()) + { + if (it->second != nullptr) + { + it->second->hide(); + it->second->deleteLater(); + } + + m_legendWidgets.erase(it); + } + + this->updateLegendLayout(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuGridCrossQwtPlot::removeDanglingDataSetLegends() +{ + for (auto it = m_legendWidgets.begin(); it != m_legendWidgets.end();) + { + if (it->first.isNull()) + { + if (it->second != nullptr) + { + it->second->hide(); + it->second->deleteLater(); + } + m_legendWidgets.erase(it++); + } + else + { + ++it; + } + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuGridCrossQwtPlot::updateLegendSizesToMatchPlot() +{ + RimGridCrossPlot* crossPlot = dynamic_cast(ownerPlotDefinition()); + if (!crossPlot) return; + + bool anyLegendResized = false; + + for (RimGridCrossPlotDataSet* dataSet : crossPlot->dataSets()) + { + if (!dataSet->isChecked() || !dataSet->legendConfig()->showLegend()) continue; + + auto pairIt = m_legendWidgets.find(dataSet); + if (pairIt != m_legendWidgets.end()) + { + RiuCvfOverlayItemWidget* overlayWidget = pairIt->second; + caf::TitledOverlayFrame* overlayItem = dataSet->legendConfig()->titledOverlayFrame(); + applyFontSizeToOverlayItem(overlayItem); + if (resizeOverlayItemToFitPlot(overlayItem)) + { + anyLegendResized = true; + overlayWidget->updateFromOverlayItem(overlayItem); + } + } + } + if (anyLegendResized) + { + updateLegendLayout(); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuGridCrossQwtPlot::updateAnnotationObjects(RimPlotAxisProperties* axisProperties) +{ + m_annotationTool->detachAllAnnotations(); + + for (auto annotation : axisProperties->annotations()) + { + m_annotationTool->attachAnnotationLine(this, annotation->color(), annotation->name(), annotation->value()); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuGridCrossQwtPlot::updateLayout() +{ + QwtPlot::updateLayout(); + updateInfoBoxLayout(); + updateLegendLayout(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuGridCrossQwtPlot::updateInfoBoxLayout() +{ + RimGridCrossPlot* crossPlot = dynamic_cast(ownerPlotDefinition()); + if (!crossPlot) return; + + bool showInfo = false; + if (crossPlot->showInfoBox()) + { + QStringList curveInfoTexts; + for (auto dataSet : crossPlot->dataSets()) + { + QString curveInfoText = dataSet->infoText(); + if (dataSet->isChecked() && !curveInfoText.isEmpty()) + { + curveInfoTexts += curveInfoText; + } + } + QStringList infoText; + if (curveInfoTexts.size() > 1) + { + infoText += QString("
    "); + for (QString curveInfoText : curveInfoTexts) + { + infoText += QString("
  1. %1
  2. ").arg(curveInfoText); + } + infoText += QString("
"); + } + else if (curveInfoTexts.size() > 0) + { + infoText += curveInfoTexts.front(); + } + if (!infoText.empty()) + { + m_infoBox->label()->setText(infoText.join("\n")); + QFont font = m_infoBox->font(); + font.setPointSize(crossPlot->legendFontSize()); + m_infoBox->setFont(font); + m_infoBox->adjustSize(); + QRect infoRect = m_infoBox->frameGeometry(); + QRect canvasRect = canvas()->frameGeometry(); + infoRect.moveTop(canvasRect.top() + 4); + infoRect.moveRight(canvasRect.right() - 4); + m_infoBox->move(infoRect.topLeft()); + showInfo = true; + } + } + if (showInfo) + { + m_infoBox->show(); + } + else + { + m_infoBox->hide(); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuGridCrossQwtPlot::updateLegendLayout() +{ + const int spacing = 5; + int startMarginX = this->canvas()->pos().x() + spacing; + int startMarginY = this->canvas()->pos().y() + spacing; + + int xpos = startMarginX; + int ypos = startMarginY; + int maxColumnWidth = 0; + + removeDanglingDataSetLegends(); + + RimGridCrossPlot* crossPlot = dynamic_cast(ownerPlotDefinition()); + + if (!crossPlot) return; + + std::set legendTypes; + + for (RimGridCrossPlotDataSet* dataSet : crossPlot->dataSets()) + { + if (dataSet->isChecked() && dataSet->groupingEnabled() && dataSet->legendConfig()->showLegend()) + { + + auto pairIt = m_legendWidgets.find(dataSet); + if (pairIt != m_legendWidgets.end()) + { + RiuCvfOverlayItemWidget* overlayWidget = pairIt->second; + + // Show only one copy of each legend type + if (!legendTypes.count(dataSet->groupParameter())) + { + if (ypos + overlayWidget->height() + spacing > this->canvas()->height()) + { + xpos += spacing + maxColumnWidth; + ypos = startMarginY; + maxColumnWidth = 0; + } + + overlayWidget->show(); + overlayWidget->move(xpos, ypos); + + ypos += pairIt->second->height() + spacing; + maxColumnWidth = std::max(maxColumnWidth, pairIt->second->width()); + legendTypes.insert(dataSet->groupParameter()); + } + } + } + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuGridCrossQwtPlot::resizeEvent(QResizeEvent* e) +{ + QwtPlot::resizeEvent(e); + updateLegendSizesToMatchPlot(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RiuGridCrossQwtPlot::resizeOverlayItemToFitPlot(caf::TitledOverlayFrame* overlayItem) +{ + QSize plotSize = this->canvas()->contentsRect().size(); + cvf::Vec2ui existingRenderSize = overlayItem->renderSize(); + cvf::Vec2ui legendSize = overlayItem->preferredSize(); + + bool sizeAltered = false; + + if (plotSize.width() > 0 && (double)legendSize.x() > 0.9 * plotSize.width()) + { + legendSize.x() = (plotSize.width() * 9) / 10; + sizeAltered = true; + } + if (plotSize.height() > 0 && (double)legendSize.y() > 0.9 * plotSize.height()) + { + legendSize.y() = (plotSize.height() * 9) / 10; + sizeAltered = true; + } + overlayItem->setRenderSize(legendSize); + + if (legendSize.x() != existingRenderSize.x() || legendSize.y() != existingRenderSize.y()) + { + sizeAltered = true; + } + + return sizeAltered; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuGridCrossQwtPlot::contextMenuEvent(QContextMenuEvent* event) +{ + QMenu menu; + caf::CmdFeatureMenuBuilder menuBuilder; + + caf::SelectionManager::instance()->setSelectedItem(ownerViewWindow()); + + menuBuilder << "RicSwapGridCrossPlotDataSetAxesFeature"; + menuBuilder << "Separator"; + menuBuilder << "RicShowPlotDataFeature"; + + menuBuilder.appendToMenu(&menu); + + if (menu.actions().size() > 0) + { + menu.exec(event->globalPos()); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuGridCrossQwtPlot::selectSample(QwtPlotCurve* curve, int sampleNumber) +{ + QPointF sample = curve->sample(sampleNumber); + m_selectedPointMarker->setValue(sample); + m_selectedPointMarker->setAxes(QwtPlot::xBottom, QwtPlot::yLeft); + m_selectedPointMarker->attach(this); + QString curveName, xAxisName, yAxisName; + if (curveText(curve, &curveName, &xAxisName, &yAxisName)) + { + QString labelFormat("
%1:
%2 = %3, %4 = %5
"); + QString labelString = labelFormat.arg(curveName).arg(xAxisName).arg(sample.x()).arg(yAxisName).arg(sample.y()); + QwtText curveLabel(labelString, QwtText::RichText); + curveLabel.setBackgroundBrush(QBrush(QColor(250, 250, 250, 220))); + curveLabel.setPaintAttribute(QwtText::PaintBackground); + curveLabel.setBorderPen(QPen(Qt::black, 1.0)); + curveLabel.setBorderRadius(2.0); + m_selectedPointMarker->setLabel(curveLabel); + } + replot(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuGridCrossQwtPlot::clearSampleSelection() +{ + m_selectedPointMarker->detach(); + replot(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RiuGridCrossQwtPlot::curveText(const QwtPlotCurve* curve, + QString* curveTitle, + QString* xParamName, + QString* yParamName) const +{ + CVF_ASSERT(curveTitle && xParamName && yParamName); + + auto riuCurve = dynamic_cast(curve); + if (riuCurve) + { + auto crossPlotCurve = dynamic_cast(riuCurve->ownerRimCurve()); + if (crossPlotCurve) + { + *curveTitle = crossPlotCurve->curveName(); + + RimGridCrossPlotDataSet* dataSet = nullptr; + crossPlotCurve->firstAncestorOrThisOfType(dataSet); + if (dataSet) + { + *xParamName = dataSet->xAxisName(); + *yParamName = dataSet->yAxisName(); + return true; + } + } + } + return false; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuGridCrossQwtPlot::applyFontSizeToOverlayItem(caf::TitledOverlayFrame* overlayItem) +{ + RimGridCrossPlot* crossPlot = static_cast(ownerViewWindow()); + int fontSize = crossPlot->legendFontSize(); + cvf::ref cafFont = RiaFontCache::getFont(RiaFontCache::fontSizeEnumFromPointSize(fontSize)); + overlayItem->setFont(cafFont.p()); +} diff --git a/ApplicationCode/UserInterface/RiuGridCrossQwtPlot.h b/ApplicationCode/UserInterface/RiuGridCrossQwtPlot.h new file mode 100644 index 0000000000..29079518b9 --- /dev/null +++ b/ApplicationCode/UserInterface/RiuGridCrossQwtPlot.h @@ -0,0 +1,81 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2019- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// +#pragma once + +#include "RiuInterfaceToViewWindow.h" +#include "RiuPlotAnnotationTool.h" +#include "RiuQwtPlot.h" + +#include "cafPdmPointer.h" + +#include + +#include + +class RimGridCrossPlotDataSet; +class RimPlotAxisProperties; +class RiuCvfOverlayItemWidget; +class RiuDraggableOverlayFrame; +class RiuPlotAnnotationTool; + +namespace caf +{ +class TitledOverlayFrame; +} + +//================================================================================================== +// +// +// +//================================================================================================== +class RiuGridCrossQwtPlot : public RiuQwtPlot +{ + Q_OBJECT; + +public: + RiuGridCrossQwtPlot(RimViewWindow* ownerViewWindow, QWidget* parent = nullptr); + ~RiuGridCrossQwtPlot(); + void addOrUpdateDataSetLegend(RimGridCrossPlotDataSet* dataSetToShowLegendFor); + void removeDataSetLegend(RimGridCrossPlotDataSet* dataSetToShowLegendFor); + void removeDanglingDataSetLegends(); + void updateLegendSizesToMatchPlot(); + void updateAnnotationObjects(RimPlotAxisProperties* axisProperties); + +protected: + void updateLayout() override; + void updateInfoBoxLayout(); + void updateLegendLayout(); + void resizeEvent(QResizeEvent* e) override; + bool resizeOverlayItemToFitPlot(caf::TitledOverlayFrame* overlayItem); + void contextMenuEvent(QContextMenuEvent*) override; + + void selectSample(QwtPlotCurve* curve, int sampleNumber) override; + void clearSampleSelection() override; + bool curveText(const QwtPlotCurve* curve, QString* curveTitle, QString* xParamName, QString* yParamName) const; + void applyFontSizeToOverlayItem(caf::TitledOverlayFrame* overlayItem); +private: + typedef caf::PdmPointer DataSetPtr; + typedef QPointer LegendPtr; + typedef QPointer InfoBoxPtr; + + InfoBoxPtr m_infoBox; + std::map m_legendWidgets; + std::unique_ptr m_annotationTool; + QwtPlotMarker* m_selectedPointMarker; + +}; diff --git a/ApplicationCode/UserInterface/RiuMainWindow.cpp b/ApplicationCode/UserInterface/RiuMainWindow.cpp index bd0b04ce24..2d70a0a69d 100644 --- a/ApplicationCode/UserInterface/RiuMainWindow.cpp +++ b/ApplicationCode/UserInterface/RiuMainWindow.cpp @@ -3,17 +3,17 @@ // Copyright (C) 2011- Statoil ASA // Copyright (C) 2013- Ceetron Solutions AS // Copyright (C) 2011-2012 Ceetron AS -// +// // ResInsight 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 3 of the License, or // (at your option) any later version. -// +// // ResInsight 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 at +// +// See the GNU General Public License at // for more details. // ///////////////////////////////////////////////////////////////////////////////// @@ -26,12 +26,12 @@ #include "RiaRegressionTest.h" #include "RiaRegressionTestRunner.h" -#include "RimContourMapView.h" #include "Rim2dIntersectionView.h" #include "Rim3dView.h" #include "RimCellEdgeColors.h" #include "RimCommandObject.h" #include "RimEclipseCase.h" +#include "RimEclipseContourMapView.h" #include "RimEclipseFaultColors.h" #include "RimEclipsePropertyFilter.h" #include "RimEclipseResultDefinition.h" @@ -75,6 +75,7 @@ #include "cafUtils.h" #include "ExportCommands/RicSnapshotAllViewsToFileFeature.h" +#include "MeasurementCommands/RicToggleMeasurementModeFeature.h" #include "SummaryPlotCommands/RicEditSummaryPlotFeature.h" #include "SummaryPlotCommands/RicShowSummaryCurveCalculatorFeature.h" @@ -88,17 +89,16 @@ #include #include #include -#include #include #include #include #include +#include #include #include #include - //================================================================================================== /// /// \class RiuMainWindow @@ -107,52 +107,39 @@ /// //================================================================================================== - -RiuMainWindow* RiuMainWindow::sm_mainWindowInstance = nullptr; - //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- RiuMainWindow::RiuMainWindow() - : m_pdmRoot(nullptr), - m_mainViewer(nullptr), - m_relPermPlotPanel(nullptr), - m_pvtPlotPanel(nullptr), - m_mohrsCirclePlot(nullptr), - m_windowMenu(nullptr), - m_blockSlotSubWindowActivated(false), - m_holoLensToolBar(nullptr) -{ - CVF_ASSERT(sm_mainWindowInstance == nullptr); - - m_mdiArea = new QMdiArea; - m_mdiArea->setOption(QMdiArea::DontMaximizeSubWindowOnActivation, true); - connect(m_mdiArea, SIGNAL(subWindowActivated(QMdiSubWindow *)), SLOT(slotSubWindowActivated(QMdiSubWindow*))); + : m_pdmRoot(nullptr) + , m_relPermPlotPanel(nullptr) + , m_pvtPlotPanel(nullptr) + , m_mohrsCirclePlot(nullptr) + , m_windowMenu(nullptr) + , m_holoLensToolBar(nullptr) +{ + m_mdiArea = new RiuMdiArea; + connect(m_mdiArea, SIGNAL(subWindowActivated(QMdiSubWindow*)), SLOT(slotSubWindowActivated(QMdiSubWindow*))); setCentralWidget(m_mdiArea); - //m_mainViewer = createViewer(); + // m_mainViewer = createViewer(); createActions(); createMenus(); createToolBars(); createDockPanels(); - // Store the layout so we can offer reset option - m_initialDockAndToolbarLayout = saveState(0); - - sm_mainWindowInstance = this; - m_dragDropInterface = std::unique_ptr(new RiuDragDrop()); initializeGuiNewProjectLoaded(); // Enabling the line below will activate the undo stack // When enableUndoCommandSystem is set false, all commands are executed and deleted immediately - //caf::CmdExecCommandManager::instance()->enableUndoCommandSystem(true); + // caf::CmdExecCommandManager::instance()->enableUndoCommandSystem(true); m_memoryCriticalWarning = new QLabel(""); - m_memoryUsedButton = new QToolButton(nullptr); - m_memoryTotalStatus = new QLabel(""); + m_memoryUsedButton = new QToolButton(nullptr); + m_memoryTotalStatus = new QLabel(""); m_memoryUsedButton->setDefaultAction(caf::CmdFeatureManager::instance()->action("RicShowMemoryCleanupDialogFeature")); @@ -160,8 +147,6 @@ RiuMainWindow::RiuMainWindow() statusBar()->addPermanentWidget(m_memoryUsedButton); statusBar()->addPermanentWidget(m_memoryTotalStatus); - - updateMemoryUsage(); m_memoryRefreshTimer = new QTimer(this); @@ -169,17 +154,16 @@ RiuMainWindow::RiuMainWindow() m_memoryRefreshTimer->start(1000); } - //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- RiuMainWindow* RiuMainWindow::instance() { - return sm_mainWindowInstance; + return RiaApplication::instance()->mainWindow(); } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- QString RiuMainWindow::mainWindowName() { @@ -187,12 +171,18 @@ QString RiuMainWindow::mainWindowName() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RiuMainWindow::initializeGuiNewProjectLoaded() { setPdmRoot(RiaApplication::instance()->project()); restoreTreeViewState(); + + if (subWindowsAreTiled()) + { + tileSubWindows(); + } + slotRefreshFileActions(); slotRefreshEditActions(); slotRefreshViewActions(); @@ -208,7 +198,17 @@ void RiuMainWindow::initializeGuiNewProjectLoaded() if (statusBar() && !RiaRegressionTestRunner::instance()->isRunningRegressionTests()) { - statusBar()->showMessage("Ready ..."); + statusBar()->showMessage("Ready ..."); + } + + QMdiSubWindow* activeSubWindow = m_mdiArea->activeSubWindow(); + if (activeSubWindow) + { + auto w = findViewWindowFromSubWindow(activeSubWindow); + if (w && w->mdiWindowGeometry().isMaximized) + { + activeSubWindow->showMaximized(); + } } } @@ -231,9 +231,9 @@ void RiuMainWindow::cleanupGuiCaseClose() m_pdmUiPropertyView->showProperties(nullptr); } - for (size_t i = 0; i < additionalProjectViews.size(); i++) + for (auto& additionalProjectView : m_additionalProjectViews) { - RiuProjectAndPropertyView* projPropView = dynamic_cast(additionalProjectViews[i]->widget()); + RiuProjectAndPropertyView* projPropView = dynamic_cast(additionalProjectView->widget()); if (projPropView) { projPropView->showProperties(nullptr); @@ -241,7 +241,8 @@ void RiuMainWindow::cleanupGuiCaseClose() } m_processMonitor->startMonitorWorkProcess(nullptr); - RicEditSummaryPlotFeature* editSumCurves = dynamic_cast(caf::CmdFeatureManager::instance()->getCommandFeature("RicEditSummaryPlotFeature")); + RicEditSummaryPlotFeature* editSumCurves = dynamic_cast( + caf::CmdFeatureManager::instance()->getCommandFeature("RicEditSummaryPlotFeature")); if (editSumCurves) { editSumCurves->closeDialogAndResetTargetPlot(); @@ -251,7 +252,7 @@ void RiuMainWindow::cleanupGuiCaseClose() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RiuMainWindow::cleanupGuiBeforeProjectClose() { @@ -261,14 +262,18 @@ void RiuMainWindow::cleanupGuiBeforeProjectClose() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RiuMainWindow::closeEvent(QCloseEvent* event) { RiaApplication* app = RiaApplication::instance(); + app->saveMainWinGeoAndDockToolBarLayout(); + if (app->isMainPlotWindowVisible()) { + event->ignore(); // Make Qt think we don't do anything, otherwise it closes the window. + this->hide(); // Instead we just hide it. return; } @@ -278,63 +283,72 @@ void RiuMainWindow::closeEvent(QCloseEvent* event) return; } - app->saveWinGeoAndDockToolBarLayout(); - - if (!app->tryClosePlotWindow()) return; + app->closeMainPlotWindowIfOpenButHidden(); app->closeProject(); } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RiuMainWindow::createActions() { // File actions - m_mockModelAction = new QAction("&Mock Model", this); - m_mockResultsModelAction = new QAction("Mock Model With &Results", this); + m_mockModelAction = new QAction("&Mock Model", this); + m_mockResultsModelAction = new QAction("Mock Model With &Results", this); m_mockLargeResultsModelAction = new QAction("Large Mock Model", this); - m_mockModelCustomizedAction = new QAction("Customized Mock Model", this); - m_mockInputModelAction = new QAction("Input Mock Model", this); + m_mockModelCustomizedAction = new QAction("Customized Mock Model", this); + m_mockInputModelAction = new QAction("Input Mock Model", this); - m_snapshotAllViewsToFile = new QAction(QIcon(":/SnapShotSaveViews.png"), "Snapshot All Views To File", this); + m_snapshotAllViewsToFile = new QAction(QIcon(":/SnapShotSaveViews.png"), "Snapshot All Views To File", this); - m_createCommandObject = new QAction("Create Command Object", this); - m_showRegressionTestDialog = new QAction("Regression Test Dialog", this); + m_createCommandObject = new QAction("Create Command Object", this); + m_showRegressionTestDialog = new QAction("Regression Test Dialog", this); m_executePaintEventPerformanceTest = new QAction("&Paint Event Performance Test", this); - connect(m_mockModelAction, SIGNAL(triggered()), SLOT(slotMockModel())); - connect(m_mockResultsModelAction, SIGNAL(triggered()), SLOT(slotMockResultsModel())); - connect(m_mockLargeResultsModelAction, SIGNAL(triggered()), SLOT(slotMockLargeResultsModel())); - connect(m_mockModelCustomizedAction, SIGNAL(triggered()), SLOT(slotMockModelCustomized())); - connect(m_mockInputModelAction, SIGNAL(triggered()), SLOT(slotInputMockModel())); + connect(m_mockModelAction, SIGNAL(triggered()), SLOT(slotMockModel())); + connect(m_mockResultsModelAction, SIGNAL(triggered()), SLOT(slotMockResultsModel())); + connect(m_mockLargeResultsModelAction, SIGNAL(triggered()), SLOT(slotMockLargeResultsModel())); + connect(m_mockModelCustomizedAction, SIGNAL(triggered()), SLOT(slotMockModelCustomized())); + connect(m_mockInputModelAction, SIGNAL(triggered()), SLOT(slotInputMockModel())); - connect(m_snapshotAllViewsToFile, SIGNAL(triggered()), SLOT(slotSnapshotAllViewsToFile())); + connect(m_snapshotAllViewsToFile, SIGNAL(triggered()), SLOT(slotSnapshotAllViewsToFile())); - connect(m_createCommandObject, SIGNAL(triggered()), SLOT(slotCreateCommandObject())); + connect(m_createCommandObject, SIGNAL(triggered()), SLOT(slotCreateCommandObject())); connect(m_showRegressionTestDialog, SIGNAL(triggered()), SLOT(slotShowRegressionTestDialog())); connect(m_executePaintEventPerformanceTest, SIGNAL(triggered()), SLOT(slotExecutePaintEventPerformanceTest())); - + // View actions - m_viewFromNorth = new QAction(QIcon(":/SouthViewArrow.png"), "Look South", this); - m_viewFromNorth->setToolTip("Look South"); - m_viewFromSouth = new QAction(QIcon(":/NorthViewArrow.png"),"Look North", this); - m_viewFromSouth->setToolTip("Look North"); - m_viewFromEast = new QAction(QIcon(":/WestViewArrow.png"),"Look West", this); - m_viewFromEast->setToolTip("Look West"); - m_viewFromWest = new QAction(QIcon(":/EastViewArrow.png"),"Look East", this); - m_viewFromWest->setToolTip("Look East"); - m_viewFromAbove = new QAction(QIcon(":/DownViewArrow.png"),"Look Down", this); - m_viewFromAbove->setToolTip("Look Down"); - m_viewFromBelow = new QAction(QIcon(":/UpViewArrow.png"),"Look Up", this); - m_viewFromBelow->setToolTip("Look Up"); - - connect(m_viewFromNorth, SIGNAL(triggered()), SLOT(slotViewFromNorth())); - connect(m_viewFromSouth, SIGNAL(triggered()), SLOT(slotViewFromSouth())); - connect(m_viewFromEast, SIGNAL(triggered()), SLOT(slotViewFromEast())); - connect(m_viewFromWest, SIGNAL(triggered()), SLOT(slotViewFromWest())); - connect(m_viewFromAbove, SIGNAL(triggered()), SLOT(slotViewFromAbove())); - connect(m_viewFromBelow, SIGNAL(triggered()), SLOT(slotViewFromBelow())); + m_viewFromNorth = new QAction(QIcon(":/SouthViewArrow.png"), "Look South", this); + m_viewFromNorth->setToolTip("Look South (Ctrl+Alt+S)"); + m_viewFromNorth->setShortcut(QKeySequence(tr("Ctrl+Alt+S"))); + + m_viewFromSouth = new QAction(QIcon(":/NorthViewArrow.png"), "Look North", this); + m_viewFromSouth->setToolTip("Look North (Ctrl+Alt+N)"); + m_viewFromSouth->setShortcut(QKeySequence(tr("Ctrl+Alt+N"))); + + m_viewFromEast = new QAction(QIcon(":/WestViewArrow.png"), "Look West", this); + m_viewFromEast->setToolTip("Look West (Ctrl+Alt+W)"); + m_viewFromEast->setShortcut(QKeySequence(tr("Ctrl+Alt+W"))); + + m_viewFromWest = new QAction(QIcon(":/EastViewArrow.png"), "Look East", this); + m_viewFromWest->setToolTip("Look East (Ctrl+Alt+E)"); + m_viewFromWest->setShortcut(QKeySequence(tr("Ctrl+Alt+E"))); + + m_viewFromAbove = new QAction(QIcon(":/DownViewArrow.png"), "Look Down", this); + m_viewFromAbove->setToolTip("Look Down (Ctrl+Alt+D)"); + m_viewFromAbove->setShortcut(QKeySequence(tr("Ctrl+Alt+D"))); + + m_viewFromBelow = new QAction(QIcon(":/UpViewArrow.png"), "Look Up", this); + m_viewFromBelow->setToolTip("Look Up (Ctrl+Alt+U)"); + m_viewFromBelow->setShortcut(QKeySequence(tr("Ctrl+Alt+U"))); + + connect(m_viewFromNorth, SIGNAL(triggered()), SLOT(slotViewFromNorth())); + connect(m_viewFromSouth, SIGNAL(triggered()), SLOT(slotViewFromSouth())); + connect(m_viewFromEast, SIGNAL(triggered()), SLOT(slotViewFromEast())); + connect(m_viewFromWest, SIGNAL(triggered()), SLOT(slotViewFromWest())); + connect(m_viewFromAbove, SIGNAL(triggered()), SLOT(slotViewFromAbove())); + connect(m_viewFromBelow, SIGNAL(triggered()), SLOT(slotViewFromBelow())); // Debug actions m_newPropertyView = new QAction("New Project and Property View", this); @@ -343,45 +357,44 @@ void RiuMainWindow::createActions() // Draw style actions m_dsActionGroup = new QActionGroup(this); - m_drawStyleLinesAction = new QAction(QIcon(":/draw_style_lines_24x24.png"), "&Mesh Only", this); - //connect(m_drawStyleLinesAction, SIGNAL(triggered()), SLOT(slotDrawStyleLines())); + m_drawStyleLinesAction = new QAction(QIcon(":/draw_style_lines_24x24.png"), "&Mesh Only", this); + // connect(m_drawStyleLinesAction, SIGNAL(triggered()), SLOT(slotDrawStyleLines())); m_dsActionGroup->addAction(m_drawStyleLinesAction); - m_drawStyleLinesSolidAction = new QAction(QIcon(":/draw_style_meshlines_24x24.png"), "Mesh And Surfaces", this); - //connect(m_drawStyleLinesSolidAction, SIGNAL(triggered()), SLOT(slotDrawStyleLinesSolid())); - m_dsActionGroup->addAction(m_drawStyleLinesSolidAction); + m_drawStyleLinesSolidAction = new QAction(QIcon(":/draw_style_meshlines_24x24.png"), "Mesh And Surfaces", this); + // connect(m_drawStyleLinesSolidAction, SIGNAL(triggered()), SLOT(slotDrawStyleLinesSolid())); + m_dsActionGroup->addAction(m_drawStyleLinesSolidAction); - m_drawStyleFaultLinesSolidAction = new QAction(QIcon(":/draw_style_surface_w_fault_mesh_24x24.png"), "Fault Mesh And Surfaces", this); - m_dsActionGroup->addAction(m_drawStyleFaultLinesSolidAction); + m_drawStyleFaultLinesSolidAction = + new QAction(QIcon(":/draw_style_surface_w_fault_mesh_24x24.png"), "Fault Mesh And Surfaces", this); + m_dsActionGroup->addAction(m_drawStyleFaultLinesSolidAction); - m_drawStyleSurfOnlyAction = new QAction(QIcon(":/draw_style_surface_24x24.png"), "&Surface Only", this); - //connect(m_drawStyleSurfOnlyAction, SIGNAL(triggered()), SLOT(slotDrawStyleSurfOnly())); + m_drawStyleSurfOnlyAction = new QAction(QIcon(":/draw_style_surface_24x24.png"), "&Surface Only", this); + // connect(m_drawStyleSurfOnlyAction, SIGNAL(triggered()), SLOT(slotDrawStyleSurfOnly())); m_dsActionGroup->addAction(m_drawStyleSurfOnlyAction); - connect(m_dsActionGroup, SIGNAL(triggered(QAction*)), SLOT(slotDrawStyleChanged(QAction*))); m_disableLightingAction = new QAction(QIcon(":/disable_lighting_24x24.png"), "&Disable Results Lighting", this); m_disableLightingAction->setCheckable(true); - connect(m_disableLightingAction, SIGNAL(toggled(bool)), SLOT(slotDisableLightingAction(bool))); - + connect(m_disableLightingAction, SIGNAL(toggled(bool)), SLOT(slotDisableLightingAction(bool))); - m_drawStyleHideGridCellsAction = new QAction( QIcon(":/draw_style_faults_24x24.png"), "&Hide Grid Cells", this); + m_drawStyleHideGridCellsAction = new QAction(QIcon(":/draw_style_faults_24x24.png"), "&Hide Grid Cells", this); m_drawStyleHideGridCellsAction->setCheckable(true); - connect(m_drawStyleHideGridCellsAction, SIGNAL(toggled(bool)), SLOT(slotToggleHideGridCellsAction(bool))); + connect(m_drawStyleHideGridCellsAction, SIGNAL(toggled(bool)), SLOT(slotToggleHideGridCellsAction(bool))); - m_toggleFaultsLabelAction = new QAction( QIcon(":/draw_style_faults_label_24x24.png"), "&Show Fault Labels", this); + m_toggleFaultsLabelAction = new QAction(QIcon(":/draw_style_faults_label_24x24.png"), "&Show Fault Labels", this); m_toggleFaultsLabelAction->setCheckable(true); - connect(m_toggleFaultsLabelAction, SIGNAL(toggled(bool)), SLOT(slotToggleFaultLabelsAction(bool))); + connect(m_toggleFaultsLabelAction, SIGNAL(toggled(bool)), SLOT(slotToggleFaultLabelsAction(bool))); m_showWellCellsAction = new QAction(QIcon(":/draw_style_WellCellsToRangeFilter_24x24.png"), "&Show Well Cells", this); m_showWellCellsAction->setCheckable(true); m_showWellCellsAction->setToolTip("Show Well Cells"); - connect(m_showWellCellsAction, SIGNAL(toggled(bool)), SLOT(slotShowWellCellsAction(bool))); + connect(m_showWellCellsAction, SIGNAL(toggled(bool)), SLOT(slotShowWellCellsAction(bool))); } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RiuMainWindow::createMenus() { @@ -393,7 +406,7 @@ void RiuMainWindow::createMenus() fileMenu->setTitle("&File"); menuBar()->addMenu(fileMenu); - + fileMenu->addAction(cmdFeatureMgr->action("RicOpenProjectFeature")); fileMenu->addAction(cmdFeatureMgr->action("RicOpenLastUsedFileFeature")); fileMenu->addSeparator(); @@ -415,13 +428,13 @@ void RiuMainWindow::createMenus() importSummaryMenu->addAction(cmdFeatureMgr->action("RicImportSummaryGroupFeature")); importSummaryMenu->addAction(cmdFeatureMgr->action("RicImportEnsembleFeature")); - #ifdef USE_ODB_API +#ifdef USE_ODB_API importMenu->addSeparator(); - QMenu* importGeoMechMenu = importMenu->addMenu(QIcon(":/GeoMechCase48x48.png"), "Geo Mechanical Cases"); + QMenu* importGeoMechMenu = importMenu->addMenu(QIcon(":/GeoMechCase24x24.png"), "Geo Mechanical Cases"); importGeoMechMenu->addAction(cmdFeatureMgr->action("RicImportGeoMechCaseFeature")); importGeoMechMenu->addAction(cmdFeatureMgr->action("RicImportGeoMechCaseTimeStepFilterFeature")); importGeoMechMenu->addAction(cmdFeatureMgr->action("RicImportElementPropertyFeature")); - #endif +#endif importMenu->addSeparator(); QMenu* importWellMenu = importMenu->addMenu(QIcon(":/Well.png"), "Well Data"); @@ -437,8 +450,9 @@ void RiuMainWindow::createMenus() QMenu* exportMenu = fileMenu->addMenu("&Export"); exportMenu->addAction(cmdFeatureMgr->action("RicSnapshotViewToFileFeature")); exportMenu->addAction(m_snapshotAllViewsToFile); - exportMenu->addAction(cmdFeatureMgr->action("RicExportMultipleSnapshotsFeature")); + exportMenu->addAction(cmdFeatureMgr->action("RicAdvancedSnapshotExportFeature")); exportMenu->addSeparator(); + exportMenu->addAction(cmdFeatureMgr->action("RicExportEclipseInputGridFeature")); exportMenu->addAction(cmdFeatureMgr->action("RicSaveEclipseInputActiveVisibleCellsFeature")); exportMenu->addAction(cmdFeatureMgr->action("RicExportCompletionsForVisibleWellPathsFeature")); exportMenu->addAction(cmdFeatureMgr->action("RicExportVisibleWellPathsFeature")); @@ -452,7 +466,7 @@ void RiuMainWindow::createMenus() { fileMenu->addAction(act); } - + fileMenu->addSeparator(); QMenu* testMenu = fileMenu->addMenu("&Testing"); @@ -473,7 +487,6 @@ void RiuMainWindow::createMenus() connect(editMenu, SIGNAL(aboutToShow()), SLOT(slotRefreshEditActions())); - // View menu QMenu* viewMenu = menuBar()->addMenu("&View"); viewMenu->addAction(cmdFeatureMgr->action("RicViewZoomAllFeature")); @@ -517,9 +530,8 @@ void RiuMainWindow::createMenus() helpMenu->addAction(cmdFeatureMgr->action("RicHelpOpenUsersGuideFeature")); } - //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RiuMainWindow::createToolBars() { @@ -529,11 +541,29 @@ void RiuMainWindow::createToolBars() { QToolBar* toolbar = addToolBar(tr("Standard")); toolbar->setObjectName(toolbar->windowTitle()); + toolbar->addAction(cmdFeatureMgr->action("RicImportGeneralDataFeature")); + toolbar->addAction(cmdFeatureMgr->action("RicOpenProjectFeature")); + toolbar->addAction(cmdFeatureMgr->action("RicSaveProjectFeature")); + } + + { + QToolBar* toolbar = addToolBar(tr("Import")); + toolbar->setObjectName(toolbar->windowTitle()); toolbar->addAction(cmdFeatureMgr->action("RicImportEclipseCaseFeature")); toolbar->addAction(cmdFeatureMgr->action("RicImportInputEclipseCaseFeature")); toolbar->addAction(cmdFeatureMgr->action("RicImportSummaryCaseFeature")); - toolbar->addAction(cmdFeatureMgr->action("RicOpenProjectFeature")); - toolbar->addAction(cmdFeatureMgr->action("RicSaveProjectFeature")); + toolbar->addAction(cmdFeatureMgr->action("RicImportEnsembleFeature")); + toolbar->hide(); + } + { +#ifdef USE_ODB_API + QToolBar* toolbar = addToolBar(tr("Import GeoMech")); + toolbar->setObjectName(toolbar->windowTitle()); + toolbar->addAction(cmdFeatureMgr->action("RicImportGeoMechCaseFeature")); + toolbar->addAction(cmdFeatureMgr->action("RicImportGeoMechCaseTimeStepFilterFeature")); + toolbar->addAction(cmdFeatureMgr->action("RicImportElementPropertyFeature")); + toolbar->hide(); +#endif } { @@ -550,8 +580,9 @@ void RiuMainWindow::createToolBars() toolbar->addAction(cmdFeatureMgr->action("RicSnapshotViewToClipboardFeature")); toolbar->addAction(cmdFeatureMgr->action("RicSnapshotViewToFileFeature")); toolbar->addAction(m_snapshotAllViewsToFile); - } + toolbar->hide(); + } // View toolbar { @@ -575,7 +606,7 @@ void RiuMainWindow::createToolBars() toolbar->addWidget(m_scaleFactor); connect(m_scaleFactor, SIGNAL(valueChanged(int)), SLOT(slotScaleChanged(int))); } - + { QToolBar* dsToolBar = addToolBar(tr("Draw Style")); dsToolBar->setObjectName(dsToolBar->windowTitle()); @@ -595,9 +626,19 @@ void RiuMainWindow::createToolBars() m_holoLensToolBar->addAction(cmdFeatureMgr->action("RicHoloLensCreateSessionFeature")); m_holoLensToolBar->addAction(cmdFeatureMgr->action("RicHoloLensTerminateSessionFeature")); + m_holoLensToolBar->addAction(cmdFeatureMgr->action("RicHoloLensAutoExportToSharingServerFeature")); m_holoLensToolBar->addAction(cmdFeatureMgr->action("RicHoloLensExportToSharingServerFeature")); } + { + QToolBar* toolbar = addToolBar(tr("Measurement")); + toolbar->setObjectName(toolbar->windowTitle()); + auto measureAction = cmdFeatureMgr->action("RicToggleMeasurementModeFeature"); + toolbar->addAction(measureAction); + auto polyMeasureAction = cmdFeatureMgr->action("RicTogglePolyMeasurementModeFeature"); + toolbar->addAction(polyMeasureAction); + } + RiaApplication* app = RiaApplication::instance(); if (app->preferences()->showTestToolbar()) { @@ -617,7 +658,7 @@ void RiuMainWindow::createToolBars() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- class RiuDockWidget : public QDockWidget { @@ -637,7 +678,7 @@ class RiuDockWidget : public QDockWidget }; //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RiuMainWindow::createDockPanels() { @@ -673,12 +714,14 @@ void RiuMainWindow::createDockPanels() connect(m_projectTreeView, SIGNAL(selectionChanged()), this, SLOT(selectedObjectsChanged())); m_projectTreeView->treeView()->setContextMenuPolicy(Qt::CustomContextMenu); - connect(m_projectTreeView->treeView(), SIGNAL(customContextMenuRequested(const QPoint&)), SLOT(customMenuRequested(const QPoint&))); + connect(m_projectTreeView->treeView(), + SIGNAL(customContextMenuRequested(const QPoint&)), + SLOT(customMenuRequested(const QPoint&))); } - - QDockWidget* resultPlotDock = nullptr; + + QDockWidget* resultPlotDock = nullptr; QDockWidget* relPermPlotDock = nullptr; - QDockWidget* pvtPlotDock = nullptr; + QDockWidget* pvtPlotDock = nullptr; #ifdef USE_ODB_API QDockWidget* mohrsCirclePlotDock = nullptr; #endif @@ -740,7 +783,7 @@ void RiuMainWindow::createDockPanels() dockWidget->hide(); } #endif - + { QDockWidget* dockWidget = new RiuDockWidget("Relative Permeability Plot", this); dockWidget->setObjectName(dwt->relPermPlotName()); @@ -792,7 +835,7 @@ void RiuMainWindow::createDockPanels() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RiuMainWindow::setResultInfo(const QString& info) const { @@ -813,10 +856,8 @@ void RiuMainWindow::refreshViewActions() // //================================================================================================== - - //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RiuMainWindow::slotRefreshFileActions() { @@ -828,32 +869,33 @@ void RiuMainWindow::slotRefreshFileActions() CVF_ASSERT(cmdFeatureMgr); cmdFeatureMgr->action("RicWellPathsImportSsihubFeature")->setEnabled(projectFileExists); - QStringList commandIdList; + commandIdList << "RicExportEclipseInputGridFeature"; + commandIdList << "RicSaveEclipseInputVisibleCellsFeature"; + commandIdList << "RicSaveEclipseInputActiveVisibleCellsFeature"; commandIdList << "RicExportCompletionsForVisibleWellPathsFeature"; commandIdList << "RicExportVisibleWellPathsFeature"; cmdFeatureMgr->refreshStates(commandIdList); -} +} //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RiuMainWindow::slotRefreshEditActions() { -// RiaApplication* app = RiaApplication::instance(); -// RISceneManager* proj = app->project(); + // RiaApplication* app = RiaApplication::instance(); + // RISceneManager* proj = app->project(); } - //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RiuMainWindow::slotRefreshViewActions() { - RimGridView* gridView = RiaApplication::instance()->activeGridView(); - RimContourMapView* view2d = dynamic_cast(gridView); - bool enabled = gridView != nullptr && view2d == nullptr; + RimGridView* gridView = RiaApplication::instance()->activeGridView(); + RimEclipseContourMapView* view2d = dynamic_cast(gridView); + bool enabled = gridView != nullptr && view2d == nullptr; m_viewFromNorth->setEnabled(enabled); m_viewFromSouth->setEnabled(enabled); m_viewFromEast->setEnabled(enabled); @@ -863,22 +905,33 @@ void RiuMainWindow::slotRefreshViewActions() updateScaleValue(); - QStringList commandIds; - commandIds << "RicLinkVisibleViewsFeature" - << "RicTileWindowsFeature" - << "RicTogglePerspectiveViewFeature" - << "RicViewZoomAllFeature"; + { + QStringList commandIds; + commandIds << "RicLinkVisibleViewsFeature" + << "RicTileWindowsFeature" + << "RicTogglePerspectiveViewFeature" + << "RicViewZoomAllFeature"; + + caf::CmdFeatureManager::instance()->refreshEnabledState(commandIds); + } + + { + QStringList commandIds; + commandIds << "RicTileWindowsFeature"; + commandIds << "RicToggleMeasurementModeFeature"; + commandIds << "RicTogglePolyMeasurementModeFeature"; - caf::CmdFeatureManager::instance()->refreshEnabledState(commandIds); + caf::CmdFeatureManager::instance()->refreshCheckedState(commandIds); + } } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RiuMainWindow::refreshAnimationActions() { caf::FrameAnimationControl* animationControl = nullptr; - Rim3dView * activeView = RiaApplication::instance()->activeReservoirView(); + Rim3dView* activeView = RiaApplication::instance()->activeReservoirView(); if (activeView && activeView->viewer()) { @@ -892,20 +945,18 @@ void RiuMainWindow::refreshAnimationActions() int currentTimeStepIndex = 0; bool enableAnimControls = false; - if (activeView && - activeView->viewer() && - activeView->viewer()->frameCount()) + if (activeView && activeView->viewer() && activeView->viewer()->frameCount()) { enableAnimControls = true; - - if ( activeView->isTimeStepDependentDataVisible() ) + + if (activeView->isTimeStepDependentDataVisible()) { timeStepStrings = activeView->ownerCase()->timeStepStrings(); } else { - RimEclipseView * activeRiv = dynamic_cast(activeView); - if ( activeRiv && activeRiv->currentGridCellResults() ) + RimEclipseView* activeRiv = dynamic_cast(activeView); + if (activeRiv && activeRiv->currentGridCellResults()) { timeStepStrings.push_back(tr("Static Property")); } @@ -930,7 +981,7 @@ void RiuMainWindow::refreshAnimationActions() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RiuMainWindow::slotMockModel() { @@ -939,7 +990,7 @@ void RiuMainWindow::slotMockModel() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RiuMainWindow::slotMockResultsModel() { @@ -947,9 +998,8 @@ void RiuMainWindow::slotMockResultsModel() app->createResultsMockModel(); } - //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RiuMainWindow::slotMockLargeResultsModel() { @@ -958,7 +1008,7 @@ void RiuMainWindow::slotMockLargeResultsModel() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RiuMainWindow::slotMockModelCustomized() { @@ -967,7 +1017,7 @@ void RiuMainWindow::slotMockModelCustomized() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RiuMainWindow::slotInputMockModel() { @@ -976,12 +1026,12 @@ void RiuMainWindow::slotInputMockModel() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- QMdiSubWindow* RiuMainWindow::findMdiSubWindow(QWidget* viewer) { QList subws = m_mdiArea->subWindowList(); - int i; + int i; for (i = 0; i < subws.size(); ++i) { if (subws[i]->widget() == viewer) @@ -1011,10 +1061,8 @@ RimViewWindow* RiuMainWindow::findViewWindowFromSubWindow(QMdiSubWindow* subWind return nullptr; } - - //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- QList RiuMainWindow::subWindowList(QMdiArea::WindowOrder order) { @@ -1022,7 +1070,7 @@ QList RiuMainWindow::subWindowList(QMdiArea::WindowOrder order) } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- RiuResultQwtPlot* RiuMainWindow::resultPlot() { @@ -1030,7 +1078,7 @@ RiuResultQwtPlot* RiuMainWindow::resultPlot() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- RiuRelativePermeabilityPlotPanel* RiuMainWindow::relativePermeabilityPlotPanel() { @@ -1038,7 +1086,7 @@ RiuRelativePermeabilityPlotPanel* RiuMainWindow::relativePermeabilityPlotPanel() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- RiuPvtPlotPanel* RiuMainWindow::pvtPlotPanel() { @@ -1046,7 +1094,7 @@ RiuPvtPlotPanel* RiuMainWindow::pvtPlotPanel() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- RiuMohrsCirclePlot* RiuMainWindow::mohrsCirclePlot() { @@ -1054,7 +1102,7 @@ RiuMohrsCirclePlot* RiuMainWindow::mohrsCirclePlot() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- RiuMessagePanel* RiuMainWindow::messagePanel() { @@ -1062,68 +1110,33 @@ RiuMessagePanel* RiuMainWindow::messagePanel() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RiuMainWindow::removeViewer(QWidget* viewer) { - m_blockSlotSubWindowActivated = true; - m_mdiArea->removeSubWindow(findMdiSubWindow(viewer)); - m_blockSlotSubWindowActivated = false; - + removeViewerFromMdiArea(m_mdiArea, viewer); slotRefreshViewActions(); } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RiuMainWindow::addViewer(QWidget* viewer, const RimMdiWindowGeometry& windowsGeometry) { - RiuMdiSubWindow* subWin = new RiuMdiSubWindow(m_mdiArea); - subWin->setAttribute(Qt::WA_DeleteOnClose); // Make sure the contained widget is destroyed when the MDI window is closed - subWin->setWidget(viewer); - - QSize subWindowSize; + QSize subWindowSize; QPoint subWindowPos(-1, -1); - bool initialStateMaximized = false; if (windowsGeometry.isValid()) { - subWindowPos = QPoint(windowsGeometry.x, windowsGeometry.y); + subWindowPos = QPoint(windowsGeometry.x, windowsGeometry.y); subWindowSize = QSize(windowsGeometry.width, windowsGeometry.height); - - initialStateMaximized = windowsGeometry.isMaximized; } else { subWindowSize = QSize(400, 400); - - if (m_mdiArea->subWindowList().size() < 1) - { - // Show first 3D view maximized - initialStateMaximized = true; - } } - if (m_mdiArea->currentSubWindow() && m_mdiArea->currentSubWindow()->isMaximized()) - { - initialStateMaximized = true; - } - - subWin->show(); - - // Move and resize must be done after window is visible - // If not, the position and size of the window is different to specification (Windows 7) - // Might be a Qt bug, must be tested on Linux - if (subWindowPos.x() > -1) - { - subWin->move(subWindowPos); - } - subWin->resize(subWindowSize); - - if (initialStateMaximized) - { - subWin->showMaximized(); - } + addViewerToMdiArea(m_mdiArea, viewer, subWindowPos, subWindowSize); slotRefreshViewActions(); } @@ -1139,11 +1152,11 @@ void RiuMainWindow::setPdmRoot(caf::PdmObject* pdmRoot) // For debug only : m_projectTreeView->treeView()->expandAll(); m_projectTreeView->setDragDropInterface(m_dragDropInterface.get()); - for (size_t i = 0; i < additionalProjectViews.size(); i++) + for (auto& additionalProjectView : m_additionalProjectViews) { - if (!additionalProjectViews[i]) continue; + if (!additionalProjectView) continue; - RiuProjectAndPropertyView* projPropView = dynamic_cast(additionalProjectViews[i]->widget()); + RiuProjectAndPropertyView* projPropView = dynamic_cast(additionalProjectView->widget()); if (projPropView) { projPropView->setPdmItem(pdmRoot); @@ -1154,92 +1167,91 @@ void RiuMainWindow::setPdmRoot(caf::PdmObject* pdmRoot) } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RiuMainWindow::slotViewFromNorth() { - if (RiaApplication::instance()->activeReservoirView() && RiaApplication::instance()->activeReservoirView()->viewer()) + if (RiaApplication::instance()->activeReservoirView() && RiaApplication::instance()->activeReservoirView()->viewer()) { - RiaApplication::instance()->activeReservoirView()->viewer()->setView(cvf::Vec3d(0,-1,0), cvf::Vec3d(0,0,1)); + RiaApplication::instance()->activeReservoirView()->viewer()->setView(cvf::Vec3d(0, -1, 0), cvf::Vec3d(0, 0, 1)); } } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RiuMainWindow::slotViewFromSouth() { - if (RiaApplication::instance()->activeReservoirView() && RiaApplication::instance()->activeReservoirView()->viewer()) + if (RiaApplication::instance()->activeReservoirView() && RiaApplication::instance()->activeReservoirView()->viewer()) { - RiaApplication::instance()->activeReservoirView()->viewer()->setView(cvf::Vec3d(0,1,0), cvf::Vec3d(0,0,1)); + RiaApplication::instance()->activeReservoirView()->viewer()->setView(cvf::Vec3d(0, 1, 0), cvf::Vec3d(0, 0, 1)); } } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RiuMainWindow::slotViewFromEast() { - if (RiaApplication::instance()->activeReservoirView() && RiaApplication::instance()->activeReservoirView()->viewer()) + if (RiaApplication::instance()->activeReservoirView() && RiaApplication::instance()->activeReservoirView()->viewer()) { - RiaApplication::instance()->activeReservoirView()->viewer()->setView(cvf::Vec3d(-1,0,0), cvf::Vec3d(0,0,1)); + RiaApplication::instance()->activeReservoirView()->viewer()->setView(cvf::Vec3d(-1, 0, 0), cvf::Vec3d(0, 0, 1)); } } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RiuMainWindow::slotViewFromWest() { - if (RiaApplication::instance()->activeReservoirView() && RiaApplication::instance()->activeReservoirView()->viewer()) + if (RiaApplication::instance()->activeReservoirView() && RiaApplication::instance()->activeReservoirView()->viewer()) { - RiaApplication::instance()->activeReservoirView()->viewer()->setView(cvf::Vec3d(1,0,0), cvf::Vec3d(0,0,1)); + RiaApplication::instance()->activeReservoirView()->viewer()->setView(cvf::Vec3d(1, 0, 0), cvf::Vec3d(0, 0, 1)); } } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RiuMainWindow::slotViewFromAbove() { - if (RiaApplication::instance()->activeReservoirView() && RiaApplication::instance()->activeReservoirView()->viewer()) + if (RiaApplication::instance()->activeReservoirView() && RiaApplication::instance()->activeReservoirView()->viewer()) { - RiaApplication::instance()->activeReservoirView()->viewer()->setView(cvf::Vec3d(0,0,-1), cvf::Vec3d(0,1,0)); + RiaApplication::instance()->activeReservoirView()->viewer()->setView(cvf::Vec3d(0, 0, -1), cvf::Vec3d(0, 1, 0)); } } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RiuMainWindow::slotViewFromBelow() { - if (RiaApplication::instance()->activeReservoirView() && RiaApplication::instance()->activeReservoirView()->viewer()) + if (RiaApplication::instance()->activeReservoirView() && RiaApplication::instance()->activeReservoirView()->viewer()) { - RiaApplication::instance()->activeReservoirView()->viewer()->setView(cvf::Vec3d(0,0,1), cvf::Vec3d(0,1,0)); + RiaApplication::instance()->activeReservoirView()->viewer()->setView(cvf::Vec3d(0, 0, 1), cvf::Vec3d(0, 1, 0)); } } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RiuMainWindow::slotSubWindowActivated(QMdiSubWindow* subWindow) { if (!subWindow) return; - if (m_blockSlotSubWindowActivated) return; + if (blockSlotSubWindowActivated()) return; - RimProject * proj = RiaApplication::instance()->project(); + RimProject* proj = RiaApplication::instance()->project(); if (!proj) return; // Find the activated 3D view - + Rim3dView* activatedView = nullptr; std::vector allCases; proj->allCases(allCases); - for (size_t caseIdx = 0; caseIdx < allCases.size(); ++caseIdx) + for (RimCase* reservoirCase : allCases) { - RimCase* reservoirCase = allCases[caseIdx]; if (reservoirCase == nullptr) continue; std::vector views = reservoirCase->views(); @@ -1249,10 +1261,7 @@ void RiuMainWindow::slotSubWindowActivated(QMdiSubWindow* subWindow) { Rim3dView* riv = views[viewIdx]; - if (riv && - riv->viewer() && - riv->viewer()->layoutWidget() && - riv->viewer()->layoutWidget()->parent() == subWindow) + if (riv && riv->viewer() && riv->viewer()->layoutWidget() && riv->viewer()->layoutWidget()->parent() == subWindow) { activatedView = riv; break; @@ -1264,20 +1273,28 @@ void RiuMainWindow::slotSubWindowActivated(QMdiSubWindow* subWindow) Rim3dView* previousActiveReservoirView = RiaApplication::instance()->activeReservoirView(); RiaApplication::instance()->setActiveReservoirView(activatedView); - if (previousActiveReservoirView != activatedView) + bool is3dViewCurrentlySelected = false; + if (caf::SelectionManager::instance()->selectedItem()) + { + if (caf::SelectionManager::instance()->selectedItemAncestorOfType()) + { + is3dViewCurrentlySelected = true; + } + } + + if (is3dViewCurrentlySelected && (previousActiveReservoirView != activatedView)) { QModelIndex newViewModelIndex = m_projectTreeView->findModelIndex(activatedView); QModelIndex newSelectionIndex = newViewModelIndex; - if (previousActiveReservoirView) + if (previousActiveReservoirView && is3dViewCurrentlySelected) { // Try to select the same entry in the new View, as was selected in the previous QModelIndex previousViewModelIndex = m_projectTreeView->findModelIndex(previousActiveReservoirView); - QModelIndex currentSelectionIndex = m_projectTreeView->treeView()->selectionModel()->currentIndex(); + QModelIndex currentSelectionIndex = m_projectTreeView->treeView()->selectionModel()->currentIndex(); - if (currentSelectionIndex != newViewModelIndex && - currentSelectionIndex.isValid()) + if (currentSelectionIndex != newViewModelIndex && currentSelectionIndex.isValid()) { QVector route; // Contains all model indices from current selection up to previous view @@ -1298,7 +1315,8 @@ void RiuMainWindow::slotSubWindowActivated(QMdiSubWindow* subWindow) QModelIndex tmp = route[i]; if (newSelectionIndex.isValid()) { - newSelectionIndex = m_projectTreeView->treeView()->model()->index(tmp.row(), tmp.column(), newSelectionIndex); + newSelectionIndex = + m_projectTreeView->treeView()->model()->index(tmp.row(), tmp.column(), newSelectionIndex); } } @@ -1315,7 +1333,6 @@ void RiuMainWindow::slotSubWindowActivated(QMdiSubWindow* subWindow) { m_projectTreeView->treeView()->setExpanded(newViewModelIndex, true); } - } slotRefreshViewActions(); @@ -1324,22 +1341,17 @@ void RiuMainWindow::slotSubWindowActivated(QMdiSubWindow* subWindow) } } - //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RiuMainWindow::setActiveViewer(QWidget* viewer) { - m_blockSlotSubWindowActivated = true; - - QMdiSubWindow * swin = findMdiSubWindow(viewer); - if (swin) m_mdiArea->setActiveSubWindow(swin); - - m_blockSlotSubWindowActivated = false; + QMdiSubWindow* swin = findMdiSubWindow(viewer); + if (swin) m_mdiArea->setActiveSubWindow(swin); } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- RiuProcessMonitor* RiuMainWindow::processMonitor() { @@ -1347,13 +1359,13 @@ RiuProcessMonitor* RiuMainWindow::processMonitor() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void appendToggleActionForDockingWidget(QMenu* menu, QWidget* parent, const QString& dockWidgetName) { if (menu) { - auto dwt = RiuDockWidgetTools::instance(); + auto dwt = RiuDockWidgetTools::instance(); QAction* action = dwt->toggleActionForWidget(parent, dockWidgetName); if (action) { @@ -1364,13 +1376,17 @@ void appendToggleActionForDockingWidget(QMenu* menu, QWidget* parent, const QStr } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RiuMainWindow::slotBuildWindowActions() { m_windowMenu->clear(); - m_windowMenu->addAction(m_newPropertyView); - m_windowMenu->addSeparator(); + + { + caf::CmdFeatureManager* cmdFeatureMgr = caf::CmdFeatureManager::instance(); + m_windowMenu->addAction(cmdFeatureMgr->action("RicShowPlotWindowFeature")); + m_windowMenu->addSeparator(); + } auto dwt = RiuDockWidgetTools::instance(); @@ -1397,10 +1413,13 @@ void RiuMainWindow::slotBuildWindowActions() m_windowMenu->addAction(caf::CmdFeatureManager::instance()->action("RicTileWindowsFeature")); m_windowMenu->addAction(cascadeWindowsAction); m_windowMenu->addAction(closeAllSubWindowsAction); + + m_windowMenu->addSeparator(); + m_windowMenu->addAction(m_newPropertyView); } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RiuMainWindow::selectedObjectsChanged() { @@ -1420,7 +1439,7 @@ void RiuMainWindow::selectedObjectsChanged() if (uiItems.size() == 1 && m_allowActiveViewChangeFromSelection) { - // Find the reservoir view or the Plot that the selected item is within + // Find the reservoir view or the Plot that the selected item is within if (!firstSelectedObject) { @@ -1438,7 +1457,7 @@ void RiuMainWindow::selectedObjectsChanged() } bool isActiveViewChanged = false; - + if (selectedReservoirView) { // Set focus in MDI area to this window if it exists @@ -1466,13 +1485,13 @@ void RiuMainWindow::selectedObjectsChanged() } } - //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RiuMainWindow::slotNewObjectPropertyView() { - QDockWidget* dockWidget = new QDockWidget(QString("Additional Project Tree (%1)").arg(additionalProjectViews.size() + 1), this); + QDockWidget* dockWidget = + new QDockWidget(QString("Additional Project Tree (%1)").arg(m_additionalProjectViews.size() + 1), this); dockWidget->setObjectName("dockWidget"); dockWidget->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea); @@ -1482,11 +1501,11 @@ void RiuMainWindow::slotNewObjectPropertyView() addDockWidget(Qt::RightDockWidgetArea, dockWidget); - additionalProjectViews.push_back(dockWidget); + m_additionalProjectViews.push_back(dockWidget); } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RiuMainWindow::slotSnapshotAllViewsToFile() { @@ -1498,20 +1517,20 @@ void RiuMainWindow::slotSnapshotAllViewsToFile() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RiuMainWindow::hideAllDockWindows() { QList dockWidgets = findChildren(); - for (int i = 0; i < dockWidgets.size(); i++) + for (auto* dockWidget : dockWidgets) { - dockWidgets[i]->close(); + dockWidget->close(); } } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RiuMainWindow::slotDrawStyleChanged(QAction* activatedAction) { @@ -1533,23 +1552,21 @@ void RiuMainWindow::slotDrawStyleChanged(QAction* activatedAction) { RiaApplication::instance()->activeReservoirView()->setFaultMeshSurfDrawstyle(); } - } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RiuMainWindow::slotToggleHideGridCellsAction(bool hideGridCells) { if (!RiaApplication::instance()->activeReservoirView()) return; - + RimGridView* rigv = RiaApplication::instance()->activeGridView(); if (rigv) rigv->showGridCells(!hideGridCells); } - //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RiuMainWindow::slotToggleFaultLabelsAction(bool showLabels) { @@ -1573,18 +1590,17 @@ void RiuMainWindow::slotToggleFaultLabelsAction(bool showLabels) } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RiuMainWindow::refreshDrawStyleActions() { - RimGridView* gridView = RiaApplication::instance()->activeGridView(); - RimContourMapView* view2d = dynamic_cast(gridView); - bool is2dMap = view2d != nullptr; - bool is3dGridView = gridView != nullptr && !is2dMap; - - Rim3dView* view = RiaApplication::instance()->activeReservoirView(); - bool is3dView = view != nullptr && !is2dMap; + RimGridView* gridView = RiaApplication::instance()->activeGridView(); + RimEclipseContourMapView* view2d = dynamic_cast(gridView); + bool is2dMap = view2d != nullptr; + bool is3dGridView = gridView != nullptr && !is2dMap; + Rim3dView* view = RiaApplication::instance()->activeReservoirView(); + bool is3dView = view != nullptr && !is2dMap; m_drawStyleLinesAction->setEnabled(is3dView); m_drawStyleLinesSolidAction->setEnabled(is3dView); @@ -1611,8 +1627,8 @@ void RiuMainWindow::refreshDrawStyleActions() bool hasEclipseView = eclView != nullptr; m_showWellCellsAction->setEnabled(hasEclipseView && !is2dMap); - if (hasEclipseView && !is2dMap) - { + if (hasEclipseView && !is2dMap) + { m_showWellCellsAction->blockSignals(true); eclView->wellCollection()->updateStateForVisibilityCheckboxes(); m_showWellCellsAction->setChecked(eclView->wellCollection()->showWellCells()); @@ -1621,27 +1637,25 @@ void RiuMainWindow::refreshDrawStyleActions() if (!eclView) { - Rim2dIntersectionView * intView = dynamic_cast(view); - if (intView) + Rim2dIntersectionView* intView = dynamic_cast(view); + if (intView && intView->intersection()) { intView->intersection()->firstAncestorOrThisOfType(eclView); } } - + m_toggleFaultsLabelAction->setEnabled(eclView != nullptr); - if (eclView ) + if (eclView) { m_toggleFaultsLabelAction->blockSignals(true); m_toggleFaultsLabelAction->setChecked(eclView->faultCollection()->showFaultLabel()); m_toggleFaultsLabelAction->blockSignals(false); } - } - //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RiuMainWindow::slotDisableLightingAction(bool disable) { @@ -1653,7 +1667,7 @@ void RiuMainWindow::slotDisableLightingAction(bool disable) } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RiuMainWindow::restoreTreeViewState() { @@ -1669,16 +1683,17 @@ void RiuMainWindow::restoreTreeViewState() QString currentIndexString = RiaApplication::instance()->project()->mainWindowCurrentModelIndexPath; if (!currentIndexString.isEmpty()) { - QModelIndex mi = caf::QTreeViewStateSerializer::getModelIndexFromString(m_projectTreeView->treeView()->model(), currentIndexString); + QModelIndex mi = caf::QTreeViewStateSerializer::getModelIndexFromString(m_projectTreeView->treeView()->model(), + currentIndexString); m_projectTreeView->treeView()->setCurrentIndex(mi); } } } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- -void RiuMainWindow::showDockPanel(const QString &dockPanelName) +void RiuMainWindow::showDockPanel(const QString& dockPanelName) { QList dockWidgets = findChildren(); @@ -1695,33 +1710,33 @@ void RiuMainWindow::showDockPanel(const QString &dockPanelName) } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RiuMainWindow::updateUiFieldsFromActiveResult(caf::PdmObjectHandle* objectToUpdate) { RimEclipseResultDefinition* resultDefinition = nullptr; - resultDefinition = dynamic_cast(objectToUpdate); + resultDefinition = dynamic_cast(objectToUpdate); if (resultDefinition) { resultDefinition->updateUiFieldsFromActiveResult(); } RimEclipsePropertyFilter* eclPropFilter = nullptr; - eclPropFilter = dynamic_cast(objectToUpdate); + eclPropFilter = dynamic_cast(objectToUpdate); if (eclPropFilter) { eclPropFilter->updateUiFieldsFromActiveResult(); } RimEclipseFaultColors* eclFaultColors = nullptr; - eclFaultColors = dynamic_cast(objectToUpdate); + eclFaultColors = dynamic_cast(objectToUpdate); if (eclFaultColors) { eclFaultColors->updateUiFieldsFromActiveResult(); } RimCellEdgeColors* cellEdgeColors = nullptr; - cellEdgeColors = dynamic_cast(objectToUpdate); + cellEdgeColors = dynamic_cast(objectToUpdate); if (cellEdgeColors) { cellEdgeColors->updateUiFieldsFromActiveResult(); @@ -1733,15 +1748,15 @@ void RiuMainWindow::updateUiFieldsFromActiveResult(caf::PdmObjectHandle* objectT //-------------------------------------------------------------------------------------------------- void RiuMainWindow::updateMemoryUsage() { - uint64_t currentUsage = caf::MemoryInspector::getApplicationPhysicalMemoryUsageMiB(); - uint64_t totalPhysicalMemory = caf::MemoryInspector::getTotalPhysicalMemoryMiB(); - uint64_t totalVirtualMemory = caf::MemoryInspector::getTotalVirtualMemoryMiB(); - uint64_t availVirtualMemory = caf::MemoryInspector::getAvailableVirtualMemoryMiB(); + uint64_t currentUsage = caf::MemoryInspector::getApplicationPhysicalMemoryUsageMiB(); + uint64_t totalPhysicalMemory = caf::MemoryInspector::getTotalPhysicalMemoryMiB(); + uint64_t totalVirtualMemory = caf::MemoryInspector::getTotalVirtualMemoryMiB(); + uint64_t availVirtualMemory = caf::MemoryInspector::getAvailableVirtualMemoryMiB(); QColor okColor(0, 150, 0); QColor warningColor(200, 0, 0); QColor criticalColor(255, 100, 0); - + float currentUsageFraction = 0.0f; float availVirtualFraction = 1.0f; if (currentUsage > 0u && totalPhysicalMemory > 0u) @@ -1761,7 +1776,8 @@ void RiuMainWindow::updateMemoryUsage() if (availVirtualFraction < caf::MemoryInspector::getRemainingMemoryCriticalThresholdFraction()) { m_memoryCriticalWarning->setText(QString("Available System Memory Critically Low!")); - m_memoryCriticalWarning->setStyleSheet(QString("QLabel {color: %1; padding: 0px 5px 0px 0px;}").arg(criticalColor.name())); + m_memoryCriticalWarning->setStyleSheet( + QString("QLabel {color: %1; padding: 0px 5px 0px 0px;}").arg(criticalColor.name())); } else { @@ -1771,12 +1787,12 @@ void RiuMainWindow::updateMemoryUsage() m_memoryUsedButton->setText(QString("Memory Used: %1 MiB").arg(currentUsage)); m_memoryTotalStatus->setText(QString("Total Physical Memory: %1 MiB").arg(totalPhysicalMemory)); - m_memoryUsedButton->setStyleSheet(QString("QLabel {color: %1; padding: 0px 5px 0px 0px;}").arg(usageColor.name())); + m_memoryUsedButton->setStyleSheet(QString("QLabel {color: %1; padding: 0px 5px 0px 0px;}").arg(usageColor.name())); m_memoryTotalStatus->setStyleSheet(QString("QLabel {padding: 0px 5px 0px 0px; }")); } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RiuMainWindow::showProcessMonitorDockPanel() { @@ -1784,7 +1800,7 @@ void RiuMainWindow::showProcessMonitorDockPanel() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RiuMainWindow::setDefaultToolbarVisibility() { @@ -1792,7 +1808,18 @@ void RiuMainWindow::setDefaultToolbarVisibility() } //-------------------------------------------------------------------------------------------------- -/// +/// +//-------------------------------------------------------------------------------------------------- +void RiuMainWindow::applyFontSizesToDockedPlots() +{ + m_resultQwtPlot->applyFontSizes(true); + m_mohrsCirclePlot->applyFontSizes(true); + m_relPermPlotPanel->applyFontSizes(true); + m_pvtPlotPanel->applyFontSizes(true); +} + +//-------------------------------------------------------------------------------------------------- +/// //-------------------------------------------------------------------------------------------------- void RiuMainWindow::slotScaleChanged(int scaleValue) { @@ -1803,12 +1830,12 @@ void RiuMainWindow::slotScaleChanged(int scaleValue) } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RiuMainWindow::updateScaleValue() { - Rim3dView* view = RiaApplication::instance()->activeReservoirView(); - bool isRegularReservoirView = view && dynamic_cast(view) == nullptr; + Rim3dView* view = RiaApplication::instance()->activeReservoirView(); + bool isRegularReservoirView = view && dynamic_cast(view) == nullptr; if (isRegularReservoirView) { m_scaleFactor->setEnabled(true); @@ -1833,7 +1860,7 @@ void RiuMainWindow::selectedCases(std::vector& cases) } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RiuMainWindow::slotCreateCommandObject() { @@ -1844,23 +1871,23 @@ void RiuMainWindow::slotCreateCommandObject() m_projectTreeView->selectedUiItems(selectedUiItems); caf::PdmObjectGroup selectedObjects; - for (size_t i = 0; i < selectedUiItems.size(); ++i) + for (auto* selectedUiItem : selectedUiItems) { - caf::PdmUiObjectHandle* uiObj = dynamic_cast(selectedUiItems[i]); - if (uiObj) + caf::PdmUiObjectHandle* uiObj = dynamic_cast(selectedUiItem); + if (uiObj) { selectedObjects.addObject(uiObj->objectHandle()); } } - if (selectedObjects.objects.size()) - { + if (!selectedObjects.objects.empty()) + { std::vector commandObjects; RimCommandFactory::createCommandObjects(selectedObjects, &commandObjects); - for (size_t i = 0; i < commandObjects.size(); i++) + for (auto* commandObject : commandObjects) { - app->project()->commandObjects.push_back(commandObjects[i]); + app->project()->commandObjects.push_back(commandObject); } app->project()->updateConnectedEditors(); @@ -1868,7 +1895,7 @@ void RiuMainWindow::slotCreateCommandObject() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RiuMainWindow::slotShowRegressionTestDialog() { @@ -1876,7 +1903,7 @@ void RiuMainWindow::slotShowRegressionTestDialog() regTestConfig.readSettingsFromApplicationStore(); caf::PdmUiPropertyViewDialog regressionTestDialog(this, ®TestConfig, "Regression Test", ""); - regressionTestDialog.resize(QSize(600, 300)); + regressionTestDialog.resize(QSize(600, 350)); if (regressionTestDialog.exec() == QDialog::Accepted) { @@ -1888,12 +1915,11 @@ void RiuMainWindow::slotShowRegressionTestDialog() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RiuMainWindow::slotExecutePaintEventPerformanceTest() { - - if (RiaApplication::instance()->activeReservoirView() && RiaApplication::instance()->activeReservoirView()->viewer()) + if (RiaApplication::instance()->activeReservoirView() && RiaApplication::instance()->activeReservoirView()->viewer()) { size_t redrawCount = 50; @@ -1907,15 +1933,18 @@ void RiuMainWindow::slotExecutePaintEventPerformanceTest() double totalTimeMS = timer.time() * 1000.0; - double msPerFrame = totalTimeMS / redrawCount; + double msPerFrame = totalTimeMS / redrawCount; - QString resultInfo = QString("Total time '%1 ms' for %2 number of redraws, frame time '%3 ms'").arg(totalTimeMS).arg(redrawCount).arg(msPerFrame); + QString resultInfo = QString("Total time '%1 ms' for %2 number of redraws, frame time '%3 ms'") + .arg(totalTimeMS) + .arg(redrawCount) + .arg(msPerFrame); setResultInfo(resultInfo); } } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RiuMainWindow::setDefaultWindowSize() { @@ -1923,7 +1952,7 @@ void RiuMainWindow::setDefaultWindowSize() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RiuMainWindow::slotShowWellCellsAction(bool doAdd) { @@ -1935,7 +1964,7 @@ void RiuMainWindow::slotShowWellCellsAction(bool doAdd) } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RiuMainWindow::setExpanded(const caf::PdmUiItem* uiItem, bool expanded) { @@ -1943,7 +1972,7 @@ void RiuMainWindow::setExpanded(const caf::PdmUiItem* uiItem, bool expanded) } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RiuMainWindow::customMenuRequested(const QPoint& pos) { @@ -1953,9 +1982,9 @@ void RiuMainWindow::customMenuRequested(const QPoint& pos) app->project()->actionsBasedOnSelection(menu); // Qt doc: QAbstractScrollArea and its subclasses that map the context menu event to coordinates of the viewport(). - // Since we might get this signal from different treeViews, we need to map the position accordingly. - QObject* senderObj = this->sender(); - QTreeView* treeView = dynamic_cast(senderObj); + // Since we might get this signal from different treeViews, we need to map the position accordingly. + QObject* senderObj = this->sender(); + QTreeView* treeView = dynamic_cast(senderObj); if (treeView) { QPoint globalPos = treeView->viewport()->mapToGlobal(pos); @@ -1964,27 +1993,12 @@ void RiuMainWindow::customMenuRequested(const QPoint& pos) } //-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -RimMdiWindowGeometry RiuMainWindow::windowGeometryForViewer(QWidget* viewer) -{ - QMdiSubWindow* mdiWindow = findMdiSubWindow(viewer); - if (mdiWindow) - { - return RiuMdiSubWindow::windowGeometryForWidget(mdiWindow); - } - - RimMdiWindowGeometry geo; - return geo; -} - -//-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- -void RiuMainWindow::tileWindows() +void RiuMainWindow::tileSubWindows() { QMdiArea::WindowOrder currentActivationOrder = m_mdiArea->activationOrder(); - + // Tile Windows so the one with the leftmost left edge gets sorted first. std::list windowList; for (QMdiSubWindow* subWindow : m_mdiArea->subWindowList(currentActivationOrder)) @@ -1993,9 +2007,9 @@ void RiuMainWindow::tileWindows() } // Get the active view linker if there is one - RimProject * proj = RiaApplication::instance()->project(); + RimProject* proj = RiaApplication::instance()->project(); RimViewLinkerCollection* viewLinkerCollection = proj->viewLinkerCollection(); - RimViewLinker* viewLinker = nullptr; + RimViewLinker* viewLinker = nullptr; if (viewLinkerCollection && viewLinkerCollection->isActive()) { viewLinker = viewLinkerCollection->viewLinker(); @@ -2003,12 +2017,11 @@ void RiuMainWindow::tileWindows() // Perform stable sort of list so we first sort by window position but retain activation order // for windows with the same position. Needs to be sorted in decreasing order for the workaround below. - windowList.sort([this, viewLinker](QMdiSubWindow* lhs, QMdiSubWindow* rhs) - { + windowList.sort([this, viewLinker](QMdiSubWindow* lhs, QMdiSubWindow* rhs) { RimViewWindow* lhsViewWindow = findViewWindowFromSubWindow(lhs); RimViewWindow* rhsViewWindow = findViewWindowFromSubWindow(rhs); - RimGridView* lhsGridView = dynamic_cast(lhsViewWindow); - RimGridView* rhsGridView = dynamic_cast(rhsViewWindow); + RimGridView* lhsGridView = dynamic_cast(lhsViewWindow); + RimGridView* rhsGridView = dynamic_cast(rhsViewWindow); if (viewLinker) { @@ -2023,13 +2036,16 @@ void RiuMainWindow::tileWindows() } return lhs->frameGeometry().topLeft().rx() > rhs->frameGeometry().topLeft().rx(); }); - + // Based on workaround described here // https://forum.qt.io/topic/50053/qmdiarea-tilesubwindows-always-places-widgets-in-activationhistoryorder-in-subwindowview-mode + bool prevActivationBlock = blockSlotSubWindowActivated(); // Force activation order so they end up in the order of the loop. m_mdiArea->setActivationOrder(QMdiArea::ActivationHistoryOrder); - QMdiSubWindow *a = m_mdiArea->activeSubWindow(); + QMdiSubWindow* a = m_mdiArea->activeSubWindow(); + + setBlockSlotSubWindowActivated(true); for (QMdiSubWindow* subWindow : windowList) { m_mdiArea->setActiveSubWindow(subWindow); @@ -2038,14 +2054,52 @@ void RiuMainWindow::tileWindows() m_mdiArea->tileSubWindows(); // Set back the original activation order to avoid messing with the standard ordering m_mdiArea->setActivationOrder(currentActivationOrder); - m_mdiArea->setActiveSubWindow(a); + m_mdiArea->setActiveSubWindow(a); + setBlockSlotSubWindowActivated(prevActivationBlock); + + storeSubWindowTiling(true); } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- -bool RiuMainWindow::isAnyMdiSubWindowVisible() +void RiuMainWindow::storeSubWindowTiling(bool tiled) +{ + RiaApplication::instance()->project()->setSubWindowsTiledIn3DWindow(tiled); + refreshViewActions(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuMainWindow::clearWindowTiling() +{ + QMdiArea::WindowOrder currentActivationOrder = m_mdiArea->activationOrder(); + + for (QMdiSubWindow* subWindow : m_mdiArea->subWindowList(currentActivationOrder)) + { + subWindow->hide(); + subWindow->showNormal(); + } + storeSubWindowTiling(false); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RiuMainWindow::subWindowsAreTiled() const { - return m_mdiArea->subWindowList().size() > 0; + if (RiaApplication::instance()->project()) + { + return RiaApplication::instance()->project()->subWindowsTiled3DWindow(); + } + return false; } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RiuMainWindow::isAnyMdiSubWindowVisible() +{ + return !m_mdiArea->subWindowList().empty(); +} diff --git a/ApplicationCode/UserInterface/RiuMainWindow.h b/ApplicationCode/UserInterface/RiuMainWindow.h index 7d5b2fce2a..e62fd33b4f 100644 --- a/ApplicationCode/UserInterface/RiuMainWindow.h +++ b/ApplicationCode/UserInterface/RiuMainWindow.h @@ -21,13 +21,13 @@ #pragma once #include "RiuMainWindowBase.h" +#include "RiuMdiArea.h" #include "cafPdmUiDragDropInterface.h" #include "cafPdmObjectHandle.h" #include #include -#include #include #include @@ -47,7 +47,6 @@ class RiuMessagePanel; class RiuProcessMonitor; class RiuResultInfoPanel; class RiuResultQwtPlot; -class RiuViewer; class RiuRelativePermeabilityPlotPanel; class RiuPvtPlotPanel; class RiuMohrsCirclePlot; @@ -111,11 +110,13 @@ class RiuMainWindow : public RiuMainWindowBase void setExpanded(const caf::PdmUiItem* uiItem, bool expanded = true); - RimMdiWindowGeometry windowGeometryForViewer(QWidget* viewer) override; + void tileSubWindows() override; + void storeSubWindowTiling(bool tiled) override; + void clearWindowTiling() override; - void tileWindows(); + bool subWindowsAreTiled() const override; bool isAnyMdiSubWindowVisible(); - QMdiSubWindow* findMdiSubWindow(QWidget* viewer); + QMdiSubWindow* findMdiSubWindow(QWidget* viewer) override; RimViewWindow* findViewWindowFromSubWindow(QMdiSubWindow* lhs); QList subWindowList(QMdiArea::WindowOrder order); @@ -127,6 +128,7 @@ class RiuMainWindow : public RiuMainWindowBase void showProcessMonitorDockPanel(); void setDefaultToolbarVisibility(); + void applyFontSizesToDockedPlots(); protected: void closeEvent(QCloseEvent* event) override; @@ -143,11 +145,6 @@ class RiuMainWindow : public RiuMainWindowBase void updateUiFieldsFromActiveResult(caf::PdmObjectHandle* objectToUpdate); -private: - static RiuMainWindow* sm_mainWindowInstance; - - QByteArray m_initialDockAndToolbarLayout; // Initial dock window and toolbar layout, used to reset GUI - private: // Edit actions QAction* m_newPropertyView; @@ -175,8 +172,7 @@ class RiuMainWindow : public RiuMainWindowBase caf::AnimationToolBar* m_animationToolBar; - QMdiArea* m_mdiArea; - RiuViewer* m_mainViewer; + RiuMdiArea* m_mdiArea; RiuResultInfoPanel* m_resultInfoPanel; RiuProcessMonitor* m_processMonitor; QPointer m_messagePanel; @@ -273,7 +269,6 @@ private slots: QToolBar* m_holoLensToolBar; - std::vector > additionalProjectViews; + std::vector > m_additionalProjectViews; - bool m_blockSlotSubWindowActivated; }; diff --git a/ApplicationCode/UserInterface/RiuMainWindowBase.cpp b/ApplicationCode/UserInterface/RiuMainWindowBase.cpp index 93e4ac482b..2e6004f59f 100644 --- a/ApplicationCode/UserInterface/RiuMainWindowBase.cpp +++ b/ApplicationCode/UserInterface/RiuMainWindowBase.cpp @@ -1,45 +1,69 @@ ///////////////////////////////////////////////////////////////////////////////// // // Copyright (C) 2016 Statoil ASA -// +// // ResInsight 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 3 of the License, or // (at your option) any later version. -// +// // ResInsight 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 at +// +// See the GNU General Public License at // for more details. // ///////////////////////////////////////////////////////////////////////////////// #include "RiuMainWindowBase.h" +#include "RiaApplication.h" #include "RiaVersionInfo.h" #include "RiuDockWidgetTools.h" +#include "RiuMdiSubWindow.h" + +#include "RimViewWindow.h" +#include "RimProject.h" #include "cafPdmObject.h" #include "cafPdmUiTreeView.h" -#include #include +#include +#include +#include //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- RiuMainWindowBase::RiuMainWindowBase() : m_projectTreeView(nullptr) , m_allowActiveViewChangeFromSelection(true) + , m_showFirstVisibleWindowMaximized(true) + , m_blockSlotSubWindowActivated(false) { setDockNestingEnabled(true); } //-------------------------------------------------------------------------------------------------- -/// +/// +//-------------------------------------------------------------------------------------------------- +RimMdiWindowGeometry RiuMainWindowBase::windowGeometryForViewer(QWidget* viewer) +{ + RiuMdiSubWindow* mdiWindow = dynamic_cast(findMdiSubWindow(viewer)); + if (mdiWindow) + { + return mdiWindow->windowGeometry(); + } + + RimMdiWindowGeometry geo; + return geo; +} + +//-------------------------------------------------------------------------------------------------- +/// //-------------------------------------------------------------------------------------------------- void RiuMainWindowBase::loadWinGeoAndDockToolBarLayout() { @@ -62,7 +86,7 @@ void RiuMainWindowBase::loadWinGeoAndDockToolBarLayout() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RiuMainWindowBase::saveWinGeoAndDockToolBarLayout() { @@ -79,7 +103,7 @@ void RiuMainWindowBase::saveWinGeoAndDockToolBarLayout() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RiuMainWindowBase::showWindow() { @@ -96,12 +120,12 @@ void RiuMainWindowBase::showWindow() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- QString RiuMainWindowBase::registryFolderName() { QString versionName(STRPRODUCTVER); - QString regFolder = QString("%1/%2").arg(versionName).arg(mainWindowName()); + QString regFolder = QString("%1_Qt%2/%3").arg(versionName).arg(QT_VERSION_STR).arg(mainWindowName()); return regFolder; } @@ -115,6 +139,68 @@ void RiuMainWindowBase::selectAsCurrentItem(const caf::PdmObject* object, bool a m_allowActiveViewChangeFromSelection = true; } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuMainWindowBase::enableShowFirstVisibleMdiWindowMaximized(bool enable) +{ + m_showFirstVisibleWindowMaximized = enable; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuMainWindowBase::setBlockSlotSubWindowActivated(bool block) +{ + m_blockSlotSubWindowActivated = block; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RiuMainWindowBase::blockSlotSubWindowActivated() const +{ + return m_blockSlotSubWindowActivated; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuMainWindowBase::removeViewerFromMdiArea(QMdiArea* mdiArea, QWidget* viewer) +{ + bool wasMaximized = viewer && viewer->isMaximized(); + + QMdiSubWindow* subWindowBeingClosed = findMdiSubWindow(viewer); + bool removedSubWindowWasActive = false; + if (subWindowBeingClosed->isActiveWindow()) + { + // If we are removing the active window, we will need a new active window + // Start by making the window inactive so Qt doesn't pick the active window itself + mdiArea->setActiveSubWindow(nullptr); + removedSubWindowWasActive = true; + } + mdiArea->removeSubWindow(subWindowBeingClosed); + + QList subWindowList = mdiArea->subWindowList(QMdiArea::ActivationHistoryOrder); + if (!subWindowList.empty()) + { + if (removedSubWindowWasActive) + { + mdiArea->setActiveSubWindow(nullptr); + // Make the last activated window the current activated one + mdiArea->setActiveSubWindow(subWindowList.back()); + } + if (wasMaximized && mdiArea->currentSubWindow()) + { + mdiArea->currentSubWindow()->showMaximized(); + } + else if (subWindowsAreTiled()) + { + tileSubWindows(); + } + } +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -123,10 +209,10 @@ void RiuMainWindowBase::setExpanded(const caf::PdmUiItem* uiItem, bool expanded) m_projectTreeView->setExpanded(uiItem, expanded); } -//-------------------------------------------------------------------------------------------------- -/// -/// -//-------------------------------------------------------------------------------------------------- +//-------------------------------------------------------------------------------------------------- +/// +/// +//-------------------------------------------------------------------------------------------------- void RiuMainWindowBase::slotDockWidgetToggleViewActionTriggered() { if (!sender()) return; @@ -136,10 +222,58 @@ void RiuMainWindowBase::slotDockWidgetToggleViewActionTriggered() { if (dockWidget->isVisible()) { - // Raise the dock widget to make it visible if the widget is part of a tab widget + // Raise the dock widget to make it visible if the widget is part of a tab widget dockWidget->raise(); } RiuDockWidgetTools::instance()->setDockWidgetVisibility(dockWidget->objectName(), dockWidget->isVisible()); } } + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuMainWindowBase::addViewerToMdiArea(QMdiArea* mdiArea, + QWidget* viewer, + const QPoint& subWindowPos, + const QSize& subWindowSize) +{ + RiuMdiSubWindow* subWin = new RiuMdiSubWindow(nullptr, Qt::CustomizeWindowHint | Qt::WindowCloseButtonHint | Qt::WindowMaximizeButtonHint); + subWin->setAttribute(Qt::WA_DeleteOnClose); // Make sure the contained widget is destroyed when the MDI window is closed + subWin->setWidget(viewer); + + bool initialStateTiled = subWindowsAreTiled(); + bool initialStateMaximized = false; + + if (m_showFirstVisibleWindowMaximized && mdiArea->subWindowList().empty()) + { + // Show first 3D view maximized + initialStateMaximized = true; + } + + if (mdiArea->currentSubWindow() && mdiArea->currentSubWindow()->isMaximized()) + { + initialStateMaximized = true; + } + + mdiArea->addSubWindow(subWin); + + if (subWindowPos.x() > -1) + { + subWin->move(subWindowPos); + } + subWin->resize(subWindowSize); + + if (initialStateMaximized) + { + subWin->showMaximized(); + } + else + { + subWin->showNormal(); + if (initialStateTiled) + { + tileSubWindows(); + } + } +} diff --git a/ApplicationCode/UserInterface/RiuMainWindowBase.h b/ApplicationCode/UserInterface/RiuMainWindowBase.h index bef70f453a..1e41360426 100644 --- a/ApplicationCode/UserInterface/RiuMainWindowBase.h +++ b/ApplicationCode/UserInterface/RiuMainWindowBase.h @@ -20,6 +20,7 @@ #include +class QMdiArea; struct RimMdiWindowGeometry; namespace caf @@ -29,6 +30,11 @@ namespace caf class PdmUiItem; } + +class QMdiArea; +class QMdiSubWindow; + + //================================================================================================== /// //================================================================================================== @@ -45,8 +51,9 @@ class RiuMainWindowBase : public QMainWindow virtual void addViewer(QWidget* viewer, const RimMdiWindowGeometry& windowsGeometry)= 0; virtual void setActiveViewer(QWidget* subWindow) = 0; - virtual RimMdiWindowGeometry windowGeometryForViewer(QWidget* viewer) = 0; + virtual QMdiSubWindow* findMdiSubWindow(QWidget* viewer) = 0; + RimMdiWindowGeometry windowGeometryForViewer(QWidget* viewer); void loadWinGeoAndDockToolBarLayout(); void saveWinGeoAndDockToolBarLayout(); void showWindow(); @@ -55,16 +62,33 @@ class RiuMainWindowBase : public QMainWindow void setExpanded(const caf::PdmUiItem* uiItem, bool expanded = true); void selectAsCurrentItem(const caf::PdmObject* object, bool allowActiveViewChange = true); + + void enableShowFirstVisibleMdiWindowMaximized(bool enable); + + virtual void tileSubWindows() = 0; + virtual void storeSubWindowTiling(bool tiled) = 0; + virtual void clearWindowTiling() = 0; + virtual bool subWindowsAreTiled() const = 0; + + void setBlockSlotSubWindowActivated(bool block); + bool blockSlotSubWindowActivated() const; + +protected: + void removeViewerFromMdiArea(QMdiArea* mdiArea, QWidget* viewer); protected slots: void slotDockWidgetToggleViewActionTriggered(); + void addViewerToMdiArea(QMdiArea* mdiArea, QWidget* viewer, const QPoint& subWindowPos, const QSize& subWindowSize); protected: caf::PdmUiTreeView* m_projectTreeView; bool m_allowActiveViewChangeFromSelection; // To be used in selectedObjectsChanged() to control // whether to select the corresponding active view or not - - private: QString registryFolderName(); + +private: + bool m_showFirstVisibleWindowMaximized; + bool m_blockSlotSubWindowActivated; + }; diff --git a/ApplicationCode/UserInterface/RiuMdiArea.cpp b/ApplicationCode/UserInterface/RiuMdiArea.cpp new file mode 100644 index 0000000000..33ef05fa42 --- /dev/null +++ b/ApplicationCode/UserInterface/RiuMdiArea.cpp @@ -0,0 +1,128 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2019- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// +#include "RiuMdiArea.h" + +#include "RiuMainWindow.h" +#include "RiuPlotMainWindow.h" +#include "RiuMdiSubWindow.h" +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::list RiuMdiArea::subWindowListSortedByPosition() +{ + // Tile Windows so the one with the leftmost left edge gets sorted first. + std::list windowList; + for (QMdiSubWindow* subWindow : subWindowList(QMdiArea::CreationOrder)) + { + windowList.push_back(subWindow); + } + + // Sort of list so we first sort by window position but retain activation order + // for windows with the same position + windowList.sort([this](QMdiSubWindow* lhs, QMdiSubWindow* rhs) { + if (lhs->frameGeometry().topLeft().rx() == rhs->frameGeometry().topLeft().rx()) + { + return lhs->frameGeometry().topLeft().ry() < rhs->frameGeometry().topLeft().ry(); + } + return lhs->frameGeometry().topLeft().rx() < rhs->frameGeometry().topLeft().rx(); + }); + return windowList; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuMdiArea::resizeEvent(QResizeEvent* resizeEvent) +{ + if (subWindowsAreTiled()) + { + for (auto subWindow : subWindowList()) + { + auto riuWindow = dynamic_cast(subWindow); + riuWindow->blockTilingChanges(true); + } + + RiuMainWindowBase* mainWindow = dynamic_cast(window()); + mainWindow->setBlockSlotSubWindowActivated(true); + + // Workaround for Qt bug #51761: https://bugreports.qt.io/browse/QTBUG-51761 + // Set the first window to be the active window then perform resize event and set back. + auto a = activeSubWindow(); + setActiveSubWindow(subWindowListSortedByPosition().front()); + + QMdiArea::resizeEvent(resizeEvent); + tileSubWindows(); + + setActiveSubWindow(a); + + mainWindow->setBlockSlotSubWindowActivated(false); + + for (auto subWindow : subWindowList()) + { + auto riuWindow = dynamic_cast(subWindow); + riuWindow->blockTilingChanges(false); + } + } + else + { + QMdiArea::resizeEvent(resizeEvent); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuMdiArea::moveEvent(QMoveEvent* event) +{ + for (auto subWindow : subWindowList()) + { + auto riuWindow = dynamic_cast(subWindow); + riuWindow->blockTilingChanges(true); + } + + QMdiArea::moveEvent(event); + + for (auto subWindow : subWindowList()) + { + auto riuWindow = dynamic_cast(subWindow); + riuWindow->blockTilingChanges(false); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RiuMdiArea::subWindowsAreTiled() const +{ + RiuMainWindow* mainWindow = dynamic_cast(window()); + + if (mainWindow) + { + return mainWindow->subWindowsAreTiled() && subWindowList().size() > 0; + } + else + { + RiuPlotMainWindow* plotWindow = dynamic_cast(window()); + if (plotWindow) + { + return plotWindow->subWindowsAreTiled() && subWindowList().size() > 0; + } + } + + return false; +} diff --git a/ApplicationCode/UserInterface/RiuMdiArea.h b/ApplicationCode/UserInterface/RiuMdiArea.h new file mode 100644 index 0000000000..a23aa2a67b --- /dev/null +++ b/ApplicationCode/UserInterface/RiuMdiArea.h @@ -0,0 +1,39 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2019- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include + +#include + +class QMdiSubWindow; + +class RiuMdiArea : public QMdiArea +{ + Q_OBJECT + +public: + std::list subWindowListSortedByPosition(); + +protected: + void resizeEvent(QResizeEvent *resizeEvent) override; + void moveEvent(QMoveEvent *event) override; + + bool subWindowsAreTiled() const; +}; diff --git a/ApplicationCode/UserInterface/RiuMdiSubWindow.cpp b/ApplicationCode/UserInterface/RiuMdiSubWindow.cpp index 29469b21a6..56ddd44deb 100644 --- a/ApplicationCode/UserInterface/RiuMdiSubWindow.cpp +++ b/ApplicationCode/UserInterface/RiuMdiSubWindow.cpp @@ -1,17 +1,17 @@ ///////////////////////////////////////////////////////////////////////////////// // // Copyright (C) 2016 Statoil ASA -// +// // ResInsight 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 3 of the License, or // (at your option) any later version. -// +// // ResInsight 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 at +// +// See the GNU General Public License at // for more details. // ///////////////////////////////////////////////////////////////////////////////// @@ -20,26 +20,31 @@ #include "RiaApplication.h" -#include "RimSummaryPlot.h" #include "Rim3dView.h" +#include "RimSummaryPlot.h" #include "RimWellLogPlot.h" -#include "RiuPlotMainWindow.h" #include "RiuMainWindow.h" -#include "RiuSummaryQwtPlot.h" +#include "RiuPlotMainWindow.h" #include "RiuViewer.h" #include "RiuWellLogPlot.h" +#include + +#include + //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- -RiuMdiSubWindow::RiuMdiSubWindow(QWidget* parent /*= 0*/, Qt::WindowFlags flags /*= 0*/) : QMdiSubWindow(parent, flags) +RiuMdiSubWindow::RiuMdiSubWindow(QWidget* parent /*= 0*/, Qt::WindowFlags flags /*= 0*/) + : QMdiSubWindow(parent, flags) + , m_normalWindowGeometry(QRect()) + , m_blockTilingChanges(false) { - } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- RiuMdiSubWindow::~RiuMdiSubWindow() { @@ -47,64 +52,120 @@ RiuMdiSubWindow::~RiuMdiSubWindow() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- -void RiuMdiSubWindow::closeEvent(QCloseEvent* event) +RimMdiWindowGeometry RiuMdiSubWindow::windowGeometry() const { - QWidget* mainWidget = widget(); + RimMdiWindowGeometry geo; - RimViewWindow* viewWindow = RiuInterfaceToViewWindow::viewWindowFromWidget(mainWidget); - if ( viewWindow ) + int mainWinID = 0; + if (window() == RiaApplication::instance()->mainPlotWindow()) { - viewWindow->setMdiWindowGeometry(windowGeometryForWidget(this)); + mainWinID = 1; } - else + + geo.mainWindowID = mainWinID; + geo.isMaximized = isMaximized(); + + // Save normal/non-maximized size and position so this can be restored + QRect currentGeometry = frameGeometry(); + if (isMaximized() && !m_normalWindowGeometry.isNull()) + { + currentGeometry = m_normalWindowGeometry; + } + + geo.x = currentGeometry.topLeft().x(); + geo.y = currentGeometry.topLeft().y(); + geo.width = currentGeometry.width(); + geo.height = currentGeometry.height(); + + return geo; +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuMdiSubWindow::blockTilingChanges(bool block) +{ + m_blockTilingChanges = block; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuMdiSubWindow::closeEvent(QCloseEvent* event) +{ + QWidget* mainWidget = widget(); + + RimViewWindow* viewWindow = RiuInterfaceToViewWindow::viewWindowFromWidget(mainWidget); + if (!viewWindow) { RiuViewer* viewer = mainWidget->findChild(); if (viewer) { - viewer->ownerReservoirView()->setMdiWindowGeometry(windowGeometryForWidget(this)); + viewWindow = viewer->ownerViewWindow(); } } - QMdiSubWindow::closeEvent(event); -} + if (viewWindow) + { + viewWindow->setMdiWindowGeometry(windowGeometry()); + viewWindow->handleMdiWindowClosed(); + event->accept(); + } + else + { + QMdiSubWindow::closeEvent(event); + } +} //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- -RimMdiWindowGeometry RiuMdiSubWindow::windowGeometryForWidget(QWidget* widget) +void RiuMdiSubWindow::resizeEvent(QResizeEvent* resizeEvent) { - RimMdiWindowGeometry geo; - - if (widget) + if (!isMaximized()) { - // Find topmost parent + m_normalWindowGeometry = frameGeometry(); + } - QWidget* nextParent = widget->parentWidget(); - QWidget* parent = nullptr; - while (nextParent) + if (!m_blockTilingChanges) + { + if (window() == RiaApplication::instance()->mainWindow()) { - parent = nextParent; - nextParent = nextParent->parentWidget(); + RiaApplication::instance()->mainWindow()->storeSubWindowTiling(false); } - - int mainWinID = 0; - if (parent) + else if (window() == RiaApplication::instance()->mainPlotWindow()) { - if (parent == RiaApplication::instance()->mainPlotWindow()) - { - mainWinID = 1; - } + RiaApplication::instance()->mainPlotWindow()->storeSubWindowTiling(false); } + } + + QMdiSubWindow::resizeEvent(resizeEvent); +} - geo.mainWindowID = mainWinID; - geo.x = widget->pos().x(); - geo.y = widget->pos().y(); - geo.width = widget->size().width(); - geo.height = widget->size().height(); - geo.isMaximized = widget->isMaximized(); +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuMdiSubWindow::moveEvent(QMoveEvent* moveEvent) +{ + if (!isMaximized()) + { + m_normalWindowGeometry = frameGeometry(); + } + + if (!m_blockTilingChanges) + { + if (window() == RiaApplication::instance()->mainWindow()) + { + RiaApplication::instance()->mainWindow()->storeSubWindowTiling(false); + } + else if (window() == RiaApplication::instance()->mainPlotWindow()) + { + RiaApplication::instance()->mainPlotWindow()->storeSubWindowTiling(false); + } } - return geo; + QMdiSubWindow::moveEvent(moveEvent); } diff --git a/ApplicationCode/UserInterface/RiuMdiSubWindow.h b/ApplicationCode/UserInterface/RiuMdiSubWindow.h index 5a2da2f8fa..fdd0dffd23 100644 --- a/ApplicationCode/UserInterface/RiuMdiSubWindow.h +++ b/ApplicationCode/UserInterface/RiuMdiSubWindow.h @@ -21,17 +21,24 @@ #include #include "RimViewWindow.h" - class RiuMdiSubWindow : public QMdiSubWindow { + Q_OBJECT public: RiuMdiSubWindow(QWidget* parent = nullptr, Qt::WindowFlags flags = nullptr); ~RiuMdiSubWindow() override; - static RimMdiWindowGeometry windowGeometryForWidget(QWidget* widget); + RimMdiWindowGeometry windowGeometry() const; + void blockTilingChanges(bool block); protected: void closeEvent(QCloseEvent* event) override; + void resizeEvent(QResizeEvent* resizeEvent) override; + void moveEvent(QMoveEvent *moveEvent) override; + +private: + QRect m_normalWindowGeometry; + bool m_blockTilingChanges; }; diff --git a/ApplicationCode/UserInterface/RiuMohrsCirclePlot.cpp b/ApplicationCode/UserInterface/RiuMohrsCirclePlot.cpp index 7eac3f6953..e1b8052ce7 100644 --- a/ApplicationCode/UserInterface/RiuMohrsCirclePlot.cpp +++ b/ApplicationCode/UserInterface/RiuMohrsCirclePlot.cpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018 Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -20,8 +20,8 @@ #include "RiaColorTables.h" -#include "RiuSelectionManager.h" -#include "RiuSummaryQwtPlot.h" +#include "Riu3dSelectionManager.h" +#include "RiuQwtPlotTools.h" #include "RigFemPart.h" #include "RigFemPartCollection.h" @@ -62,11 +62,11 @@ /// //-------------------------------------------------------------------------------------------------- RiuMohrsCirclePlot::RiuMohrsCirclePlot(QWidget* parent) - : QwtPlot(parent) + : RiuDockedQwtPlot(parent) , m_sourceGeoMechViewOfLastPlot(nullptr) , m_scheduleUpdateAxisScaleTimer(nullptr) { - RiuSummaryQwtPlot::setCommonPlotBehaviour(this); + RiuQwtPlotTools::setCommonPlotBehaviour(this); enableAxis(QwtPlot::xBottom, true); enableAxis(QwtPlot::yLeft, true); @@ -76,6 +76,8 @@ RiuMohrsCirclePlot::RiuMohrsCirclePlot(QWidget* parent) setAxisTitle(QwtPlot::xBottom, "Effective Normal Stress"); setAxisTitle(QwtPlot::yLeft, "Shear Stress"); + applyFontSizes(false); + // The legend will be deleted in the destructor of the plot or when // another legend is inserted. QwtLegend* legend = new QwtLegend(this); diff --git a/ApplicationCode/UserInterface/RiuMohrsCirclePlot.h b/ApplicationCode/UserInterface/RiuMohrsCirclePlot.h index 7e803421f4..28331b3f39 100644 --- a/ApplicationCode/UserInterface/RiuMohrsCirclePlot.h +++ b/ApplicationCode/UserInterface/RiuMohrsCirclePlot.h @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018 Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -18,6 +18,8 @@ #pragma once +#include "RiuDockedQwtPlot.h" + #include "qwt_plot.h" #include "qwt_plot_curve.h" #include "qwt_plot_item.h" @@ -39,7 +41,7 @@ class RiuSelectionItem; // // //================================================================================================== -class RiuMohrsCirclePlot : public QwtPlot +class RiuMohrsCirclePlot : public RiuDockedQwtPlot { Q_OBJECT diff --git a/ApplicationCode/UserInterface/RiuPickItemInfo.cpp b/ApplicationCode/UserInterface/RiuPickItemInfo.cpp index 26339096af..2488bad98f 100644 --- a/ApplicationCode/UserInterface/RiuPickItemInfo.cpp +++ b/ApplicationCode/UserInterface/RiuPickItemInfo.cpp @@ -52,13 +52,13 @@ RiuPickItemInfo RiuPickItemInfo::extractPickItemInfo(const cvf::HitItem* hitItem //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -std::vector RiuPickItemInfo::convertToPickItemInfos( const cvf::HitItemCollection &hitItems) +std::vector RiuPickItemInfo::convertToPickItemInfos( const cvf::HitItemCollection &hitItems, const cvf::Vec3d& globalRayOrigin) { std::vector pickItemInfos; pickItemInfos.reserve(hitItems.count()); for ( size_t i = 0; i < hitItems.count(); i++ ) { - pickItemInfos.emplace_back(RiuPickItemInfo(hitItems.item(i))); + pickItemInfos.emplace_back(RiuPickItemInfo(hitItems.item(i), globalRayOrigin)); } return pickItemInfos; } diff --git a/ApplicationCode/UserInterface/RiuPickItemInfo.h b/ApplicationCode/UserInterface/RiuPickItemInfo.h index f01073b49d..f554d04469 100644 --- a/ApplicationCode/UserInterface/RiuPickItemInfo.h +++ b/ApplicationCode/UserInterface/RiuPickItemInfo.h @@ -28,6 +28,7 @@ namespace cvf class Object; class HitItem; class HitItemCollection; + class Ray; } @@ -39,18 +40,21 @@ class RiuPickItemInfo , m_pickedPart(nullptr) , m_globalPickedPoint (cvf::Vec3d::UNDEFINED) , m_localPickedPoint (cvf::Vec3d::UNDEFINED) + , m_globalRayOrigin(cvf::Vec3d::UNDEFINED) , m_sourceInfo (nullptr) , m_faceIdx (-1) {} - explicit RiuPickItemInfo(const cvf::HitItem* hitItem) + explicit RiuPickItemInfo(const cvf::HitItem* hitItem, const cvf::Vec3d& globalRayOrigin) : m_pickedPart(nullptr) , m_globalPickedPoint (cvf::Vec3d::UNDEFINED) , m_localPickedPoint (cvf::Vec3d::UNDEFINED) + , m_globalRayOrigin(cvf::Vec3d::UNDEFINED) , m_sourceInfo (nullptr) , m_faceIdx (-1) { *this = extractPickItemInfo(hitItem); + m_globalRayOrigin = globalRayOrigin; } const cvf::Part* pickedPart() const { return m_pickedPart;} @@ -59,18 +63,19 @@ class RiuPickItemInfo const cvf::Object* sourceInfo() const { return m_sourceInfo;} cvf::uint faceIdx() const { return m_faceIdx;} double distanceAlongRay() const { return m_distanceAlongRay;} + cvf::Vec3d globalRayOrigin() const { return m_globalRayOrigin;} static RiuPickItemInfo extractPickItemInfo(const cvf::HitItem* hitItem); - static std::vector convertToPickItemInfos(const cvf::HitItemCollection &hitItems); + static std::vector convertToPickItemInfos(const cvf::HitItemCollection &hitItems, const cvf::Vec3d& globalRayOrigin); private: double m_distanceAlongRay; const cvf::Part* m_pickedPart; cvf::Vec3d m_globalPickedPoint; cvf::Vec3d m_localPickedPoint; + cvf::Vec3d m_globalRayOrigin; const cvf::Object* m_sourceInfo; cvf::uint m_faceIdx; - }; diff --git a/ApplicationCode/UserInterface/RiuPlotAnnotationTool.cpp b/ApplicationCode/UserInterface/RiuPlotAnnotationTool.cpp index 465e227167..b56197bbd8 100644 --- a/ApplicationCode/UserInterface/RiuPlotAnnotationTool.cpp +++ b/ApplicationCode/UserInterface/RiuPlotAnnotationTool.cpp @@ -92,6 +92,22 @@ void RiuPlotAnnotationTool::attachWellPicks(QwtPlot* plot, const std::vectorattach(m_plot); + m_markers.push_back(std::move(line)); +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -112,10 +128,18 @@ void RiuPlotAnnotationTool::detachAllAnnotations() /// //-------------------------------------------------------------------------------------------------- void RiuPlotAnnotationTool::horizontalDashedLine(QwtPlotMarker* line, const QString& name, double yValue) +{ + horizontalDashedLineWithColor(line, QColor(0, 0, 100), name, yValue); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuPlotAnnotationTool::horizontalDashedLineWithColor(QwtPlotMarker* line, const QColor& color, const QString& name, double yValue) { QPen curvePen; curvePen.setStyle(Qt::DashLine); - curvePen.setColor(QColor(0, 0, 100)); + curvePen.setColor(color); curvePen.setWidth(1); line->setLineStyle(QwtPlotMarker::HLine); diff --git a/ApplicationCode/UserInterface/RiuPlotAnnotationTool.h b/ApplicationCode/UserInterface/RiuPlotAnnotationTool.h index da1d4c327e..80c197a64f 100644 --- a/ApplicationCode/UserInterface/RiuPlotAnnotationTool.h +++ b/ApplicationCode/UserInterface/RiuPlotAnnotationTool.h @@ -36,10 +36,14 @@ class RiuPlotAnnotationTool void attachFormationNames(QwtPlot* plot, const std::vector& names, const std::vector> yPositions, bool showNames = true); void attachWellPicks(QwtPlot* plot, const std::vector& names, const std::vector yPositions); + + void attachAnnotationLine(QwtPlot* plot, const QColor& color, const QString& annotationText, const double yPosition); + void detachAllAnnotations(); private: static void horizontalDashedLine(QwtPlotMarker* line, const QString& name, double yValue); + static void horizontalDashedLineWithColor(QwtPlotMarker* line, const QColor& color, const QString& name, double yValue); private: QPointer m_plot; diff --git a/ApplicationCode/UserInterface/RiuPlotMainWindow.cpp b/ApplicationCode/UserInterface/RiuPlotMainWindow.cpp index ee344ec73f..cc0fa9b57b 100644 --- a/ApplicationCode/UserInterface/RiuPlotMainWindow.cpp +++ b/ApplicationCode/UserInterface/RiuPlotMainWindow.cpp @@ -21,11 +21,14 @@ #include "RiaApplication.h" #include "RiaBaseDefs.h" #include "RiaPreferences.h" +#include "RiaSummaryTools.h" #include "RimEnsembleCurveSetCollection.h" #include "RimProject.h" +#include "RimSummaryCaseMainCollection.h" #include "RimSummaryCurveCollection.h" #include "RimSummaryPlot.h" +#include "RimSummaryPlotCollection.h" #include "RimViewWindow.h" #include "RimWellAllocationPlot.h" #include "RimWellLogCurveCommonDataSource.h" @@ -33,13 +36,13 @@ #include "RiuDragDrop.h" #include "RiuMdiSubWindow.h" -#include "RiuSummaryQwtPlot.h" #include "RiuToolTipMenu.h" #include "RiuTreeViewEventFilter.h" #include "RiuWellAllocationPlot.h" #include "RiuWellLogPlot.h" #include "cafCmdFeatureManager.h" +#include "cafPdmObjectHandle.h" #include "cafPdmUiPropertyView.h" #include "cafPdmUiToolBarEditor.h" #include "cafPdmUiTreeView.h" @@ -54,14 +57,14 @@ #include #include - //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -RiuPlotMainWindow::RiuPlotMainWindow() : m_activePlotViewWindow(nullptr), m_windowMenu(nullptr), m_blockSlotSubWindowActivated(false) +RiuPlotMainWindow::RiuPlotMainWindow() + : m_activePlotViewWindow(nullptr) + , m_windowMenu(nullptr) { - m_mdiArea = new QMdiArea; - m_mdiArea->setOption(QMdiArea::DontMaximizeSubWindowOnActivation, true); + m_mdiArea = new RiuMdiArea; connect(m_mdiArea, SIGNAL(subWindowActivated(QMdiSubWindow*)), SLOT(slotSubWindowActivated(QMdiSubWindow*))); setCentralWidget(m_mdiArea); @@ -100,6 +103,39 @@ void RiuPlotMainWindow::initializeGuiNewProjectLoaded() m_pdmUiPropertyView->currentObject()->uiCapability()->updateConnectedEditors(); } + { + auto* obj = RiaSummaryTools::summaryCaseMainCollection(); + if (obj) + { + setExpanded(obj); + } + } + + { + auto* obj = RiaSummaryTools::summaryPlotCollection(); + if (obj) + { + setExpanded(obj); + } + } + + if (subWindowsAreTiled()) + { + tileSubWindows(); + } + + if (m_activePlotViewWindow && m_activePlotViewWindow->viewWidget()) + { + if (m_activePlotViewWindow->mdiWindowGeometry().isMaximized) + { + auto subWin = findMdiSubWindow(m_activePlotViewWindow->viewWidget()); + if (subWin) + { + subWin->showMaximized(); + } + } + } + refreshToolbars(); } @@ -144,8 +180,12 @@ void RiuPlotMainWindow::closeEvent(QCloseEvent* event) { RiaApplication* app = RiaApplication::instance(); + app->savePlotWinGeoAndDockToolBarLayout(); + if (app->isMain3dWindowVisible()) { + event->ignore(); + this->hide(); return; } @@ -155,10 +195,7 @@ void RiuPlotMainWindow::closeEvent(QCloseEvent* event) return; } - app->saveWinGeoAndDockToolBarLayout(); - - if (!app->tryCloseMainWindow()) - return; + app->closeMainWindowIfOpenButHidden(); app->closeProject(); } @@ -266,9 +303,9 @@ QStringList RiuPlotMainWindow::toolbarCommandIds(const QString& toolbarName) if (toolbarName.isEmpty() || toolbarName == "Standard") { - commandIds << "RicImportEclipseCaseFeature"; - commandIds << "RicImportInputEclipseCaseFeature"; + commandIds << "RicImportGeneralDataFeature"; commandIds << "RicImportSummaryCaseFeature"; + commandIds << "RicImportEnsembleFeature"; commandIds << "RicOpenProjectFeature"; commandIds << "RicSaveProjectFeature"; } @@ -336,6 +373,7 @@ void RiuPlotMainWindow::refreshToolbars() QStringList allToolbarCommandNames = toolbarCommandIds(); caf::CmdFeatureManager::instance()->refreshEnabledState(allToolbarCommandNames); + caf::CmdFeatureManager::instance()->refreshCheckedState(allToolbarCommandNames); } //-------------------------------------------------------------------------------------------------- @@ -373,7 +411,8 @@ void RiuPlotMainWindow::createDockPanels() connect(m_projectTreeView, SIGNAL(selectionChanged()), this, SLOT(selectedObjectsChanged())); m_projectTreeView->treeView()->setContextMenuPolicy(Qt::CustomContextMenu); - connect(m_projectTreeView->treeView(), SIGNAL(customContextMenuRequested(const QPoint&)), + connect(m_projectTreeView->treeView(), + SIGNAL(customContextMenuRequested(const QPoint&)), SLOT(customMenuRequested(const QPoint&))); m_projectTreeView->setUiConfigurationName("PlotWindow"); @@ -387,8 +426,6 @@ void RiuPlotMainWindow::createDockPanels() m_pdmUiPropertyView = new caf::PdmUiPropertyView(dockWidget); dockWidget->setWidget(m_pdmUiPropertyView); - m_pdmUiPropertyView->layout()->setContentsMargins(5, 0, 0, 0); - addDockWidget(Qt::LeftDockWidgetArea, dockWidget); } @@ -494,7 +531,7 @@ void RiuPlotMainWindow::updateWellLogPlotToolBar() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RiuPlotMainWindow::updateSummaryPlotToolBar(bool forceUpdateUi) { @@ -524,13 +561,14 @@ void RiuPlotMainWindow::updateSummaryPlotToolBar(bool forceUpdateUi) if (!m_summaryPlotToolBarEditor->isEditorDataValid(toolBarFields)) { m_summaryPlotToolBarEditor->setFields(toolBarFields); - m_summaryPlotToolBarEditor->updateUi(); } else if (forceUpdateUi) { m_summaryPlotToolBarEditor->updateUi(); } + m_summaryPlotToolBarEditor->updateUi(); + m_summaryPlotToolBarEditor->show(); } else @@ -548,10 +586,7 @@ void RiuPlotMainWindow::updateSummaryPlotToolBar(bool forceUpdateUi) //-------------------------------------------------------------------------------------------------- void RiuPlotMainWindow::removeViewer(QWidget* viewer) { - m_blockSlotSubWindowActivated = true; - m_mdiArea->removeSubWindow(findMdiSubWindow(viewer)); - m_blockSlotSubWindowActivated = false; - + removeViewerFromMdiArea(m_mdiArea, viewer); refreshToolbars(); } @@ -560,62 +595,29 @@ void RiuPlotMainWindow::removeViewer(QWidget* viewer) //-------------------------------------------------------------------------------------------------- void RiuPlotMainWindow::addViewer(QWidget* viewer, const RimMdiWindowGeometry& windowsGeometry) { - RiuMdiSubWindow* subWin = new RiuMdiSubWindow(m_mdiArea); - subWin->setAttribute(Qt::WA_DeleteOnClose); // Make sure the contained widget is destroyed when the MDI window is closed - subWin->setWidget(viewer); - QSize subWindowSize; QPoint subWindowPos(-1, -1); - bool initialStateMaximized = false; if (windowsGeometry.isValid()) { subWindowPos = QPoint(windowsGeometry.x, windowsGeometry.y); subWindowSize = QSize(windowsGeometry.width, windowsGeometry.height); - - initialStateMaximized = windowsGeometry.isMaximized; } else { - RiuWellLogPlot* wellLogPlot = dynamic_cast(subWin->widget()); + RiuWellLogPlot* wellLogPlot = dynamic_cast(viewer); if (wellLogPlot) { QSize preferredSize = wellLogPlot->preferredSize(); - subWindowSize = - QSize(preferredSize.width(), m_mdiArea->height()); + subWindowSize = QSize(preferredSize.width(), m_mdiArea->height()); } else { subWindowSize = QSize(400, 400); - - if (m_mdiArea->subWindowList().size() < 1) - { - // Show first 3D view maximized - initialStateMaximized = true; - } } } - if (m_mdiArea->currentSubWindow() && m_mdiArea->currentSubWindow()->isMaximized()) - { - initialStateMaximized = true; - } - - subWin->show(); - - // Move and resize must be done after window is visible - // If not, the position and size of the window is different to specification (Windows 7) - // Might be a Qt bug, must be tested on Linux - if (subWindowPos.x() > -1) - { - subWin->move(subWindowPos); - } - subWin->resize(subWindowSize); - - if (initialStateMaximized) - { - subWin->showMaximized(); - } + addViewerToMdiArea(m_mdiArea, viewer, subWindowPos, subWindowSize); refreshToolbars(); } @@ -635,12 +637,11 @@ void RiuPlotMainWindow::setPdmRoot(caf::PdmObject* pdmRoot) //-------------------------------------------------------------------------------------------------- void RiuPlotMainWindow::slotSubWindowActivated(QMdiSubWindow* subWindow) { - if (!subWindow) - return; + if (!subWindow) return; + if (blockSlotSubWindowActivated()) return; RimProject* proj = RiaApplication::instance()->project(); - if (!proj) - return; + if (!proj) return; // Select in Project Tree @@ -648,11 +649,7 @@ void RiuPlotMainWindow::slotSubWindowActivated(QMdiSubWindow* subWindow) if (viewWindow && viewWindow != m_activePlotViewWindow) { - if (!m_blockSlotSubWindowActivated) - { - selectAsCurrentItem(viewWindow); - } - + selectAsCurrentItem(viewWindow); m_activePlotViewWindow = viewWindow; } @@ -665,13 +662,8 @@ void RiuPlotMainWindow::slotSubWindowActivated(QMdiSubWindow* subWindow) //-------------------------------------------------------------------------------------------------- void RiuPlotMainWindow::setActiveViewer(QWidget* viewer) { - m_blockSlotSubWindowActivated = true; - QMdiSubWindow* swin = findMdiSubWindow(viewer); - if (swin) - m_mdiArea->setActiveSubWindow(swin); - - m_blockSlotSubWindowActivated = false; + if (swin) m_mdiArea->setActiveSubWindow(swin); } //-------------------------------------------------------------------------------------------------- @@ -681,6 +673,12 @@ void RiuPlotMainWindow::slotBuildWindowActions() { m_windowMenu->clear(); + { + caf::CmdFeatureManager* cmdFeatureMgr = caf::CmdFeatureManager::instance(); + m_windowMenu->addAction(cmdFeatureMgr->action("RicShowMainWindowFeature")); + m_windowMenu->addSeparator(); + } + QList dockWidgets = findChildren(); for (QDockWidget* dock : dockWidgets) { @@ -738,7 +736,6 @@ void RiuPlotMainWindow::selectedObjectsChanged() if (!firstSelectedObject) return; - RimViewWindow* selectedWindow = dynamic_cast(firstSelectedObject); if (!selectedWindow) { @@ -806,7 +803,6 @@ void RiuPlotMainWindow::restoreTreeViewState() } } - //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -839,21 +835,7 @@ void RiuPlotMainWindow::customMenuRequested(const QPoint& pos) //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -RimMdiWindowGeometry RiuPlotMainWindow::windowGeometryForViewer(QWidget* viewer) -{ - QMdiSubWindow* mdiWindow = findMdiSubWindow(viewer); - if (mdiWindow) - { - return RiuMdiSubWindow::windowGeometryForWidget(mdiWindow); - } - - RimMdiWindowGeometry geo; - return geo; -} -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RiuPlotMainWindow::tileWindows() +void RiuPlotMainWindow::tileSubWindows() { QMdiArea::WindowOrder currentActivationOrder = m_mdiArea->activationOrder(); @@ -865,8 +847,7 @@ void RiuPlotMainWindow::tileWindows() // Perform stable sort of list so we first sort by window position but retain activation order // for windows with the same position. Needs to be sorted in decreasing order for workaround below. - windowList.sort([](const QMdiSubWindow* lhs, const QMdiSubWindow* rhs) - { + windowList.sort([](const QMdiSubWindow* lhs, const QMdiSubWindow* rhs) { return lhs->frameGeometry().topLeft().rx() > rhs->frameGeometry().topLeft().rx(); }); @@ -885,6 +866,44 @@ void RiuPlotMainWindow::tileWindows() // Set back the original activation order to avoid messing with the standard ordering m_mdiArea->setActivationOrder(currentActivationOrder); m_mdiArea->setActiveSubWindow(a); + + storeSubWindowTiling(true); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuPlotMainWindow::storeSubWindowTiling(bool tiled) +{ + RiaApplication::instance()->project()->setSubWindowsTiledInPlotWindow(tiled); + refreshToolbars(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuPlotMainWindow::clearWindowTiling() +{ + QMdiArea::WindowOrder currentActivationOrder = m_mdiArea->activationOrder(); + + for (QMdiSubWindow* subWindow : m_mdiArea->subWindowList(currentActivationOrder)) + { + subWindow->hide(); + subWindow->showNormal(); + } + storeSubWindowTiling(false); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RiuPlotMainWindow::subWindowsAreTiled() const +{ + if (RiaApplication::instance()->project()) + { + return RiaApplication::instance()->project()->subWindowsTiledPlotWindow(); + } + return false; } //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/UserInterface/RiuPlotMainWindow.h b/ApplicationCode/UserInterface/RiuPlotMainWindow.h index e18370b782..7e19e9cd10 100644 --- a/ApplicationCode/UserInterface/RiuPlotMainWindow.h +++ b/ApplicationCode/UserInterface/RiuPlotMainWindow.h @@ -19,12 +19,11 @@ #pragma once #include "RiuMainWindowBase.h" +#include "RiuMdiArea.h" #include "cafPdmUiDragDropInterface.h" #include "cafPdmPointer.h" -#include - #include class QMdiSubWindow; @@ -69,12 +68,13 @@ class RiuPlotMainWindow : public RiuMainWindowBase void setDefaultWindowSize(); + void tileSubWindows() override; + void storeSubWindowTiling(bool tiled) override; + void clearWindowTiling() override; + bool subWindowsAreTiled() const override; - RimMdiWindowGeometry windowGeometryForViewer(QWidget* viewer) override; - - void tileWindows(); bool isAnyMdiSubWindowVisible(); - QMdiSubWindow* findMdiSubWindow(QWidget* viewer); + QMdiSubWindow* findMdiSubWindow(QWidget* viewer) override; QList subWindowList(QMdiArea::WindowOrder order); void setWidthOfMdiWindow(QWidget* mdiWindowWidget, int newWidth); @@ -113,7 +113,7 @@ private slots: private: QByteArray m_initialDockAndToolbarLayout; // Initial dock window and toolbar layout, used to reset GUI - QMdiArea* m_mdiArea; + RiuMdiArea* m_mdiArea; caf::PdmPointer m_activePlotViewWindow; QMenu* m_windowMenu; @@ -124,7 +124,5 @@ private slots: caf::PdmUiPropertyView* m_pdmUiPropertyView; - bool m_blockSlotSubWindowActivated; - std::vector m_temporaryWidgets; }; diff --git a/ApplicationCode/UserInterface/RiuPlotMainWindowTools.cpp b/ApplicationCode/UserInterface/RiuPlotMainWindowTools.cpp index ba6230a2c9..4248fdaf79 100644 --- a/ApplicationCode/UserInterface/RiuPlotMainWindowTools.cpp +++ b/ApplicationCode/UserInterface/RiuPlotMainWindowTools.cpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018- Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by diff --git a/ApplicationCode/UserInterface/RiuPlotMainWindowTools.h b/ApplicationCode/UserInterface/RiuPlotMainWindowTools.h index 6400a6467a..a44441b526 100644 --- a/ApplicationCode/UserInterface/RiuPlotMainWindowTools.h +++ b/ApplicationCode/UserInterface/RiuPlotMainWindowTools.h @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018- Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by diff --git a/ApplicationCode/UserInterface/RiuProcessMonitor.cpp b/ApplicationCode/UserInterface/RiuProcessMonitor.cpp index 1254ba7ed4..541d088b1c 100644 --- a/ApplicationCode/UserInterface/RiuProcessMonitor.cpp +++ b/ApplicationCode/UserInterface/RiuProcessMonitor.cpp @@ -59,10 +59,6 @@ RiuProcessMonitor::RiuProcessMonitor(QDockWidget* pParent) m_textEdit->setReadOnly(true); m_textEdit->setLineWrapMode(QPlainTextEdit::NoWrap); - QFont font("Courier", 8); - //QFont font("Terminal", 11); - m_textEdit->setFont(font); - QVBoxLayout* pLayout = new QVBoxLayout(); pLayout->addLayout(pTopLayout); pLayout->addWidget(m_textEdit); diff --git a/ApplicationCode/UserInterface/RiuProcessMonitor.h b/ApplicationCode/UserInterface/RiuProcessMonitor.h index 46fec6b862..7fac681a2a 100644 --- a/ApplicationCode/UserInterface/RiuProcessMonitor.h +++ b/ApplicationCode/UserInterface/RiuProcessMonitor.h @@ -18,7 +18,7 @@ #pragma once -#include +#include class QDockWidget; class QLabel; diff --git a/ApplicationCode/UserInterface/RiuPropertyViewTabWidget.cpp b/ApplicationCode/UserInterface/RiuPropertyViewTabWidget.cpp index 7e7ee5632f..e1c17e2205 100644 --- a/ApplicationCode/UserInterface/RiuPropertyViewTabWidget.cpp +++ b/ApplicationCode/UserInterface/RiuPropertyViewTabWidget.cpp @@ -37,7 +37,7 @@ RiuPropertyViewTabWidget::RiuPropertyViewTabWidget(QWidget* parent, caf::PdmObje setWindowTitle(windowTitle); QTabWidget* tabWidget = new QTabWidget; - + for (int i = 0; i < uiConfigNameForTabs.size(); i++) { QHBoxLayout* widgetLayout = new QHBoxLayout; @@ -63,11 +63,12 @@ RiuPropertyViewTabWidget::RiuPropertyViewTabWidget(QWidget* parent, caf::PdmObje dialogLayout->addWidget(tabWidget); // Buttons - QDialogButtonBox* buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); - connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept())); - connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject())); + m_dialogButtonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); + connect(m_dialogButtonBox, SIGNAL(accepted()), this, SLOT(accept())); + connect(m_dialogButtonBox, SIGNAL(rejected()), this, SLOT(reject())); + + dialogLayout->addWidget(m_dialogButtonBox); - dialogLayout->addWidget(buttonBox); } //-------------------------------------------------------------------------------------------------- @@ -81,13 +82,31 @@ RiuPropertyViewTabWidget::~RiuPropertyViewTabWidget() } } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QSize RiuPropertyViewTabWidget::minimumSizeHint() const +{ + QSize maxSizeHint(0, 0); + + for (auto w : m_pageWidgets) + { + QSize pageSize = w->minimumSizeHint(); + pageSize += QSize(0, 100); + + maxSizeHint = maxSizeHint.expandedTo(pageSize); + } + + return maxSizeHint; + +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- QSize RiuPropertyViewTabWidget::sizeHint() const { - QSize maxSizeHint = QDialog::sizeHint(); - //qDebug() << "dialog size hint : " << maxSizeHint; + QSize maxSizeHint(0, 0); for (auto w : m_pageWidgets) { @@ -101,3 +120,11 @@ QSize RiuPropertyViewTabWidget::sizeHint() const return maxSizeHint; } + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QDialogButtonBox* RiuPropertyViewTabWidget::dialogButtonBox() +{ + return m_dialogButtonBox; +} diff --git a/ApplicationCode/UserInterface/RiuPropertyViewTabWidget.h b/ApplicationCode/UserInterface/RiuPropertyViewTabWidget.h index 67080c207d..b984b127cc 100644 --- a/ApplicationCode/UserInterface/RiuPropertyViewTabWidget.h +++ b/ApplicationCode/UserInterface/RiuPropertyViewTabWidget.h @@ -26,6 +26,7 @@ namespace caf { class PdmUiPropertyView; } +class QDialogButtonBox; class QWidget; class QString; class QStringList; @@ -36,8 +37,10 @@ class RiuPropertyViewTabWidget : public QDialog RiuPropertyViewTabWidget(QWidget* parent, caf::PdmObject* object, const QString& windowTitle, const QStringList& uiConfigNameForTabs); ~RiuPropertyViewTabWidget() override; + QSize minimumSizeHint() const override; QSize sizeHint() const override; - + QDialogButtonBox* dialogButtonBox(); private: std::vector m_pageWidgets; + QDialogButtonBox* m_dialogButtonBox; }; diff --git a/ApplicationCode/UserInterface/RiuPvtPlotPanel.cpp b/ApplicationCode/UserInterface/RiuPvtPlotPanel.cpp index 43bb927d4c..19e12cd3fe 100644 --- a/ApplicationCode/UserInterface/RiuPvtPlotPanel.cpp +++ b/ApplicationCode/UserInterface/RiuPvtPlotPanel.cpp @@ -17,8 +17,9 @@ ///////////////////////////////////////////////////////////////////////////////// #include "RiuPvtPlotPanel.h" + +#include "RiuDockedQwtPlot.h" #include "RiuPvtPlotUpdater.h" -#include "RiuSummaryQwtPlot.h" #include "RigFlowDiagSolverInterface.h" @@ -50,10 +51,10 @@ // // //================================================================================================== -class PvtQwtPlot : public QwtPlot +class PvtQwtPlot : public RiuDockedQwtPlot { public: - PvtQwtPlot(QWidget* parent) : QwtPlot(parent) {} + PvtQwtPlot(QWidget* parent) : RiuDockedQwtPlot(parent) {} QSize sizeHint() const override { return QSize(100, 100); } QSize minimumSizeHint() const override { return QSize(0, 0); } }; @@ -104,6 +105,7 @@ RiuPvtPlotWidget::RiuPvtPlotWidget(RiuPvtPlotPanel* parent) { m_qwtPlot = new PvtQwtPlot(this); setPlotDefaults(m_qwtPlot); + applyFontSizes(false); QHBoxLayout* layout = new QHBoxLayout(); layout->addWidget(m_qwtPlot); @@ -148,7 +150,7 @@ void RiuPvtPlotWidget::setPlotDefaults(QwtPlot* plot) // Axis number font { QFont axisFont = plot->axisFont(QwtPlot::xBottom); - axisFont.setPixelSize(11); + axisFont.setPointSize(8); plot->setAxisFont(QwtPlot::xBottom, axisFont); plot->setAxisFont(QwtPlot::yLeft, axisFont); } @@ -157,7 +159,7 @@ void RiuPvtPlotWidget::setPlotDefaults(QwtPlot* plot) { QwtText axisTitle = plot->axisTitle(QwtPlot::xBottom); QFont axisTitleFont = axisTitle.font(); - axisTitleFont.setPixelSize(11); + axisTitleFont.setPointSize(8); axisTitleFont.setBold(false); axisTitle.setFont(axisTitleFont); axisTitle.setRenderFlags(Qt::AlignRight); @@ -169,7 +171,7 @@ void RiuPvtPlotWidget::setPlotDefaults(QwtPlot* plot) { QwtText plotTitle = plot->title(); QFont titleFont = plotTitle.font(); - titleFont.setPixelSize(14); + titleFont.setPointSize(12); plotTitle.setFont(titleFont); plot->setTitle(plotTitle); } @@ -308,6 +310,14 @@ void RiuPvtPlotWidget::plotCurves(RiaEclipseUnitTools::UnitSystem unitSystem, co m_qwtPlot->replot(); } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuPvtPlotWidget::applyFontSizes(bool replot) +{ + m_qwtPlot->applyFontSizes(replot); +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -507,7 +517,7 @@ RiuPvtPlotPanel::RiuPvtPlotPanel(QDockWidget* parent) m_titleLabel = new QLabel("", this); m_titleLabel->setAlignment(Qt::AlignHCenter); QFont font = m_titleLabel->font(); - font.setPixelSize(14); + font.setPointSize(10); font.setBold(true); m_titleLabel->setFont(font); @@ -594,6 +604,17 @@ RiuPvtPlotUpdater* RiuPvtPlotPanel::plotUpdater() return m_plotUpdater.get(); } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuPvtPlotPanel::applyFontSizes(bool replot) +{ + if (m_fvfPlot) + m_fvfPlot->applyFontSizes(replot); + if (m_viscosityPlot) + m_viscosityPlot->applyFontSizes(replot); +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/UserInterface/RiuPvtPlotPanel.h b/ApplicationCode/UserInterface/RiuPvtPlotPanel.h index fee336c767..0494f12cab 100644 --- a/ApplicationCode/UserInterface/RiuPvtPlotPanel.h +++ b/ApplicationCode/UserInterface/RiuPvtPlotPanel.h @@ -27,6 +27,7 @@ #include #include +class RiuDockedQwtPlot; class RiuPvtPlotUpdater; class RiuPvtQwtPicker; class RiuPvtPlotPanel; @@ -63,6 +64,7 @@ class RiuPvtPlotWidget : public QWidget, public RiuPvtTrackerTextProvider RiuPvtPlotWidget(RiuPvtPlotPanel* parent); void plotCurves(RiaEclipseUnitTools::UnitSystem unitSystem, const std::vector& curveArr, double pressure, double pointMarkerYValue, QString pointMarkerLabel, QString plotTitle, QString yAxisTitle); + void applyFontSizes(bool replot); private: static void setPlotDefaults(QwtPlot* plot); @@ -76,7 +78,7 @@ class RiuPvtPlotWidget : public QWidget, public RiuPvtTrackerTextProvider void slotPickerPointChanged(const QPoint& pt); private: - QPointer m_qwtPlot; + QPointer m_qwtPlot; std::vector m_pvtCurveArr; // Array of source Pvt curves currently being plotted std::vector m_qwtCurveArr; // Array of corresponding qwt curves used for mapping to Pvt curve when doing tracking @@ -124,6 +126,7 @@ class RiuPvtPlotPanel : public QWidget void setPlotData(RiaEclipseUnitTools::UnitSystem unitSystem, const std::vector& fvfCurveArr, const std::vector& viscosityCurveArr, FvfDynProps fvfDynProps, ViscosityDynProps viscosityDynProps, CellValues cellValues, QString cellReferenceText); void clearPlot(); RiuPvtPlotUpdater* plotUpdater(); + void applyFontSizes(bool replot); private: void plotUiSelectedCurves(); diff --git a/ApplicationCode/UserInterface/RiuPvtPlotUpdater.cpp b/ApplicationCode/UserInterface/RiuPvtPlotUpdater.cpp index d0126d8412..cc024633a6 100644 --- a/ApplicationCode/UserInterface/RiuPvtPlotUpdater.cpp +++ b/ApplicationCode/UserInterface/RiuPvtPlotUpdater.cpp @@ -19,7 +19,7 @@ #include "RiuPvtPlotUpdater.h" #include "RiuPvtPlotPanel.h" #include "RiuRelativePermeabilityPlotUpdater.h" -#include "RiuSelectionManager.h" +#include "Riu3dSelectionManager.h" #include "RigEclipseCaseData.h" #include "RigGridBase.h" @@ -118,7 +118,7 @@ void RiuPvtPlotUpdater::updateOnTimeStepChanged(Rim3dView* changedView) } // Fetch the current global selection and only continue if the selection's view matches the view with time step change - const RiuEclipseSelectionItem* eclipseSelectionItem = dynamic_cast(RiuSelectionManager::instance()->selectedItem()); + const RiuEclipseSelectionItem* eclipseSelectionItem = dynamic_cast(Riu3dSelectionManager::instance()->selectedItem()); if (eclipseSelectionItem && eclipseSelectionItem->m_view == eclipseView) { const size_t gridIndex = eclipseSelectionItem->m_gridIndex; @@ -153,15 +153,15 @@ bool RiuPvtPlotUpdater::queryDataAndUpdatePlot(const RimEclipseView& eclipseView // The following calls will read results from file in preparation for the queries below RigCaseCellResultsData* cellResultsData = eclipseCaseData->results(RiaDefines::MATRIX_MODEL); - cellResultsData->findOrLoadScalarResult(RiaDefines::DYNAMIC_NATIVE, "RS"); - cellResultsData->findOrLoadScalarResult(RiaDefines::DYNAMIC_NATIVE, "RV"); - cellResultsData->findOrLoadScalarResult(RiaDefines::DYNAMIC_NATIVE, "PRESSURE"); - cellResultsData->findOrLoadScalarResult(RiaDefines::STATIC_NATIVE, "PVTNUM"); - - cvf::ref rsAccessor = RigResultAccessorFactory::createFromNameAndType(eclipseCaseData, gridIndex, RiaDefines::MATRIX_MODEL, timeStepIndex, "RS", RiaDefines::DYNAMIC_NATIVE); - cvf::ref rvAccessor = RigResultAccessorFactory::createFromNameAndType(eclipseCaseData, gridIndex, RiaDefines::MATRIX_MODEL, timeStepIndex, "RV", RiaDefines::DYNAMIC_NATIVE); - cvf::ref pressureAccessor = RigResultAccessorFactory::createFromNameAndType(eclipseCaseData, gridIndex, RiaDefines::MATRIX_MODEL, timeStepIndex, "PRESSURE", RiaDefines::DYNAMIC_NATIVE); - cvf::ref pvtnumAccessor = RigResultAccessorFactory::createFromNameAndType(eclipseCaseData, gridIndex, RiaDefines::MATRIX_MODEL, timeStepIndex, "PVTNUM", RiaDefines::STATIC_NATIVE); + cellResultsData->ensureKnownResultLoaded(RigEclipseResultAddress(RiaDefines::DYNAMIC_NATIVE, "RS")); + cellResultsData->ensureKnownResultLoaded(RigEclipseResultAddress(RiaDefines::DYNAMIC_NATIVE, "RV")); + cellResultsData->ensureKnownResultLoaded(RigEclipseResultAddress(RiaDefines::DYNAMIC_NATIVE, "PRESSURE")); + cellResultsData->ensureKnownResultLoaded(RigEclipseResultAddress(RiaDefines::STATIC_NATIVE, "PVTNUM")); + + cvf::ref rsAccessor = RigResultAccessorFactory::createFromResultAddress(eclipseCaseData, gridIndex, RiaDefines::MATRIX_MODEL, timeStepIndex, RigEclipseResultAddress(RiaDefines::DYNAMIC_NATIVE, "RS" )); + cvf::ref rvAccessor = RigResultAccessorFactory::createFromResultAddress(eclipseCaseData, gridIndex, RiaDefines::MATRIX_MODEL, timeStepIndex, RigEclipseResultAddress(RiaDefines::DYNAMIC_NATIVE, "RV" )); + cvf::ref pressureAccessor = RigResultAccessorFactory::createFromResultAddress(eclipseCaseData, gridIndex, RiaDefines::MATRIX_MODEL, timeStepIndex, RigEclipseResultAddress(RiaDefines::DYNAMIC_NATIVE, "PRESSURE" )); + cvf::ref pvtnumAccessor = RigResultAccessorFactory::createFromResultAddress(eclipseCaseData, gridIndex, RiaDefines::MATRIX_MODEL, timeStepIndex, RigEclipseResultAddress(RiaDefines::STATIC_NATIVE , "PVTNUM" )); RiuPvtPlotPanel::CellValues cellValues; cellValues.rs = rsAccessor.notNull() ? rsAccessor->cellScalar(gridLocalCellIndex) : HUGE_VAL; diff --git a/ApplicationCode/UserInterface/RiuQwtCurvePointTracker.cpp b/ApplicationCode/UserInterface/RiuQwtCurvePointTracker.cpp index d8a4922df8..2e37c67e04 100644 --- a/ApplicationCode/UserInterface/RiuQwtCurvePointTracker.cpp +++ b/ApplicationCode/UserInterface/RiuQwtCurvePointTracker.cpp @@ -26,7 +26,7 @@ #include "qwt_plot_curve.h" #include "qwt_date_scale_draw.h" -#include // For DBL_MAX +#include // For DBL_MAX #include diff --git a/ApplicationCode/UserInterface/RiuQwtPlot.cpp b/ApplicationCode/UserInterface/RiuQwtPlot.cpp new file mode 100644 index 0000000000..ccbb7dde03 --- /dev/null +++ b/ApplicationCode/UserInterface/RiuQwtPlot.cpp @@ -0,0 +1,240 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2016- Statoil ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "RiuQwtPlot.h" + +#include "RimProject.h" + +#include "RiuPlotMainWindowTools.h" +#include "RiuQwtCurvePointTracker.h" +#include "RiuQwtPlotTools.h" +#include "RiuQwtPlotWheelZoomer.h" +#include "RiuQwtPlotZoomer.h" +#include "RiuQwtScalePicker.h" + +#include "qwt_date_scale_draw.h" +#include "qwt_date_scale_engine.h" +#include "qwt_legend.h" +#include "qwt_plot_curve.h" +#include "qwt_plot_grid.h" +#include "qwt_plot_layout.h" +#include "qwt_plot_magnifier.h" +#include "qwt_plot_marker.h" +#include "qwt_plot_panner.h" +#include "qwt_plot_zoomer.h" +#include "qwt_scale_engine.h" +#include "qwt_symbol.h" + +#include +#include +#include + +#include + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RiuQwtPlot::RiuQwtPlot(RimViewWindow* viewWindow, QWidget* parent) : QwtPlot(parent) +{ + Q_ASSERT(viewWindow); + m_ownerViewWindow = viewWindow; + + // LeftButton for the zooming + m_zoomerLeft = new RiuQwtPlotZoomer(canvas()); + m_zoomerLeft->setRubberBandPen(QColor(Qt::black)); + m_zoomerLeft->setTrackerMode(QwtPicker::AlwaysOff); + m_zoomerLeft->setTrackerPen(QColor(Qt::black)); + m_zoomerLeft->initMousePattern(1); + + // Attach a zoomer for the right axis + m_zoomerRight = new RiuQwtPlotZoomer(canvas()); + m_zoomerRight->setAxis(xTop, yRight); + m_zoomerRight->setTrackerMode(QwtPicker::AlwaysOff); + m_zoomerRight->initMousePattern(1); + + // MidButton for the panning + QwtPlotPanner* panner = new QwtPlotPanner(canvas()); + panner->setMouseButton(Qt::MidButton); + + auto wheelZoomer = new RiuQwtPlotWheelZoomer(this); + + connect(wheelZoomer, SIGNAL(zoomUpdated()), SLOT(onZoomedSlot())); + connect(m_zoomerLeft, SIGNAL(zoomed( const QRectF & )), SLOT(onZoomedSlot())); + connect(panner, SIGNAL(panned( int , int )), SLOT(onZoomedSlot())); + + RiuQwtScalePicker* scalePicker = new RiuQwtScalePicker(this); + connect(scalePicker, SIGNAL(clicked(int, double)), this, SLOT(onAxisClicked(int, double))); + + RiuQwtPlotTools::setCommonPlotBehaviour(this); + RiuQwtPlotTools::setDefaultAxes(this); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RiuQwtPlot::~RiuQwtPlot() +{ + if (ownerPlotDefinition()) + { + ownerPlotDefinition()->detachAllCurves(); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimRiuQwtPlotOwnerInterface* RiuQwtPlot::ownerPlotDefinition() const +{ + RimRiuQwtPlotOwnerInterface* plotDefinition = dynamic_cast(ownerViewWindow()); + return plotDefinition; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimViewWindow* RiuQwtPlot::ownerViewWindow() const +{ + return m_ownerViewWindow; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QSize RiuQwtPlot::minimumSizeHint() const +{ + return QSize(0, 100); +} + +//-------------------------------------------------------------------------------------------------- +/// Empty default implementation +//-------------------------------------------------------------------------------------------------- +void RiuQwtPlot::selectSample(QwtPlotCurve* curve, int sampleNumber) +{ +} + +//-------------------------------------------------------------------------------------------------- +/// Empty default implementation +//-------------------------------------------------------------------------------------------------- +void RiuQwtPlot::clearSampleSelection() +{ +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QSize RiuQwtPlot::sizeHint() const +{ + return QSize(0, 0); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QwtInterval RiuQwtPlot::currentAxisRange(QwtPlot::Axis axis) +{ + return axisScaleDiv(axis).interval(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RiuQwtPlot::eventFilter(QObject* watched, QEvent* event) +{ + if(watched == canvas()) + { + QMouseEvent* mouseEvent = dynamic_cast(event); + if(mouseEvent) + { + if(mouseEvent->button() == Qt::LeftButton && mouseEvent->type() == QMouseEvent::MouseButtonRelease) + { + selectClosestCurve(mouseEvent->pos()); + } + } + } + + return QwtPlot::eventFilter(watched, event); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuQwtPlot::selectClosestCurve(const QPoint& pos) +{ + QwtPlotCurve* closestCurve = nullptr; + double distMin = DBL_MAX; + int closestCurvePoint = -1; + const QwtPlotItemList& itmList = itemList(); + for(QwtPlotItemIterator it = itmList.begin(); it != itmList.end(); it++) + { + if((*it)->rtti() == QwtPlotItem::Rtti_PlotCurve) + { + QwtPlotCurve* candidateCurve = static_cast(*it); + double dist = DBL_MAX; + int curvePoint = candidateCurve->closestPoint(pos, &dist); + if(dist < distMin) + { + closestCurve = candidateCurve; + distMin = dist; + closestCurvePoint = curvePoint; + } + } + } + + if (closestCurve && distMin < 20) + { + CVF_ASSERT(closestCurvePoint >= 0); + caf::PdmObject* selectedPlotObject = ownerPlotDefinition()->findRimPlotObjectFromQwtCurve(closestCurve); + + if (selectedPlotObject) + { + RimProject* proj = nullptr; + selectedPlotObject->firstAncestorOrThisOfType(proj); + + if (proj) + { + RiuPlotMainWindowTools::showPlotMainWindow(); + RiuPlotMainWindowTools::selectAsCurrentItem(selectedPlotObject); + } + } + } + + if (closestCurve && distMin < 10) + { + selectSample(closestCurve, closestCurvePoint); + } + else + { + clearSampleSelection(); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuQwtPlot::onZoomedSlot() +{ + ownerPlotDefinition()->updateZoomWindowFromQwt(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuQwtPlot::onAxisClicked(int axis, double value) +{ + ownerPlotDefinition()->selectAxisInPropertyEditor(axis); +} diff --git a/ApplicationCode/UserInterface/RiuQwtPlot.h b/ApplicationCode/UserInterface/RiuQwtPlot.h new file mode 100644 index 0000000000..ff81a5d539 --- /dev/null +++ b/ApplicationCode/UserInterface/RiuQwtPlot.h @@ -0,0 +1,78 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2016- Statoil ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "RiuInterfaceToViewWindow.h" + +#include "RimRiuQwtPlotOwnerInterface.h" + +#include "cafPdmPointer.h" + +#include "qwt_plot.h" + +#include + +class QwtPlotCurve; +class QwtPlotGrid; +class QwtPlotZoomer; +class QwtInterval; +class QwtPicker; +class QwtPlotMarker; +class QwtScaleWidget; + +//================================================================================================== +// +// +// +//================================================================================================== +class RiuQwtPlot : public QwtPlot, public RiuInterfaceToViewWindow +{ + Q_OBJECT; +public: + RiuQwtPlot(RimViewWindow* viewWindow, QWidget* parent = nullptr); + ~RiuQwtPlot() override; + + RimRiuQwtPlotOwnerInterface* ownerPlotDefinition() const; + RimViewWindow* ownerViewWindow() const override; + + QwtInterval currentAxisRange(QwtPlot::Axis axis); + +protected: + bool eventFilter(QObject* watched, QEvent* event) override; + + QSize sizeHint() const override; + QSize minimumSizeHint() const override; + + virtual void selectSample(QwtPlotCurve* curve, int sampleNumber); + virtual void clearSampleSelection(); +private: + void selectClosestCurve(const QPoint& pos); + +private slots: + void onZoomedSlot( ); + void onAxisClicked(int axis, double value); + +private: + caf::PdmPointer m_ownerViewWindow; + + QPointer m_zoomerLeft; + QPointer m_zoomerRight; + +}; + diff --git a/ApplicationCode/UserInterface/RiuQwtPlotCurve.cpp b/ApplicationCode/UserInterface/RiuQwtPlotCurve.cpp index 60f97cf916..27e2c4fbe2 100644 --- a/ApplicationCode/UserInterface/RiuQwtPlotCurve.cpp +++ b/ApplicationCode/UserInterface/RiuQwtPlotCurve.cpp @@ -20,6 +20,7 @@ #include "RiuQwtPlotCurve.h" #include "RiaCurveDataTools.h" +#include "RiaImageTools.h" #include "RiuQwtSymbol.h" #include "qwt_symbol.h" @@ -59,6 +60,7 @@ RiuQwtPlotCurve::RiuQwtPlotCurve(const QString &title) m_showErrorBars = true; m_attachedToPlot = nullptr; + m_blackAndWhiteLegendIcon = false; } //-------------------------------------------------------------------------------------------------- @@ -320,15 +322,18 @@ void RiuQwtPlotCurve::setErrorBarsColor(QColor color) /// //-------------------------------------------------------------------------------------------------- void RiuQwtPlotCurve::setAppearance(LineStyleEnum lineStyle, - CurveInterpolationEnum interpolationType, - int curveThickness, - const QColor& curveColor) + CurveInterpolationEnum interpolationType, + int requestedCurveThickness, + const QColor& curveColor) { QwtPlotCurve::CurveStyle curveStyle = QwtPlotCurve::NoCurve; - Qt::PenStyle penStyle = Qt::SolidLine; + Qt::PenStyle penStyle = Qt::NoPen; + // Qwt bug workaround (#4135): need to set 0 curve thickness for STYLE_NONE + int curveThickness = 0; if (lineStyle != STYLE_NONE) { + curveThickness = requestedCurveThickness; switch (interpolationType) { case INTERPOLATION_STEP_LEFT: @@ -368,6 +373,31 @@ void RiuQwtPlotCurve::setAppearance(LineStyleEnum lineStyle, setStyle(curveStyle); } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuQwtPlotCurve::setBlackAndWhiteLegendIcon(bool blackAndWhite) +{ + m_blackAndWhiteLegendIcon = blackAndWhite; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QwtGraphic RiuQwtPlotCurve::legendIcon(int index, const QSizeF& size) const +{ + QwtGraphic icon = QwtPlotCurve::legendIcon(index, size); + if (m_blackAndWhiteLegendIcon) + { + QImage image = icon.toImage(); + RiaImageTools::makeGrayScale(image); + + QPainter painter(&icon); + painter.drawImage(QPoint(0, 0), image); + } + return icon; +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/UserInterface/RiuQwtPlotCurve.h b/ApplicationCode/UserInterface/RiuQwtPlotCurve.h index ac0d3a4e33..22739307ed 100644 --- a/ApplicationCode/UserInterface/RiuQwtPlotCurve.h +++ b/ApplicationCode/UserInterface/RiuQwtPlotCurve.h @@ -113,6 +113,8 @@ class RiuQwtPlotCurve : public QwtPlotCurve CurveInterpolationEnum interpolationType, int curveThickness, const QColor& curveColor); + void setBlackAndWhiteLegendIcon(bool blackAndWhite); + QwtGraphic legendIcon(int index, const QSizeF& size) const override; protected: void drawCurve(QPainter* p, int style, @@ -138,4 +140,5 @@ class RiuQwtPlotCurve : public QwtPlotCurve bool m_showErrorBars; QwtPlotIntervalCurve* m_errorBars; QwtPlot* m_attachedToPlot; + bool m_blackAndWhiteLegendIcon; }; diff --git a/ApplicationCode/UserInterface/RiuQwtPlotTools.cpp b/ApplicationCode/UserInterface/RiuQwtPlotTools.cpp new file mode 100644 index 0000000000..35de490a1c --- /dev/null +++ b/ApplicationCode/UserInterface/RiuQwtPlotTools.cpp @@ -0,0 +1,119 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2019- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// +#include "RiuQwtPlotTools.h" + +#include "qwt_date_scale_draw.h" +#include "qwt_date_scale_engine.h" +#include "qwt_plot.h" +#include "qwt_plot_grid.h" +#include "qwt_plot_layout.h" + +#include + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuQwtPlotTools::setCommonPlotBehaviour(QwtPlot* plot) +{ + // Plot background and frame look + + QPalette newPalette(plot->palette()); + newPalette.setColor(QPalette::Background, Qt::white); + plot->setPalette(newPalette); + + plot->setAutoFillBackground(true); + plot->setCanvasBackground(Qt::white); + + QFrame* canvasFrame = dynamic_cast(plot->canvas()); + if (canvasFrame) + { + canvasFrame->setFrameShape(QFrame::NoFrame); + } + + // Grid + + QwtPlotGrid* grid = new QwtPlotGrid; + grid->attach(plot); + QPen gridPen(Qt::SolidLine); + gridPen.setColor(Qt::lightGray); + grid->setPen(gridPen); + + // Axis number font + QFont axisFont = plot->axisFont(QwtPlot::xBottom); + axisFont.setPointSize(10); + + plot->setAxisFont(QwtPlot::xBottom, axisFont); + plot->setAxisFont(QwtPlot::xTop, axisFont); + plot->setAxisFont(QwtPlot::yLeft, axisFont); + plot->setAxisFont(QwtPlot::yRight, axisFont); + + // Axis title font + std::vector axes = { QwtPlot::xBottom, QwtPlot::xTop, QwtPlot::yLeft, QwtPlot::yRight }; + + for (QwtPlot::Axis axis : axes) + { + QwtText axisTitle = plot->axisTitle(axis); + QFont axisTitleFont = axisTitle.font(); + axisTitleFont.setPointSize(10); + axisTitleFont.setBold(false); + axisTitle.setFont(axisTitleFont); + axisTitle.setRenderFlags(Qt::AlignRight); + + plot->setAxisTitle(axis, axisTitle); + } + + // Set a focus policy to allow it taking key press events. + // This is not strictly necessary since this widget inherit QwtPlot + // which already has a focus policy. + // However, for completeness we still do it here. + plot->setFocusPolicy(Qt::WheelFocus); + + // Enable mousetracking and event filter + plot->canvas()->setMouseTracking(true); + plot->canvas()->installEventFilter(plot); + plot->plotLayout()->setAlignCanvasToScales(true); + + plot->setContentsMargins(4, 4, 4, 4); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuQwtPlotTools::setDefaultAxes(QwtPlot* plot) +{ + plot->enableAxis(QwtPlot::xBottom, true); + plot->enableAxis(QwtPlot::yLeft, true); + plot->enableAxis(QwtPlot::xTop, false); + plot->enableAxis(QwtPlot::yRight, false); + + plot->setAxisMaxMinor(QwtPlot::xBottom, 2); + plot->setAxisMaxMinor(QwtPlot::yLeft, 3); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuQwtPlotTools::enableDateBasedBottomXAxis(QwtPlot* plot) +{ + QwtDateScaleDraw* scaleDraw = new QwtDateScaleDraw(Qt::UTC); + scaleDraw->setDateFormat(QwtDate::Year, QString("dd-MM-yyyy")); + + QwtDateScaleEngine* scaleEngine = new QwtDateScaleEngine(Qt::UTC); + plot->setAxisScaleEngine(QwtPlot::xBottom, scaleEngine); + plot->setAxisScaleDraw(QwtPlot::xBottom, scaleDraw); +} \ No newline at end of file diff --git a/ApplicationCode/UserInterface/RiuQwtPlotTools.h b/ApplicationCode/UserInterface/RiuQwtPlotTools.h new file mode 100644 index 0000000000..a54578dfd7 --- /dev/null +++ b/ApplicationCode/UserInterface/RiuQwtPlotTools.h @@ -0,0 +1,29 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2019- Equinor ASA +// +// ResInsight 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 3 of the License, or +// (at your option) any later version. +// +// ResInsight 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 at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// +#pragma once + +class QwtPlot; + +class RiuQwtPlotTools +{ +public: + static void setCommonPlotBehaviour(QwtPlot* plot); + static void setDefaultAxes(QwtPlot* plot); + static void enableDateBasedBottomXAxis(QwtPlot* plot); +}; + diff --git a/ApplicationCode/UserInterface/RiuQwtSymbol.cpp b/ApplicationCode/UserInterface/RiuQwtSymbol.cpp index e46f3d6cff..2c529c2c9b 100644 --- a/ApplicationCode/UserInterface/RiuQwtSymbol.cpp +++ b/ApplicationCode/UserInterface/RiuQwtSymbol.cpp @@ -102,6 +102,18 @@ RiuQwtSymbol::RiuQwtSymbol(PointSymbolEnum riuStyle, const QString& label, Label setPinPoint(QPointF(0, 10)); } break; + case SYMBOL_UP_TRIANGLE: + style = QwtSymbol::UTriangle; + break; + case SYMBOL_STAR1: + style = QwtSymbol::Star1; + break; + case SYMBOL_STAR2: + style = QwtSymbol::Star2; + break; + case SYMBOL_HEXAGON: + style = QwtSymbol::Hexagon; + break; default: break; } @@ -136,6 +148,14 @@ void RiuQwtSymbol::renderSymbolLabel(QPainter *painter, const QPointF& position) painter->drawText(labelRect.topLeft(), m_label); } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuQwtSymbol::setLabel(const QString& label) +{ + m_label = label; +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -144,6 +164,41 @@ void RiuQwtSymbol::setLabelPosition(LabelPosition labelPosition) m_labelPosition = labelPosition; } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RiuQwtSymbol::PointSymbolEnum RiuQwtSymbol::cycledSymbolStyle(int indexLevel1, int indexLevel2) +{ + std::vector> categorisedStyles = + { + {SYMBOL_ELLIPSE, SYMBOL_RECT, SYMBOL_DIAMOND}, + {SYMBOL_DOWN_TRIANGLE, SYMBOL_UP_TRIANGLE}, + {SYMBOL_LEFT_TRIANGLE, SYMBOL_RIGHT_TRIANGLE}, + {SYMBOL_LEFT_ANGLED_TRIANGLE, SYMBOL_RIGHT_ANGLED_TRIANGLE}, + {SYMBOL_CROSS, SYMBOL_XCROSS}, + {SYMBOL_STAR1, SYMBOL_STAR2}, + }; + + int level1Category = indexLevel1 % int(categorisedStyles.size()); + int level2Category = indexLevel2 % int(categorisedStyles[level1Category].size()); + + return categorisedStyles[level1Category][level2Category]; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RiuQwtSymbol::PointSymbolEnum RiuQwtSymbol::cycledSymbolStyle(int indexLevel) +{ + std::vector contrastingSymbols = + { + SYMBOL_ELLIPSE, SYMBOL_CROSS, SYMBOL_RECT, SYMBOL_DOWN_TRIANGLE, SYMBOL_UP_TRIANGLE, + SYMBOL_LEFT_TRIANGLE, SYMBOL_RIGHT_TRIANGLE, SYMBOL_STAR2, SYMBOL_DIAMOND, SYMBOL_STAR1 + }; + + return contrastingSymbols[indexLevel % (int)contrastingSymbols.size()]; +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/UserInterface/RiuQwtSymbol.h b/ApplicationCode/UserInterface/RiuQwtSymbol.h index c3f7986645..cead7e965e 100644 --- a/ApplicationCode/UserInterface/RiuQwtSymbol.h +++ b/ApplicationCode/UserInterface/RiuQwtSymbol.h @@ -44,22 +44,30 @@ class RiuQwtSymbol : public QwtSymbol SYMBOL_RECT, SYMBOL_DIAMOND, SYMBOL_TRIANGLE, + SYMBOL_DOWN_TRIANGLE, SYMBOL_CROSS, SYMBOL_XCROSS, - SYMBOL_DOWN_TRIANGLE, SYMBOL_LEFT_TRIANGLE, SYMBOL_RIGHT_TRIANGLE, SYMBOL_LEFT_ANGLED_TRIANGLE, - SYMBOL_RIGHT_ANGLED_TRIANGLE + SYMBOL_RIGHT_ANGLED_TRIANGLE, + SYMBOL_UP_TRIANGLE, + SYMBOL_STAR1, + SYMBOL_STAR2, + SYMBOL_HEXAGON }; RiuQwtSymbol(PointSymbolEnum riuStyle, const QString& label, LabelPosition labelPosition = LabelAboveSymbol); - + void renderSymbols(QPainter *painter, const QPointF *points, int numPoints) const override; void renderSymbolLabel(QPainter *painter, const QPointF& position) const; QString label() const { return m_label; } + void setLabel(const QString& label); void setLabelPosition(LabelPosition labelPosition); + + static PointSymbolEnum cycledSymbolStyle(int indexLevel1, int indexLevel2); + static PointSymbolEnum cycledSymbolStyle(int indexLevel); private: QRect labelBoundingRect(const QPainter* painter, const QRect& symbolRect) const; diff --git a/ApplicationCode/UserInterface/RiuRelativePermeabilityPlotPanel.cpp b/ApplicationCode/UserInterface/RiuRelativePermeabilityPlotPanel.cpp index ed8c43f4d6..8c64960e65 100644 --- a/ApplicationCode/UserInterface/RiuRelativePermeabilityPlotPanel.cpp +++ b/ApplicationCode/UserInterface/RiuRelativePermeabilityPlotPanel.cpp @@ -16,10 +16,11 @@ // ///////////////////////////////////////////////////////////////////////////////// +#include "RiuDockedQwtPlot.h" #include "RiuRelativePermeabilityPlotPanel.h" #include "RiuRelativePermeabilityPlotUpdater.h" -#include "RiuSummaryQwtPlot.h" #include "RiuQwtPlotCurve.h" +#include "RiuQwtPlotTools.h" #include "RiuTextDialog.h" #include "RiaCurveDataTools.h" @@ -56,10 +57,10 @@ // // //================================================================================================== -class RelPermQwtPlot : public QwtPlot +class RelPermQwtPlot : public RiuDockedQwtPlot { public: - RelPermQwtPlot(QWidget* parent) : QwtPlot(parent) {} + RelPermQwtPlot(QWidget* parent) : RiuDockedQwtPlot(parent) {} QSize sizeHint() const override { return QSize(100, 100); } QSize minimumSizeHint() const override { return QSize(0, 0); } }; @@ -88,6 +89,7 @@ RiuRelativePermeabilityPlotPanel::RiuRelativePermeabilityPlotPanel(QDockWidget* { m_qwtPlot = new RelPermQwtPlot(this); setPlotDefaults(m_qwtPlot); + applyFontSizes(false); m_selectedCurvesButtonGroup = new QButtonGroup(this); m_selectedCurvesButtonGroup->setExclusive(false); @@ -154,12 +156,12 @@ RiuRelativePermeabilityPlotPanel::~RiuRelativePermeabilityPlotPanel() //-------------------------------------------------------------------------------------------------- void RiuRelativePermeabilityPlotPanel::setPlotDefaults(QwtPlot* plot) { - RiuSummaryQwtPlot::setCommonPlotBehaviour(plot); + RiuQwtPlotTools::setCommonPlotBehaviour(plot); { QwtText plotTitle = plot->title(); QFont titleFont = plotTitle.font(); - titleFont.setPixelSize(14); + titleFont.setPointSize(10); plotTitle.setFont(titleFont); plot->setTitle(plotTitle); } @@ -228,6 +230,14 @@ RiuRelativePermeabilityPlotUpdater* RiuRelativePermeabilityPlotPanel::plotUpdate return m_plotUpdater.get(); } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuRelativePermeabilityPlotPanel::applyFontSizes(bool replot /*= true*/) +{ + m_qwtPlot->applyFontSizes(replot); +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -465,7 +475,6 @@ void RiuRelativePermeabilityPlotPanel::plotCurvesInQwt(RiaEclipseUnitTools::Unit plot->setAxisTitle(QwtPlot::xBottom, determineXAxisTitleFromCurveCollection(curveArr)); plot->setAxisTitle(QwtPlot::yLeft, "Kr"); plot->setAxisTitle(QwtPlot::yRight, QString("Pc [%1]").arg(RiaEclipseUnitTools::unitStringPressure(unitSystem))); - plot->replot(); } diff --git a/ApplicationCode/UserInterface/RiuRelativePermeabilityPlotPanel.h b/ApplicationCode/UserInterface/RiuRelativePermeabilityPlotPanel.h index d5a5d65b03..c6bdd073d9 100644 --- a/ApplicationCode/UserInterface/RiuRelativePermeabilityPlotPanel.h +++ b/ApplicationCode/UserInterface/RiuRelativePermeabilityPlotPanel.h @@ -21,10 +21,12 @@ #include "RiaEclipseUnitTools.h" #include "RigFlowDiagSolverInterface.h" +#include #include #include +class RiuDockedQwtPlot; class RiuRelativePermeabilityPlotUpdater; class QDockWidget; class QButtonGroup; @@ -54,6 +56,7 @@ class RiuRelativePermeabilityPlotPanel : public QWidget QString cellReferenceText); void clearPlot(); RiuRelativePermeabilityPlotUpdater* plotUpdater(); + void applyFontSizes(bool replot); private: enum WhichYAxis @@ -124,7 +127,7 @@ private slots: double m_sgas; QString m_caseName; QString m_cellReferenceText; - QwtPlot* m_qwtPlot; + QPointer m_qwtPlot; std::vector m_myPlotMarkers; QButtonGroup* m_selectedCurvesButtonGroup; diff --git a/ApplicationCode/UserInterface/RiuRelativePermeabilityPlotUpdater.cpp b/ApplicationCode/UserInterface/RiuRelativePermeabilityPlotUpdater.cpp index 2683be34d6..ca5356046a 100644 --- a/ApplicationCode/UserInterface/RiuRelativePermeabilityPlotUpdater.cpp +++ b/ApplicationCode/UserInterface/RiuRelativePermeabilityPlotUpdater.cpp @@ -18,7 +18,7 @@ #include "RiuRelativePermeabilityPlotUpdater.h" #include "RiuRelativePermeabilityPlotPanel.h" -#include "RiuSelectionManager.h" +#include "Riu3dSelectionManager.h" #include "RigEclipseCaseData.h" #include "RigGridBase.h" @@ -118,7 +118,7 @@ void RiuRelativePermeabilityPlotUpdater::updateOnTimeStepChanged(Rim3dView* chan } // Fetch the current global selection and only continue if the selection's view matches the view with time step change - const RiuEclipseSelectionItem* eclipseSelectionItem = dynamic_cast(RiuSelectionManager::instance()->selectedItem()); + const RiuEclipseSelectionItem* eclipseSelectionItem = dynamic_cast(Riu3dSelectionManager::instance()->selectedItem()); if (eclipseSelectionItem && eclipseSelectionItem->m_view == eclipseView) { const size_t gridIndex = eclipseSelectionItem->m_gridIndex; @@ -150,15 +150,15 @@ bool RiuRelativePermeabilityPlotUpdater::queryDataAndUpdatePlot(const RimEclipse // Make sure we load the results that we'll query below RigCaseCellResultsData* cellResultsData = eclipseCaseData->results(RiaDefines::MATRIX_MODEL); - cellResultsData->findOrLoadScalarResult(RiaDefines::DYNAMIC_NATIVE, "SWAT"); - cellResultsData->findOrLoadScalarResult(RiaDefines::DYNAMIC_NATIVE, "SGAS"); - cellResultsData->findOrLoadScalarResult(RiaDefines::STATIC_NATIVE, "SATNUM"); + cellResultsData->ensureKnownResultLoaded(RigEclipseResultAddress(RiaDefines::DYNAMIC_NATIVE, "SWAT")); + cellResultsData->ensureKnownResultLoaded(RigEclipseResultAddress(RiaDefines::DYNAMIC_NATIVE, "SGAS")); + cellResultsData->ensureKnownResultLoaded(RigEclipseResultAddress(RiaDefines::STATIC_NATIVE, "SATNUM")); // Fetch SWAT and SGAS cell values for the selected cell const size_t timeStepIndex = static_cast(eclipseView.currentTimeStep()); - cvf::ref swatAccessor = RigResultAccessorFactory::createFromNameAndType(eclipseCaseData, gridIndex, RiaDefines::MATRIX_MODEL, timeStepIndex, "SWAT", RiaDefines::DYNAMIC_NATIVE); - cvf::ref sgasAccessor = RigResultAccessorFactory::createFromNameAndType(eclipseCaseData, gridIndex, RiaDefines::MATRIX_MODEL, timeStepIndex, "SGAS", RiaDefines::DYNAMIC_NATIVE); - cvf::ref satnumAccessor = RigResultAccessorFactory::createFromNameAndType(eclipseCaseData, gridIndex, RiaDefines::MATRIX_MODEL, timeStepIndex, "SATNUM", RiaDefines::STATIC_NATIVE); + cvf::ref swatAccessor = RigResultAccessorFactory::createFromResultAddress(eclipseCaseData, gridIndex, RiaDefines::MATRIX_MODEL, timeStepIndex, RigEclipseResultAddress(RiaDefines::DYNAMIC_NATIVE, "SWAT" )); + cvf::ref sgasAccessor = RigResultAccessorFactory::createFromResultAddress(eclipseCaseData, gridIndex, RiaDefines::MATRIX_MODEL, timeStepIndex, RigEclipseResultAddress(RiaDefines::DYNAMIC_NATIVE, "SGAS" )); + cvf::ref satnumAccessor = RigResultAccessorFactory::createFromResultAddress(eclipseCaseData, gridIndex, RiaDefines::MATRIX_MODEL, timeStepIndex, RigEclipseResultAddress(RiaDefines::STATIC_NATIVE , "SATNUM")); const double cellSWAT = swatAccessor.notNull() ? swatAccessor->cellScalar(gridLocalCellIndex) : HUGE_VAL; const double cellSGAS = sgasAccessor.notNull() ? sgasAccessor->cellScalar(gridLocalCellIndex) : HUGE_VAL; const double cellSATNUM = satnumAccessor.notNull() ? satnumAccessor->cellScalar(gridLocalCellIndex) : HUGE_VAL; diff --git a/ApplicationCode/UserInterface/RiuResultInfoPanel.h b/ApplicationCode/UserInterface/RiuResultInfoPanel.h index f067383d33..c50281639f 100644 --- a/ApplicationCode/UserInterface/RiuResultInfoPanel.h +++ b/ApplicationCode/UserInterface/RiuResultInfoPanel.h @@ -18,7 +18,7 @@ #pragma once -#include +#include class QDockWidget; class QTextEdit; diff --git a/ApplicationCode/UserInterface/RiuResultQwtPlot.cpp b/ApplicationCode/UserInterface/RiuResultQwtPlot.cpp index e844873ff4..13e36fdd35 100644 --- a/ApplicationCode/UserInterface/RiuResultQwtPlot.cpp +++ b/ApplicationCode/UserInterface/RiuResultQwtPlot.cpp @@ -19,14 +19,16 @@ #include "RiuResultQwtPlot.h" +#include "RiaApplication.h" #include "RiaCurveDataTools.h" +#include "RiaPreferences.h" #include "RiaQDateTimeTools.h" #include "RimContextCommandBuilder.h" #include "RimCase.h" #include "RiuQwtPlotCurve.h" -#include "RiuSummaryQwtPlot.h" +#include "RiuQwtPlotTools.h" #include "RiuTextDialog.h" #include "cafCmdFeatureMenuBuilder.h" @@ -50,7 +52,7 @@ /// //-------------------------------------------------------------------------------------------------- RiuResultQwtPlot::RiuResultQwtPlot(QWidget* parent) - : QwtPlot(parent) + : RiuDockedQwtPlot(parent) { setDefaults(); } @@ -84,6 +86,7 @@ void RiuResultQwtPlot::addCurve(const RimCase* rimCase, const QString& curveName m_plotCurves.push_back(plotCurve); this->setAxisScale( QwtPlot::xTop, QwtDate::toDouble(dateTimes.front()), QwtDate::toDouble(dateTimes.back())); + this->applyFontSizes(false); this->replot(); @@ -173,18 +176,20 @@ void RiuResultQwtPlot::contextMenuEvent(QContextMenuEvent* event) //-------------------------------------------------------------------------------------------------- void RiuResultQwtPlot::setDefaults() { - RiuSummaryQwtPlot::setCommonPlotBehaviour(this); + RiuQwtPlotTools::setCommonPlotBehaviour(this); enableAxis(QwtPlot::xBottom, true); enableAxis(QwtPlot::yLeft, true); enableAxis(QwtPlot::xTop, false); enableAxis(QwtPlot::yRight, false); - RiuSummaryQwtPlot::enableDateBasedBottomXAxis(this); + RiuQwtPlotTools::enableDateBasedBottomXAxis(this); setAxisMaxMinor(QwtPlot::xBottom, 2); setAxisMaxMinor(QwtPlot::yLeft, 3); + applyFontSizes(false); + // The legend will be deleted in the destructor of the plot or when // another legend is inserted. QwtLegend* legend = new QwtLegend(this); diff --git a/ApplicationCode/UserInterface/RiuResultQwtPlot.h b/ApplicationCode/UserInterface/RiuResultQwtPlot.h index 85ec959cbe..e8da66dc69 100644 --- a/ApplicationCode/UserInterface/RiuResultQwtPlot.h +++ b/ApplicationCode/UserInterface/RiuResultQwtPlot.h @@ -19,6 +19,8 @@ #pragma once +#include "RiuDockedQwtPlot.h" + #include "qwt_plot.h" #include @@ -39,7 +41,7 @@ namespace cvf // // //================================================================================================== -class RiuResultQwtPlot : public QwtPlot +class RiuResultQwtPlot : public RiuDockedQwtPlot { Q_OBJECT diff --git a/ApplicationCode/UserInterface/RiuResultTextBuilder.cpp b/ApplicationCode/UserInterface/RiuResultTextBuilder.cpp index 2017ed62b2..9de8498c24 100644 --- a/ApplicationCode/UserInterface/RiuResultTextBuilder.cpp +++ b/ApplicationCode/UserInterface/RiuResultTextBuilder.cpp @@ -424,19 +424,19 @@ QString RiuResultTextBuilder::nncResultText() if (m_reservoirView->currentFaultResultColors()) { - size_t scalarResultIdx = m_reservoirView->currentFaultResultColors()->scalarResultIndex(); + RigEclipseResultAddress eclipseResultAddress = m_reservoirView->currentFaultResultColors()->eclipseResultAddress(); RiaDefines::ResultCatType resultType = m_reservoirView->currentFaultResultColors()->resultType(); const std::vector* nncValues = nullptr; if (resultType == RiaDefines::STATIC_NATIVE) { - nncValues = nncData->staticConnectionScalarResult(scalarResultIdx); + nncValues = nncData->staticConnectionScalarResult(eclipseResultAddress); } else if (resultType == RiaDefines::DYNAMIC_NATIVE) { if (m_reservoirView.notNull() && m_reservoirView->eclipseCase()) { size_t nativeTimeStep = m_reservoirView->eclipseCase()->uiToNativeTimeStepIndex(m_timeStepIndex); - nncValues = nncData->dynamicConnectionScalarResult(scalarResultIdx, nativeTimeStep); + nncValues = nncData->dynamicConnectionScalarResult(eclipseResultAddress, nativeTimeStep); } } if (nncValues && (m_nncIndex < nncValues->size())) @@ -470,13 +470,13 @@ void RiuResultTextBuilder::appendTextFromResultColors(RigEclipseCaseData* eclips RigCaseCellResultsData* gridCellResults = resultColors->currentGridCellResults(); if (gridCellResults) { - size_t soilScalarSetIndex = gridCellResults->findOrLoadScalarResult(RiaDefines::DYNAMIC_NATIVE, "SOIL"); - size_t sgasScalarSetIndex = gridCellResults->findOrLoadScalarResult(RiaDefines::DYNAMIC_NATIVE, "SGAS"); - size_t swatScalarSetIndex = gridCellResults->findOrLoadScalarResult(RiaDefines::DYNAMIC_NATIVE, "SWAT"); + gridCellResults->ensureKnownResultLoaded(RigEclipseResultAddress(RiaDefines::DYNAMIC_NATIVE, "SOIL")); + gridCellResults->ensureKnownResultLoaded(RigEclipseResultAddress(RiaDefines::DYNAMIC_NATIVE, "SGAS")); + gridCellResults->ensureKnownResultLoaded(RigEclipseResultAddress(RiaDefines::DYNAMIC_NATIVE, "SWAT")); - cvf::ref dataAccessObjectX = RigResultAccessorFactory::createFromResultIdx(eclipseCase, gridIndex, porosityModel, timeStepIndex, soilScalarSetIndex); - cvf::ref dataAccessObjectY = RigResultAccessorFactory::createFromResultIdx(eclipseCase, gridIndex, porosityModel, timeStepIndex, sgasScalarSetIndex); - cvf::ref dataAccessObjectZ = RigResultAccessorFactory::createFromResultIdx(eclipseCase, gridIndex, porosityModel, timeStepIndex, swatScalarSetIndex); + cvf::ref dataAccessObjectX = RigResultAccessorFactory::createFromResultAddress(eclipseCase, gridIndex, porosityModel, timeStepIndex, RigEclipseResultAddress(RiaDefines::DYNAMIC_NATIVE, "SOIL")); + cvf::ref dataAccessObjectY = RigResultAccessorFactory::createFromResultAddress(eclipseCase, gridIndex, porosityModel, timeStepIndex, RigEclipseResultAddress(RiaDefines::DYNAMIC_NATIVE, "SGAS")); + cvf::ref dataAccessObjectZ = RigResultAccessorFactory::createFromResultAddress(eclipseCase, gridIndex, porosityModel, timeStepIndex, RigEclipseResultAddress(RiaDefines::DYNAMIC_NATIVE, "SWAT")); double scalarValue = 0.0; @@ -501,7 +501,7 @@ void RiuResultTextBuilder::appendTextFromResultColors(RigEclipseCaseData* eclips { if (resultColors->resultVariable().compare(RiaDefines::combinedTransmissibilityResultName(), Qt::CaseInsensitive) == 0) { - cvf::ref transResultAccessor = RigResultAccessorFactory::createFromUiResultName(eclipseCase, gridIndex, porosityModel, 0, RiaDefines::combinedTransmissibilityResultName()); + cvf::ref transResultAccessor = RigResultAccessorFactory::createFromResultAddress(eclipseCase, gridIndex, porosityModel, 0, RigEclipseResultAddress(RiaDefines::combinedTransmissibilityResultName())); { double scalarValue = transResultAccessor->cellFaceScalar(cellIndex, cvf::StructGridInterface::POS_I); resultInfoText->append(QString("Tran X : %1\n").arg(scalarValue)); @@ -517,7 +517,7 @@ void RiuResultTextBuilder::appendTextFromResultColors(RigEclipseCaseData* eclips } else if (resultColors->resultVariable().compare(RiaDefines::combinedMultResultName(), Qt::CaseInsensitive) == 0) { - cvf::ref multResultAccessor = RigResultAccessorFactory::createFromUiResultName(eclipseCase, gridIndex, porosityModel, 0, RiaDefines::combinedMultResultName()); + cvf::ref multResultAccessor = RigResultAccessorFactory::createFromResultAddress(eclipseCase, gridIndex, porosityModel, 0, RigEclipseResultAddress(RiaDefines::combinedMultResultName())); { double scalarValue = multResultAccessor->cellFaceScalar(cellIndex, cvf::StructGridInterface::POS_I); resultInfoText->append(QString("MULTX : %1\n").arg(scalarValue)); @@ -539,7 +539,7 @@ void RiuResultTextBuilder::appendTextFromResultColors(RigEclipseCaseData* eclips } else if (resultColors->resultVariable().compare(RiaDefines::combinedRiTranResultName(), Qt::CaseInsensitive) == 0) { - cvf::ref transResultAccessor = RigResultAccessorFactory::createFromUiResultName(eclipseCase, gridIndex, porosityModel, 0, RiaDefines::combinedRiTranResultName()); + cvf::ref transResultAccessor = RigResultAccessorFactory::createFromResultAddress(eclipseCase, gridIndex, porosityModel, 0, RigEclipseResultAddress(RiaDefines::combinedRiTranResultName())); { double scalarValue = transResultAccessor->cellFaceScalar(cellIndex, cvf::StructGridInterface::POS_I); resultInfoText->append(QString("riTran X : %1\n").arg(scalarValue)); @@ -555,7 +555,7 @@ void RiuResultTextBuilder::appendTextFromResultColors(RigEclipseCaseData* eclips } else if (resultColors->resultVariable().compare(RiaDefines::combinedRiMultResultName(), Qt::CaseInsensitive) == 0) { - cvf::ref resultAccessor = RigResultAccessorFactory::createFromUiResultName(eclipseCase, gridIndex, porosityModel, 0, RiaDefines::combinedRiMultResultName()); + cvf::ref resultAccessor = RigResultAccessorFactory::createFromResultAddress(eclipseCase, gridIndex, porosityModel, 0, RigEclipseResultAddress(RiaDefines::combinedRiMultResultName())); { double scalarValue = resultAccessor->cellFaceScalar(cellIndex, cvf::StructGridInterface::POS_I); resultInfoText->append(QString("riMult X : %1\n").arg(scalarValue)); @@ -571,7 +571,7 @@ void RiuResultTextBuilder::appendTextFromResultColors(RigEclipseCaseData* eclips } else if (resultColors->resultVariable().compare(RiaDefines::combinedRiAreaNormTranResultName(), Qt::CaseInsensitive) == 0) { - cvf::ref resultAccessor = RigResultAccessorFactory::createFromUiResultName(eclipseCase, gridIndex, porosityModel, 0, RiaDefines::combinedRiAreaNormTranResultName()); + cvf::ref resultAccessor = RigResultAccessorFactory::createFromResultAddress(eclipseCase, gridIndex, porosityModel, 0, RigEclipseResultAddress(RiaDefines::combinedRiAreaNormTranResultName())); { double scalarValue = resultAccessor->cellFaceScalar(cellIndex, cvf::StructGridInterface::POS_I); resultInfoText->append(QString("riTransByArea X : %1\n").arg(scalarValue)); @@ -612,14 +612,14 @@ QString RiuResultTextBuilder::cellEdgeResultDetails() std::vector metaData; m_reservoirView->cellEdgeResult()->cellEdgeMetaData(&metaData); - std::set uniqueResultIndices; + std::set uniqueResultIndices; for (int idx = 0; idx < 6; idx++) { - size_t resultIndex = metaData[idx].m_resultIndex; - if (resultIndex == cvf::UNDEFINED_SIZE_T) continue; + RigEclipseResultAddress resultAddr = metaData[idx].m_eclipseResultAddress; + if ( !resultAddr.isValid()) continue; - if (uniqueResultIndices.find(resultIndex) != uniqueResultIndices.end()) continue; + if (uniqueResultIndices.find(resultAddr) != uniqueResultIndices.end()) continue; size_t adjustedTimeStep = m_timeStepIndex; if (metaData[idx].m_isStatic) @@ -628,13 +628,17 @@ QString RiuResultTextBuilder::cellEdgeResultDetails() } RiaDefines::PorosityModelType porosityModel = m_reservoirView->cellResult()->porosityModel(); - cvf::ref resultAccessor = RigResultAccessorFactory::createFromResultIdx(m_reservoirView->eclipseCase()->eclipseCaseData(), m_gridIndex, porosityModel, adjustedTimeStep, resultIndex); + cvf::ref resultAccessor = RigResultAccessorFactory::createFromResultAddress(m_reservoirView->eclipseCase()->eclipseCaseData(), + m_gridIndex, + porosityModel, + adjustedTimeStep, + resultAddr); if (resultAccessor.notNull()) { double scalarValue = resultAccessor->cellScalar(m_cellIndex); text.append(QString("%1 : %2\n").arg(metaData[idx].m_resultVariable).arg(scalarValue)); - uniqueResultIndices.insert(resultIndex); + uniqueResultIndices.insert(resultAddr); } } } @@ -749,15 +753,15 @@ QString RiuResultTextBuilder::cellResultText(RimEclipseCellColors* resultColors) RigCaseCellResultsData* gridCellResults = m_reservoirView->cellResult()->currentGridCellResults(); if (gridCellResults) { - size_t soilScalarSetIndex = gridCellResults->findOrLoadScalarResult(RiaDefines::DYNAMIC_NATIVE, "SOIL"); - size_t sgasScalarSetIndex = gridCellResults->findOrLoadScalarResult(RiaDefines::DYNAMIC_NATIVE, "SGAS"); - size_t swatScalarSetIndex = gridCellResults->findOrLoadScalarResult(RiaDefines::DYNAMIC_NATIVE, "SWAT"); + gridCellResults->ensureKnownResultLoaded(RigEclipseResultAddress(RiaDefines::DYNAMIC_NATIVE, "SOIL")); + gridCellResults->ensureKnownResultLoaded(RigEclipseResultAddress(RiaDefines::DYNAMIC_NATIVE, "SGAS")); + gridCellResults->ensureKnownResultLoaded(RigEclipseResultAddress(RiaDefines::DYNAMIC_NATIVE, "SWAT")); RiaDefines::PorosityModelType porosityModel = resultColors->porosityModel(); - cvf::ref dataAccessObjectX = RigResultAccessorFactory::createFromResultIdx(eclipseCaseData, m_gridIndex, porosityModel, m_timeStepIndex, soilScalarSetIndex); - cvf::ref dataAccessObjectY = RigResultAccessorFactory::createFromResultIdx(eclipseCaseData, m_gridIndex, porosityModel, m_timeStepIndex, sgasScalarSetIndex); - cvf::ref dataAccessObjectZ = RigResultAccessorFactory::createFromResultIdx(eclipseCaseData, m_gridIndex, porosityModel, m_timeStepIndex, swatScalarSetIndex); + cvf::ref dataAccessObjectX = RigResultAccessorFactory::createFromResultAddress(eclipseCaseData, m_gridIndex, porosityModel, m_timeStepIndex, RigEclipseResultAddress(RiaDefines::DYNAMIC_NATIVE, "SOIL")); + cvf::ref dataAccessObjectY = RigResultAccessorFactory::createFromResultAddress(eclipseCaseData, m_gridIndex, porosityModel, m_timeStepIndex, RigEclipseResultAddress(RiaDefines::DYNAMIC_NATIVE, "SGAS")); + cvf::ref dataAccessObjectZ = RigResultAccessorFactory::createFromResultAddress(eclipseCaseData, m_gridIndex, porosityModel, m_timeStepIndex, RigEclipseResultAddress(RiaDefines::DYNAMIC_NATIVE, "SWAT")); double scalarValue = 0.0; @@ -829,7 +833,7 @@ QString RiuResultTextBuilder::wellResultText() } const RigWellResultFrame& wellResultFrame = singleWellResultData->wellResultFrame(m_timeStepIndex); - const RigWellResultPoint* wellResultCell = wellResultFrame.findResultCell(m_gridIndex, m_cellIndex); + const RigWellResultPoint* wellResultCell = wellResultFrame.findResultCellWellHeadIncluded(m_gridIndex, m_cellIndex); if (wellResultCell) { text += QString("-- Well-cell connection info --\n Well Name: %1\n Branch Id: %2\n Segment Id: %3\n").arg(singleWellResultData->m_wellName).arg(wellResultCell->m_ertBranchId).arg(wellResultCell->m_ertSegmentId); diff --git a/ApplicationCode/UserInterface/RiuRimQwtPlotCurve.cpp b/ApplicationCode/UserInterface/RiuRimQwtPlotCurve.cpp index 78ed505893..b6369c9b79 100644 --- a/ApplicationCode/UserInterface/RiuRimQwtPlotCurve.cpp +++ b/ApplicationCode/UserInterface/RiuRimQwtPlotCurve.cpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018- Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -36,3 +36,11 @@ RimPlotCurve * RiuRimQwtPlotCurve::ownerRimCurve() { return m_ownerRimCurve; } + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +const RimPlotCurve* RiuRimQwtPlotCurve::ownerRimCurve() const +{ + return m_ownerRimCurve; +} diff --git a/ApplicationCode/UserInterface/RiuRimQwtPlotCurve.h b/ApplicationCode/UserInterface/RiuRimQwtPlotCurve.h index 5234bcdbf9..9f60525103 100644 --- a/ApplicationCode/UserInterface/RiuRimQwtPlotCurve.h +++ b/ApplicationCode/UserInterface/RiuRimQwtPlotCurve.h @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018- Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -29,6 +29,7 @@ class RiuRimQwtPlotCurve: public RiuQwtPlotCurve explicit RiuRimQwtPlotCurve(RimPlotCurve* ownerRimCurve, const QString &title = QString::null); RimPlotCurve * ownerRimCurve(); + const RimPlotCurve * ownerRimCurve() const; private: caf::PdmPointer m_ownerRimCurve; diff --git a/ApplicationCode/UserInterface/RiuRmsNavigation.cpp b/ApplicationCode/UserInterface/RiuRmsNavigation.cpp index f081ec8588..0ac38821e7 100644 --- a/ApplicationCode/UserInterface/RiuRmsNavigation.cpp +++ b/ApplicationCode/UserInterface/RiuRmsNavigation.cpp @@ -105,7 +105,7 @@ bool RiuRmsNavigation::handleInputEvent(QInputEvent* inputEvent) m_isZooming = true; } } - + forcePointOfInterestUpdateDuringNextWheelZoom(); } break; case QEvent::MouseButtonRelease: @@ -130,6 +130,7 @@ bool RiuRmsNavigation::handleInputEvent(QInputEvent* inputEvent) m_hasMovedMouseDuringNavigation = false; } } + forcePointOfInterestUpdateDuringNextWheelZoom(); } break; case QEvent::MouseMove: @@ -169,11 +170,12 @@ bool RiuRmsNavigation::handleInputEvent(QInputEvent* inputEvent) { if (inputEvent->modifiers() == Qt::NoModifier) { - initializeRotationCenter(); + QWheelEvent* we = static_cast(inputEvent); + + updatePointOfInterestDuringZoomIfNecessary(we->x(), we->y()); + if (m_isRotCenterInitialized) { - QWheelEvent* we = static_cast ( inputEvent); - int translatedMousePosX, translatedMousePosY; cvfEventPos(we->x(), we->y(), &translatedMousePosX, &translatedMousePosY); diff --git a/ApplicationCode/UserInterface/RiuSelectionChangedHandler.cpp b/ApplicationCode/UserInterface/RiuSelectionChangedHandler.cpp index 69e86f26dd..32784f1d40 100644 --- a/ApplicationCode/UserInterface/RiuSelectionChangedHandler.cpp +++ b/ApplicationCode/UserInterface/RiuSelectionChangedHandler.cpp @@ -48,13 +48,13 @@ #include "RiuRelativePermeabilityPlotUpdater.h" #include "RiuResultQwtPlot.h" #include "RiuResultTextBuilder.h" -#include "RiuSelectionManager.h" +#include "Riu3dSelectionManager.h" #include #include -#include +#include diff --git a/ApplicationCode/UserInterface/RiuSelectionManager.cpp b/ApplicationCode/UserInterface/RiuSelectionManager.cpp deleted file mode 100644 index 39da507361..0000000000 --- a/ApplicationCode/UserInterface/RiuSelectionManager.cpp +++ /dev/null @@ -1,290 +0,0 @@ -///////////////////////////////////////////////////////////////////////////////// -// -// Copyright (C) 2015- Statoil ASA -// Copyright (C) 2015- Ceetron Solutions AS -// -// ResInsight 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 3 of the License, or -// (at your option) any later version. -// -// ResInsight 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 at -// for more details. -// -///////////////////////////////////////////////////////////////////////////////// - -#include "RiuSelectionManager.h" - -#include "RimGridView.h" -#include "RimEclipseView.h" -#include "RimGeoMechView.h" -#include "RimSimWellInView.h" -#include "Rim2dIntersectionView.h" -#include "RimWellPath.h" - -#include "RivSimWellPipeSourceInfo.h" -#include "RivWellPathSourceInfo.h" - -#include "RiuSelectionChangedHandler.h" - - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -RiuSelectionManager::RiuSelectionManager() - : m_notificationCenter(new RiuSelectionChangedHandler) -{ - m_selection.resize(2); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -RiuSelectionManager::~RiuSelectionManager() -{ - deleteAllItemsFromSelection(RUI_APPLICATION_GLOBAL); - deleteAllItemsFromSelection(RUI_TEMPORARY); - - delete m_notificationCenter; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -RiuSelectionManager* RiuSelectionManager::instance() -{ - static RiuSelectionManager* singleton = new RiuSelectionManager; - return singleton; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RiuSelectionManager::selectedItems(std::vector& items, int role) const -{ - const std::vector& s = m_selection[role]; - - items = s; -} - - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -RiuSelectionItem* RiuSelectionManager::selectedItem(int role /*= RUI_APPLICATION_GLOBAL*/) const -{ - const std::vector& s = m_selection[role]; - - if (s.size() == 1) - { - if (s[0]) - { - return s[0]; - } - } - - return nullptr; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RiuSelectionManager::appendItemToSelection(RiuSelectionItem* item, int role) -{ - std::vector& s = m_selection[role]; - - s.push_back(item); - - if (role == RUI_APPLICATION_GLOBAL) m_notificationCenter->handleItemAppended(item); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RiuSelectionManager::setSelectedItem(RiuSelectionItem* item, int role) -{ - deleteAllItemsFromSelection(role); - - std::vector& s = m_selection[role]; - - s.push_back(item); - - if (role == RUI_APPLICATION_GLOBAL) m_notificationCenter->handleSetSelectedItem(item); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RiuSelectionManager::deleteAllItems(int role) -{ - if (!isEmpty(role)) - { - deleteAllItemsFromSelection(role); - - if (role == RUI_APPLICATION_GLOBAL) m_notificationCenter->handleSelectionDeleted(); - } -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -bool RiuSelectionManager::isEmpty(int role) const -{ - const std::vector& s = m_selection[role]; - - return s.size() == 0; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RiuSelectionManager::deleteAllItemsFromSelection(int role) -{ - std::vector& s = m_selection[role]; - - for (RiuSelectionItem* item : s) - { - delete item; - } - - s.clear(); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -RiuEclipseSelectionItem::RiuEclipseSelectionItem(RimEclipseView* view, - size_t gridIndex, - size_t cellIndex, - size_t nncIndex, - cvf::Color3f color, - cvf::StructGridInterface::FaceType face, - const cvf::Vec3d& localIntersectionPointInDisplay) - : m_view(view), - m_gridIndex(gridIndex), - m_gridLocalCellIndex(cellIndex), - m_nncIndex(nncIndex), - m_color(color), - m_face(face), - m_localIntersectionPointInDisplay(localIntersectionPointInDisplay) -{ -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -RiuGeoMechSelectionItem::RiuGeoMechSelectionItem(RimGeoMechView* view, - size_t gridIndex, - size_t cellIndex, - cvf::Color3f color, - int elementFace, - const cvf::Vec3d& localIntersectionPointInDisplay) - : m_view(view) - , m_gridIndex(gridIndex) - , m_cellIndex(cellIndex) - , m_color(color) - , m_elementFace(elementFace) - , m_hasIntersectionTriangle(false) - , m_localIntersectionPointInDisplay(localIntersectionPointInDisplay) -{ -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -RiuGeoMechSelectionItem::RiuGeoMechSelectionItem(RimGeoMechView* view, - size_t gridIndex, - size_t cellIndex, - cvf::Color3f color, - int elementFace, - const cvf::Vec3d& localIntersectionPointInDisplay, - const std::array& intersectionTriangle) - : m_view(view) - , m_gridIndex(gridIndex) - , m_cellIndex(cellIndex) - , m_color(color) - , m_elementFace(elementFace) - , m_hasIntersectionTriangle(true) - , m_intersectionTriangle(intersectionTriangle) - , m_localIntersectionPointInDisplay(localIntersectionPointInDisplay) -{ -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -Riu2dIntersectionSelectionItem::Riu2dIntersectionSelectionItem(Rim2dIntersectionView* view, RiuSelectionItem *selItem) -{ - m_view = view; - m_eclipseSelItem = dynamic_cast(selItem); - m_geoMechSelItem = dynamic_cast(selItem); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -Riu2dIntersectionSelectionItem::~Riu2dIntersectionSelectionItem() -{ - if (m_eclipseSelItem) delete m_eclipseSelItem; - if (m_geoMechSelItem) delete m_geoMechSelItem; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -caf::PdmPointer Riu2dIntersectionSelectionItem::view() const -{ - return m_view; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -RiuEclipseSelectionItem* Riu2dIntersectionSelectionItem::eclipseSelectionItem() const -{ - return m_eclipseSelItem; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -RiuGeoMechSelectionItem* Riu2dIntersectionSelectionItem::geoMechSelectionItem() const -{ - return m_geoMechSelItem; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -RiuWellPathSelectionItem::RiuWellPathSelectionItem(const RivWellPathSourceInfo* wellPathSourceInfo, - const cvf::Vec3d& pipeCenterLineIntersectionInDomainCoords, - double measuredDepth) - : m_pipeCenterlineIntersectionInDomainCoords(pipeCenterLineIntersectionInDomainCoords), - m_measuredDepth(measuredDepth) -{ - m_wellpath = wellPathSourceInfo->wellPath(); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -RiuSimWellSelectionItem::RiuSimWellSelectionItem(RimSimWellInView* simwell, - cvf::Vec3d m_domainCoord, - size_t m_branchIndex) - : m_simWell(simwell), - m_domainCoord(m_domainCoord), - m_branchIndex(m_branchIndex) -{ -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -RiuGeneralSelectionItem::RiuGeneralSelectionItem(caf::PdmObject* object) - : m_object(object) -{ -} diff --git a/ApplicationCode/UserInterface/RiuSelectionManager.h b/ApplicationCode/UserInterface/RiuSelectionManager.h deleted file mode 100644 index b06af4fad8..0000000000 --- a/ApplicationCode/UserInterface/RiuSelectionManager.h +++ /dev/null @@ -1,301 +0,0 @@ -///////////////////////////////////////////////////////////////////////////////// -// -// Copyright (C) 2015- Statoil ASA -// Copyright (C) 2015- Ceetron Solutions AS -// -// ResInsight 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 3 of the License, or -// (at your option) any later version. -// -// ResInsight 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 at -// for more details. -// -///////////////////////////////////////////////////////////////////////////////// - -#pragma once - -#include "cafPdmPointer.h" -#include "cafPdmObject.h" - -#include "cvfBase.h" -#include "cvfColor3.h" -#include "cvfStructGrid.h" - -#include -#include -#include -// #include "RivWellPathSourceInfo.h" -// #include "RivWellPipeSourceInfo.h" - -class RimGridView; -class RimEclipseView; -class RimGeoMechView; -class RimSimWellInView; -class Rim2dIntersectionView; -class RimWellPath; -class RiuSelectionChangedHandler; -class RiuSelectionItem; -class RivSimWellPipeSourceInfo; -class RivWellPathSourceInfo; - -//================================================================================================== -// -// -// -//================================================================================================== -class RiuSelectionManager -{ -public: - enum SelectionRole - { - RUI_APPLICATION_GLOBAL, // Selection role intended to manage the cells selected by left mouse click in the 3D view - RUI_TEMPORARY // Selection role intended to manage the items selected by a right mouse click in the 3D view - }; - -public: - static RiuSelectionManager* instance(); - - // Returns selected items - // Selection manager owns the selection items - void selectedItems(std::vector& items, int role = RUI_APPLICATION_GLOBAL) const; - - // Returns selected items - // Selection manager owns the selection items - RiuSelectionItem* selectedItem(int role = RUI_APPLICATION_GLOBAL) const; - // PdmUiItem* selectedItem(int role = SelectionManager::APPLICATION_GLOBAL); - - - // Append item to selected items - // SelectionManager takes ownership of the item - void appendItemToSelection(RiuSelectionItem* item, int role = RUI_APPLICATION_GLOBAL); - - // Set one selected item - // SelectionManager takes ownership of the item - void setSelectedItem(RiuSelectionItem* item, int role = RUI_APPLICATION_GLOBAL); - - // Deletes all items in the SelectionManager - void deleteAllItems(int role = RUI_APPLICATION_GLOBAL); - - bool isEmpty(int role = RUI_APPLICATION_GLOBAL) const; - -private: - RiuSelectionManager(); - ~RiuSelectionManager(); - RiuSelectionManager(const RiuSelectionManager&) = delete; - - void deleteAllItemsFromSelection(int role); - -private: - std::vector< std::vector > m_selection; - - RiuSelectionChangedHandler* m_notificationCenter; -}; - - -//================================================================================================== -// -// -// -//================================================================================================== -class RiuSelectionItem -{ -public: - enum RiuSelectionType - { - ECLIPSE_SELECTION_OBJECT, - GEOMECH_SELECTION_OBJECT, - WELLPATH_SELECTION_OBJECT, - SIMWELL_SELECTION_OBJECT, - GENERAL_SELECTION_OBJECT, - INTERSECTION_SELECTION_OBJECT - }; - -public: - RiuSelectionItem() {} - virtual ~RiuSelectionItem() {}; - - virtual RiuSelectionType type() const = 0; -}; - - -//================================================================================================== -// -// -// -//================================================================================================== -class RiuEclipseSelectionItem : public RiuSelectionItem -{ -public: - explicit RiuEclipseSelectionItem(RimEclipseView* view, - size_t gridIndex, - size_t cellIndex, - size_t nncIndex, - cvf::Color3f color, - cvf::StructGridInterface::FaceType face, - const cvf::Vec3d& localIntersectionPointInDisplay); - - ~RiuEclipseSelectionItem() override {}; - - RiuSelectionType type() const override - { - return ECLIPSE_SELECTION_OBJECT; - } - -public: - caf::PdmPointer m_view; - size_t m_gridIndex; - size_t m_gridLocalCellIndex; - size_t m_nncIndex; - cvf::Color3f m_color; - cvf::StructGridInterface::FaceType m_face; - cvf::Vec3d m_localIntersectionPointInDisplay; -}; - - -//================================================================================================== -// -// -// -//================================================================================================== -class RiuGeoMechSelectionItem : public RiuSelectionItem -{ -public: - explicit RiuGeoMechSelectionItem(RimGeoMechView* view, - size_t gridIndex, - size_t cellIndex, - cvf::Color3f color, - int elementFace, - const cvf::Vec3d& localIntersectionPointInDisplay); - - explicit RiuGeoMechSelectionItem(RimGeoMechView* view, - size_t gridIndex, - size_t cellIndex, - cvf::Color3f color, - int elementFace, - const cvf::Vec3d& localIntersectionPointInDisplay, - const std::array& intersectionTriangle ); - ~RiuGeoMechSelectionItem() override {}; - - RiuSelectionType type() const override - { - return GEOMECH_SELECTION_OBJECT; - } - -public: - caf::PdmPointer m_view; - size_t m_gridIndex; - size_t m_cellIndex; - cvf::Color3f m_color; - int m_elementFace; - bool m_hasIntersectionTriangle; - std::array m_intersectionTriangle; - cvf::Vec3d m_localIntersectionPointInDisplay; -}; - - -//================================================================================================== -// -// -// -//================================================================================================== -class Riu2dIntersectionSelectionItem : public RiuSelectionItem -{ -public: - explicit Riu2dIntersectionSelectionItem(Rim2dIntersectionView* view, RiuSelectionItem *selItem); - - ~Riu2dIntersectionSelectionItem() override; - - RiuSelectionType type() const override - { - return INTERSECTION_SELECTION_OBJECT; - } - -public: - caf::PdmPointer view() const; - RiuEclipseSelectionItem* eclipseSelectionItem() const; - RiuGeoMechSelectionItem* geoMechSelectionItem() const; - -private: - caf::PdmPointer m_view; - RiuEclipseSelectionItem* m_eclipseSelItem; - RiuGeoMechSelectionItem* m_geoMechSelItem; -}; - - -//================================================================================================== -// -// -// -//================================================================================================== -class RiuWellPathSelectionItem : public RiuSelectionItem -{ -public: - explicit RiuWellPathSelectionItem(const RivWellPathSourceInfo* wellPathSourceInfo, - const cvf::Vec3d& pipeCenterLineIntersectionInDomainCoords, - double measuredDepth); - - ~RiuWellPathSelectionItem() override {}; - - RiuSelectionType type() const override - { - return WELLPATH_SELECTION_OBJECT; - } - -public: - RimWellPath* m_wellpath; - cvf::Vec3d m_pipeCenterlineIntersectionInDomainCoords; - double m_measuredDepth; -}; - - - -//================================================================================================== -// -// -// -//================================================================================================== -class RiuSimWellSelectionItem : public RiuSelectionItem -{ -public: - explicit RiuSimWellSelectionItem(RimSimWellInView* simwell, cvf::Vec3d domainCoord, size_t branchIndex); - - - ~RiuSimWellSelectionItem() override {}; - - RiuSelectionType type() const override - { - return SIMWELL_SELECTION_OBJECT; - } - -public: - RimSimWellInView* m_simWell; - cvf::Vec3d m_domainCoord; - size_t m_branchIndex; -}; - - -//================================================================================================== -// -// -// -//================================================================================================== -class RiuGeneralSelectionItem : public RiuSelectionItem -{ -public: - RiuGeneralSelectionItem(caf::PdmObject* object); - - ~RiuGeneralSelectionItem() override {}; - - RiuSelectionType type() const override - { - return GENERAL_SELECTION_OBJECT; - } - -public: - caf::PdmObject* m_object; -}; diff --git a/ApplicationCode/UserInterface/RiuSimpleHistogramWidget.cpp b/ApplicationCode/UserInterface/RiuSimpleHistogramWidget.cpp index 00ce6690b7..13aceb22a0 100644 --- a/ApplicationCode/UserInterface/RiuSimpleHistogramWidget.cpp +++ b/ApplicationCode/UserInterface/RiuSimpleHistogramWidget.cpp @@ -27,8 +27,8 @@ //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -RiuSimpleHistogramWidget::RiuSimpleHistogramWidget(QWidget * parent /*= 0*/, Qt::WindowFlags f /*= 0*/): -QWidget(parent, f) +RiuSimpleHistogramWidget::RiuSimpleHistogramWidget(const QString& objectName, QWidget * parent /*= 0*/, Qt::WindowFlags f /*= 0*/) + : QWidget(parent, f) { m_minPercentile = HUGE_VAL; m_maxPercentile = HUGE_VAL; @@ -41,6 +41,8 @@ QWidget(parent, f) m_height = 0; m_x = 0; m_y = 0; + + setObjectName(objectName); } //-------------------------------------------------------------------------------------------------- @@ -48,7 +50,7 @@ QWidget(parent, f) //-------------------------------------------------------------------------------------------------- void RiuSimpleHistogramWidget::paintEvent(QPaintEvent* event) { - QPainter painter(this); + QPainter painter(this); this->draw(&painter, 0, 0, this->width()-1, this->height()-1); } @@ -64,7 +66,7 @@ void RiuSimpleHistogramWidget::draw(QPainter *painter,int x, int y, int width, i // Frame around it all; QColor windowColor = palette().color(QPalette::Window);// QColor(144, 173, 208, 180); - QColor frameColor = palette().color(QPalette::WindowText);//QColor(220, 240, 255, 100); + QColor frameColor = palette().color(QPalette::Midlight);//QColor(220, 240, 255, 100); QColor foregroundColor = palette().color(QPalette::Dark);// QColor(100, 141, 189); //painter->fillRect(r1, windowColor); diff --git a/ApplicationCode/UserInterface/RiuSimpleHistogramWidget.h b/ApplicationCode/UserInterface/RiuSimpleHistogramWidget.h index 19230f2e57..9522a85b2b 100644 --- a/ApplicationCode/UserInterface/RiuSimpleHistogramWidget.h +++ b/ApplicationCode/UserInterface/RiuSimpleHistogramWidget.h @@ -30,14 +30,14 @@ class QStringList; class RiuSimpleHistogramWidget : public QWidget { public: - RiuSimpleHistogramWidget( QWidget * parent = nullptr, Qt::WindowFlags f = nullptr); + RiuSimpleHistogramWidget(const QString& objectName, QWidget * parent = nullptr, Qt::WindowFlags f = nullptr); void setHistogramData(double min, double max, const std::vector& histogram); void setPercentiles(double pmin, double pmax); void setMean(double mean) {m_mean = mean;} protected: - void paintEvent(QPaintEvent* event) override; + void paintEvent(QPaintEvent* event) override; private: void draw(QPainter *painter,int x, int y, int width, int height ); diff --git a/ApplicationCode/UserInterface/RiuSummaryCurveDefSelection.cpp b/ApplicationCode/UserInterface/RiuSummaryCurveDefSelection.cpp index b3dcc8aff1..d41a0d46fa 100644 --- a/ApplicationCode/UserInterface/RiuSummaryCurveDefSelection.cpp +++ b/ApplicationCode/UserInterface/RiuSummaryCurveDefSelection.cpp @@ -264,7 +264,6 @@ std::vector RiuSummaryCurveDefSelection::allCurveDefi for (SummarySource* currSource : selectedSummarySources()) { - std::vector sourceSources; RimSummaryCaseCollection* ensemble = dynamic_cast(currSource); RimSummaryCase* sumCase = dynamic_cast(currSource); @@ -321,7 +320,6 @@ std::vector RiuSummaryCurveDefSelection::allCurveSetDefin RimSummaryCaseCollection* ensemble = dynamic_cast(currSource); if (!ensemble) continue; - std::vector sourceSources; std::set addressesFromSource; // Build case list @@ -425,7 +423,7 @@ void RiuSummaryCurveDefSelection::setDefaultSelection(const std::vector 0) { - RifEclipseSummaryAddress defaultAddress = RifEclipseSummaryAddress(); + RifEclipseSummaryAddress defaultAddress = RifEclipseSummaryAddress::fieldAddress("FOPT"); std::vector selectTheseSources = defaultSources; if (selectTheseSources.empty()) selectTheseSources.push_back(allSumCases[0]); @@ -580,7 +578,6 @@ QList RiuSummaryCurveDefSelection::calculateValueOptions if (fieldNeedingOptions == &m_selectedSources) { RimProject* proj = RiaApplication::instance()->project(); - std::vector topLevelCases; std::vector oilFields; proj->allOilFields(oilFields); diff --git a/ApplicationCode/UserInterface/RiuSummaryCurveDefSelectionEditor.cpp b/ApplicationCode/UserInterface/RiuSummaryCurveDefSelectionEditor.cpp index b165e19bdf..cfb815d9b1 100644 --- a/ApplicationCode/UserInterface/RiuSummaryCurveDefSelectionEditor.cpp +++ b/ApplicationCode/UserInterface/RiuSummaryCurveDefSelectionEditor.cpp @@ -216,6 +216,6 @@ QMinimizePanel* RiuSummaryCurveDefSelectionEditor::createGroupBoxWithContent(caf { QMinimizePanel* groupBox = findOrCreateGroupBox(this->widget(), group, uiConfigName); - recursivelyConfigureAndUpdateUiOrderingInGridLayoutColumn(*group, groupBox->contentFrame(), uiConfigName); + recursivelyConfigureAndUpdateUiOrderingInGridLayout(*group, groupBox->contentFrame(), uiConfigName); return groupBox; } diff --git a/ApplicationCode/UserInterface/RiuSummaryQwtPlot.cpp b/ApplicationCode/UserInterface/RiuSummaryQwtPlot.cpp index 547f8936f3..53939532e8 100644 --- a/ApplicationCode/UserInterface/RiuSummaryQwtPlot.cpp +++ b/ApplicationCode/UserInterface/RiuSummaryQwtPlot.cpp @@ -1,84 +1,80 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2016- Statoil ASA -// +// Copyright (C) 2019- Equinor ASA +// // ResInsight 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 3 of the License, or // (at your option) any later version. -// +// // ResInsight 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 at +// +// See the GNU General Public License at // for more details. // ///////////////////////////////////////////////////////////////////////////////// - #include "RiuSummaryQwtPlot.h" -#include "RiaApplication.h" - -#include "RimContextCommandBuilder.h" -#include "RimProject.h" +#include "RimEnsembleCurveSet.h" +#include "RimEnsembleCurveSetCollection.h" +#include "RimMainPlotCollection.h" +#include "RimRegularLegendConfig.h" +#include "RimSummaryCase.h" #include "RimSummaryCurve.h" #include "RimSummaryCurveCollection.h" #include "RimSummaryPlot.h" +#include "RimSummaryPlotCollection.h" -#include "RiuPlotMainWindowTools.h" +#include "RiuCvfOverlayItemWidget.h" #include "RiuQwtCurvePointTracker.h" -#include "RiuQwtPlotWheelZoomer.h" +#include "RiuRimQwtPlotCurve.h" +#include "RiuWidgetDragger.h" + +#include "RiuPlotMainWindowTools.h" #include "RiuQwtPlotZoomer.h" +#include "RiuQwtPlotTools.h" +#include "RiuQwtPlotWheelZoomer.h" #include "RiuQwtScalePicker.h" -#include "cafSelectionManager.h" +#include "RimProject.h" + #include "cafCmdFeatureMenuBuilder.h" +#include "cafSelectionManager.h" +#include "cafTitledOverlayFrame.h" -#include "qwt_date_scale_draw.h" -#include "qwt_date_scale_engine.h" +#include "qwt_interval.h" #include "qwt_legend.h" #include "qwt_plot_curve.h" -#include "qwt_plot_grid.h" -#include "qwt_plot_layout.h" -#include "qwt_plot_magnifier.h" #include "qwt_plot_panner.h" #include "qwt_plot_zoomer.h" +#include "qwt_date_scale_draw.h" +#include "qwt_date_scale_engine.h" +#include "qwt_scale_div.h" +#include "qwt_scale_draw.h" #include "qwt_scale_engine.h" #include #include +#include #include -#include "RiuWidgetDragger.h" -#include "RiuCvfOverlayItemWidget.h" -#include "RimEnsembleCurveSet.h" -#include "RimRegularLegendConfig.h" -#include "cafTitledOverlayFrame.h" -#include "RimEnsembleCurveSetCollection.h" -#include "RimMainPlotCollection.h" -#include "RimSummaryPlotCollection.h" -#include "RimSummaryCase.h" -#include "RiuRimQwtPlotCurve.h" -#include "RimSummaryCurve.h" - -#include - //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- class EnsembleCurveInfoTextProvider : public IPlotCurveInfoTextProvider { public: //-------------------------------------------------------------------------------------------------- - /// + /// //-------------------------------------------------------------------------------------------------- QString curveInfoText(QwtPlotCurve* curve) override { - RiuRimQwtPlotCurve* riuCurve = dynamic_cast(curve); - RimSummaryCurve* sumCurve = nullptr; + RiuRimQwtPlotCurve* riuCurve = dynamic_cast(curve); + RimSummaryCurve* sumCurve = nullptr; if (riuCurve) { sumCurve = dynamic_cast(riuCurve->ownerRimCurve()); @@ -90,184 +86,102 @@ class EnsembleCurveInfoTextProvider : public IPlotCurveInfoTextProvider static EnsembleCurveInfoTextProvider ensembleCurveInfoTextProvider; //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- -RiuSummaryQwtPlot::RiuSummaryQwtPlot(RimSummaryPlot* plotDefinition, QWidget* parent) : QwtPlot(parent) +RiuSummaryQwtPlot::RiuSummaryQwtPlot(RimViewWindow* viewWindow, QWidget* parent /*= nullptr*/) + : RiuQwtPlot(viewWindow, parent) { - Q_ASSERT(plotDefinition); - m_plotDefinition = plotDefinition; - setDefaults(); - - // LeftButton for the zooming - m_zoomerLeft = new RiuQwtPlotZoomer(canvas()); - m_zoomerLeft->setRubberBandPen(QColor(Qt::black)); - m_zoomerLeft->setTrackerMode(QwtPicker::AlwaysOff); - m_zoomerLeft->setTrackerPen(QColor(Qt::black)); - m_zoomerLeft->initMousePattern(1); - - // Attach a zoomer for the right axis - m_zoomerRight = new RiuQwtPlotZoomer(canvas()); - m_zoomerRight->setAxis(xTop, yRight); - m_zoomerRight->setTrackerMode(QwtPicker::AlwaysOff); - m_zoomerRight->initMousePattern(1); - - // MidButton for the panning - QwtPlotPanner* panner = new QwtPlotPanner(canvas()); - panner->setMouseButton(Qt::MidButton); - - auto wheelZoomer = new RiuQwtPlotWheelZoomer(this); - - connect(wheelZoomer, SIGNAL(zoomUpdated()), SLOT(onZoomedSlot())); - connect(m_zoomerLeft, SIGNAL(zoomed( const QRectF & )), SLOT(onZoomedSlot())); - connect(panner, SIGNAL(panned( int , int )), SLOT(onZoomedSlot())); - - RiuQwtScalePicker* scalePicker = new RiuQwtScalePicker(this); - connect(scalePicker, SIGNAL(clicked(int, double)), this, SLOT(onAxisClicked(int, double))); - -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -RiuSummaryQwtPlot::~RiuSummaryQwtPlot() -{ - if (m_plotDefinition) - { - m_plotDefinition->detachAllCurves(); - m_plotDefinition->handleMdiWindowClosed(); - } + new RiuQwtCurvePointTracker(this, true, &ensembleCurveInfoTextProvider); } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- -RimSummaryPlot* RiuSummaryQwtPlot::ownerPlotDefinition() +void RiuSummaryQwtPlot::useDateBasedTimeAxis() { - return m_plotDefinition; + RiuQwtPlotTools::enableDateBasedBottomXAxis(this); } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- -RimViewWindow* RiuSummaryQwtPlot::ownerViewWindow() const +void RiuSummaryQwtPlot::useTimeBasedTimeAxis() { - return m_plotDefinition; + setAxisScaleEngine(QwtPlot::xBottom, new QwtLinearScaleEngine()); + setAxisScaleDraw(QwtPlot::xBottom, new QwtScaleDraw()); } -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RiuSummaryQwtPlot::currentVisibleWindow(QwtInterval* leftAxis, QwtInterval* rightAxis, QwtInterval* timeAxis) const -{ - *leftAxis = axisScaleDiv(yLeft).interval(); - *rightAxis = axisScaleDiv(yRight).interval(); - *timeAxis = axisScaleDiv(xBottom).interval(); -} //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- -void RiuSummaryQwtPlot::updateEnsembleLegendLayout() +void RiuSummaryQwtPlot::addOrUpdateEnsembleCurveSetLegend(RimEnsembleCurveSet* curveSetToShowLegendFor) { - const int spacing = 5; - int startMarginX = this->canvas()->pos().x() + spacing; - int startMarginY = this->canvas()->pos().y() + spacing; - - int xpos = startMarginX; - int ypos = startMarginY; - int maxColumnWidth = 0; + RiuCvfOverlayItemWidget* overlayWidget = nullptr; - if (!ownerPlotDefinition() || !ownerPlotDefinition()->ensembleCurveSetCollection()) return; - - for (RimEnsembleCurveSet * curveSet : ownerPlotDefinition()->ensembleCurveSetCollection()->curveSets()) + auto it = m_ensembleLegendWidgets.find(curveSetToShowLegendFor); + if (it == m_ensembleLegendWidgets.end() || it->second == nullptr) + { + overlayWidget = new RiuCvfOverlayItemWidget(this, canvas()); + m_ensembleLegendWidgets[curveSetToShowLegendFor] = overlayWidget; + } + else { - auto pairIt = m_ensembleLegendWidgets.find(curveSet); - if (pairIt != m_ensembleLegendWidgets.end()) - { - if (ypos + pairIt->second->height() + spacing > this->canvas()->height()) - { - xpos += spacing + maxColumnWidth; - ypos = startMarginY; - maxColumnWidth = 0; - } - - RiuCvfOverlayItemWidget* overlayWidget = pairIt->second; - overlayWidget->move(xpos, ypos); - - ypos += pairIt->second->height() + spacing; - maxColumnWidth = std::max(maxColumnWidth, pairIt->second->width()); - } - } -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RiuSummaryQwtPlot::addOrUpdateEnsembleCurveSetLegend(RimEnsembleCurveSet * curveSetToShowLegendFor) -{ - RiuCvfOverlayItemWidget* overlayWidget = nullptr; - - auto it = m_ensembleLegendWidgets.find(curveSetToShowLegendFor); - if (it == m_ensembleLegendWidgets.end() || it->second == nullptr) - { - overlayWidget = new RiuCvfOverlayItemWidget(this); - - new RiuWidgetDragger(overlayWidget); - - m_ensembleLegendWidgets[curveSetToShowLegendFor] = overlayWidget; - - } - else - { overlayWidget = it->second; - } + } - if ( overlayWidget ) - { - caf::TitledOverlayFrame* overlyItem = curveSetToShowLegendFor->legendConfig()->titledOverlayFrame(); - overlyItem->setRenderSize(overlyItem->preferredSize()); + if (overlayWidget) + { + caf::TitledOverlayFrame* overlayItem = curveSetToShowLegendFor->legendConfig()->titledOverlayFrame(); + overlayItem->setRenderSize(overlayItem->preferredSize()); - overlayWidget->updateFromOverlyItem(curveSetToShowLegendFor->legendConfig()->titledOverlayFrame()); - overlayWidget->show(); - } + overlayWidget->updateFromOverlayItem(curveSetToShowLegendFor->legendConfig()->titledOverlayFrame()); + overlayWidget->show(); + } - this->updateEnsembleLegendLayout(); + this->updateLegendLayout(); } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- -void RiuSummaryQwtPlot::removeEnsembleCurveSetLegend(RimEnsembleCurveSet * curveSetToShowLegendFor) +void RiuSummaryQwtPlot::removeEnsembleCurveSetLegend(RimEnsembleCurveSet* curveSetToShowLegendFor) { auto it = m_ensembleLegendWidgets.find(curveSetToShowLegendFor); - if ( it != m_ensembleLegendWidgets.end() ) + if (it != m_ensembleLegendWidgets.end()) { - if ( it->second != nullptr ) it->second->deleteLater(); - + if (it->second != nullptr) it->second->deleteLater(); + m_ensembleLegendWidgets.erase(it); } - this->updateEnsembleLegendLayout(); + this->updateLegendLayout(); } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- -QSize RiuSummaryQwtPlot::minimumSizeHint() const +void RiuSummaryQwtPlot::keyPressEvent(QKeyEvent* keyEvent) { - return QSize(0, 100); + RimSummaryPlot* summaryPlot = dynamic_cast(ownerPlotDefinition()); + + if (summaryPlot && summaryPlot->summaryCurveCollection()) + { + RimSummaryCurveCollection* curveColl = summaryPlot->summaryCurveCollection(); + curveColl->handleKeyPressEvent(keyEvent); + } } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RiuSummaryQwtPlot::contextMenuEvent(QContextMenuEvent* event) { - QMenu menu; + QMenu menu; caf::CmdFeatureMenuBuilder menuBuilder; - caf::SelectionManager::instance()->setSelectedItem(ownerPlotDefinition()); + caf::SelectionManager::instance()->setSelectedItem(ownerViewWindow()); menuBuilder << "RicShowPlotDataFeature"; @@ -280,224 +194,61 @@ void RiuSummaryQwtPlot::contextMenuEvent(QContextMenuEvent* event) } //-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RiuSummaryQwtPlot::keyPressEvent(QKeyEvent* keyEvent) -{ - if (m_plotDefinition && m_plotDefinition->summaryCurveCollection()) - { - RimSummaryCurveCollection* curveColl = m_plotDefinition->summaryCurveCollection(); - curveColl->handleKeyPressEvent(keyEvent); - } -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -QSize RiuSummaryQwtPlot::sizeHint() const -{ - return QSize(0, 0); -} - -//-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RiuSummaryQwtPlot::setDefaults() { - setCommonPlotBehaviour(this); - - enableAxis(QwtPlot::xBottom, true); - enableAxis(QwtPlot::yLeft, true); - enableAxis(QwtPlot::xTop, false); - enableAxis(QwtPlot::yRight, false); - useDateBasedTimeAxis(); - setAxisMaxMinor(QwtPlot::xBottom, 2); - setAxisMaxMinor(QwtPlot::yLeft, 3); - - // The legend will be deleted in the destructor of the plot or when + // The legend will be deleted in the destructor of the plot or when // another legend is inserted. QwtLegend* legend = new QwtLegend(this); this->insertLegend(legend, BottomLegend); } -void RiuSummaryQwtPlot::setCommonPlotBehaviour(QwtPlot* plot) -{ - // Plot background and frame look - - QPalette newPalette(plot->palette()); - newPalette.setColor(QPalette::Background, Qt::white); - plot->setPalette(newPalette); - - plot->setAutoFillBackground(true); - plot->setCanvasBackground(Qt::white); - - QFrame* canvasFrame = dynamic_cast(plot->canvas()); - if (canvasFrame) - { - canvasFrame->setFrameShape(QFrame::NoFrame); - } - - // Grid - - QwtPlotGrid* grid = new QwtPlotGrid; - grid->attach(plot); - QPen gridPen(Qt::SolidLine); - gridPen.setColor(Qt::lightGray); - grid->setPen(gridPen); - - // Axis number font - QFont axisFont = plot->axisFont(QwtPlot::xBottom); - axisFont.setPixelSize(11); - - plot->setAxisFont(QwtPlot::xBottom, axisFont); - plot->setAxisFont(QwtPlot::xTop, axisFont); - plot->setAxisFont(QwtPlot::yLeft, axisFont); - plot->setAxisFont(QwtPlot::yRight, axisFont); - - // Axis title font - QwtText axisTitle = plot->axisTitle(QwtPlot::xBottom); - QFont axisTitleFont = axisTitle.font(); - axisTitleFont.setPixelSize(11); - axisTitleFont.setBold(false); - axisTitle.setFont(axisTitleFont); - axisTitle.setRenderFlags(Qt::AlignRight); - - plot->setAxisTitle(QwtPlot::xBottom, axisTitle); - plot->setAxisTitle(QwtPlot::xTop, axisTitle); - plot->setAxisTitle(QwtPlot::yLeft, axisTitle); - plot->setAxisTitle(QwtPlot::yRight, axisTitle); - - // Set a focus policy to allow it taking key press events. - // This is not strictly necessary since this widget inherit QwtPlot - // which already has a focus policy. - // However, for completeness we still do it here. - plot->setFocusPolicy(Qt::WheelFocus); - - // Enable mousetracking and event filter - plot->canvas()->setMouseTracking(true); - plot->canvas()->installEventFilter(plot); - plot->plotLayout()->setAlignCanvasToScales(true); - - new RiuQwtCurvePointTracker(plot, true, &ensembleCurveInfoTextProvider); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RiuSummaryQwtPlot::useDateBasedTimeAxis() -{ - enableDateBasedBottomXAxis(this); -} - -//-------------------------------------------------------------------------------------------------- -/// //-------------------------------------------------------------------------------------------------- -void RiuSummaryQwtPlot::enableDateBasedBottomXAxis(QwtPlot* plot) -{ - QwtDateScaleDraw* scaleDraw = new QwtDateScaleDraw(Qt::UTC); - scaleDraw->setDateFormat(QwtDate::Year, QString("dd-MM-yyyy")); - - QwtDateScaleEngine* scaleEngine = new QwtDateScaleEngine(Qt::UTC); - plot->setAxisScaleEngine(QwtPlot::xBottom, scaleEngine); - plot->setAxisScaleDraw(QwtPlot::xBottom, scaleDraw); -} - -//-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RiuSummaryQwtPlot::updateLayout() { QwtPlot::updateLayout(); - updateEnsembleLegendLayout(); + updateLegendLayout(); } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- -void RiuSummaryQwtPlot::useTimeBasedTimeAxis() +void RiuSummaryQwtPlot::updateLegendLayout() { - setAxisScaleEngine(QwtPlot::xBottom, new QwtLinearScaleEngine()); - setAxisScaleDraw(QwtPlot::xBottom, new QwtScaleDraw()); -} + const int spacing = 5; + int startMarginX = this->canvas()->pos().x() + spacing; + int startMarginY = this->canvas()->pos().y() + spacing; -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -bool RiuSummaryQwtPlot::eventFilter(QObject* watched, QEvent* event) -{ - if(watched == canvas()) - { - QMouseEvent* mouseEvent = dynamic_cast(event); - if(mouseEvent) - { - if(mouseEvent->button() == Qt::LeftButton && mouseEvent->type() == QMouseEvent::MouseButtonRelease) - { - selectClosestCurve(mouseEvent->pos()); - } - } - } + int xpos = startMarginX; + int ypos = startMarginY; + int maxColumnWidth = 0; - return QwtPlot::eventFilter(watched, event); -} + RimSummaryPlot* summaryPlot = dynamic_cast(ownerPlotDefinition()); -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RiuSummaryQwtPlot::selectClosestCurve(const QPoint& pos) -{ - QwtPlotCurve* closestCurve = nullptr; - double distMin = DBL_MAX; + if (!summaryPlot || !summaryPlot->ensembleCurveSetCollection()) return; - const QwtPlotItemList& itmList = itemList(); - for(QwtPlotItemIterator it = itmList.begin(); it != itmList.end(); it++) + for (RimEnsembleCurveSet* curveSet : summaryPlot->ensembleCurveSetCollection()->curveSets()) { - if((*it)->rtti() == QwtPlotItem::Rtti_PlotCurve) + auto pairIt = m_ensembleLegendWidgets.find(curveSet); + if (pairIt != m_ensembleLegendWidgets.end()) { - QwtPlotCurve* candidateCurve = static_cast(*it); - double dist = DBL_MAX; - candidateCurve->closestPoint(pos, &dist); - if(dist < distMin) + if (ypos + pairIt->second->height() + spacing > this->canvas()->height()) { - closestCurve = candidateCurve; - distMin = dist; + xpos += spacing + maxColumnWidth; + ypos = startMarginY; + maxColumnWidth = 0; } - } - } - - if (closestCurve && distMin < 20) - { - caf::PdmObject* selectedPlotObject = m_plotDefinition->findRimPlotObjectFromQwtCurve(closestCurve); - if (selectedPlotObject) - { - RimProject* proj = nullptr; - selectedPlotObject->firstAncestorOrThisOfType(proj); + RiuCvfOverlayItemWidget* overlayWidget = pairIt->second; + overlayWidget->move(xpos, ypos); - if (proj) - { - RiuPlotMainWindowTools::showPlotMainWindow(); - RiuPlotMainWindowTools::selectAsCurrentItem(selectedPlotObject); - } + ypos += pairIt->second->height() + spacing; + maxColumnWidth = std::max(maxColumnWidth, pairIt->second->width()); } } } - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RiuSummaryQwtPlot::onZoomedSlot() -{ - m_plotDefinition->updateZoomWindowFromQwt(); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RiuSummaryQwtPlot::onAxisClicked(int axis, double value) -{ - if (!m_plotDefinition) return; - - m_plotDefinition->selectAxisInPropertyEditor(axis); -} diff --git a/ApplicationCode/UserInterface/RiuSummaryQwtPlot.h b/ApplicationCode/UserInterface/RiuSummaryQwtPlot.h index c031338ce0..a70d9c068f 100644 --- a/ApplicationCode/UserInterface/RiuSummaryQwtPlot.h +++ b/ApplicationCode/UserInterface/RiuSummaryQwtPlot.h @@ -1,17 +1,17 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2016- Statoil ASA -// +// Copyright (C) 2019- Equinor ASA +// // ResInsight 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 3 of the License, or // (at your option) any later version. -// +// // ResInsight 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 at +// +// See the GNU General Public License at // for more details. // ///////////////////////////////////////////////////////////////////////////////// @@ -19,79 +19,40 @@ #pragma once #include "RiuInterfaceToViewWindow.h" +#include "RiuQwtPlot.h" #include "cafPdmPointer.h" -#include "qwt_plot.h" - #include -class QwtPlotCurve; -class QwtPlotGrid; -class QwtPlotZoomer; -class QwtInterval; -class QwtPicker; -class QwtPlotMarker; -class QwtScaleWidget; - -class RiuCvfOverlayItemWidget; - -class RimSummaryPlot; class RimEnsembleCurveSet; +class RiuCvfOverlayItemWidget; //================================================================================================== // // // //================================================================================================== -class RiuSummaryQwtPlot : public QwtPlot, public RiuInterfaceToViewWindow +class RiuSummaryQwtPlot : public RiuQwtPlot { Q_OBJECT; -public: - RiuSummaryQwtPlot(RimSummaryPlot* plotDefinition, QWidget* parent = nullptr); - ~RiuSummaryQwtPlot() override; - - RimSummaryPlot* ownerPlotDefinition(); - RimViewWindow* ownerViewWindow() const override; - void useDateBasedTimeAxis(); - void useTimeBasedTimeAxis(); - - void currentVisibleWindow(QwtInterval* leftAxis, - QwtInterval* rightAxis, - QwtInterval* timeAxis) const; +public: + RiuSummaryQwtPlot(RimViewWindow* ownerViewWindow, QWidget* parent = nullptr); - void addOrUpdateEnsembleCurveSetLegend(RimEnsembleCurveSet * curveSetToShowLegendFor); - void removeEnsembleCurveSetLegend(RimEnsembleCurveSet * curveSetToShowLegendFor); + void useDateBasedTimeAxis(); + void useTimeBasedTimeAxis(); - static void setCommonPlotBehaviour(QwtPlot* plot); - static void enableDateBasedBottomXAxis(QwtPlot* plot); + void addOrUpdateEnsembleCurveSetLegend(RimEnsembleCurveSet* curveSetToShowLegendFor); + void removeEnsembleCurveSetLegend(RimEnsembleCurveSet* curveSetToShowLegendFor); protected: - bool eventFilter(QObject* watched, QEvent* event) override; - void keyPressEvent(QKeyEvent *) override; - - QSize sizeHint() const override; - QSize minimumSizeHint() const override; - void contextMenuEvent(QContextMenuEvent *) override; - void updateLayout() override; - -private: - void setDefaults(); - void selectClosestCurve(const QPoint& pos); - void updateEnsembleLegendLayout(); - -private slots: - void onZoomedSlot( ); - void onAxisClicked(int axis, double value); - + void keyPressEvent(QKeyEvent*) override; + void contextMenuEvent(QContextMenuEvent*) override; + void setDefaults(); + void updateLayout() override; private: - caf::PdmPointer m_plotDefinition; - - QPointer m_zoomerLeft; - QPointer m_zoomerRight; - - std::map< caf::PdmPointer, QPointer > m_ensembleLegendWidgets; + void updateLegendLayout(); + std::map, QPointer> m_ensembleLegendWidgets; }; - diff --git a/ApplicationCode/UserInterface/RiuTextDialog.cpp b/ApplicationCode/UserInterface/RiuTextDialog.cpp index f7a87f7582..05aabdc2fe 100644 --- a/ApplicationCode/UserInterface/RiuTextDialog.cpp +++ b/ApplicationCode/UserInterface/RiuTextDialog.cpp @@ -25,6 +25,8 @@ #include "SummaryPlotCommands/RicAsciiExportSummaryPlotFeature.h" +#include "cafCmdFeature.h" + #include #include #include @@ -101,12 +103,12 @@ void RiuQPlainTextEdit::slotSelectAll() void RiuQPlainTextEdit::slotExportToFile() { // Get dialog - RiuShowTabbedPlotDataDialog* dialog = nullptr; + RiuTabbedTextDialog* dialog = nullptr; auto curr = parent(); while (dialog == nullptr) { if (!curr) break; - dialog = dynamic_cast(curr); + dialog = dynamic_cast(curr); if (dialog) break; curr = curr->parent(); } @@ -164,7 +166,7 @@ void RiuTextDialog::contextMenuEvent(QContextMenuEvent* event) actionToSetup->setText("Copy"); actionToSetup->setIcon(QIcon(":/Copy.png")); - actionToSetup->setShortcuts(QKeySequence::Copy); + caf::CmdFeature::applyShortcutWithHintToAction(actionToSetup, QKeySequence::Copy); connect(actionToSetup, SIGNAL(triggered()), m_textEdit, SLOT(slotCopyContentToClipboard())); @@ -175,7 +177,7 @@ void RiuTextDialog::contextMenuEvent(QContextMenuEvent* event) QAction* actionToSetup = new QAction(this); actionToSetup->setText("Select All"); - actionToSetup->setShortcuts(QKeySequence::SelectAll); + caf::CmdFeature::applyShortcutWithHintToAction(actionToSetup, QKeySequence::SelectAll); connect(actionToSetup, SIGNAL(triggered()), m_textEdit, SLOT(slotSelectAll())); @@ -190,21 +192,19 @@ void RiuTextDialog::contextMenuEvent(QContextMenuEvent* event) //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -RiuShowTabbedPlotDataDialog::RiuShowTabbedPlotDataDialog(QWidget* parent /*= nullptr*/) - : QDialog(parent, RiuTools::defaultDialogFlags()) +RiuTabbedTextDialog::RiuTabbedTextDialog(RiuTabbedTextProvider* textProvider, QWidget* parent /*= nullptr*/) + : m_textProvider(textProvider), QDialog(parent, RiuTools::defaultDialogFlags()) { m_tabWidget = new QTabWidget(this); connect(m_tabWidget, SIGNAL(currentChanged(int)), this, SLOT(slotTabChanged(int))); - for(auto timePeriod : RiaQDateTimeTools::dateTimePeriods()) - { - if(timePeriod == DateTimePeriod::DECADE) continue; - - QString tabTitle = - timePeriod == DateTimePeriod::NONE ? "No Resampling" : - QString("Plot Data, %1").arg(RiaQDateTimeTools::dateTimePeriodName(timePeriod)); + CVF_ASSERT(m_textProvider->isValid()); + this->setWindowTitle(m_textProvider->description()); + for (int tabIndex = 0; tabIndex < m_textProvider->tabCount(); ++tabIndex) + { + QString tabTitle = m_textProvider->tabTitle(tabIndex); RiuQPlainTextEdit* textEdit = new RiuQPlainTextEdit(); textEdit->setReadOnly(true); textEdit->setLineWrapMode(QPlainTextEdit::NoWrap); @@ -218,88 +218,89 @@ RiuShowTabbedPlotDataDialog::RiuShowTabbedPlotDataDialog(QWidget* parent /*= nul m_tabWidget->addTab(textEdit, tabTitle); } + m_tabTexts.resize(m_textProvider->tabCount()); QVBoxLayout* layout = new QVBoxLayout(); layout->addWidget(m_tabWidget); setLayout(layout); -} -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RiuShowTabbedPlotDataDialog::setDescription(const QString& description) -{ - m_description = description; + updateTabText(); } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- -QString RiuShowTabbedPlotDataDialog::description() const +QString RiuTabbedTextDialog::description() const { - if (m_description.isEmpty()) return "Plot Data"; - return m_description; + if (m_textProvider && m_textProvider->isValid()) + { + return m_textProvider->description(); + } + else + { + return "Data Invalid"; + } } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- -void RiuShowTabbedPlotDataDialog::setTextProvider(std::function textProvider) +void RiuTabbedTextDialog::redrawText() { - m_textProvider = textProvider; + auto textEdit = currentTextEdit(); + auto currIndex = m_tabWidget->currentIndex(); - updateText(); -} + textEdit->setPlainText("Populating Text View..."); + textEdit->repaint(); -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -RiuQPlainTextEdit * RiuShowTabbedPlotDataDialog::currentTextEdit() const -{ - return dynamic_cast(m_tabWidget->currentWidget()); + if (currIndex < (int)m_tabTexts.size()) + { + if (m_tabTexts[currIndex].isEmpty()) + { + updateTabText(); + } + textEdit->setPlainText(m_tabTexts[currIndex]); + textEdit->repaint(); + } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -DateTimePeriod RiuShowTabbedPlotDataDialog::indexToPeriod(int index) +RiuQPlainTextEdit * RiuTabbedTextDialog::currentTextEdit() const { - auto currTabTitle = m_tabWidget->tabText(index); - if (currTabTitle.contains(RiaQDateTimeTools::TIMESPAN_DAY_NAME)) return DateTimePeriod::DAY; - if (currTabTitle.contains(RiaQDateTimeTools::TIMESPAN_WEEK_NAME)) return DateTimePeriod::WEEK; - if (currTabTitle.contains(RiaQDateTimeTools::TIMESPAN_MONTH_NAME)) return DateTimePeriod::MONTH; - if (currTabTitle.contains(RiaQDateTimeTools::TIMESPAN_QUARTER_NAME)) return DateTimePeriod::QUARTER; - if (currTabTitle.contains(RiaQDateTimeTools::TIMESPAN_HALFYEAR_NAME)) return DateTimePeriod::HALFYEAR; - if (currTabTitle.contains(RiaQDateTimeTools::TIMESPAN_YEAR_NAME)) return DateTimePeriod::YEAR; - if (currTabTitle.contains(RiaQDateTimeTools::TIMESPAN_DECADE_NAME)) return DateTimePeriod::DECADE; - return DateTimePeriod::NONE; + return dynamic_cast(m_tabWidget->currentWidget()); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RiuShowTabbedPlotDataDialog::updateText() -{ - auto textEdit = currentTextEdit(); +void RiuTabbedTextDialog::updateTabText() +{ auto currIndex = m_tabWidget->currentIndex(); - if (textEdit && textEdit->toPlainText().isEmpty() && m_textProvider) + if (m_textProvider && m_textProvider->isValid() && + m_tabWidget->tabText(currIndex) == m_textProvider->tabTitle(currIndex)) + { + m_tabTexts[currIndex] = m_textProvider->tabText(currIndex); + } + else { - textEdit->setPlainText(m_textProvider(indexToPeriod(currIndex))); + m_tabTexts[currIndex] = "Data Source No Longer Valid"; } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RiuShowTabbedPlotDataDialog::slotTabChanged(int index) +void RiuTabbedTextDialog::slotTabChanged(int index) { - updateText(); + redrawText(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RiuShowTabbedPlotDataDialog::contextMenuEvent(QContextMenuEvent* event) +void RiuTabbedTextDialog::contextMenuEvent(QContextMenuEvent* event) { QMenu menu; RiuQPlainTextEdit* textEdit = dynamic_cast(m_tabWidget->currentWidget()); @@ -310,7 +311,7 @@ void RiuShowTabbedPlotDataDialog::contextMenuEvent(QContextMenuEvent* event) actionToSetup->setText("Copy"); actionToSetup->setIcon(QIcon(":/Copy.png")); - actionToSetup->setShortcuts(QKeySequence::Copy); + caf::CmdFeature::applyShortcutWithHintToAction(actionToSetup, QKeySequence::Copy); connect(actionToSetup, SIGNAL(triggered()), textEdit, SLOT(slotCopyContentToClipboard())); @@ -321,7 +322,7 @@ void RiuShowTabbedPlotDataDialog::contextMenuEvent(QContextMenuEvent* event) QAction* actionToSetup = new QAction(this); actionToSetup->setText("Select All"); - actionToSetup->setShortcuts(QKeySequence::SelectAll); + caf::CmdFeature::applyShortcutWithHintToAction(actionToSetup, QKeySequence::SelectAll); connect(actionToSetup, SIGNAL(triggered()), textEdit, SLOT(slotSelectAll())); @@ -332,7 +333,6 @@ void RiuShowTabbedPlotDataDialog::contextMenuEvent(QContextMenuEvent* event) QAction* actionToSetup = new QAction(this); actionToSetup->setText("Export to File..."); - //actionToSetup->setShortcuts(QKeySequence::); connect(actionToSetup, SIGNAL(triggered()), textEdit, SLOT(slotExportToFile())); diff --git a/ApplicationCode/UserInterface/RiuTextDialog.h b/ApplicationCode/UserInterface/RiuTextDialog.h index f666ef066d..de1979ce35 100644 --- a/ApplicationCode/UserInterface/RiuTextDialog.h +++ b/ApplicationCode/UserInterface/RiuTextDialog.h @@ -22,6 +22,7 @@ #include #include +#include #include @@ -67,28 +68,38 @@ class RiuTextDialog : public QDialog }; +class RiuTabbedTextProvider : public QObject +{ + Q_OBJECT + +public: + virtual bool isValid() const = 0; + virtual QString description() const = 0; + virtual QString tabTitle(int tabIndex) const = 0; + virtual QString tabText(int tabIndex) const = 0; + virtual int tabCount() const = 0; +}; + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -class RiuShowTabbedPlotDataDialog : public QDialog +class RiuTabbedTextDialog : public QDialog { Q_OBJECT public: - explicit RiuShowTabbedPlotDataDialog(QWidget* parent = nullptr); + explicit RiuTabbedTextDialog(RiuTabbedTextProvider* textProvider, QWidget* parent = nullptr); - void setDescription(const QString& description); QString description() const; - void setTextProvider(std::function textProvider); + void redrawText(); private: - RiuQPlainTextEdit * currentTextEdit() const; - DateTimePeriod indexToPeriod(int index); - void updateText(); + RiuQPlainTextEdit* currentTextEdit() const; + void updateTabText(); - QTabWidget* m_tabWidget; - QString m_description; - std::function m_textProvider; + QTabWidget* m_tabWidget; + QPointer m_textProvider; + std::vector m_tabTexts; private slots: void slotTabChanged(int index); diff --git a/ApplicationCode/UserInterface/RiuTofAccumulatedPhaseFractionsPlot.cpp b/ApplicationCode/UserInterface/RiuTofAccumulatedPhaseFractionsPlot.cpp index ba6b4150fa..b962dc2d85 100644 --- a/ApplicationCode/UserInterface/RiuTofAccumulatedPhaseFractionsPlot.cpp +++ b/ApplicationCode/UserInterface/RiuTofAccumulatedPhaseFractionsPlot.cpp @@ -38,7 +38,7 @@ #include #include -#include +#include //-------------------------------------------------------------------------------------------------- /// @@ -57,7 +57,7 @@ RiuTofAccumulatedPhaseFractionsPlot::RiuTofAccumulatedPhaseFractionsPlot(RimTofA setDefaults(); QwtText title("Cumulative Saturation by Time of Flight"); QFont titleFont = title.font(); - titleFont.setPixelSize(12); + titleFont.setPointSize(12); title.setFont(titleFont); setTitle(title); @@ -89,11 +89,6 @@ RiuTofAccumulatedPhaseFractionsPlot::RiuTofAccumulatedPhaseFractionsPlot(RimTofA //-------------------------------------------------------------------------------------------------- RiuTofAccumulatedPhaseFractionsPlot::~RiuTofAccumulatedPhaseFractionsPlot() { - if (m_plotDefinition) - { - m_plotDefinition->handleMdiWindowClosed(); - } - if (m_watCurve) { m_watCurve->detach(); @@ -249,7 +244,7 @@ void RiuTofAccumulatedPhaseFractionsPlot::setCommonPlotBehaviour(QwtPlot* plot) // Axis number font QFont axisFont = plot->axisFont(QwtPlot::xBottom); - axisFont.setPixelSize(11); + axisFont.setPointSize(10); plot->setAxisFont(QwtPlot::xBottom, axisFont); plot->setAxisFont(QwtPlot::xTop, axisFont); @@ -259,7 +254,7 @@ void RiuTofAccumulatedPhaseFractionsPlot::setCommonPlotBehaviour(QwtPlot* plot) // Axis title font QwtText axisTitle = plot->axisTitle(QwtPlot::xBottom); QFont axisTitleFont = axisTitle.font(); - axisTitleFont.setPixelSize(11); + axisTitleFont.setPointSize(10); axisTitleFont.setBold(false); axisTitle.setFont(axisTitleFont); axisTitle.setRenderFlags(Qt::AlignRight); diff --git a/ApplicationCode/UserInterface/RiuTools.cpp b/ApplicationCode/UserInterface/RiuTools.cpp index 2d7ced7be0..d168734ae8 100644 --- a/ApplicationCode/UserInterface/RiuTools.cpp +++ b/ApplicationCode/UserInterface/RiuTools.cpp @@ -23,7 +23,7 @@ //-------------------------------------------------------------------------------------------------- Qt::WindowFlags RiuTools::defaultDialogFlags() { - Qt::WindowFlags f = Qt::WindowTitleHint | Qt::WindowSystemMenuHint; + Qt::WindowFlags f = Qt::WindowTitleHint | Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint; return f; } diff --git a/ApplicationCode/UserInterface/RiuTreeViewEventFilter.cpp b/ApplicationCode/UserInterface/RiuTreeViewEventFilter.cpp index 094858d8ec..957683e7fa 100644 --- a/ApplicationCode/UserInterface/RiuTreeViewEventFilter.cpp +++ b/ApplicationCode/UserInterface/RiuTreeViewEventFilter.cpp @@ -80,6 +80,10 @@ bool RiuTreeViewEventFilter::eventFilter(QObject *obj, QEvent *event) matches = caf::CmdFeatureManager::instance()->commandFeaturesMatchingSubString("Paste"); } } + else if (keyEvent->matches(QKeySequence::Delete)) + { + matches = caf::CmdFeatureManager::instance()->commandFeaturesMatchingKeyboardShortcut(QKeySequence::Delete); + } for (caf::CmdFeature* feature : matches) { diff --git a/ApplicationCode/UserInterface/RiuViewer.cpp b/ApplicationCode/UserInterface/RiuViewer.cpp index 8df36b5af0..70084ed0d2 100644 --- a/ApplicationCode/UserInterface/RiuViewer.cpp +++ b/ApplicationCode/UserInterface/RiuViewer.cpp @@ -3,17 +3,17 @@ // Copyright (C) 2011- Statoil ASA // Copyright (C) 2013- Ceetron Solutions AS // Copyright (C) 2011-2012 Ceetron AS -// +// // ResInsight 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 3 of the License, or // (at your option) any later version. -// +// // ResInsight 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 at +// +// See the GNU General Public License at // for more details. // ///////////////////////////////////////////////////////////////////////////////// @@ -27,13 +27,14 @@ #include "RiaRegressionTestRunner.h" #include "RimCase.h" -#include "RimProject.h" #include "RimGridView.h" +#include "RimProject.h" #include "RimViewController.h" #include "RimViewLinker.h" #include "RivGridBoxGenerator.h" #include "RivTernarySaturationOverlayItem.h" +#include "WindowEdgeAxesOverlayItem/RivWindowEdgeAxesOverlayItem.h" #include "RiuCadNavigation.h" #include "RiuGeoQuestNavigation.h" @@ -41,98 +42,77 @@ #include "RiuSimpleHistogramWidget.h" #include "RiuViewerCommands.h" -#include "cafTitledOverlayFrame.h" +#include "cafPdmUiSelection3dEditorVisualizer.h" + #include "cafCategoryLegend.h" -#include "cafOverlayScalarMapperLegend.h" #include "cafCeetronPlusNavigation.h" #include "cafDisplayCoordTransform.h" #include "cafEffectGenerator.h" #include "cafFrameAnimationControl.h" +#include "cafOverlayScalarMapperLegend.h" +#include "cafOverlayScaleLegend.h" +#include "cafTitledOverlayFrame.h" +#include "cafQStyledProgressBar.h" +#include "cafStyleSheetTools.h" #include "cvfCamera.h" #include "cvfFont.h" #include "cvfOpenGLResourceManager.h" #include "cvfOverlayAxisCross.h" +#include "cvfOverlayItem.h" #include "cvfPartRenderHintCollection.h" #include "cvfRenderQueueSorter.h" #include "cvfRenderSequence.h" #include "cvfRendering.h" #include "cvfScene.h" -#include #include #include -#include -#include "WindowEdgeAxesOverlayItem/RivWindowEdgeAxesOverlayItem.h" -#include -#include "WellPathCommands/PointTangentManipulator/RicPointTangentManipulator.h" +#include using cvf::ManipulatorTrackball; - const double RI_MIN_NEARPLANE_DISTANCE = 0.1; +std::unique_ptr RiuViewer::s_hoverCursor; + //================================================================================================== /// /// \class RiuViewer /// \ingroup ResInsight /// -/// +/// /// //================================================================================================== - //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- RiuViewer::RiuViewer(const QGLFormat& format, QWidget* parent) -: caf::Viewer(format, parent), m_isNavigationRotationEnabled(true) + : caf::Viewer(format, parent) + , m_isNavigationRotationEnabled(true) { - cvf::Font* standardFont = RiaApplication::instance()->standardFont(); - m_axisCross = new cvf::OverlayAxisCross(m_mainCamera.p(), standardFont); + cvf::Font* standardFont = RiaApplication::instance()->defaultSceneFont(); + QFont font = QApplication::font(); + font.setPointSize(RiaFontCache::pointSizeFromFontSizeEnum(RiaApplication::instance()->preferences()->defaultSceneFontSize())); + + m_axisCross = new cvf::OverlayAxisCross(m_mainCamera.p(), standardFont); m_axisCross->setAxisLabels("X", "Y", "Z"); m_axisCross->setLayout(cvf::OverlayItem::VERTICAL, cvf::OverlayItem::BOTTOM_RIGHT); m_mainRendering->addOverlayItem(m_axisCross.p()); m_showAxisCross = true; - this->enableOverlyPainting(true); + this->enableOverlayPainting(true); this->setReleaseOGLResourcesEachFrame(true); - QColor c; - QPalette p = QApplication::palette(); - //QColor frameAndTextColor(255, 255, 255, 255); - QColor frameAndTextColor(0, 0, 0, 255); - QColor progressAndHistogramColor(0,0,90,70); // Also Progressbar dark text color - - //p.setColor(QPalette::Window, QColor(144, 173, 208, 180)); - p.setColor(QPalette::Window, QColor(255, 255, 255, 50)); - - p.setColor(QPalette::WindowText, frameAndTextColor); - - c = p.color(QPalette::Base ); - c.setAlpha(100); - p.setColor(QPalette::Base, c); - - //c = p.color(QPalette::AlternateBase ); - //c.setAlpha(0); - //p.setColor(QPalette::AlternateBase, c); - - - //p.setColor(QPalette::Highlight, QColor(20, 20, 130, 40)); - p.setColor(QPalette::Highlight, progressAndHistogramColor); - - //p.setColor(QPalette::HighlightedText, frameAndTextColor); - p.setColor(QPalette::HighlightedText, QColor(255, 255, 255, 255)); //Progressbar light text color - - //p.setColor(QPalette::Dark, QColor(230, 250, 255, 100)); - p.setColor(QPalette::Dark, progressAndHistogramColor); - // Info Text m_infoLabel = new QLabel(); - m_infoLabel->setPalette(p); + m_infoLabel->setObjectName("InfoLabel"); m_infoLabel->setFrameShape(QFrame::Box); + m_infoLabel->setFrameShadow(QFrame::Plain); m_infoLabel->setMinimumWidth(275); + m_infoLabel->setFont(font); m_showInfoText = true; // Version info label @@ -140,27 +120,31 @@ RiuViewer::RiuViewer(const QGLFormat& format, QWidget* parent) m_versionInfoLabel->setFrameShape(QFrame::NoFrame); m_versionInfoLabel->setAlignment(Qt::AlignRight); m_versionInfoLabel->setText(QString("%1 v%2").arg(RI_APPLICATION_NAME, RiaApplication::getVersionStringApp(false))); - - QPalette versionInfoPalette = p; - QColor versionInfoLabelColor = p.color(QPalette::Window); - versionInfoLabelColor.setAlpha(0); - versionInfoPalette.setColor(QPalette::Window, versionInfoLabelColor); - m_versionInfoLabel->setPalette(versionInfoPalette); + m_versionInfoLabel->setFont(font); + m_showVersionInfo = true; + + // Z scale label + m_zScaleLabel = new QLabel(); + m_zScaleLabel->setFrameShape(QFrame::NoFrame); + m_zScaleLabel->setAlignment(Qt::AlignLeft); + m_zScaleLabel->setText(QString("Z: ")); + m_zScaleLabel->setFont(font); + m_showZScaleLabel = true; + m_hideZScaleCheckbox = false; // Animation progress bar - m_animationProgress = new QProgressBar(); - m_animationProgress->setPalette(p); + m_animationProgress = new caf::QStyledProgressBar("AnimationProgress"); m_animationProgress->setFormat("Time Step: %v/%m"); m_animationProgress->setTextVisible(true); + m_animationProgress->setAlignment(Qt::AlignCenter); + m_animationProgress->setObjectName("AnimationProgress"); + m_animationProgress->setFont(font); - m_progressBarStyle = new QCDEStyle(); - m_animationProgress->setStyle(m_progressBarStyle); m_showAnimProgress = false; // Histogram - m_histogramWidget = new RiuSimpleHistogramWidget(); - m_histogramWidget->setPalette(p); - m_showHistogram = false; + m_histogramWidget = new RiuSimpleHistogramWidget("HistogramWidget"); + m_showHistogram = false; m_viewerCommands = new RiuViewerCommands(this); @@ -173,6 +157,7 @@ RiuViewer::RiuViewer(const QGLFormat& format, QWidget* parent) m_versionInfoLabel->setFont(regTestFont); m_animationProgress->setFont(regTestFont); m_histogramWidget->setFont(regTestFont); + m_zScaleLabel->setFont(regTestFont); } // When a context menu is created in the viewer is, and the action triggered is displaying a dialog, @@ -184,35 +169,42 @@ RiuViewer::RiuViewer(const QGLFormat& format, QWidget* parent) m_gridBoxGenerator = new RivGridBoxGenerator; m_cursorPositionDomainCoords = cvf::Vec3d::UNDEFINED; - m_windowEdgeAxisOverlay = new RivWindowEdgeAxesOverlayItem(standardFont); - m_showWindowEdgeAxes = false; + m_windowEdgeAxisOverlay = new RivWindowEdgeAxesOverlayItem(standardFont); + m_showWindowEdgeAxes = false; + + m_selectionVisualizerManager = new caf::PdmUiSelection3dEditorVisualizer(this); - m_selectionVisualizerManager = new caf::PdmUiSelectionVisualizer3d(this); + m_scaleLegend = new caf::OverlayScaleLegend(standardFont); + m_scaleLegend->setOrientation(caf::OverlayScaleLegend::HORIZONTAL); } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- RiuViewer::~RiuViewer() { if (m_rimView) { - m_rimView->handleMdiWindowClosed(); - m_rimView->setCameraPosition(m_mainCamera->viewMatrix()); - m_rimView->setCameraPointOfInterest( pointOfInterest()); + m_rimView->setCameraPointOfInterest(pointOfInterest()); } delete m_infoLabel; delete m_animationProgress; delete m_histogramWidget; - delete m_progressBarStyle; delete m_gridBoxGenerator; } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuViewer::clearRimView() +{ + m_rimView = nullptr; +} //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RiuViewer::setDefaultView() { @@ -220,7 +212,7 @@ void RiuViewer::setDefaultView() if (!bb.isValid()) { bb.add(cvf::Vec3d(-1, -1, -1)); - bb.add(cvf::Vec3d( 1, 1, 1)); + bb.add(cvf::Vec3d(1, 1, 1)); } if (m_mainCamera->projection() == cvf::Camera::PERSPECTIVE) @@ -238,9 +230,8 @@ void RiuViewer::setDefaultView() m_mainCamera->fitView(bb, -cvf::Vec3d::Z_AXIS, cvf::Vec3d::Y_AXIS); } - //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RiuViewer::mouseReleaseEvent(QMouseEvent* event) { @@ -268,7 +259,6 @@ void RiuViewer::mouseReleaseEvent(QMouseEvent* event) m_viewerCommands->handlePickAction(event->x(), event->y(), event->modifiers()); return; - } else if (event->button() == Qt::RightButton) { @@ -285,22 +275,21 @@ void RiuViewer::mouseReleaseEvent(QMouseEvent* event) } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RiuViewer::slotEndAnimation() { - cvf::Rendering* firstRendering = m_mainRendering.p(); - CVF_ASSERT(firstRendering); + CVF_ASSERT(m_mainRendering.notNull()); if (m_rimView) m_rimView->endAnimation(); - + caf::Viewer::slotEndAnimation(); caf::EffectGenerator::releaseUnreferencedEffects(); } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RiuViewer::slotSetCurrentFrame(int frameIndex) { @@ -317,7 +306,7 @@ void RiuViewer::slotSetCurrentFrame(int frameIndex) } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- cvf::Vec3d RiuViewer::pointOfInterest() { @@ -325,7 +314,7 @@ cvf::Vec3d RiuViewer::pointOfInterest() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RiuViewer::setPointOfInterest(cvf::Vec3d poi) { @@ -333,9 +322,9 @@ void RiuViewer::setPointOfInterest(cvf::Vec3d poi) } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- -void RiuViewer::setOwnerReservoirView(RiuViewerToViewInterface * owner) +void RiuViewer::setOwnerReservoirView(RiuViewerToViewInterface* owner) { m_rimView = owner; @@ -343,7 +332,7 @@ void RiuViewer::setOwnerReservoirView(RiuViewerToViewInterface * owner) } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RiuViewer::setEnableMask(unsigned int mask) { @@ -351,17 +340,17 @@ void RiuViewer::setEnableMask(unsigned int mask) } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RiuViewer::paintOverlayItems(QPainter* painter) { int columnWidth = 200; - int edgeAxisFrameBorderWidth = m_showWindowEdgeAxes ? m_windowEdgeAxisOverlay->frameBorderWidth(): 0; - int edgeAxisFrameBorderHeight = m_showWindowEdgeAxes ? m_windowEdgeAxisOverlay->frameBorderHeight(): 0; + int edgeAxisFrameBorderWidth = m_showWindowEdgeAxes ? m_windowEdgeAxisOverlay->frameBorderWidth() : 0; + int edgeAxisFrameBorderHeight = m_showWindowEdgeAxes ? m_windowEdgeAxisOverlay->frameBorderHeight() : 0; int margin = 5; - int yPos = margin + edgeAxisFrameBorderHeight; + int yPos = margin + edgeAxisFrameBorderHeight; bool showAnimBar = false; if (isAnimationActive() && frameCount() > 1) showAnimBar = true; @@ -379,9 +368,8 @@ void RiuViewer::paintOverlayItems(QPainter* painter) m_animationProgress->setValue(currentFrameIndex()); m_animationProgress->resize(columnWidth, m_animationProgress->sizeHint().height()); - m_animationProgress->render(painter,QPoint(columnPos, yPos)); - yPos += m_animationProgress->height() + margin; - + m_animationProgress->render(painter, QPoint(columnPos, yPos)); + yPos += m_animationProgress->height() + margin; } if (m_showInfoText) @@ -394,7 +382,7 @@ void RiuViewer::paintOverlayItems(QPainter* painter) m_infoLabelOverlayArea.setBottom(yPos + m_infoLabel->height()); m_infoLabelOverlayArea.setRight(columnPos + columnWidth); - yPos += m_infoLabel->height() + margin; + yPos += m_infoLabel->height() + margin; } else { @@ -404,18 +392,27 @@ void RiuViewer::paintOverlayItems(QPainter* painter) if (m_showHistogram) { m_histogramWidget->resize(columnWidth, 40); - m_histogramWidget->render(painter,QPoint(columnPos, yPos)); - //yPos += m_histogramWidget->height() + margin; + m_histogramWidget->render(painter, QPoint(columnPos, yPos)); + // yPos += m_histogramWidget->height() + margin; } - if (m_showInfoText) // Version Label + if (m_showVersionInfo) // Version Label { - QSize size(m_versionInfoLabel->sizeHint().width(), m_versionInfoLabel->sizeHint().height()); - QPoint pos(this->width() - size.width() - margin - edgeAxisFrameBorderWidth, this->height() - size.height() - margin - edgeAxisFrameBorderHeight); + QSize size(m_versionInfoLabel->sizeHint().width(), m_versionInfoLabel->sizeHint().height()); + QPoint pos(this->width() - size.width() - margin - edgeAxisFrameBorderWidth, + this->height() - size.height() - margin - edgeAxisFrameBorderHeight); m_versionInfoLabel->resize(size.width(), size.height()); m_versionInfoLabel->render(painter, pos); } + if (m_showZScaleLabel) // Z scale Label + { + QSize size(m_zScaleLabel->sizeHint().width(), m_zScaleLabel->sizeHint().height()); + QPoint pos(margin + edgeAxisFrameBorderWidth, margin + edgeAxisFrameBorderHeight); + m_zScaleLabel->resize(size.width(), size.height()); + m_zScaleLabel->render(painter, pos); + } + if (!m_cursorPositionDomainCoords.isUndefined()) { if (mainCamera()) @@ -427,21 +424,23 @@ void RiuViewer::paintOverlayItems(QPainter* painter) cvf::Vec3d screenCoords; if (mainCamera()->project(displayCoord, &screenCoords)) { - int translatedMousePosY = height() - screenCoords.y(); + int translatedMousePosY = height() - screenCoords.y(); QPoint centerPos(screenCoords.x(), translatedMousePosY); // Draw a cross hair marker int markerHalfLength = 6; - painter->drawLine(centerPos.x(), centerPos.y() - markerHalfLength, centerPos.x(), centerPos.y() + markerHalfLength); - painter->drawLine(centerPos.x() - markerHalfLength, centerPos.y(), centerPos.x() + markerHalfLength, centerPos.y()); + painter->drawLine( + centerPos.x(), centerPos.y() - markerHalfLength, centerPos.x(), centerPos.y() + markerHalfLength); + painter->drawLine( + centerPos.x() - markerHalfLength, centerPos.y(), centerPos.x() + markerHalfLength, centerPos.y()); } } - } + } } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RiuViewer::setInfoText(QString text) { @@ -449,7 +448,31 @@ void RiuViewer::setInfoText(QString text) } //-------------------------------------------------------------------------------------------------- -/// +/// +//-------------------------------------------------------------------------------------------------- +void RiuViewer::hideZScaleCheckbox(bool hide) +{ + m_hideZScaleCheckbox = hide; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuViewer::showZScaleLabel(bool enable) +{ + m_showZScaleLabel = enable; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuViewer::setZScale(int scale) +{ + m_zScaleLabel->setText(QString("Z: %1").arg(scale)); +} + +//-------------------------------------------------------------------------------------------------- +/// //-------------------------------------------------------------------------------------------------- void RiuViewer::showInfoText(bool enable) { @@ -459,13 +482,21 @@ void RiuViewer::showInfoText(bool enable) //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- +void RiuViewer::showVersionInfo(bool enable) +{ + m_showVersionInfo = enable; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- void RiuViewer::setHistogram(double min, double max, const std::vector& histogram) { m_histogramWidget->setHistogramData(min, max, histogram); } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RiuViewer::setHistogramPercentiles(double pmin, double pmax, double mean) { @@ -474,7 +505,7 @@ void RiuViewer::setHistogramPercentiles(double pmin, double pmax, double mean) } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RiuViewer::showGridBox(bool enable) { @@ -487,7 +518,7 @@ void RiuViewer::showGridBox(bool enable) } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RiuViewer::showAnimationProgress(bool enable) { @@ -495,7 +526,7 @@ void RiuViewer::showAnimationProgress(bool enable) } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RiuViewer::showHistogram(bool enable) { @@ -503,7 +534,7 @@ void RiuViewer::showHistogram(bool enable) } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RiuViewer::mousePressEvent(QMouseEvent* event) { @@ -511,7 +542,7 @@ void RiuViewer::mousePressEvent(QMouseEvent* event) } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RiuViewer::removeAllColorLegends() { @@ -524,13 +555,13 @@ void RiuViewer::removeAllColorLegends() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RiuViewer::addColorLegendToBottomLeftCorner(caf::TitledOverlayFrame* addedLegend) { RiaApplication* app = RiaApplication::instance(); CVF_ASSERT(app); - RiaPreferences* preferences = app->preferences(); + RiaPreferences* preferences = app->preferences(); cvf::Rendering* firstRendering = m_mainRendering.p(); CVF_ASSERT(preferences); CVF_ASSERT(firstRendering); @@ -538,110 +569,123 @@ void RiuViewer::addColorLegendToBottomLeftCorner(caf::TitledOverlayFrame* addedL if (addedLegend) { cvf::Color4f backgroundColor = mainCamera()->viewport()->clearColor(); - backgroundColor.a() = 0.8f; + backgroundColor.a() = 0.8f; cvf::Color3f frameColor(backgroundColor.r(), backgroundColor.g(), backgroundColor.b()); updateLegendTextAndTickMarkColor(addedLegend); - + firstRendering->addOverlayItem(addedLegend); addedLegend->enableBackground(preferences->showLegendBackground()); addedLegend->setBackgroundColor(backgroundColor); addedLegend->setBackgroundFrameColor(cvf::Color4f(RiaColorTools::computeOffsetColor(frameColor, 0.3f), 0.9f)); + addedLegend->setFont(app->defaultSceneFont()); m_visibleLegends.push_back(addedLegend); } updateLegendLayout(); - } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RiuViewer::updateLegendLayout() { int viewPortHeight = static_cast(m_mainCamera->viewport()->height()); - const float maxFreeLegendHeight = 0.7f*viewPortHeight; - const int border = 3; - int edgeAxisBorderWidth = m_showWindowEdgeAxes ? m_windowEdgeAxisOverlay->frameBorderWidth(): 0; - int edgeAxisBorderHeight = m_showWindowEdgeAxes ? m_windowEdgeAxisOverlay->frameBorderHeight(): 0; + const float maxFreeLegendHeight = 0.7f * viewPortHeight; + const int border = 3; + int edgeAxisBorderWidth = m_showWindowEdgeAxes ? m_windowEdgeAxisOverlay->frameBorderWidth() : 0; + int edgeAxisBorderHeight = m_showWindowEdgeAxes ? m_windowEdgeAxisOverlay->frameBorderHeight() : 0; - int xPos = border + edgeAxisBorderWidth; - int yPos = border + edgeAxisBorderHeight; + { + int xPos = border + edgeAxisBorderWidth; + int yPos = border + edgeAxisBorderHeight; - std::vector standardHeightLegends; - - // Place the legends needing the full height, and sort out the standard height legends + std::vector standardHeightLegends; - for ( cvf::ref legend : m_visibleLegends ) - { - cvf::Vec2ui prefSize = legend->preferredSize(); - if (prefSize.y() > maxFreeLegendHeight) - { - int legendWidth = prefSize.x(); - legend->setLayoutFixedPosition(cvf::Vec2i(xPos, yPos)); - legend->setRenderSize(cvf::Vec2ui(legendWidth, viewPortHeight - 2 * border - 2 * edgeAxisBorderHeight)); - xPos += legendWidth + border; - } - else + // Place the legends needing the full height, and sort out the standard height legends + + for (cvf::ref legend : m_visibleLegends) { - standardHeightLegends.push_back(legend.p()); + cvf::Vec2ui prefSize = legend->preferredSize(); + if (prefSize.y() > maxFreeLegendHeight) + { + int legendWidth = prefSize.x(); + legend->setLayoutFixedPosition(cvf::Vec2i(xPos, yPos)); + legend->setRenderSize(cvf::Vec2ui(legendWidth, viewPortHeight - 2 * border - 2 * edgeAxisBorderHeight)); + xPos += legendWidth + border; + } + else + { + standardHeightLegends.push_back(legend.p()); + } } - } - // Place the rest of the legends in columns that fits within the screen height - - int maxColumnWidht = 0; - std::vector columnLegends; + // Place the rest of the legends in columns that fits within the screen height - for ( caf::TitledOverlayFrame* legend : standardHeightLegends ) - { - cvf::Vec2ui prefSize = legend->preferredSize(); + int maxColumnWidht = 0; + std::vector columnLegends; - // Check if we need a new column - if ((yPos + (int)prefSize.y() + border) > viewPortHeight) + for (caf::TitledOverlayFrame* legend : standardHeightLegends) { - xPos += border + maxColumnWidht; - yPos = border + edgeAxisBorderHeight; + cvf::Vec2ui prefSize = legend->preferredSize(); - // Set same width to all legends in the column - for (caf::TitledOverlayFrame* columnLegend : columnLegends ) + // Check if we need a new column + if ((yPos + (int)prefSize.y() + border) > viewPortHeight) { - columnLegend->setRenderSize(cvf::Vec2ui(maxColumnWidht, columnLegend->renderSize().y())); + xPos += border + maxColumnWidht; + yPos = border + edgeAxisBorderHeight; + + // Set same width to all legends in the column + for (caf::TitledOverlayFrame* columnLegend : columnLegends) + { + columnLegend->setRenderSize(cvf::Vec2ui(maxColumnWidht, columnLegend->renderSize().y())); + } + maxColumnWidht = 0; + columnLegends.clear(); } - maxColumnWidht = 0; - columnLegends.clear(); + + legend->setLayoutFixedPosition(cvf::Vec2i(xPos, yPos)); + legend->setRenderSize(cvf::Vec2ui(prefSize.x(), prefSize.y())); + columnLegends.push_back(legend); + + yPos += legend->renderSize().y() + border; + maxColumnWidht = std::max(maxColumnWidht, (int)prefSize.x()); } - legend->setLayoutFixedPosition(cvf::Vec2i(xPos, yPos)); - legend->setRenderSize(cvf::Vec2ui(prefSize.x(), prefSize.y())); - columnLegends.push_back(legend); + // Set same width to all legends in the last column - yPos += legend->renderSize().y() + border; - maxColumnWidht = std::max(maxColumnWidht, (int)prefSize.x()); + for (caf::TitledOverlayFrame* legend : columnLegends) + { + legend->setRenderSize(cvf::Vec2ui(maxColumnWidht, legend->renderSize().y())); + } } - // Set same width to all legends in the last column - - for (caf::TitledOverlayFrame* legend : columnLegends ) { - legend->setRenderSize(cvf::Vec2ui(maxColumnWidht, legend->renderSize().y())); + int margin = 5; + auto scaleLegendSize = m_scaleLegend->renderSize(); + auto otherItemsHeight = m_versionInfoLabel->sizeHint().height(); + + const int xPos = width() - (int)scaleLegendSize.x() - margin - edgeAxisBorderWidth; + const int yPos = margin + edgeAxisBorderHeight + margin + otherItemsHeight; + + m_scaleLegend->setLayoutFixedPosition({xPos, yPos}); } } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RiuViewer::enableNavigationRotation(bool enable) { - auto tbNavPol = dynamic_cast(m_navigationPolicy.p()); + auto tbNavPol = dynamic_cast(m_navigationPolicy.p()); m_isNavigationRotationEnabled = enable; if (tbNavPol) tbNavPol->enableRotation(m_isNavigationRotationEnabled); } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RiuViewer::updateNavigationPolicy() { @@ -672,12 +716,12 @@ void RiuViewer::updateNavigationPolicy() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RiuViewer::navigationPolicyUpdate() { caf::Viewer::navigationPolicyUpdate(); - + ownerViewWindow()->viewNavigationChanged(); if (m_rimView) { RimViewLinker* viewLinker = m_rimView->assosiatedViewLinker(); @@ -689,22 +733,21 @@ void RiuViewer::navigationPolicyUpdate() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RiuViewer::setCurrentFrame(int frameIndex) { - cvf::Rendering* firstRendering = m_mainRendering.p(); - CVF_ASSERT(firstRendering); + CVF_ASSERT(m_mainRendering.notNull()); if (m_rimView) m_rimView->setCurrentTimeStepAndUpdate(frameIndex); - + animationControl()->setCurrentFrameOnly(frameIndex); caf::Viewer::slotSetCurrentFrame(frameIndex); } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RiuViewer::showAxisCross(bool enable) { @@ -718,7 +761,7 @@ void RiuViewer::showAxisCross(bool enable) } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- RiuViewerToViewInterface* RiuViewer::ownerReservoirView() { @@ -726,15 +769,15 @@ RiuViewerToViewInterface* RiuViewer::ownerReservoirView() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- RimViewWindow* RiuViewer::ownerViewWindow() const { - return dynamic_cast( m_rimView.p()); + return dynamic_cast(m_rimView.p()); } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RiuViewer::optimizeClippingPlanes() { @@ -745,11 +788,15 @@ void RiuViewer::optimizeClippingPlanes() } m_gridBoxGenerator->updateFromCamera(mainCamera()); + + m_scaleLegend->setDisplayCoordTransform(m_rimView->displayCoordTransform().p()); + m_scaleLegend->updateFromCamera(mainCamera()); + caf::Viewer::optimizeClippingPlanes(); } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RiuViewer::resizeGL(int width, int height) { @@ -758,7 +805,7 @@ void RiuViewer::resizeGL(int width, int height) } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RiuViewer::mouseMoveEvent(QMouseEvent* mouseEvent) { @@ -771,7 +818,9 @@ void RiuViewer::mouseMoveEvent(QMouseEvent* mouseEvent) int translatedMousePosY = height() - mouseEvent->pos().y(); cvf::Vec3d displayCoord(0, 0, 0); - if (mainCamera()->unproject(cvf::Vec3d(static_cast(translatedMousePosX), static_cast(translatedMousePosY), 0), &displayCoord)) + if (mainCamera()->unproject( + cvf::Vec3d(static_cast(translatedMousePosX), static_cast(translatedMousePosY), 0), + &displayCoord)) { if (m_cursorPositionDomainCoords != cvf::Vec3d::UNDEFINED) { @@ -782,10 +831,10 @@ void RiuViewer::mouseMoveEvent(QMouseEvent* mouseEvent) update(); } - cvf::ref trans = m_rimView->displayCoordTransform(); - cvf::Vec3d domainCoord = trans->transformToDomainCoord(displayCoord); + cvf::ref trans = m_rimView->displayCoordTransform(); + cvf::Vec3d domainCoord = trans->transformToDomainCoord(displayCoord); - viewLinker->updateCursorPosition(dynamic_cast(m_rimView.p()) , domainCoord); + viewLinker->updateCursorPosition(dynamic_cast(m_rimView.p()), domainCoord); } } } @@ -794,10 +843,24 @@ void RiuViewer::mouseMoveEvent(QMouseEvent* mouseEvent) } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- -void RiuViewer::leaveEvent(QEvent *) +void RiuViewer::enterEvent(QEvent* e) { + if (s_hoverCursor) + { + QApplication::setOverrideCursor(*s_hoverCursor); + } + caf::Viewer::enterEvent(e); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuViewer::leaveEvent(QEvent*) +{ + QApplication::restoreOverrideCursor(); + if (m_rimView && m_rimView->assosiatedViewLinker()) { RimViewLinker* viewLinker = m_rimView->assosiatedViewLinker(); @@ -806,11 +869,11 @@ void RiuViewer::leaveEvent(QEvent *) } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- -void RiuViewer::updateGridBoxData(double scaleZ, - const cvf::Vec3d& displayModelOffset, - const cvf::Color3f& backgroundColor, +void RiuViewer::updateGridBoxData(double scaleZ, + const cvf::Vec3d& displayModelOffset, + const cvf::Color3f& backgroundColor, const cvf::BoundingBox& domainCoordBoundingBox) { m_gridBoxGenerator->setScaleZ(scaleZ); @@ -837,11 +900,14 @@ void RiuViewer::showEdgeTickMarksXY(bool enable, bool showAxisLines) m_windowEdgeAxisOverlay->setShowAxisLines(showAxisLines); m_mainRendering->addOverlayItem(m_windowEdgeAxisOverlay.p()); } + m_showWindowEdgeAxes = enable; + + updateLegendLayout(); } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RiuViewer::showEdgeTickMarksXZ(bool enable, bool showAxisLines) { @@ -854,11 +920,14 @@ void RiuViewer::showEdgeTickMarksXZ(bool enable, bool showAxisLines) m_windowEdgeAxisOverlay->setShowAxisLines(showAxisLines); m_mainRendering->addOverlayItem(m_windowEdgeAxisOverlay.p()); } + m_showWindowEdgeAxes = enable; + + updateLegendLayout(); } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RiuViewer::updateAnnotationItems() { @@ -866,7 +935,7 @@ void RiuViewer::updateAnnotationItems() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RiuViewer::setAxisLabels(const cvf::String& xLabel, const cvf::String& yLabel, const cvf::String& zLabel) { @@ -874,7 +943,7 @@ void RiuViewer::setAxisLabels(const cvf::String& xLabel, const cvf::String& yLab } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- cvf::Vec3d RiuViewer::lastPickPositionInDomainCoords() const { @@ -884,7 +953,7 @@ cvf::Vec3d RiuViewer::lastPickPositionInDomainCoords() const } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- cvf::OverlayItem* RiuViewer::pickFixedPositionedLegend(int winPosX, int winPosY) { @@ -904,7 +973,7 @@ cvf::OverlayItem* RiuViewer::pickFixedPositionedLegend(int winPosX, int winPosY) } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RiuViewer::setCursorPosition(const cvf::Vec3d& domainCoord) { @@ -917,7 +986,7 @@ void RiuViewer::setCursorPosition(const cvf::Vec3d& domainCoord) } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- std::vector> RiuViewer::visibleParts() { @@ -925,8 +994,8 @@ std::vector> RiuViewer::visibleParts() if (m_mainRendering.notNull()) { - auto enableMask = m_mainRendering->enableMask(); - cvf::Scene* scene = currentScene(); + auto enableMask = m_mainRendering->enableMask(); + cvf::Scene* scene = currentScene(); for (cvf::uint i = 0; i < scene->modelCount(); i++) { @@ -951,7 +1020,68 @@ std::vector> RiuViewer::visibleParts() } //-------------------------------------------------------------------------------------------------- -/// +/// +//-------------------------------------------------------------------------------------------------- +void RiuViewer::showScaleLegend(bool show) +{ + if (show) + { + if (m_scaleLegend->orientation() == caf::OverlayScaleLegend::HORIZONTAL) + m_scaleLegend->setRenderSize({280, 45}); + else + m_scaleLegend->setRenderSize({50, 280}); + + m_mainRendering->addOverlayItem(m_scaleLegend.p()); + } + else + { + m_mainRendering->removeOverlayItem(m_scaleLegend.p()); + } + + updateLegendLayout(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuViewer::setHoverCursor(const QCursor& cursor) +{ + s_hoverCursor.reset(new QCursor(cursor)); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuViewer::clearHoverCursor() +{ + s_hoverCursor.reset(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuViewer::updateFonts() +{ + cvf::Font* standardFont = RiaApplication::instance()->defaultSceneFont(); + m_mainRendering->removeOverlayItem(m_axisCross.p()); + + m_axisCross = new cvf::OverlayAxisCross(m_mainCamera.p(), standardFont); + m_axisCross->setAxisLabels("X", "Y", "Z"); + m_axisCross->setLayout(cvf::OverlayItem::VERTICAL, cvf::OverlayItem::BOTTOM_RIGHT); + m_mainRendering->addOverlayItem(m_axisCross.p()); + m_showAxisCross = true; + + QFont font = QApplication::font(); + font.setPointSize(RiaFontCache::pointSizeFromFontSizeEnum(RiaApplication::instance()->preferences()->defaultSceneFontSize())); + + m_zScaleLabel->setFont(font); + m_infoLabel->setFont(font); + m_animationProgress->setFont(font); + m_versionInfoLabel->setFont(font); +} + +//-------------------------------------------------------------------------------------------------- +/// //-------------------------------------------------------------------------------------------------- void RiuViewer::updateLegendTextAndTickMarkColor(cvf::OverlayItem* legend) { @@ -981,7 +1111,7 @@ void RiuViewer::updateLegendTextAndTickMarkColor(cvf::OverlayItem* legend) } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RiuViewer::updateTextAndTickMarkColorForOverlayItems() { @@ -991,10 +1121,12 @@ void RiuViewer::updateTextAndTickMarkColorForOverlayItems() } updateAxisCrossTextColor(); + + updateOverlayItemsStyle(); } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RiuViewer::updateAxisCrossTextColor() { @@ -1004,7 +1136,54 @@ void RiuViewer::updateAxisCrossTextColor() } //-------------------------------------------------------------------------------------------------- -/// +/// +//-------------------------------------------------------------------------------------------------- +void RiuViewer::updateOverlayItemsStyle() +{ + QColor backgroundColor; + QColor backgroundFrameColor; + QColor contrastColor; + { + cvf::Color4f cvf_backgroundColor = mainCamera()->viewport()->clearColor(); + cvf_backgroundColor.a() = 0.65f; + + cvf::Color4f cvf_backgroundFrameColor = + cvf::Color4f(RiaColorTools::computeOffsetColor(cvf_backgroundColor.toColor3f(), 0.3f), 0.9f); + + cvf::Color3f cvf_contrastColor = computeContrastColor(); + + backgroundColor = RiaColorTools::toQColor(cvf_backgroundColor); + backgroundFrameColor = RiaColorTools::toQColor(cvf_backgroundFrameColor); + contrastColor = RiaColorTools::toQColor(cvf_contrastColor); + } + + QPalette p = QApplication::palette(); + + p.setColor(QPalette::Window, backgroundColor); + p.setColor(QPalette::Base, backgroundColor); + + p.setColor(QPalette::WindowText, contrastColor); + + p.setColor(QPalette::Shadow, backgroundFrameColor); + p.setColor(QPalette::Light, backgroundFrameColor); + p.setColor(QPalette::Midlight, backgroundFrameColor); + p.setColor(QPalette::Dark, backgroundFrameColor); + p.setColor(QPalette::Mid, backgroundFrameColor); + + m_infoLabel->setStyleSheet(caf::StyleSheetTools::createFrameStyleSheet("QLabel", "InfoLabel", contrastColor, backgroundColor, backgroundFrameColor)); + m_histogramWidget->setStyleSheet(caf::StyleSheetTools::createFrameStyleSheet("", "HistogramWidget", contrastColor, backgroundColor, backgroundFrameColor)); + m_histogramWidget->setPalette(p); + + m_versionInfoLabel->setPalette(p); + m_zScaleLabel->setPalette(p); + + QColor progressColor(Qt::green); progressColor.setAlphaF(0.8f); + backgroundColor.setAlphaF(0.8f); + m_animationProgress->setTextBackgroundAndProgressColor(contrastColor, backgroundColor, backgroundFrameColor, progressColor); +} + +//-------------------------------------------------------------------------------------------------- +/// //-------------------------------------------------------------------------------------------------- cvf::Color3f RiuViewer::computeContrastColor() const { @@ -1012,8 +1191,8 @@ cvf::Color3f RiuViewer::computeContrastColor() const if (m_rimView.notNull()) { - contrastColor = RiaColorTools::constrastColor(m_rimView->backgroundColor()); + contrastColor = RiaColorTools::contrastColor(m_rimView->backgroundColor()); } - + return contrastColor; } diff --git a/ApplicationCode/UserInterface/RiuViewer.h b/ApplicationCode/UserInterface/RiuViewer.h index a7820a60ae..b954bc28c7 100644 --- a/ApplicationCode/UserInterface/RiuViewer.h +++ b/ApplicationCode/UserInterface/RiuViewer.h @@ -21,15 +21,17 @@ #pragma once #include "RiuViewerToViewInterface.h" -#include "cafViewer.h" +#include "RiuInterfaceToViewWindow.h" +#include "cafMouseState.h" #include "cafPdmObject.h" #include "cafPdmPointer.h" #include "cafPdmInterfacePointer.h" +#include "cafViewer.h" -#include "cafMouseState.h" #include "cvfStructGrid.h" -#include "RiuInterfaceToViewWindow.h" + +#include class RicCommandFeature; class Rim3dView; @@ -38,14 +40,14 @@ class RiuViewerCommands; class RivGridBoxGenerator; class RivWindowEdgeAxesOverlayItem; -class QCDEStyle; class QLabel; -class QProgressBar; namespace caf { + class OverlayScaleLegend; class TitledOverlayFrame; - class PdmUiSelectionVisualizer3d; + class PdmUiSelection3dEditorVisualizer; + class QStyledProgressBar; } namespace cvf @@ -70,7 +72,7 @@ class RiuViewer : public caf::Viewer, public RiuInterfaceToViewWindow public: RiuViewer(const QGLFormat& format, QWidget* parent); ~RiuViewer() override; - + void clearRimView(); void setDefaultView(); cvf::Vec3d pointOfInterest(); void setPointOfInterest(cvf::Vec3d poi); @@ -80,7 +82,13 @@ class RiuViewer : public caf::Viewer, public RiuInterfaceToViewWindow void setEnableMask(unsigned int mask); void showInfoText(bool enable); + void showVersionInfo(bool enable); void setInfoText(QString text); + + void hideZScaleCheckbox(bool hide); + void showZScaleLabel(bool enable); + void setZScale(int scale); + void showHistogram(bool enable); void setHistogram(double min, double max, const std::vector& histogram); void setHistogramPercentiles(double pmin, double pmax, double mean); @@ -118,6 +126,13 @@ class RiuViewer : public caf::Viewer, public RiuInterfaceToViewWindow std::vector> visibleParts(); + void showScaleLegend(bool show); + + static void setHoverCursor(const QCursor& cursor); + static void clearHoverCursor(); + + void updateFonts(); + public slots: void slotSetCurrentFrame(int frameIndex) override; void slotEndAnimation() override; @@ -125,8 +140,9 @@ public slots: protected: void optimizeClippingPlanes() override; void resizeGL(int width, int height) override; - void mouseMoveEvent(QMouseEvent* e) override; - void leaveEvent(QEvent *) override; + void mouseMoveEvent(QMouseEvent* e) override; + void enterEvent(QEvent* e) override; + void leaveEvent(QEvent*) override; private: void updateLegendLayout(); @@ -136,6 +152,7 @@ public slots: cvf::Color3f computeContrastColor() const; void updateAxisCrossTextColor(); + void updateOverlayItemsStyle(); void paintOverlayItems(QPainter* painter) override; @@ -147,15 +164,18 @@ public slots: QRect m_infoLabelOverlayArea; QLabel* m_versionInfoLabel; - bool m_showInfoText; + bool m_showInfoText; + bool m_showVersionInfo; - QProgressBar* m_animationProgress; + QLabel* m_zScaleLabel; + bool m_showZScaleLabel; + bool m_hideZScaleCheckbox; + + caf::QStyledProgressBar* m_animationProgress; bool m_showAnimProgress; RiuSimpleHistogramWidget* m_histogramWidget; bool m_showHistogram; - QCDEStyle* m_progressBarStyle; - cvf::ref m_axisCross; bool m_showAxisCross; cvf::Collection m_visibleLegends; @@ -169,9 +189,13 @@ public slots: cvf::ref m_windowEdgeAxisOverlay; bool m_showWindowEdgeAxes; - caf::PdmUiSelectionVisualizer3d* m_selectionVisualizerManager; + caf::PdmUiSelection3dEditorVisualizer* m_selectionVisualizerManager; cvf::Vec3d m_cursorPositionDomainCoords; bool m_isNavigationRotationEnabled; + + cvf::ref m_scaleLegend; + + static std::unique_ptr s_hoverCursor; }; diff --git a/ApplicationCode/UserInterface/RiuViewerCommands.cpp b/ApplicationCode/UserInterface/RiuViewerCommands.cpp index 2b7b00893f..fe20460bd4 100644 --- a/ApplicationCode/UserInterface/RiuViewerCommands.cpp +++ b/ApplicationCode/UserInterface/RiuViewerCommands.cpp @@ -2,17 +2,17 @@ // // Copyright (C) 2015- Statoil ASA // Copyright (C) 2015- Ceetron Solutions AS -// +// // ResInsight 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 3 of the License, or // (at your option) any later version. -// +// // ResInsight 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 at +// +// See the GNU General Public License at // for more details. // ///////////////////////////////////////////////////////////////////////////////// @@ -23,10 +23,11 @@ #include "RiaColorTables.h" #include "RiaDefines.h" +#include "MeasurementCommands/RicMeasurementPickEventHandler.h" +#include "RicContourMapPickEventHandler.h" #include "RicEclipsePropertyFilterNewExec.h" #include "RicGeoMechPropertyFilterNewExec.h" #include "RicPickEventHandler.h" -#include "RicContourMapPickEventHandler.h" #include "WellLogCommands/Ric3dWellLogCurvePickEventHandler.h" #include "WellPathCommands/RicIntersectionPickEventHandler.h" #include "WellPathCommands/RicWellPathPickEventHandler.h" @@ -59,20 +60,22 @@ #include "RimPerforationInterval.h" #include "RimSimWellInView.h" #include "RimStimPlanFractureTemplate.h" +#include "RimTextAnnotation.h" #include "RimViewController.h" #include "RimWellPath.h" +#include "Riu3dSelectionManager.h" #include "RiuMainWindow.h" +#include "RiuPickItemInfo.h" #include "RiuResultTextBuilder.h" -#include "RiuSelectionManager.h" #include "RiuViewer.h" -#include "RiuPickItemInfo.h" #include "RivFemPartGeometryGenerator.h" #include "RivFemPickSourceInfo.h" #include "RivIntersectionBoxSourceInfo.h" #include "RivIntersectionSourceInfo.h" #include "RivObjectSourceInfo.h" +#include "RivPartPriority.h" #include "RivSimWellConnectionSourceInfo.h" #include "RivSimWellPipeSourceInfo.h" #include "RivSourceInfo.h" @@ -85,14 +88,17 @@ #include "cafCmdFeatureManager.h" #include "cafCmdFeatureMenuBuilder.h" #include "cafDisplayCoordTransform.h" +#include "cafOverlayScalarMapperLegend.h" #include "cafPdmUiTreeView.h" #include "cafSelectionManager.h" -#include "cafOverlayScalarMapperLegend.h" #include "cvfDrawableGeo.h" +#include "cvfDrawableText.h" #include "cvfHitItemCollection.h" #include "cvfOverlayAxisCross.h" #include "cvfPart.h" +#include "cvfRay.h" +#include "cvfScene.h" #include "cvfTransform.h" #include @@ -101,19 +107,16 @@ #include - - //================================================================================================== // // RiaViewerCommands // //================================================================================================== -RicPickEventHandler* RiuViewerCommands::sm_overridingPickHandler = nullptr; - -std::vector RiuViewerCommands::sm_defaultPickEventHandlers; +Ric3dViewPickEventHandler* RiuViewerCommands::sm_overridingPickHandler = nullptr; +std::vector RiuViewerCommands::sm_defaultPickEventHandlers; //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- RiuViewerCommands::RiuViewerCommands(RiuViewer* ownerViewer) : QObject(ownerViewer) @@ -123,7 +126,7 @@ RiuViewerCommands::RiuViewerCommands(RiuViewer* ownerViewer) , m_currentPickPositionInDomainCoords(cvf::Vec3d::UNDEFINED) , m_viewer(ownerViewer) { - if ( sm_defaultPickEventHandlers.empty() ) + if (sm_defaultPickEventHandlers.empty()) { addDefaultPickEventHandler(RicIntersectionPickEventHandler::instance()); addDefaultPickEventHandler(Ric3dWellLogCurvePickEventHandler::instance()); @@ -133,24 +136,20 @@ RiuViewerCommands::RiuViewerCommands(RiuViewer* ownerViewer) } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- -RiuViewerCommands::~RiuViewerCommands() -{ - -} +RiuViewerCommands::~RiuViewerCommands() {} //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- -void RiuViewerCommands::setOwnerView(Rim3dView * owner) +void RiuViewerCommands::setOwnerView(Rim3dView* owner) { m_reservoirView = owner; } - //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RiuViewerCommands::displayContextMenu(QMouseEvent* event) { @@ -159,45 +158,43 @@ void RiuViewerCommands::displayContextMenu(QMouseEvent* event) std::vector pickItemInfos; { cvf::HitItemCollection hitItems; - if (m_viewer->rayPick( event->x(), event->y(), &hitItems)) + cvf::Vec3d globalRayOrigin; + if (m_viewer->rayPick(event->x(), event->y(), &hitItems, &globalRayOrigin)) { - pickItemInfos = RiuPickItemInfo::convertToPickItemInfos(hitItems); + pickItemInfos = RiuPickItemInfo::convertToPickItemInfos(hitItems, globalRayOrigin); } } // Find the following data - const cvf::Part* firstHitPart = nullptr; - uint firstPartTriangleIndex = cvf::UNDEFINED_UINT; - m_currentPickPositionInDomainCoords = cvf::Vec3d::UNDEFINED; + const cvf::Part* firstHitPart = nullptr; + const cvf::Part* additionalHitPart = nullptr; + uint firstPartTriangleIndex = cvf::UNDEFINED_UINT; + m_currentPickPositionInDomainCoords = cvf::Vec3d::UNDEFINED; if (pickItemInfos.size()) { - cvf::Vec3d globalIntersectionPoint(cvf::Vec3d::ZERO); - - if ( pickItemInfos.size() ) - { - globalIntersectionPoint = pickItemInfos[0].globalPickedPoint(); - } + cvf::Vec3d globalIntersectionPoint = pickItemInfos[0].globalPickedPoint(); for (const auto& pickItem : pickItemInfos) { const RivObjectSourceInfo* objectSourceInfo = dynamic_cast(pickItem.sourceInfo()); - if ( objectSourceInfo && dynamic_cast(objectSourceInfo->object()) ) + if (objectSourceInfo && dynamic_cast(objectSourceInfo->object())) { - // Skip picking on perforation interval, display well path context menu + // Store any component hit, but keep going to find main well path + additionalHitPart = pickItem.pickedPart(); continue; } const RivSourceInfo* rivSourceInfo = dynamic_cast(pickItem.sourceInfo()); - if ( rivSourceInfo && rivSourceInfo->hasNNCIndices()) + if (rivSourceInfo && rivSourceInfo->hasNNCIndices()) { // Skip picking on nnc-s continue; } - firstHitPart = pickItem.pickedPart(); - firstPartTriangleIndex = pickItem.faceIdx(); + firstHitPart = pickItem.pickedPart(); + firstPartTriangleIndex = pickItem.faceIdx(); globalIntersectionPoint = pickItem.globalPickedPoint(); break; } @@ -207,28 +204,30 @@ void RiuViewerCommands::displayContextMenu(QMouseEvent* event) if (m_reservoirView.p()) { cvf::ref transForm = m_reservoirView.p()->displayCoordTransform(); - m_currentPickPositionInDomainCoords = transForm->transformToDomainCoord(globalIntersectionPoint); + m_currentPickPositionInDomainCoords = transForm->transformToDomainCoord(globalIntersectionPoint); } } // Build menue - QMenu menu; + QMenu menu; caf::CmdFeatureMenuBuilder menuBuilder; - m_currentGridIdx = cvf::UNDEFINED_SIZE_T; + m_currentGridIdx = cvf::UNDEFINED_SIZE_T; m_currentCellIndex = cvf::UNDEFINED_SIZE_T; // Check type of view - RimGridView* gridView = dynamic_cast(m_reservoirView.p()); + RimGridView* gridView = dynamic_cast(m_reservoirView.p()); Rim2dIntersectionView* int2dView = dynamic_cast(m_reservoirView.p()); if (firstHitPart && firstPartTriangleIndex != cvf::UNDEFINED_UINT) { - const RivSourceInfo* rivSourceInfo = dynamic_cast(firstHitPart->sourceInfo()); - const RivFemPickSourceInfo* femSourceInfo = dynamic_cast(firstHitPart->sourceInfo()); - const RivIntersectionSourceInfo* crossSectionSourceInfo = dynamic_cast(firstHitPart->sourceInfo()); - const RivIntersectionBoxSourceInfo* intersectionBoxSourceInfo = dynamic_cast(firstHitPart->sourceInfo()); + const RivSourceInfo* rivSourceInfo = dynamic_cast(firstHitPart->sourceInfo()); + const RivFemPickSourceInfo* femSourceInfo = dynamic_cast(firstHitPart->sourceInfo()); + const RivIntersectionSourceInfo* crossSectionSourceInfo = + dynamic_cast(firstHitPart->sourceInfo()); + const RivIntersectionBoxSourceInfo* intersectionBoxSourceInfo = + dynamic_cast(firstHitPart->sourceInfo()); if (rivSourceInfo || femSourceInfo || crossSectionSourceInfo || intersectionBoxSourceInfo) { @@ -238,13 +237,13 @@ void RiuViewerCommands::displayContextMenu(QMouseEvent* event) // Set the data regarding what was hit - m_currentGridIdx = rivSourceInfo->gridIndex(); + m_currentGridIdx = rivSourceInfo->gridIndex(); m_currentCellIndex = rivSourceInfo->m_cellFaceFromTriangleMapper->cellIndex(firstPartTriangleIndex); m_currentFaceIndex = rivSourceInfo->m_cellFaceFromTriangleMapper->cellFace(firstPartTriangleIndex); } else if (femSourceInfo) { - m_currentGridIdx = femSourceInfo->femPartIndex(); + m_currentGridIdx = femSourceInfo->femPartIndex(); m_currentCellIndex = femSourceInfo->triangleToElmMapper()->elementIndex(firstPartTriangleIndex); } else if (crossSectionSourceInfo) @@ -253,8 +252,8 @@ void RiuViewerCommands::displayContextMenu(QMouseEvent* event) m_currentFaceIndex = cvf::StructGridInterface::NO_FACE; RiuSelectionItem* selItem = new RiuGeneralSelectionItem(crossSectionSourceInfo->crossSection()); - RiuSelectionManager::instance()->setSelectedItem(selItem, RiuSelectionManager::RUI_TEMPORARY); - + Riu3dSelectionManager::instance()->setSelectedItem(selItem, Riu3dSelectionManager::RUI_TEMPORARY); + if (gridView) { menuBuilder << "RicHideIntersectionFeature"; @@ -273,7 +272,7 @@ void RiuViewerCommands::displayContextMenu(QMouseEvent* event) m_currentFaceIndex = cvf::StructGridInterface::NO_FACE; RiuSelectionItem* selItem = new RiuGeneralSelectionItem(intersectionBoxSourceInfo->intersectionBox()); - RiuSelectionManager::instance()->setSelectedItem(selItem, RiuSelectionManager::RUI_TEMPORARY); + Riu3dSelectionManager::instance()->setSelectedItem(selItem, Riu3dSelectionManager::RUI_TEMPORARY); menuBuilder << "RicHideIntersectionBoxFeature"; menuBuilder.addSeparator(); @@ -334,12 +333,12 @@ void RiuViewerCommands::displayContextMenu(QMouseEvent* event) menuBuilder.addSeparator(); - RimEclipseView* eclipseView = dynamic_cast(m_reservoirView.p()); if (eclipseView) { // Hide faults command - const RigFault* fault = eclipseView->mainGrid()->findFaultFromCellIndexAndCellFace(m_currentCellIndex, m_currentFaceIndex); + const RigFault* fault = + eclipseView->mainGrid()->findFaultFromCellIndexAndCellFace(m_currentCellIndex, m_currentFaceIndex); if (fault) { menuBuilder.addSeparator(); @@ -347,82 +346,105 @@ void RiuViewerCommands::displayContextMenu(QMouseEvent* event) QString faultName = fault->name(); QVariantList hideFaultList; - qulonglong currentCellIndex = m_currentCellIndex; + qulonglong currentCellIndex = m_currentCellIndex; hideFaultList.push_back(currentCellIndex); hideFaultList.push_back(m_currentFaceIndex); - menuBuilder.addCmdFeatureWithUserData("RicEclipseHideFaultFeature", QString("Hide ") + faultName, hideFaultList); + menuBuilder.addCmdFeatureWithUserData( + "RicEclipseHideFaultFeature", QString("Hide ") + faultName, hideFaultList); } } + + menuBuilder << "RicToggleMeasurementModeFeature"; + menuBuilder << "RicTogglePolyMeasurementModeFeature"; } } // Well log curve creation commands if (firstHitPart && firstHitPart->sourceInfo()) { + RimWellPath* wellPath = nullptr; const RivWellPathSourceInfo* wellPathSourceInfo = dynamic_cast(firstHitPart->sourceInfo()); if (wellPathSourceInfo) { - RimWellPath* wellPath = wellPathSourceInfo->wellPath(); - if (wellPath) + wellPath = wellPathSourceInfo->wellPath(); + } + + RimWellPathComponentInterface* wellPathComponent = nullptr; + if (additionalHitPart) + { + const RivObjectSourceInfo* objectSourceInfo = dynamic_cast(additionalHitPart->sourceInfo()); + if (objectSourceInfo) { - if (firstPartTriangleIndex != cvf::UNDEFINED_UINT) - { - cvf::Vec3d pickedPositionInUTM = m_currentPickPositionInDomainCoords; - if (int2dView) pickedPositionInUTM = int2dView->transformToUtm(pickedPositionInUTM); + wellPathComponent = dynamic_cast(objectSourceInfo->object()); + } + } - double measuredDepth = wellPathSourceInfo->measuredDepth(firstPartTriangleIndex, pickedPositionInUTM); - cvf::Vec3d closestPointOnCenterLine = wellPathSourceInfo->closestPointOnCenterLine(firstPartTriangleIndex, pickedPositionInUTM); - RiuSelectionItem* selItem = new RiuWellPathSelectionItem(wellPathSourceInfo, closestPointOnCenterLine, measuredDepth); - RiuSelectionManager::instance()->setSelectedItem(selItem, RiuSelectionManager::RUI_TEMPORARY); - } + if (wellPath) + { + if (firstPartTriangleIndex != cvf::UNDEFINED_UINT) + { + cvf::Vec3d pickedPositionInUTM = m_currentPickPositionInDomainCoords; + if (int2dView) pickedPositionInUTM = int2dView->transformToUtm(pickedPositionInUTM); + + double measuredDepth = wellPathSourceInfo->measuredDepth(firstPartTriangleIndex, pickedPositionInUTM); + cvf::Vec3d closestPointOnCenterLine = + wellPathSourceInfo->closestPointOnCenterLine(firstPartTriangleIndex, pickedPositionInUTM); + RiuSelectionItem* selItem = + new RiuWellPathSelectionItem(wellPathSourceInfo, closestPointOnCenterLine, measuredDepth, wellPathComponent); + Riu3dSelectionManager::instance()->setSelectedItem(selItem, Riu3dSelectionManager::RUI_TEMPORARY); + } - //TODO: Update so these also use RiuWellPathSelectionItem - caf::SelectionManager::instance()->setSelectedItem(wellPath); + // TODO: Update so these also use RiuWellPathSelectionItem + caf::SelectionManager::instance()->setSelectedItem(wellPath); - menuBuilder << "RicNewWellLogCurveExtractionFeature"; - menuBuilder << "RicNewWellLogFileCurveFeature"; - - menuBuilder.addSeparator(); + menuBuilder << "RicNewWellLogCurveExtractionFeature"; + menuBuilder << "RicNewWellLogFileCurveFeature"; - menuBuilder.subMenuStart("Well Plots", QIcon(":/WellLogTrack16x16.png")); + menuBuilder.addSeparator(); - menuBuilder << "RicNewRftPlotFeature"; - menuBuilder << "RicNewPltPlotFeature"; + menuBuilder.subMenuStart("Well Plots", QIcon(":/WellLogTrack16x16.png")); - menuBuilder.addSeparator(); + menuBuilder << "RicNewRftPlotFeature"; + menuBuilder << "RicNewPltPlotFeature"; - menuBuilder << "RicShowWellAllocationPlotFeature"; - menuBuilder << "RicNewWellBoreStabilityPlotFeature"; + menuBuilder.addSeparator(); - menuBuilder.subMenuEnd(); + menuBuilder << "RicShowWellAllocationPlotFeature"; + menuBuilder << "RicNewWellBoreStabilityPlotFeature"; - menuBuilder.addSeparator(); + menuBuilder.subMenuEnd(); - menuBuilder.subMenuStart("3D Well Log Curves", QIcon(":/WellLogCurve16x16.png")); + menuBuilder.addSeparator(); - menuBuilder << "RicAdd3dWellLogCurveFeature"; - menuBuilder << "RicAdd3dWellLogFileCurveFeature"; + menuBuilder.subMenuStart("3D Well Log Curves", QIcon(":/WellLogCurve16x16.png")); - menuBuilder.subMenuEnd(); + menuBuilder << "RicAdd3dWellLogCurveFeature"; + menuBuilder << "RicAdd3dWellLogFileCurveFeature"; - menuBuilder.addSeparator(); - menuBuilder << "RicNewWellPathAttributeFeature"; - menuBuilder.subMenuStart("Completions", QIcon(":/FishBoneGroup16x16.png")); - - menuBuilder << "RicNewWellPathFractureAtPosFeature"; - menuBuilder << "RicNewFishbonesSubsAtMeasuredDepthFeature"; - menuBuilder << "RicNewPerforationIntervalAtMeasuredDepthFeature"; + menuBuilder.subMenuEnd(); - menuBuilder.subMenuEnd(); + menuBuilder.addSeparator(); + menuBuilder.subMenuStart("Create Completions", QIcon(":/FishBoneGroup16x16.png")); - menuBuilder.addSeparator(); + menuBuilder << "RicNewPerforationIntervalAtMeasuredDepthFeature"; + menuBuilder << "RicNewValveAtMeasuredDepthFeature"; + menuBuilder << "RicNewFishbonesSubsAtMeasuredDepthFeature"; + menuBuilder << "RicNewWellPathFractureAtPosFeature"; + menuBuilder.addSeparator(); + menuBuilder << "RicNewWellPathAttributeFeature"; + menuBuilder << "RicWellPathImportCompletionsFileFeature"; - menuBuilder << "RicNewWellPathIntersectionFeature"; - } + + menuBuilder.subMenuEnd(); + + menuBuilder.addSeparator(); + + menuBuilder << "RicNewWellPathIntersectionFeature"; } - const RivSimWellPipeSourceInfo* eclipseWellSourceInfo = dynamic_cast(firstHitPart->sourceInfo()); + const RivSimWellPipeSourceInfo* eclipseWellSourceInfo = + dynamic_cast(firstHitPart->sourceInfo()); if (eclipseWellSourceInfo) { RimSimWellInView* well = eclipseWellSourceInfo->well(); @@ -430,8 +452,9 @@ void RiuViewerCommands::displayContextMenu(QMouseEvent* event) { caf::SelectionManager::instance()->setSelectedItem(well); - RiuSelectionItem* selItem = new RiuSimWellSelectionItem(eclipseWellSourceInfo->well(), m_currentPickPositionInDomainCoords, eclipseWellSourceInfo->branchIndex()); - RiuSelectionManager::instance()->setSelectedItem(selItem, RiuSelectionManager::RUI_TEMPORARY); + RiuSelectionItem* selItem = new RiuSimWellSelectionItem( + eclipseWellSourceInfo->well(), m_currentPickPositionInDomainCoords, eclipseWellSourceInfo->branchIndex()); + Riu3dSelectionManager::instance()->setSelectedItem(selItem, Riu3dSelectionManager::RUI_TEMPORARY); menuBuilder << "RicNewWellLogCurveExtractionFeature"; menuBuilder << "RicNewWellLogRftCurveFeature"; @@ -444,7 +467,7 @@ void RiuViewerCommands::displayContextMenu(QMouseEvent* event) menuBuilder << "RicNewPltPlotFeature"; menuBuilder.addSeparator(); - + menuBuilder << "RicPlotProductionRateFeature"; menuBuilder << "RicShowWellAllocationPlotFeature"; @@ -475,12 +498,23 @@ void RiuViewerCommands::displayContextMenu(QMouseEvent* event) menuBuilder << "RicSelectColorResult"; } } + else + { + menuBuilder.addSeparator(); + menuBuilder << "RicCreateTextAnnotationIn3dViewFeature"; + } if (gridView) { menuBuilder.addSeparator(); menuBuilder << "RicNewGridTimeHistoryCurveFeature"; menuBuilder << "RicShowFlowCharacteristicsPlotFeature"; + if (dynamic_cast(gridView)) + { + menuBuilder << "RicCreateGridCrossPlotFeature"; + } + menuBuilder.addSeparator(); + menuBuilder << "RicExportEclipseInputGridFeature"; menuBuilder << "RicSaveEclipseInputActiveVisibleCellsFeature"; menuBuilder << "RicShowGridStatisticsFeature"; menuBuilder << "RicSelectColorResult"; @@ -497,11 +531,11 @@ void RiuViewerCommands::displayContextMenu(QMouseEvent* event) } // Delete items in temporary selection - RiuSelectionManager::instance()->deleteAllItems(RiuSelectionManager::RUI_TEMPORARY); + Riu3dSelectionManager::instance()->deleteAllItems(Riu3dSelectionManager::RUI_TEMPORARY); } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RiuViewerCommands::handlePickAction(int winPosX, int winPosY, Qt::KeyboardModifiers keyboardModifiers) { @@ -513,34 +547,36 @@ void RiuViewerCommands::handlePickAction(int winPosX, int winPosY, Qt::KeyboardM } // Do the ray intersection with the scene - + std::vector pickItemInfos; { + cvf::Vec3d globalRayOrigin; cvf::HitItemCollection hitItems; - if ( m_viewer->rayPick(winPosX, winPosY, &hitItems) ) + m_viewer->rayPick(winPosX, winPosY, &hitItems, &globalRayOrigin); + + // Do specialized text pick, since vizfwk does not hit text + handleTextPicking(winPosX, winPosY, &hitItems); + + if (hitItems.count()) { - if ( hitItems.count() ) - { - pickItemInfos = RiuPickItemInfo::convertToPickItemInfos(hitItems); - } + pickItemInfos = RiuPickItemInfo::convertToPickItemInfos(hitItems, globalRayOrigin); } } - // Make pickEventHandlers do their stuff + // Make pickEventHandlers do their stuff - if ( pickItemInfos.size() ) + if (pickItemInfos.size()) { - Ric3DPickEvent viewerEventObject(pickItemInfos, - m_reservoirView); + Ric3dPickEvent viewerEventObject(pickItemInfos, m_reservoirView); - if (sm_overridingPickHandler && sm_overridingPickHandler->handlePickEvent(viewerEventObject)) + if (sm_overridingPickHandler && sm_overridingPickHandler->handle3dPickEvent(viewerEventObject)) { return; } - for ( size_t i = 0; i < sm_defaultPickEventHandlers.size(); i++ ) + for (size_t i = 0; i < sm_defaultPickEventHandlers.size(); i++) { - if ( sm_defaultPickEventHandlers[i]->handlePickEvent(viewerEventObject) ) + if (sm_defaultPickEventHandlers[i]->handle3dPickEvent(viewerEventObject)) { return; } @@ -549,43 +585,45 @@ void RiuViewerCommands::handlePickAction(int winPosX, int winPosY, Qt::KeyboardM // Old pick handling. Todo: Encapsulate in pickEventHandlers - size_t gridIndex = cvf::UNDEFINED_SIZE_T; - size_t cellIndex = cvf::UNDEFINED_SIZE_T; - size_t nncIndex = cvf::UNDEFINED_SIZE_T; - cvf::StructGridInterface::FaceType face = cvf::StructGridInterface::NO_FACE; - int gmFace = -1; - bool intersectionHit = false; - std::array intersectionTriangleHit; + size_t gridIndex = cvf::UNDEFINED_SIZE_T; + size_t cellIndex = cvf::UNDEFINED_SIZE_T; + size_t nncIndex = cvf::UNDEFINED_SIZE_T; + cvf::StructGridInterface::FaceType face = cvf::StructGridInterface::NO_FACE; + int gmFace = -1; + bool intersectionHit = false; + std::array intersectionTriangleHit; cvf::Vec3d localIntersectionPoint(cvf::Vec3d::ZERO); cvf::Vec3d globalIntersectionPoint(cvf::Vec3d::ZERO); // Extract all the above information from the pick { - const cvf::Part* firstHitPart = nullptr; - uint firstPartTriangleIndex = cvf::UNDEFINED_UINT; + const cvf::Part* firstHitPart = nullptr; + uint firstPartTriangleIndex = cvf::UNDEFINED_UINT; - const cvf::Part* firstNncHitPart = nullptr; - uint nncPartTriangleIndex = cvf::UNDEFINED_UINT; + const cvf::Part* firstNncHitPart = nullptr; + uint nncPartTriangleIndex = cvf::UNDEFINED_UINT; - if ( pickItemInfos.size() ) + if (pickItemInfos.size()) { - size_t indexToFirstNoneNncItem = cvf::UNDEFINED_SIZE_T;; - size_t indexToNncItemNearFirstItem = cvf::UNDEFINED_SIZE_T;; + size_t indexToFirstNoneNncItem = cvf::UNDEFINED_SIZE_T; + ; + size_t indexToNncItemNearFirstItem = cvf::UNDEFINED_SIZE_T; + ; findFirstItems(pickItemInfos, &indexToFirstNoneNncItem, &indexToNncItemNearFirstItem); - if ( indexToFirstNoneNncItem != cvf::UNDEFINED_SIZE_T ) + if (indexToFirstNoneNncItem != cvf::UNDEFINED_SIZE_T) { - localIntersectionPoint = pickItemInfos[indexToFirstNoneNncItem].localPickedPoint(); + localIntersectionPoint = pickItemInfos[indexToFirstNoneNncItem].localPickedPoint(); globalIntersectionPoint = pickItemInfos[indexToFirstNoneNncItem].globalPickedPoint(); - firstHitPart = pickItemInfos[indexToFirstNoneNncItem].pickedPart(); - firstPartTriangleIndex = pickItemInfos[indexToFirstNoneNncItem].faceIdx(); + firstHitPart = pickItemInfos[indexToFirstNoneNncItem].pickedPart(); + firstPartTriangleIndex = pickItemInfos[indexToFirstNoneNncItem].faceIdx(); } - if ( indexToNncItemNearFirstItem != cvf::UNDEFINED_SIZE_T ) + if (indexToNncItemNearFirstItem != cvf::UNDEFINED_SIZE_T) { - firstNncHitPart = pickItemInfos[indexToNncItemNearFirstItem].pickedPart(); + firstNncHitPart = pickItemInfos[indexToNncItemNearFirstItem].pickedPart(); nncPartTriangleIndex = pickItemInfos[indexToNncItemNearFirstItem].faceIdx(); } } @@ -605,67 +643,84 @@ void RiuViewerCommands::handlePickAction(int winPosX, int winPosY, Qt::KeyboardM if (firstHitPart && firstHitPart->sourceInfo()) { const RivObjectSourceInfo* rivObjectSourceInfo = dynamic_cast(firstHitPart->sourceInfo()); - const RivSourceInfo* rivSourceInfo = dynamic_cast(firstHitPart->sourceInfo()); + const RivSourceInfo* rivSourceInfo = dynamic_cast(firstHitPart->sourceInfo()); const RivFemPickSourceInfo* femSourceInfo = dynamic_cast(firstHitPart->sourceInfo()); - const RivIntersectionSourceInfo* crossSectionSourceInfo = dynamic_cast(firstHitPart->sourceInfo()); - const RivIntersectionBoxSourceInfo* intersectionBoxSourceInfo = dynamic_cast(firstHitPart->sourceInfo()); - const RivSimWellPipeSourceInfo* eclipseWellSourceInfo = dynamic_cast(firstHitPart->sourceInfo()); - const RivWellConnectionSourceInfo* wellConnectionSourceInfo = dynamic_cast(firstHitPart->sourceInfo()); + const RivIntersectionSourceInfo* crossSectionSourceInfo = + dynamic_cast(firstHitPart->sourceInfo()); + const RivIntersectionBoxSourceInfo* intersectionBoxSourceInfo = + dynamic_cast(firstHitPart->sourceInfo()); + const RivSimWellPipeSourceInfo* eclipseWellSourceInfo = + dynamic_cast(firstHitPart->sourceInfo()); + const RivWellConnectionSourceInfo* wellConnectionSourceInfo = + dynamic_cast(firstHitPart->sourceInfo()); if (rivObjectSourceInfo) { RimFracture* fracture = dynamic_cast(rivObjectSourceInfo->object()); - + if (fracture) { - bool blockSelectionOfFracture = false; - if (fracture) { - std::vector uiItems; - RiuMainWindow::instance()->projectTreeView()->selectedUiItems(uiItems); + bool blockSelectionOfFracture = false; - if (uiItems.size() == 1) { - auto selectedFractureTemplate = dynamic_cast(uiItems[0]); + std::vector uiItems; + RiuMainWindow::instance()->projectTreeView()->selectedUiItems(uiItems); - if (selectedFractureTemplate != nullptr && selectedFractureTemplate == fracture->fractureTemplate()) + if (uiItems.size() == 1) { - blockSelectionOfFracture = true; + auto selectedFractureTemplate = dynamic_cast(uiItems[0]); + + if (selectedFractureTemplate != nullptr && + selectedFractureTemplate == fracture->fractureTemplate()) + { + blockSelectionOfFracture = true; + } } } - } - if (!blockSelectionOfFracture) - { - RiuMainWindow::instance()->selectAsCurrentItem(fracture); + if (!blockSelectionOfFracture) + { + RiuMainWindow::instance()->selectAsCurrentItem(fracture); + } } - } + RimStimPlanFractureTemplate* stimPlanTempl = + fracture ? dynamic_cast(fracture->fractureTemplate()) : nullptr; + RimEllipseFractureTemplate* ellipseTempl = + fracture ? dynamic_cast(fracture->fractureTemplate()) : nullptr; + if (stimPlanTempl || ellipseTempl) + { + // Set fracture resultInfo text + QString resultInfoText; - RimStimPlanFractureTemplate* stimPlanTempl = fracture ? dynamic_cast(fracture->fractureTemplate()) : nullptr; - RimEllipseFractureTemplate* ellipseTempl = fracture ? dynamic_cast(fracture->fractureTemplate()) : nullptr; - if (stimPlanTempl || ellipseTempl) - { - // Set fracture resultInfo text - QString resultInfoText; + cvf::ref transForm = m_reservoirView->displayCoordTransform(); + cvf::Vec3d domainCoord = transForm->transformToDomainCoord(globalIntersectionPoint); - cvf::ref transForm = m_reservoirView->displayCoordTransform(); - cvf::Vec3d domainCoord = transForm->transformToDomainCoord(globalIntersectionPoint); + RimEclipseView* eclView = dynamic_cast(m_reservoirView.p()); + RivWellFracturePartMgr* partMgr = fracture->fracturePartManager(); + if (eclView) resultInfoText = partMgr->resultInfoText(*eclView, domainCoord); - RimEclipseView* eclView = dynamic_cast(m_reservoirView.p()); - RivWellFracturePartMgr* partMgr = fracture->fracturePartManager(); - if (eclView) resultInfoText = partMgr->resultInfoText(*eclView, domainCoord); + // Set intersection point result text + QString intersectionPointText; - // Set intersection point result text - QString intersectionPointText; + intersectionPointText.sprintf("Intersection point : Global [E: %.2f, N: %.2f, Depth: %.2f]", + domainCoord.x(), + domainCoord.y(), + -domainCoord.z()); + resultInfoText.append(intersectionPointText); - intersectionPointText.sprintf("Intersection point : Global [E: %.2f, N: %.2f, Depth: %.2f]", domainCoord.x(), domainCoord.y(), -domainCoord.z()); - resultInfoText.append(intersectionPointText); + // Display result info text + RiuMainWindow::instance()->setResultInfo(resultInfoText); + } + } - // Display result info text - RiuMainWindow::instance()->setResultInfo(resultInfoText); + RimTextAnnotation* textAnnot = dynamic_cast(rivObjectSourceInfo->object()); + if (textAnnot) + { + RiuMainWindow::instance()->selectAsCurrentItem(textAnnot, true); } } - + if (rivSourceInfo) { gridIndex = rivSourceInfo->gridIndex(); @@ -674,34 +729,32 @@ void RiuViewerCommands::handlePickAction(int winPosX, int winPosY, Qt::KeyboardM CVF_ASSERT(rivSourceInfo->m_cellFaceFromTriangleMapper.notNull()); cellIndex = rivSourceInfo->m_cellFaceFromTriangleMapper->cellIndex(firstPartTriangleIndex); - face = rivSourceInfo->m_cellFaceFromTriangleMapper->cellFace(firstPartTriangleIndex); + face = rivSourceInfo->m_cellFaceFromTriangleMapper->cellFace(firstPartTriangleIndex); } } else if (femSourceInfo) { gridIndex = femSourceInfo->femPartIndex(); cellIndex = femSourceInfo->triangleToElmMapper()->elementIndex(firstPartTriangleIndex); - gmFace = femSourceInfo->triangleToElmMapper()->elementFace(firstPartTriangleIndex); - + gmFace = femSourceInfo->triangleToElmMapper()->elementFace(firstPartTriangleIndex); } else if (crossSectionSourceInfo) { findCellAndGridIndex(crossSectionSourceInfo, firstPartTriangleIndex, &cellIndex, &gridIndex); - intersectionHit = true; + intersectionHit = true; intersectionTriangleHit = crossSectionSourceInfo->triangle(firstPartTriangleIndex); bool allowActiveViewChange = dynamic_cast(m_viewer->ownerViewWindow()) == nullptr; - + RiuMainWindow::instance()->selectAsCurrentItem(crossSectionSourceInfo->crossSection(), allowActiveViewChange); } else if (intersectionBoxSourceInfo) { findCellAndGridIndex(intersectionBoxSourceInfo, firstPartTriangleIndex, &cellIndex, &gridIndex); - intersectionHit = true; + intersectionHit = true; intersectionTriangleHit = intersectionBoxSourceInfo->triangle(firstPartTriangleIndex); RiuMainWindow::instance()->selectAsCurrentItem(intersectionBoxSourceInfo->intersectionBox()); - } else if (eclipseWellSourceInfo) { @@ -720,16 +773,17 @@ void RiuViewerCommands::handlePickAction(int winPosX, int winPosY, Qt::KeyboardM { RimEclipseCase* eclipseCase = nullptr; eclipseView->firstAncestorOrThisOfTypeAsserted(eclipseCase); - + if (eclipseCase->eclipseCaseData() && eclipseCase->eclipseCaseData()->virtualPerforationTransmissibilities()) { std::vector completionsForOneCell; { - auto connectionFactors = eclipseCase->eclipseCaseData()->virtualPerforationTransmissibilities(); - size_t timeStep = eclipseView->currentTimeStep(); + auto connectionFactors = eclipseCase->eclipseCaseData()->virtualPerforationTransmissibilities(); + size_t timeStep = eclipseView->currentTimeStep(); - const auto& multipleCompletions = connectionFactors->multipleCompletionsPerEclipseCell(wellConnectionSourceInfo->wellPath(), timeStep); + const auto& multipleCompletions = connectionFactors->multipleCompletionsPerEclipseCell( + wellConnectionSourceInfo->wellPath(), timeStep); auto completionDataIt = multipleCompletions.find(globalCellIndex); if (completionDataIt != multipleCompletions.end()) @@ -747,7 +801,8 @@ void RiuViewerCommands::handlePickAction(int winPosX, int winPosY, Qt::KeyboardM } QString resultInfoText; - resultInfoText += QString("Well Connection Factor : %1

").arg(aggregatedConnectionFactor); + resultInfoText += + QString("Well Connection Factor : %1

").arg(aggregatedConnectionFactor); { RiuResultTextBuilder textBuilder(eclipseView, globalCellIndex, eclipseView->currentTimeStep()); @@ -761,7 +816,9 @@ void RiuViewerCommands::handlePickAction(int winPosX, int winPosY, Qt::KeyboardM { for (const auto& metaData : completionData.metadata()) { - resultInfoText += QString("Name %1 Description %2
").arg(metaData.name).arg(metaData.comment); + resultInfoText += QString("Name %1 Description %2
") + .arg(metaData.name) + .arg(metaData.comment); } } @@ -774,11 +831,12 @@ void RiuViewerCommands::handlePickAction(int winPosX, int winPosY, Qt::KeyboardM } else if (dynamic_cast(firstHitPart->sourceInfo())) { - const RivSimWellConnectionSourceInfo* simWellConnectionSourceInfo = dynamic_cast(firstHitPart->sourceInfo()); + const RivSimWellConnectionSourceInfo* simWellConnectionSourceInfo = + dynamic_cast(firstHitPart->sourceInfo()); bool allowActiveViewChange = dynamic_cast(m_viewer->ownerViewWindow()) == nullptr; - size_t globalCellIndex = simWellConnectionSourceInfo->globalCellIndexFromTriangleIndex(firstPartTriangleIndex); + size_t globalCellIndex = simWellConnectionSourceInfo->globalCellIndexFromTriangleIndex(firstPartTriangleIndex); double connectionFactor = simWellConnectionSourceInfo->connectionFactorFromTriangleIndex(firstPartTriangleIndex); RimEclipseView* eclipseView = dynamic_cast(m_reservoirView.p()); @@ -787,23 +845,25 @@ void RiuViewerCommands::handlePickAction(int winPosX, int winPosY, Qt::KeyboardM RimEclipseCase* eclipseCase = nullptr; eclipseView->firstAncestorOrThisOfTypeAsserted(eclipseCase); - if (eclipseCase->eclipseCaseData() && - eclipseCase->eclipseCaseData()->virtualPerforationTransmissibilities()) + if (eclipseCase->eclipseCaseData() && eclipseCase->eclipseCaseData()->virtualPerforationTransmissibilities()) { auto connectionFactors = eclipseCase->eclipseCaseData()->virtualPerforationTransmissibilities(); - size_t timeStep = eclipseView->currentTimeStep(); + size_t timeStep = eclipseView->currentTimeStep(); - const auto& completionData = connectionFactors->completionsForSimWell(simWellConnectionSourceInfo->simWellInView()->simWellData(), timeStep); + const auto& completionData = connectionFactors->completionsForSimWell( + simWellConnectionSourceInfo->simWellInView()->simWellData(), timeStep); for (const auto& compData : completionData) { if (compData.completionDataGridCell().globalCellIndex() == globalCellIndex) { { - QString resultInfoText = QString("Simulation Well Connection Factor : %1

").arg(connectionFactor); + QString resultInfoText = + QString("Simulation Well Connection Factor : %1

").arg(connectionFactor); { - RiuResultTextBuilder textBuilder(eclipseView, globalCellIndex, eclipseView->currentTimeStep()); + RiuResultTextBuilder textBuilder( + eclipseView, globalCellIndex, eclipseView->currentTimeStep()); resultInfoText += textBuilder.geometrySelectionText("
"); } @@ -815,18 +875,18 @@ void RiuViewerCommands::handlePickAction(int winPosX, int winPosY, Qt::KeyboardM } } } - } - RiuMainWindow::instance()->selectAsCurrentItem(simWellConnectionSourceInfo->simWellInView(), allowActiveViewChange); + RiuMainWindow::instance()->selectAsCurrentItem(simWellConnectionSourceInfo->simWellInView(), + allowActiveViewChange); } } } if (cellIndex == cvf::UNDEFINED_SIZE_T) { - RiuSelectionManager::instance()->deleteAllItems(); + Riu3dSelectionManager::instance()->deleteAllItems(); } - else + else { bool appendToSelection = false; if (keyboardModifiers & Qt::ControlModifier) @@ -835,7 +895,7 @@ void RiuViewerCommands::handlePickAction(int winPosX, int winPosY, Qt::KeyboardM } std::vector items; - RiuSelectionManager::instance()->selectedItems(items); + Riu3dSelectionManager::instance()->selectedItems(items); const caf::ColorTable& colorTable = RiaColorTables::selectionPaletteColors(); @@ -849,8 +909,8 @@ void RiuViewerCommands::handlePickAction(int winPosX, int winPosY, Qt::KeyboardM RiuSelectionItem* selItem = nullptr; { Rim2dIntersectionView* intersectionView = dynamic_cast(m_reservoirView.p()); - RimEclipseView* eclipseView = dynamic_cast(m_reservoirView.p()); - RimGeoMechView* geomView = dynamic_cast(m_reservoirView.p()); + RimEclipseView* eclipseView = dynamic_cast(m_reservoirView.p()); + RimGeoMechView* geomView = dynamic_cast(m_reservoirView.p()); if (intersectionView) { @@ -860,13 +920,18 @@ void RiuViewerCommands::handlePickAction(int winPosX, int winPosY, Qt::KeyboardM if (eclipseView) { - selItem = new RiuEclipseSelectionItem(eclipseView, gridIndex, cellIndex, nncIndex, curveColor, face, localIntersectionPoint); + selItem = new RiuEclipseSelectionItem( + eclipseView, gridIndex, cellIndex, nncIndex, curveColor, face, localIntersectionPoint); } if (geomView) { - if(intersectionHit) selItem = new RiuGeoMechSelectionItem(geomView, gridIndex, cellIndex, curveColor, gmFace, localIntersectionPoint, intersectionTriangleHit); - else selItem = new RiuGeoMechSelectionItem(geomView, gridIndex, cellIndex, curveColor, gmFace, localIntersectionPoint); + if (intersectionHit) + selItem = new RiuGeoMechSelectionItem( + geomView, gridIndex, cellIndex, curveColor, gmFace, localIntersectionPoint, intersectionTriangleHit); + else + selItem = + new RiuGeoMechSelectionItem(geomView, gridIndex, cellIndex, curveColor, gmFace, localIntersectionPoint); } if (intersectionView) selItem = new Riu2dIntersectionSelectionItem(intersectionView, selItem); @@ -874,20 +939,19 @@ void RiuViewerCommands::handlePickAction(int winPosX, int winPosY, Qt::KeyboardM if (appendToSelection) { - RiuSelectionManager::instance()->appendItemToSelection(selItem); + Riu3dSelectionManager::instance()->appendItemToSelection(selItem); } - else if(selItem) + else if (selItem) { - RiuSelectionManager::instance()->setSelectedItem(selItem); + Riu3dSelectionManager::instance()->setSelectedItem(selItem); } } - } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- -void RiuViewerCommands::setPickEventHandler(RicPickEventHandler* pickEventHandler) +void RiuViewerCommands::setPickEventHandler(Ric3dViewPickEventHandler* pickEventHandler) { if (sm_overridingPickHandler) sm_overridingPickHandler->notifyUnregistered(); @@ -895,19 +959,19 @@ void RiuViewerCommands::setPickEventHandler(RicPickEventHandler* pickEventHandle } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- -void RiuViewerCommands::removePickEventHandlerIfActive(RicPickEventHandler* pickEventHandler) +void RiuViewerCommands::removePickEventHandlerIfActive(Ric3dViewPickEventHandler* pickEventHandler) { if (sm_overridingPickHandler == pickEventHandler) - { + { sm_overridingPickHandler = nullptr; if (pickEventHandler) pickEventHandler->notifyUnregistered(); } } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- cvf::Vec3d RiuViewerCommands::lastPickPositionInDomainCoords() const { @@ -915,7 +979,7 @@ cvf::Vec3d RiuViewerCommands::lastPickPositionInDomainCoords() const } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RiuViewerCommands::addDefaultPickEventHandler(RicDefaultPickEventHandler* pickEventHandler) { @@ -927,39 +991,42 @@ void RiuViewerCommands::addDefaultPickEventHandler(RicDefaultPickEventHandler* p } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void RiuViewerCommands::removeDefaultPickEventHandler(RicDefaultPickEventHandler* pickEventHandler) { - for ( auto it = sm_defaultPickEventHandlers.begin(); it != sm_defaultPickEventHandlers.end(); ++it ) + for (auto it = sm_defaultPickEventHandlers.begin(); it != sm_defaultPickEventHandlers.end(); ++it) { - if ( *it == pickEventHandler ) + if (*it == pickEventHandler) { sm_defaultPickEventHandlers.erase(it); break; } - } + } } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- -void RiuViewerCommands::findCellAndGridIndex(const RivIntersectionSourceInfo* crossSectionSourceInfo, cvf::uint firstPartTriangleIndex, size_t* cellIndex, size_t* gridIndex) +void RiuViewerCommands::findCellAndGridIndex(const RivIntersectionSourceInfo* crossSectionSourceInfo, + cvf::uint firstPartTriangleIndex, + size_t* cellIndex, + size_t* gridIndex) { CVF_ASSERT(cellIndex && gridIndex); - RimCase* ownerCase = m_reservoirView->ownerCase(); + RimCase* ownerCase = m_reservoirView->ownerCase(); RimEclipseCase* eclipseCase = dynamic_cast(ownerCase); - RimGeoMechCase* geomCase = dynamic_cast(ownerCase); + RimGeoMechCase* geomCase = dynamic_cast(ownerCase); if (eclipseCase) { - //RimEclipseView* eclipseView = dynamic_cast(m_reservoirView.p()); + // RimEclipseView* eclipseView = dynamic_cast(m_reservoirView.p()); RimEclipseView* eclipseView; crossSectionSourceInfo->crossSection()->firstAncestorOrThisOfType(eclipseView); - size_t globalCellIndex = crossSectionSourceInfo->triangleToCellIndex()[firstPartTriangleIndex]; + size_t globalCellIndex = crossSectionSourceInfo->triangleToCellIndex()[firstPartTriangleIndex]; const RigGridBase* hostGrid = eclipseView->mainGrid()->gridAndGridLocalIdxFromGlobalCellIdx(globalCellIndex, cellIndex); - *gridIndex = hostGrid->gridIndex(); + *gridIndex = hostGrid->gridIndex(); } else if (geomCase) { @@ -969,21 +1036,24 @@ void RiuViewerCommands::findCellAndGridIndex(const RivIntersectionSourceInfo* cr } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- -void RiuViewerCommands::findCellAndGridIndex(const RivIntersectionBoxSourceInfo* intersectionBoxSourceInfo, cvf::uint firstPartTriangleIndex, size_t* cellIndex, size_t* gridIndex) +void RiuViewerCommands::findCellAndGridIndex(const RivIntersectionBoxSourceInfo* intersectionBoxSourceInfo, + cvf::uint firstPartTriangleIndex, + size_t* cellIndex, + size_t* gridIndex) { CVF_ASSERT(cellIndex && gridIndex); RimEclipseView* eclipseView = dynamic_cast(m_reservoirView.p()); - RimGeoMechView* geomView = dynamic_cast(m_reservoirView.p()); + RimGeoMechView* geomView = dynamic_cast(m_reservoirView.p()); if (eclipseView) { size_t globalCellIndex = intersectionBoxSourceInfo->triangleToCellIndex()[firstPartTriangleIndex]; const RigCell& cell = eclipseView->mainGrid()->globalCellArray()[globalCellIndex]; - *cellIndex = cell.gridLocalCellIndex(); - *gridIndex = cell.hostGrid()->gridIndex(); + *cellIndex = cell.gridLocalCellIndex(); + *gridIndex = cell.hostGrid()->gridIndex(); } else if (geomView) { @@ -992,35 +1062,34 @@ void RiuViewerCommands::findCellAndGridIndex(const RivIntersectionBoxSourceInfo* } } - //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- -void RiuViewerCommands::findFirstItems(const std::vector & pickItemInfos, - size_t* indexToFirstNoneNncItem, - size_t* indexToNncItemNearFirsItem) +void RiuViewerCommands::findFirstItems(const std::vector& pickItemInfos, + size_t* indexToFirstNoneNncItem, + size_t* indexToNncItemNearFirsItem) { CVF_ASSERT(pickItemInfos.size() > 0); CVF_ASSERT(indexToFirstNoneNncItem); CVF_ASSERT(indexToNncItemNearFirsItem); - double pickDepthThresholdSquared = 0.05 *0.05; + double pickDepthThresholdSquared = 0.05 * 0.05; { RimEclipseView* eclipseView = dynamic_cast(m_reservoirView.p()); if (eclipseView && eclipseView->mainGrid()) { double characteristicCellSize = eclipseView->mainGrid()->characteristicIJCellSize(); - pickDepthThresholdSquared = characteristicCellSize / 100.0; - pickDepthThresholdSquared = pickDepthThresholdSquared * pickDepthThresholdSquared; + pickDepthThresholdSquared = characteristicCellSize / 100.0; + pickDepthThresholdSquared = pickDepthThresholdSquared * pickDepthThresholdSquared; } } - size_t firstNonNncHitIndex = cvf::UNDEFINED_SIZE_T; - size_t nncNearFirstItemIndex = cvf::UNDEFINED_SIZE_T; + size_t firstNonNncHitIndex = cvf::UNDEFINED_SIZE_T; + size_t nncNearFirstItemIndex = cvf::UNDEFINED_SIZE_T; cvf::Vec3d firstOrFirstNonNncIntersectionPoint = pickItemInfos[0].globalPickedPoint(); - // Find first nnc part, and store as a separate thing if the nnc is first or close behind the first hit item. + // Find first nnc part, and store as a separate thing if the nnc is first or close behind the first hit item. // Find index to first ordinary (non-nnc) part for (size_t i = 0; i < pickItemInfos.size(); i++) @@ -1030,14 +1099,15 @@ void RiuViewerCommands::findFirstItems(const std::vector & pick bool canFindRelvantNNC = true; const RivSourceInfo* rivSourceInfo = dynamic_cast(pickItemInfos[i].sourceInfo()); - if ( rivSourceInfo && rivSourceInfo->hasNNCIndices() ) + if (rivSourceInfo && rivSourceInfo->hasNNCIndices()) { - if ( nncNearFirstItemIndex == cvf::UNDEFINED_SIZE_T && canFindRelvantNNC) + if (nncNearFirstItemIndex == cvf::UNDEFINED_SIZE_T && canFindRelvantNNC) { - cvf::Vec3d distFirstNonNNCToCandidate = firstOrFirstNonNncIntersectionPoint - pickItemInfos[i].globalPickedPoint(); + cvf::Vec3d distFirstNonNNCToCandidate = + firstOrFirstNonNncIntersectionPoint - pickItemInfos[i].globalPickedPoint(); // This candidate is an NNC hit - if ( distFirstNonNNCToCandidate.lengthSquared() < pickDepthThresholdSquared ) + if (distFirstNonNNCToCandidate.lengthSquared() < pickDepthThresholdSquared) { nncNearFirstItemIndex = i; } @@ -1049,35 +1119,36 @@ void RiuViewerCommands::findFirstItems(const std::vector & pick } else { - if ( firstNonNncHitIndex == cvf::UNDEFINED_SIZE_T ) + if (firstNonNncHitIndex == cvf::UNDEFINED_SIZE_T) { firstNonNncHitIndex = i; } } - if (firstNonNncHitIndex != cvf::UNDEFINED_SIZE_T && (nncNearFirstItemIndex != cvf::UNDEFINED_SIZE_T || !canFindRelvantNNC) ) + if (firstNonNncHitIndex != cvf::UNDEFINED_SIZE_T && + (nncNearFirstItemIndex != cvf::UNDEFINED_SIZE_T || !canFindRelvantNNC)) { break; // Found what can be found } } - (*indexToFirstNoneNncItem) = firstNonNncHitIndex; + (*indexToFirstNoneNncItem) = firstNonNncHitIndex; (*indexToNncItemNearFirsItem) = nncNearFirstItemIndex; } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- -void RiuViewerCommands::ijkFromCellIndex(size_t gridIdx, size_t cellIndex, size_t* i, size_t* j, size_t* k) +void RiuViewerCommands::ijkFromCellIndex(size_t gridIdx, size_t cellIndex, size_t* i, size_t* j, size_t* k) { RimEclipseView* eclipseView = dynamic_cast(m_reservoirView.p()); - RimGeoMechView* geomView = dynamic_cast(m_reservoirView.p()); + RimGeoMechView* geomView = dynamic_cast(m_reservoirView.p()); if (eclipseView && eclipseView->eclipseCase()) { eclipseView->eclipseCase()->eclipseCaseData()->grid(gridIdx)->ijkFromCellIndex(cellIndex, i, j, k); } - + if (geomView && geomView->geoMechCase()) { geomView->femParts()->part(gridIdx)->getOrCreateStructGrid()->ijkFromCellIndex(cellIndex, i, j, k); @@ -1085,7 +1156,7 @@ void RiuViewerCommands::ijkFromCellIndex(size_t gridIdx, size_t cellIndex, size } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- bool RiuViewerCommands::handleOverlayItemPicking(int winPosX, int winPosY) { @@ -1119,3 +1190,39 @@ bool RiuViewerCommands::handleOverlayItemPicking(int winPosX, int winPosY) return false; } + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuViewerCommands::handleTextPicking(int winPosX, int winPosY, cvf::HitItemCollection* hitItems) +{ + using namespace cvf; + + int translatedMousePosX = winPosX; + int translatedMousePosY = m_viewer->height() - winPosY; + + Scene* scene = m_viewer->currentScene(); + if (!scene) return; + + Collection partCollection; + scene->allParts(&partCollection); + + ref ray = m_viewer->mainCamera()->rayFromWindowCoordinates(translatedMousePosX, translatedMousePosY); + + for (size_t pIdx = 0; pIdx < partCollection.size(); ++pIdx) + { + DrawableText* textDrawable = dynamic_cast(partCollection[pIdx]->drawable()); + if (textDrawable) + { + cvf::Vec3d ppoint; + if (textDrawable->rayIntersect(*ray, *(m_viewer->mainCamera()), &ppoint)) + { + cvf::ref hitItem = new HitItem(0, ppoint); + hitItem->setPart(partCollection[pIdx].p()); + hitItems->add(hitItem.p()); + } + } + } + + hitItems->sort(); +} diff --git a/ApplicationCode/UserInterface/RiuViewerCommands.h b/ApplicationCode/UserInterface/RiuViewerCommands.h index 7ee7e0f410..ca5bf879ab 100644 --- a/ApplicationCode/UserInterface/RiuViewerCommands.h +++ b/ApplicationCode/UserInterface/RiuViewerCommands.h @@ -26,7 +26,7 @@ #include class RicDefaultPickEventHandler; -class RicPickEventHandler; +class Ric3dViewPickEventHandler; class RimEclipseView; class RimGeoMechView; class RimIntersection; @@ -60,8 +60,8 @@ class RiuViewerCommands: public QObject void displayContextMenu(QMouseEvent* event); void handlePickAction(int winPosX, int winPosY, Qt::KeyboardModifiers keyboardModifiers); - static void setPickEventHandler(RicPickEventHandler* pickEventHandler); - static void removePickEventHandlerIfActive(RicPickEventHandler* pickEventHandler); + static void setPickEventHandler(Ric3dViewPickEventHandler* pickEventHandler); + static void removePickEventHandlerIfActive(Ric3dViewPickEventHandler* pickEventHandler); cvf::Vec3d lastPickPositionInDomainCoords() const; private: @@ -87,6 +87,7 @@ class RiuViewerCommands: public QObject caf::PdmPointer m_reservoirView; QPointer m_viewer; - static RicPickEventHandler* sm_overridingPickHandler; + static Ric3dViewPickEventHandler* sm_overridingPickHandler; static std::vector sm_defaultPickEventHandlers; + void handleTextPicking(int winPosX, int winPosY, cvf::HitItemCollection* hitItems); }; diff --git a/ApplicationCode/UserInterface/RiuWellAllocationPlot.cpp b/ApplicationCode/UserInterface/RiuWellAllocationPlot.cpp index 0b13abacdb..518208df9c 100644 --- a/ApplicationCode/UserInterface/RiuWellAllocationPlot.cpp +++ b/ApplicationCode/UserInterface/RiuWellAllocationPlot.cpp @@ -104,10 +104,6 @@ RiuWellAllocationPlot::RiuWellAllocationPlot(RimWellAllocationPlot* plotDefiniti //-------------------------------------------------------------------------------------------------- RiuWellAllocationPlot::~RiuWellAllocationPlot() { - if (m_plotDefinition) - { - m_plotDefinition->handleMdiWindowClosed(); - } } //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/UserInterface/RiuWellLogPlot.cpp b/ApplicationCode/UserInterface/RiuWellLogPlot.cpp index 00dc18b030..65875b9e36 100644 --- a/ApplicationCode/UserInterface/RiuWellLogPlot.cpp +++ b/ApplicationCode/UserInterface/RiuWellLogPlot.cpp @@ -44,7 +44,7 @@ #include #include -#include +#include //-------------------------------------------------------------------------------------------------- /// @@ -85,7 +85,6 @@ RiuWellLogPlot::~RiuWellLogPlot() if (m_plotDefinition) { m_plotDefinition->detachAllCurves(); - m_plotDefinition->handleMdiWindowClosed(); } } diff --git a/ApplicationCode/UserInterface/RiuWellLogTrack.cpp b/ApplicationCode/UserInterface/RiuWellLogTrack.cpp index bb459de35d..d12ecd2845 100644 --- a/ApplicationCode/UserInterface/RiuWellLogTrack.cpp +++ b/ApplicationCode/UserInterface/RiuWellLogTrack.cpp @@ -27,6 +27,7 @@ #include "RiuPlotMainWindowTools.h" #include "RiuQwtCurvePointTracker.h" +#include "RiuQwtPlotTools.h" #include "RiuQwtLinearScaleEngine.h" @@ -45,8 +46,7 @@ #include #include -#include -#include "RiuSummaryQwtPlot.h" +#include #define RIU_SCROLLWHEEL_ZOOMFACTOR 1.1 #define RIU_SCROLLWHEEL_PANFACTOR 0.1 @@ -77,7 +77,7 @@ RiuWellLogTrack::~RiuWellLogTrack() //-------------------------------------------------------------------------------------------------- void RiuWellLogTrack::setDefaults() { - RiuSummaryQwtPlot::setCommonPlotBehaviour(this); + RiuQwtPlotTools::setCommonPlotBehaviour(this); enableAxis(QwtPlot::xTop, true); enableAxis(QwtPlot::yLeft, true); diff --git a/ApplicationCode/UserInterface/RiuWellPathComponentPlotItem.cpp b/ApplicationCode/UserInterface/RiuWellPathComponentPlotItem.cpp index 9318879725..14e497170e 100644 --- a/ApplicationCode/UserInterface/RiuWellPathComponentPlotItem.cpp +++ b/ApplicationCode/UserInterface/RiuWellPathComponentPlotItem.cpp @@ -50,6 +50,7 @@ RiuWellPathComponentPlotItem::RiuWellPathComponentPlotItem(const RimWellPath* we , m_componentType(RiaDefines::WELL_PATH) , m_columnOffset(0.0) , m_depthType(RimWellLogPlot::MEASURED_DEPTH) + , m_maxColumnOffset(0.0) , m_showLabel(false) { CVF_ASSERT(wellPath); @@ -68,6 +69,7 @@ RiuWellPathComponentPlotItem::RiuWellPathComponentPlotItem(const RimWellPath* we : m_wellPath(wellPath) , m_columnOffset(0.0) , m_depthType(RimWellLogPlot::MEASURED_DEPTH) + , m_maxColumnOffset(0.0) , m_showLabel(false) { CVF_ASSERT(wellPath && component); @@ -306,7 +308,7 @@ QwtPlotItem* RiuWellPathComponentPlotItem::createMarker(double posX, double dept QColor textColor = RiaColorTools::toQColor(baseColor.toColor3f(), 1.0); if (contrastTextColor) { - textColor = RiaColorTools::toQColor(RiaColorTools::constrastColor(baseColor.toColor3f())); + textColor = RiaColorTools::toQColor(RiaColorTools::contrastColor(baseColor.toColor3f())); } QwtPlotMarker* marker = new QwtPlotMarker(label); RiuQwtSymbol* symbol = new RiuQwtSymbol(symbolType, "", RiuQwtSymbol::LabelRightOfSymbol); diff --git a/ApplicationCode/UserInterface/RiuWellPltPlot.cpp b/ApplicationCode/UserInterface/RiuWellPltPlot.cpp index c02ee9da41..0a9852f412 100644 --- a/ApplicationCode/UserInterface/RiuWellPltPlot.cpp +++ b/ApplicationCode/UserInterface/RiuWellPltPlot.cpp @@ -87,10 +87,6 @@ RiuWellPltPlot::RiuWellPltPlot(RimWellPltPlot* plotDefinition, QWidget* parent) //-------------------------------------------------------------------------------------------------- RiuWellPltPlot::~RiuWellPltPlot() { - if (m_plotDefinition) - { - m_plotDefinition->handleMdiWindowClosed(); - } } //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/UserInterface/RiuWellRftPlot.cpp b/ApplicationCode/UserInterface/RiuWellRftPlot.cpp index ab25e0dda0..9c9b20537a 100644 --- a/ApplicationCode/UserInterface/RiuWellRftPlot.cpp +++ b/ApplicationCode/UserInterface/RiuWellRftPlot.cpp @@ -87,10 +87,6 @@ RiuWellRftPlot::RiuWellRftPlot(RimWellRftPlot* plotDefinition, QWidget* parent) //-------------------------------------------------------------------------------------------------- RiuWellRftPlot::~RiuWellRftPlot() { - if (m_plotDefinition) - { - m_plotDefinition->handleMdiWindowClosed(); - } } //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/UserInterface/RiuWidgetDragger.cpp b/ApplicationCode/UserInterface/RiuWidgetDragger.cpp index 6b2d327178..6f7036b047 100644 --- a/ApplicationCode/UserInterface/RiuWidgetDragger.cpp +++ b/ApplicationCode/UserInterface/RiuWidgetDragger.cpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018- Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -24,12 +24,22 @@ //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -RiuWidgetDragger::RiuWidgetDragger(QWidget* widgetToMove) +RiuWidgetDragger::RiuWidgetDragger(QWidget* widgetToMove, QWidget* widgetToSnapTo /*= nullptr*/, int snapMargins /*= 5*/) : QObject(widgetToMove) , m_widgetToMove(widgetToMove) + , m_widgetToSnapTo(widgetToSnapTo) + , m_snapMargins(snapMargins) , m_startPos(0,0) { - m_widgetToMove->installEventFilter(this); + addWidget(m_widgetToMove); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuWidgetDragger::addWidget(QWidget* widget) +{ + widget->installEventFilter(this); } //-------------------------------------------------------------------------------------------------- @@ -42,13 +52,75 @@ bool RiuWidgetDragger::eventFilter(QObject * watched, QEvent * event) QMouseEvent* mMoveEv = static_cast(event); if (mMoveEv->buttons() & Qt::LeftButton) { - m_widgetToMove->move( m_widgetToMove->mapToParent(mMoveEv->pos() - m_startPos)); + QPoint relativeMove = mMoveEv->pos() - m_startPos; + QRect newFrameRect = m_widgetToMove->frameGeometry().translated(relativeMove); + + if (m_widgetToSnapTo) + { + QRect snapToRect = m_widgetToSnapTo->frameGeometry(); + { + QPoint snapToTopLeft = snapToRect.topLeft(); + QPoint widgetTopLeft = newFrameRect.topLeft(); + QPoint diff = snapToTopLeft - widgetTopLeft; + if (std::abs(diff.x()) < 4 * m_snapMargins) + { + newFrameRect.moveLeft(snapToTopLeft.x() + m_snapMargins); + } + if (std::abs(diff.y()) < 4 * m_snapMargins) + { + newFrameRect.moveTop(snapToTopLeft.y() + m_snapMargins); + } + } + { + QPoint snapToBottomLeft = snapToRect.bottomLeft(); + QPoint widgetBottomLeft = newFrameRect.bottomLeft(); + QPoint diff = snapToBottomLeft - widgetBottomLeft; + if (std::abs(diff.x()) < 4 * m_snapMargins) + { + newFrameRect.moveLeft(snapToBottomLeft.x() + m_snapMargins); + } + if (std::abs(diff.y()) < 4 * m_snapMargins) + { + newFrameRect.moveBottom(snapToBottomLeft.y() - m_snapMargins); + } + } + { + QPoint snapToTopRight = snapToRect.topRight(); + QPoint widgetTopRight = newFrameRect.topRight(); + QPoint diff = snapToTopRight - widgetTopRight; + if (std::abs(diff.x()) < 4 * m_snapMargins) + { + newFrameRect.moveRight(snapToTopRight.x() - m_snapMargins); + } + if (std::abs(diff.y()) < 4 * m_snapMargins) + { + newFrameRect.moveTop(snapToTopRight.y() + m_snapMargins); + } + } + { + QPoint snapToBottomRight = snapToRect.bottomRight(); + QPoint widgetBottomRight = newFrameRect.bottomRight(); + QPoint diff = snapToBottomRight - widgetBottomRight; + if (std::abs(diff.x()) < 4 * m_snapMargins) + { + newFrameRect.moveRight(snapToBottomRight.x() - m_snapMargins); + } + if (std::abs(diff.y()) < 4 * m_snapMargins) + { + newFrameRect.moveBottom(snapToBottomRight.y() - m_snapMargins); + } + } + + } + m_widgetToMove->move(newFrameRect.topLeft()); + return true; } } else if (event->type() == QEvent::MouseButtonPress) { QMouseEvent* mEv = static_cast(event); m_startPos = mEv->pos(); + return true; } return false; diff --git a/ApplicationCode/UserInterface/RiuWidgetDragger.h b/ApplicationCode/UserInterface/RiuWidgetDragger.h index 9b51f3f5a0..f3b6aadc8c 100644 --- a/ApplicationCode/UserInterface/RiuWidgetDragger.h +++ b/ApplicationCode/UserInterface/RiuWidgetDragger.h @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018- Statoil ASA +// Copyright (C) 2018- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -28,13 +28,16 @@ class RiuWidgetDragger : public QObject { Q_OBJECT public: - RiuWidgetDragger(QWidget* widgetToMove); + RiuWidgetDragger(QWidget* widgetToMove, QWidget* widgetToSnapTo = nullptr, int snapMargins = 5); + void addWidget(QWidget* widget); bool eventFilter(QObject * watched, QEvent * event) override; private: QPointer m_widgetToMove; - QPoint m_startPos; + QPointer m_widgetToSnapTo; + int m_snapMargins; + QPoint m_startPos; }; diff --git a/ApplicationCode/WellPathImportSsihub/CMakeLists.txt b/ApplicationCode/WellPathImportSsihub/CMakeLists.txt index acaa843178..70912c0815 100644 --- a/ApplicationCode/WellPathImportSsihub/CMakeLists.txt +++ b/ApplicationCode/WellPathImportSsihub/CMakeLists.txt @@ -2,8 +2,19 @@ cmake_minimum_required (VERSION 2.8.12) project (WellPathImportSsihub) +if (RESINSIGHT_BUILD_WITH_QT5) + find_package(Qt5 COMPONENTS Core QUIET) +endif(RESINSIGHT_BUILD_WITH_QT5) + +if (Qt5Core_FOUND) + find_package(Qt5 CONFIG REQUIRED Core Network) +else() + find_package(Qt4 COMPONENTS QtCore QtNetwork REQUIRED) + include(${QT_USE_FILE}) +endif(Qt5Core_FOUND) + # These headers need to go through Qt's MOC compiler -set( QOBJECT_HEADERS +set( QT_MOC_HEADERS RiuWellImportWizard.h ) @@ -12,8 +23,13 @@ set( QT_UI_FILES ) if ( NOT CMAKE_AUTOMOC ) - qt4_wrap_cpp( MOC_FILES_CPP ${QOBJECT_HEADERS} ) - qt4_wrap_ui( FORM_FILES_CPP ${QT_UI_FILES} ) + if (Qt5Core_FOUND) + qt5_wrap_cpp(MOC_SOURCE_FILES ${QT_MOC_HEADERS} ) + qt5_wrap_ui( FORM_FILES_CPP ${QT_UI_FILES} ) + else() + qt4_wrap_cpp(MOC_SOURCE_FILES ${QT_MOC_HEADERS} ) + qt4_wrap_ui( FORM_FILES_CPP ${QT_UI_FILES} ) + endif() endif() include_directories( @@ -37,13 +53,17 @@ add_library( ${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/../FileInterface/RifJsonEncodeDecode.cpp - ${MOC_FILES_CPP} + ${MOC_SOURCE_FILES} ${FORM_FILES_CPP} ${HEADER_FILES} ) +if (Qt5Core_FOUND) + set(QT_LIBRARIES Qt5::Core Qt5::Network) +endif() + target_link_libraries ( ${PROJECT_NAME} - cafUserInterface cafPdmCvf CommonCode + cafUserInterface cafPdmCvf CommonCode ${QT_LIBRARIES} ) source_group("" FILES ${PROJECT_FILES}) diff --git a/ApplicationCode/WellPathImportSsihub/RimOilFieldEntry.h b/ApplicationCode/WellPathImportSsihub/RimOilFieldEntry.h index bbe2bdac45..6fe7faf1c8 100644 --- a/ApplicationCode/WellPathImportSsihub/RimOilFieldEntry.h +++ b/ApplicationCode/WellPathImportSsihub/RimOilFieldEntry.h @@ -32,7 +32,7 @@ class RimOilFieldEntry : public caf::PdmObject public: RimOilFieldEntry(); - ~RimOilFieldEntry(); + ~RimOilFieldEntry() override; caf::PdmField name; @@ -45,10 +45,10 @@ class RimOilFieldEntry : public caf::PdmObject RimWellPathEntry* find(const QString& name, RimWellPathEntry::WellTypeEnum wellPathType); - virtual caf::PdmFieldHandle* userDescriptionField(); - virtual caf::PdmFieldHandle* objectToggleField(); - virtual void fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue); - virtual void initAfterRead(); + caf::PdmFieldHandle* userDescriptionField() override; + caf::PdmFieldHandle* objectToggleField() override; + void fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue) override; + void initAfterRead() override; //private: void updateEnabledState(); diff --git a/ApplicationCode/WellPathImportSsihub/RimOilRegionEntry.h b/ApplicationCode/WellPathImportSsihub/RimOilRegionEntry.h index 110a53fa28..eb81d2546c 100644 --- a/ApplicationCode/WellPathImportSsihub/RimOilRegionEntry.h +++ b/ApplicationCode/WellPathImportSsihub/RimOilRegionEntry.h @@ -31,12 +31,12 @@ class RimOilRegionEntry : public caf::PdmObject public: RimOilRegionEntry(); - ~RimOilRegionEntry(); + ~RimOilRegionEntry() override; - virtual caf::PdmFieldHandle* userDescriptionField(); - virtual caf::PdmFieldHandle* objectToggleField(); + caf::PdmFieldHandle* userDescriptionField() override; + caf::PdmFieldHandle* objectToggleField() override; - virtual void fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue); + void fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue) override; void updateState(); diff --git a/ApplicationCode/WellPathImportSsihub/RimWellPathImport.h b/ApplicationCode/WellPathImportSsihub/RimWellPathImport.h index bba20d4aae..411aae8456 100644 --- a/ApplicationCode/WellPathImportSsihub/RimWellPathImport.h +++ b/ApplicationCode/WellPathImportSsihub/RimWellPathImport.h @@ -41,7 +41,7 @@ class RimWellPathImport : public caf::PdmObject public: RimWellPathImport(); - ~RimWellPathImport(); + ~RimWellPathImport() override; caf::PdmField wellTypeSurvey; caf::PdmField wellTypePlans; @@ -56,9 +56,9 @@ class RimWellPathImport : public caf::PdmObject void updateRegions(const QStringList& regions, const QStringList& fields, const QStringList& edmIds); - virtual void initAfterRead(); - virtual void fieldChangedByUi( const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue ); - virtual void defineObjectEditorAttribute( QString uiConfigName, caf::PdmUiEditorAttribute * attribute ); + void initAfterRead() override; + void fieldChangedByUi( const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue ) override; + void defineObjectEditorAttribute( QString uiConfigName, caf::PdmUiEditorAttribute * attribute ) override; void updateFieldVisibility(); diff --git a/ApplicationCode/WellPathImportSsihub/RimWellsEntry.h b/ApplicationCode/WellPathImportSsihub/RimWellsEntry.h index 268362f395..d9739a310b 100644 --- a/ApplicationCode/WellPathImportSsihub/RimWellsEntry.h +++ b/ApplicationCode/WellPathImportSsihub/RimWellsEntry.h @@ -44,8 +44,8 @@ class RimWellPathEntry : public caf::PdmObject static RimWellPathEntry* createWellPathEntry(const QString& name, const QString& surveyType, const QString& requestUrl, const QString& absolutePath, WellTypeEnum wellType); - virtual caf::PdmFieldHandle* userDescriptionField(); - virtual caf::PdmFieldHandle* objectToggleField(); + caf::PdmFieldHandle* userDescriptionField() override; + caf::PdmFieldHandle* objectToggleField() override; caf::PdmField name; caf::PdmField selected; diff --git a/ApplicationCode/WellPathImportSsihub/RiuWellImportWizard.cpp b/ApplicationCode/WellPathImportSsihub/RiuWellImportWizard.cpp index 859018bb81..c9fa8714a8 100644 --- a/ApplicationCode/WellPathImportSsihub/RiuWellImportWizard.cpp +++ b/ApplicationCode/WellPathImportSsihub/RiuWellImportWizard.cpp @@ -36,7 +36,11 @@ #include #include #include +#if QT_VERSION >= 0x050000 +#include +#else #include +#endif #include #include @@ -324,7 +328,11 @@ void RiuWellImportWizard::startRequest(QUrl url) if (supportsSsl) { QSslConfiguration config = QSslConfiguration::defaultConfiguration(); +#if QT_VERSION >= 0x050000 + config.setProtocol(QSsl::TlsV1_0); +#else config.setProtocol(QSsl::TlsV1); +#endif request.setSslConfiguration(config); } #endif diff --git a/ApplicationCode/WellPathImportSsihub/RiuWellImportWizard.h b/ApplicationCode/WellPathImportSsihub/RiuWellImportWizard.h index 1fb9b20f6c..fea1daff9f 100644 --- a/ApplicationCode/WellPathImportSsihub/RiuWellImportWizard.h +++ b/ApplicationCode/WellPathImportSsihub/RiuWellImportWizard.h @@ -59,7 +59,7 @@ class AuthenticationPage : public QWizardPage public: AuthenticationPage(const QString& webServiceAddress, QWidget *parent = nullptr); - virtual void initializePage(); + void initializePage() override; }; @@ -72,9 +72,9 @@ class FieldSelectionPage : public QWizardPage public: FieldSelectionPage(RimWellPathImport* wellPathImport, QWidget* parent = nullptr); - ~FieldSelectionPage(); + ~FieldSelectionPage() override; - virtual void initializePage(); + void initializePage() override; private: caf::PdmUiPropertyView* m_propertyView; @@ -90,7 +90,7 @@ class ObjectGroupWithHeaders : public caf::PdmObjectCollection public: ObjectGroupWithHeaders() {}; - virtual void defineObjectEditorAttribute(QString uiConfigName, caf::PdmUiEditorAttribute * attribute); + void defineObjectEditorAttribute(QString uiConfigName, caf::PdmUiEditorAttribute * attribute) override; }; //-------------------------------------------------------------------------------------------------- @@ -128,9 +128,9 @@ class WellSelectionPage : public QWizardPage public: WellSelectionPage(RimWellPathImport* wellPathImport, QWidget* parent = nullptr); - ~WellSelectionPage(); + ~WellSelectionPage() override; - virtual void initializePage(); + void initializePage() override; void buildWellTreeView(); void selectedWellPathEntries(std::vector& downloadEntities, caf::PdmObjectHandle* objHandle); @@ -155,7 +155,7 @@ class WellSummaryPage : public QWizardPage public: WellSummaryPage(RimWellPathImport* wellPathImport, QWidget* parent = nullptr); - virtual void initializePage(); + void initializePage() override; void updateSummaryPage(); @@ -183,7 +183,7 @@ class RiuWellImportWizard : public QWizard public: RiuWellImportWizard(const QString& webServiceAddress, const QString& downloadFolder, RimWellPathImport* wellPathImportObject, QWidget *parent = nullptr); - ~RiuWellImportWizard(); + ~RiuWellImportWizard() override; void setCredentials(const QString& username, const QString& password); QStringList absoluteFilePathsToWellPaths() const; diff --git a/ApplicationCode/WellPathImportSsihubTestApp/CMakeLists.txt b/ApplicationCode/WellPathImportSsihubTestApp/CMakeLists.txt index 020f3032e9..e7727c021e 100644 --- a/ApplicationCode/WellPathImportSsihubTestApp/CMakeLists.txt +++ b/ApplicationCode/WellPathImportSsihubTestApp/CMakeLists.txt @@ -3,9 +3,19 @@ cmake_minimum_required (VERSION 2.8) project ( WellPathImportSsihubTestApp ) -set (QT_COMPONENTS_REQUIRED QtCore QtGui QtMain QtOpenGl QtNetwork QtScript QtScriptTools) -find_package (Qt4 COMPONENTS ${QT_COMPONENTS_REQUIRED} REQUIRED) -include (${QT_USE_FILE}) +find_package(Qt5 CONFIG COMPONENTS Core) +if (Qt5Core_FOUND) + message(STATUS "Found Qt5") + find_package(Qt5 CONFIG REQUIRED Core Gui OpenGl Network Script ScriptTools Widgets) +else() + set (QT_COMPONENTS_REQUIRED QtCore QtGui QtMain QtOpenGl QtNetwork QtScript QtScriptTools) + find_package(Qt4 COMPONENTS ${QT_COMPONENTS_REQUIRED} REQUIRED) + include(${QT_USE_FILE}) + if (QT4_FOUND) + message(STATUS "Found Qt4") + endif(QT4_FOUND) +endif(Qt5Core_FOUND) + # Open GL find_package( OpenGL ) @@ -29,18 +39,26 @@ include_directories( set ( QT_MOC_HEADERS ) -qt4_wrap_cpp( MOC_FILES_CPP - ${QT_MOC_HEADERS} -) +if (Qt5Core_FOUND) + qt5_wrap_cpp(MOC_SOURCE_FILES ${MOC_HEADER_FILES} ) +else() + qt4_wrap_cpp(MOC_SOURCE_FILES ${MOC_HEADER_FILES} ) +endif() # Resource file set( QRC_FILES ) # Runs RCC on specified files -qt4_add_resources( QRC_FILES_CPP - ${QRC_FILES} -) +if (Qt5Core_FOUND) + qt5_add_resources( QRC_FILES_CPP + ${QRC_FILES} + ) +else() + qt4_add_resources( QRC_FILES_CPP + ${QRC_FILES} + ) +endif() # add the executable @@ -48,10 +66,14 @@ add_executable ( ${PROJECT_NAME} main.cpp TestTools.cpp TestTools.h - ${MOC_FILES_CPP} + ${MOC_SOURCE_FILES} ${QRC_FILES_CPP} ) +if (Qt5Core_FOUND) + set(QT_LIBRARIES Qt5::Core Qt5::Gui Qt5::OpenGl Qt5::Network Qt5::Script Qt5::ScriptTools Qt5::Widgets) +endif() + target_link_libraries ( ${PROJECT_NAME} cafProjectDataModel @@ -62,13 +84,23 @@ target_link_libraries ( ${PROJECT_NAME} ) # Copy Qt Dlls -if (MSVC) - foreach (qtlib ${QT_COMPONENTS_REQUIRED}) - - # Debug - execute_process(COMMAND cmake -E copy_if_different ${QT_BINARY_DIR}/${qtlib}d4.dll ${CMAKE_CURRENT_BINARY_DIR}/Debug/${qtlib}d4.dll) - - # Release - execute_process(COMMAND cmake -E copy_if_different ${QT_BINARY_DIR}/${qtlib}4.dll ${CMAKE_CURRENT_BINARY_DIR}/Release/${qtlib}4.dll) - endforeach( qtlib ) -endif(MSVC) +if (Qt5Core_FOUND) + foreach (qtlib ${QT_LIBRARIES}) + add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_if_different $ $ + ) + endforeach(qtlib) + # Copy Qt Dlls +else() + # Copy Qt Dlls + if (MSVC) + foreach (qtlib ${QT_COMPONENTS_REQUIRED}) + + # Debug + execute_process(COMMAND cmake -E copy_if_different ${QT_BINARY_DIR}/${qtlib}d4.dll ${CMAKE_BINARY_DIR}/Debug/${qtlib}d4.dll) + + # Release + execute_process(COMMAND cmake -E copy_if_different ${QT_BINARY_DIR}/${qtlib}4.dll ${CMAKE_BINARY_DIR}/Release/${qtlib}4.dll) + endforeach( qtlib ) + endif(MSVC) +endif(Qt5Core_FOUND) diff --git a/CMakeLists.txt b/CMakeLists.txt index 044eef0717..b68717c2ad 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,10 +5,13 @@ project (ResInsight) set (VIZ_MODULES_FOLDER_NAME Fwk/VizFwk) +cmake_policy(SET CMP0020 NEW) set_property(GLOBAL PROPERTY USE_FOLDERS ON) SET(BUILD_SHARED_LIBS OFF CACHE BOOL "ERT: Build shared libraries") +list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake") + ################################################################################ # Setup the main platform defines ################################################################################ @@ -50,6 +53,11 @@ endif() include (ResInsightVersion.cmake) +################################################################################ +# Octave +################################################################################ +find_package(Octave) + ################################################################################ # cotire # Fully automated CMake module for build speedup @@ -59,11 +67,17 @@ include (ResInsightVersion.cmake) option(RESINSIGHT_ENABLE_COTIRE "Experimental speedup of compilation using cotire" OFF) mark_as_advanced(FORCE RESINSIGHT_ENABLE_COTIRE) if(RESINSIGHT_ENABLE_COTIRE) - set (CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake") - include(cotire) + if(NOT COTIRE_MAXIMUM_NUMBER_OF_UNITY_INCLUDES) + message(STATUS "cotire: Setting default number of includes to 5") + set(COTIRE_MAXIMUM_NUMBER_OF_UNITY_INCLUDES 5) + endif() + + include(cotire) endif() +# always include cotire tools to avoid checking if a macro is available +include(cafCotireTools) ################################################################################ # ERT @@ -179,6 +193,14 @@ if (RESINSIGHT_ENABLE_PROTOTYPE_FEATURE_SOURING) set(RESINSIGHT_FOUND_HDF5 1) message( STATUS "Using HDF5 libraries : ${HDF5_LIBRARIES}" ) + + option (RESINSIGHT_HDF5_BUNDLE_LIBRARIES "Bundle HDF5 libraries" OFF) + mark_as_advanced(FORCE RESINSIGHT_HDF5_BUNDLE_LIBRARIES) + if (RESINSIGHT_HDF5_BUNDLE_LIBRARIES) + message( STATUS "Bundling of HDF5 libraries is enabled" ) + endif() # RESINSIGHT_HDF5_BUNDLE_LIBRARIES + + else() message( WARNING "Use of HDF5 is enabled, but no HDF5 is found." ) endif() # HDF5_FOUND @@ -231,17 +253,27 @@ list(APPEND THIRD_PARTY_LIBRARIES ################################################################################ # Qt ################################################################################ -set (QT_COMPONENTS_REQUIRED QtCore QtGui QtMain QtOpenGl QtNetwork QtScript QtScriptTools) -find_package (Qt4 COMPONENTS ${QT_COMPONENTS_REQUIRED}) -if ( NOT QT4_FOUND ) - message(FATAL_ERROR "Package Qt4 is required, but not found. Please specify qmake for variable QT_QMAKE_EXECUTABLE") -endif ( NOT QT4_FOUND ) - -if (QT_VERSION_MINOR LESS 6) - message(FATAL_ERROR "Qt 4.6 is required, please specify qmake for variable QT_QMAKE_EXECUTABLE") -endif() +option(RESINSIGHT_BUILD_WITH_QT5 "Use Qt5 folder" OFF) +if (RESINSIGHT_BUILD_WITH_QT5) + message(STATUS "Attempting to build with Qt5") + find_package(Qt5 COMPONENTS Core QUIET) +else() + message(STATUS "Attempting to build with Qt4") +endif(RESINSIGHT_BUILD_WITH_QT5) -include (${QT_USE_FILE}) +if (Qt5Core_FOUND) + message(STATUS "Found Qt5") + find_package (Qt5 CONFIG REQUIRED Core Widgets OpenGL Network Script ScriptTools) +else() + if (RESINSIGHT_BUILD_WITH_QT5) + message(WARNING "Could not find Qt5. Trying with Qt4") + endif(RESINSIGHT_BUILD_WITH_QT5) + find_package(Qt4 COMPONENTS QtCore QtGui QtMain REQUIRED) + if (QT_VERSION_MINOR LESS 6) + message(FATAL_ERROR "Qt 4.6 is required, please specify qmake for variable QT_QMAKE_EXECUTABLE") + endif() + include(${QT_USE_FILE}) +endif(Qt5Core_FOUND) # Open GL find_package( OpenGL ) @@ -317,14 +349,18 @@ if (CMAKE_COMPILER_IS_GNUCC) endif() if (HAVE_GCC_SYNC_FUNCTIONS) - message("GCC synchronization functions detected") + message(STATUS "GCC synchronization functions detected") else() - message("GCC synchronization functions NOT detected, fallback to non threadsafe reference counting") + message(STATUS "GCC synchronization functions NOT detected, fallback to non threadsafe reference counting") add_definitions(-DCVF_USE_NON_THREADSAFE_REFERENCE_COUNT) endif() endif() +if (RESINSIGHT_BUILD_WITH_QT5) + set(CEE_USE_QT5 ON) +endif(RESINSIGHT_BUILD_WITH_QT5) + add_subdirectory(${VIZ_MODULES_FOLDER_NAME}/LibCore) add_subdirectory(${VIZ_MODULES_FOLDER_NAME}/LibGeometry) add_subdirectory(${VIZ_MODULES_FOLDER_NAME}/LibRender) @@ -349,6 +385,10 @@ set_property(TARGET # Application Framework ################################################################################ +if (RESINSIGHT_BUILD_WITH_QT5) + set(CAF_USE_QT5 ON) +endif(RESINSIGHT_BUILD_WITH_QT5) + add_subdirectory(Fwk/AppFwk/cafAnimControl) add_subdirectory(Fwk/AppFwk/cafViewer) @@ -389,6 +429,24 @@ set_property(TARGET PROPERTY FOLDER "AppFwk" ) +option (RESINSIGHT_INCLUDE_APPFWK_TESTS "Enable AppFwk Tests" OFF) +if (RESINSIGHT_INCLUDE_APPFWK_TESTS) + # Unit Tests + add_subdirectory(Fwk/AppFwk/cafProjectDataModel/cafProjectDataModel_UnitTests) + set_property(TARGET cafProjectDataModel_UnitTests PROPERTY FOLDER "AppFwkTests") + + add_subdirectory(Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafPdmCore_UnitTests) + set_property(TARGET cafPdmCore_UnitTests PROPERTY FOLDER "AppFwkTests") + + add_subdirectory(Fwk/AppFwk/cafProjectDataModel/cafPdmXml/cafPdmXml_UnitTests) + set_property(TARGET cafPdmXml_UnitTests PROPERTY FOLDER "AppFwkTests") + + # Executables + add_subdirectory(Fwk/AppFwk/cafTests/cafTestApplication) + set_property(TARGET cafTestApplication PROPERTY FOLDER "AppFwkTests") +endif() + + ################################################################################ # Installation settings @@ -420,12 +478,42 @@ if (RESINSIGHT_PRIVATE_INSTALL) endif (RESINSIGHT_PRIVATE_INSTALL) +if (RESINSIGHT_HDF5_BUNDLE_LIBRARIES) + if (${CMAKE_SYSTEM_NAME} MATCHES "Linux") + foreach (FILE_TO_COPY ${HDF5_LIBRARIES}) + + # find all files containing the string "hdf" + STRING( FIND ${FILE_TO_COPY} "hdf5" POS_IN_STRING ) + if(${POS_IN_STRING} GREATER -1) + get_filename_component(ABS_DIR ${FILE_TO_COPY} REALPATH) + message (STATUS "HDF5 bundle file - ${ABS_DIR}") + + # as part of install, rename file with the extension ResInsight reports when running "ldd" + get_filename_component(FILE_NAME_WE ${FILE_TO_COPY} NAME_WE) + set(FILE_NAME_FOR_INSTALL "${FILE_NAME_WE}.so.6") + message (STATUS "HDF5 file FILE_NAME_FOR_INSTALL - ${FILE_NAME_FOR_INSTALL}") + + install(FILES ${ABS_DIR} DESTINATION ${RESINSIGHT_INSTALL_FOLDER} RENAME ${FILE_NAME_FOR_INSTALL} ) + endif() + endforeach() + + endif() + +endif (RESINSIGHT_HDF5_BUNDLE_LIBRARIES) + ################################################################################ # Application ################################################################################ add_subdirectory(ApplicationCode) -add_subdirectory(OctavePlugin) + +if (OCTAVE_MKOCTFILE) + message (STATUS "Adding OctavePlugin library") + + add_subdirectory(OctavePlugin) +else (OCTAVE_MKOCTFILE) + message (STATUS "Could not find OCTAVE_MKOCTFILE, skipping OctavePlugin library") +endif(OCTAVE_MKOCTFILE) ################################################################################ # Code documentation using Doxygen diff --git a/Fwk/AppFwk/CMakeLists.txt b/Fwk/AppFwk/CMakeLists.txt index 0bec5a502b..0fb421f1f8 100644 --- a/Fwk/AppFwk/CMakeLists.txt +++ b/Fwk/AppFwk/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required (VERSION 2.8) +cmake_minimum_required (VERSION 2.8.12) project (CeeApp) @@ -8,9 +8,13 @@ if (MSVC AND (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 19.11)) message("Add flag to disable warings from gtest - _SILENCE_TR1_NAMESPACE_DEPRECATION_WARNING") endif() - -find_package (Qt4 COMPONENTS QtCore QtGui QtMain QtOpenGl REQUIRED) -include (${QT_USE_FILE}) +find_package(Qt5Core CONFIG QUIET) +if (Qt5Core_FOUND) + find_package(Qt5 CONFIG REQUIRED Core Gui OpenGL Widgets) +else() + find_package(Qt4 COMPONENTS QtCore QtGui QtMain QtOpenGl REQUIRED) + include(${QT_USE_FILE}) +endif(Qt5Core_FOUND) if (${CMAKE_SYSTEM_NAME} MATCHES "Linux") set(CMAKE_CXX_FLAGS "-std=c++0x") diff --git a/Fwk/AppFwk/CommonCode/CMakeLists.txt b/Fwk/AppFwk/CommonCode/CMakeLists.txt index 7c1e353946..520f0ff860 100644 --- a/Fwk/AppFwk/CommonCode/CMakeLists.txt +++ b/Fwk/AppFwk/CommonCode/CMakeLists.txt @@ -3,18 +3,29 @@ cmake_minimum_required (VERSION 2.8.12) project (CommonCode) # Qt -find_package ( Qt4 COMPONENTS QtCore QtGui QtMain QtOpenGl ) -include (${QT_USE_FILE}) +if (CAF_USE_QT5) + find_package(Qt5 COMPONENTS Core Gui OpenGL Widgets REQUIRED) +else() + find_package(Qt4 COMPONENTS QtCore QtGui QtMain QtOpenGl REQUIRED) + include(${QT_USE_FILE}) +endif(CAF_USE_QT5) # Open GL find_package( OpenGL ) # These headers need to go through Qt's MOC compiler -set( QOBJECT_HEADERS +set( MOC_HEADER_FILES cafMessagePanel.h ) -qt4_wrap_cpp( MOC_FILES_CPP ${QOBJECT_HEADERS} ) +if ( NOT CMAKE_AUTOMOC ) + if (CAF_USE_QT5) + qt5_wrap_cpp(MOC_SOURCE_FILES ${MOC_HEADER_FILES} ) + else() + qt4_wrap_cpp(MOC_SOURCE_FILES ${MOC_HEADER_FILES} ) + endif(CAF_USE_QT5) +endif() + add_library( ${PROJECT_NAME} cafEffectCache.cpp @@ -44,7 +55,7 @@ add_library( ${PROJECT_NAME} cafVecIjk.cpp cafVecIjk.h - ${MOC_FILES_CPP} + ${MOC_SOURCE_FILES} ) target_include_directories(${PROJECT_NAME} @@ -52,6 +63,10 @@ target_include_directories(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR} ) +if (CAF_USE_QT5) + set(QT_LIBRARIES Qt5::Core Qt5::Gui Qt5::OpenGL Qt5::Widgets) +endif(CAF_USE_QT5) + target_link_libraries ( ${PROJECT_NAME} LibCore LibGeometry @@ -69,3 +84,11 @@ if (MSVC) endif() source_group("" FILES ${PROJECT_FILES}) + +# cotire +if (COMMAND caf_apply_cotire) + list(APPEND CAF_COTIRE_EXCLUDE_FILES + cafEffectGenerator.cpp + ) + caf_apply_cotire("${PROJECT_NAME}") +endif() diff --git a/Fwk/AppFwk/CommonCode/cafContourLines.cpp b/Fwk/AppFwk/CommonCode/cafContourLines.cpp index 9721166e30..dea695eca3 100644 --- a/Fwk/AppFwk/CommonCode/cafContourLines.cpp +++ b/Fwk/AppFwk/CommonCode/cafContourLines.cpp @@ -22,7 +22,10 @@ ///////////////////////////////////////////////////////////////////////////////// #include "cafContourLines.h" + #include +#include +#include const int caf::ContourLines::s_castab[3][3][3] = { @@ -67,7 +70,9 @@ void caf::ContourLines::create(const std::vector& dataXY, const std::vec temp2 = std::max(saneValue(gridIndex1d(i + 1, j, nx), dataXY, contourLevels), saneValue(gridIndex1d(i + 1, j + 1, nx), dataXY, contourLevels)); double dmax = std::max(temp1, temp2); - if (dmax < contourLevels[0] || dmin > contourLevels[nContourLevels - 1]) + // Using dmax <= contourLevels[0] as a deviation from Bourke because it empirically + // Reduces gridding artifacts in our code. + if (dmax <= contourLevels[0] || dmin > contourLevels[nContourLevels - 1]) continue; for (int k = 0; k < nContourLevels; k++) @@ -206,6 +211,38 @@ void caf::ContourLines::create(const std::vector& dataXY, const std::vec } /* j */ } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector caf::ContourLines::create(const std::vector& dataXY, + const std::vector& xPositions, + const std::vector& yPositions, + const std::vector& contourLevels) +{ + const double eps = 1.0e-4; + std::vector> contourLineSegments; + caf::ContourLines::create(dataXY, xPositions, yPositions, contourLevels, &contourLineSegments); + + std::vector listOfSegmentsPerLevel(contourLevels.size()); + + for (size_t i = 0; i < contourLevels.size(); ++i) + { + size_t nPoints = contourLineSegments[i].size(); + size_t nSegments = nPoints / 2; + if (nSegments >= 3u) // Need at least three segments for a closed polygon + { + ListOfLineSegments unorderedSegments; + for (size_t j = 0; j < contourLineSegments[i].size(); j += 2) + { + unorderedSegments.push_back(std::make_pair(cvf::Vec3d(contourLineSegments[i][j]), cvf::Vec3d(contourLineSegments[i][j + 1]))); + } + listOfSegmentsPerLevel[i] = unorderedSegments; + } + } + + return listOfSegmentsPerLevel; +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- diff --git a/Fwk/AppFwk/CommonCode/cafContourLines.h b/Fwk/AppFwk/CommonCode/cafContourLines.h index 62ef94be6e..f574db56ee 100644 --- a/Fwk/AppFwk/CommonCode/cafContourLines.h +++ b/Fwk/AppFwk/CommonCode/cafContourLines.h @@ -25,6 +25,11 @@ #include "cvfBase.h" #include "cvfVector2.h" +#include "cvfVector3.h" + +#include +#include +#include #include namespace caf @@ -32,12 +37,20 @@ namespace caf class ContourLines { public: + typedef std::pair LineSegment; + typedef std::list ListOfLineSegments; + + static std::vector create(const std::vector& dataXY, + const std::vector& xPositions, + const std::vector& yPositions, + const std::vector& contourLevels); + +private: static void create(const std::vector& dataXY, const std::vector& xPositions, const std::vector& yPositions, const std::vector& contourLevels, std::vector>* polygons); -private: static double contourRange(const std::vector& contourLevels); static double invalidValue(const std::vector& contourLevels); static double saneValue(int index, const std::vector& dataXY, const std::vector& contourLevels); diff --git a/Fwk/AppFwk/CommonCode/cafEffectGenerator.h b/Fwk/AppFwk/CommonCode/cafEffectGenerator.h index 4ed3278d02..5f8c3f6a3d 100644 --- a/Fwk/AppFwk/CommonCode/cafEffectGenerator.h +++ b/Fwk/AppFwk/CommonCode/cafEffectGenerator.h @@ -141,11 +141,11 @@ class SurfaceEffectGenerator : public EffectGenerator void enableLighting(bool enableLighting) { m_enableLighting = enableLighting; } protected: - virtual bool isEqual(const EffectGenerator* other) const; - virtual EffectGenerator* copy() const; + bool isEqual(const EffectGenerator* other) const override; + EffectGenerator* copy() const override; - virtual void updateForShaderBasedRendering(cvf::Effect* effect) const; - virtual void updateForFixedFunctionRendering(cvf::Effect* effect) const; + void updateForShaderBasedRendering(cvf::Effect* effect) const override; + void updateForFixedFunctionRendering(cvf::Effect* effect) const override; private: void updateCommonEffect(cvf::Effect* effect) const; @@ -183,11 +183,11 @@ class ScalarMapperEffectGenerator : public EffectGenerator static bool isImagesEqual(const cvf::TextureImage* texImg1, const cvf::TextureImage* texImg2); protected: - virtual bool isEqual(const EffectGenerator* other) const; - virtual EffectGenerator* copy() const; + bool isEqual(const EffectGenerator* other) const override; + EffectGenerator* copy() const override; - virtual void updateForShaderBasedRendering(cvf::Effect* effect) const; - virtual void updateForFixedFunctionRendering(cvf::Effect* effect) const; + void updateForShaderBasedRendering(cvf::Effect* effect) const override; + void updateForFixedFunctionRendering(cvf::Effect* effect) const override; private: void updateCommonEffect(cvf::Effect* effect) const; @@ -219,11 +219,11 @@ class ScalarMapperMeshEffectGenerator : public EffectGenerator void setUndefinedColor(cvf::Color3f color) { m_undefinedColor = color; } protected: - virtual bool isEqual(const EffectGenerator* other) const; - virtual EffectGenerator* copy() const; + bool isEqual(const EffectGenerator* other) const override; + EffectGenerator* copy() const override; - virtual void updateForShaderBasedRendering(cvf::Effect* effect) const; - virtual void updateForFixedFunctionRendering(cvf::Effect* effect) const; + void updateForShaderBasedRendering(cvf::Effect* effect) const override; + void updateForFixedFunctionRendering(cvf::Effect* effect) const override; private: void updateCommonEffect(cvf::Effect* effect) const; @@ -249,11 +249,11 @@ class MeshEffectGenerator : public EffectGenerator void setLineWidth(float lineWidth); protected: - virtual bool isEqual(const EffectGenerator* other) const; - virtual EffectGenerator* copy() const; + bool isEqual(const EffectGenerator* other) const override; + EffectGenerator* copy() const override; - virtual void updateForShaderBasedRendering(cvf::Effect* effect) const; - virtual void updateForFixedFunctionRendering(cvf::Effect* effect) const; + void updateForShaderBasedRendering(cvf::Effect* effect) const override; + void updateForFixedFunctionRendering(cvf::Effect* effect) const override; private: cvf::Color3f m_color; @@ -273,11 +273,11 @@ class TextEffectGenerator : public EffectGenerator TextEffectGenerator(); protected: - virtual bool isEqual(const EffectGenerator* other) const; - virtual EffectGenerator* copy() const; + bool isEqual(const EffectGenerator* other) const override; + EffectGenerator* copy() const override; - virtual void updateForShaderBasedRendering(cvf::Effect* effect) const; - virtual void updateForFixedFunctionRendering(cvf::Effect* effect) const; + void updateForShaderBasedRendering(cvf::Effect* effect) const override; + void updateForFixedFunctionRendering(cvf::Effect* effect) const override; }; @@ -292,10 +292,10 @@ class VectorEffectGenerator : public EffectGenerator VectorEffectGenerator(); protected: - virtual bool isEqual(const EffectGenerator* other) const; - virtual EffectGenerator* copy() const; + bool isEqual(const EffectGenerator* other) const override; + EffectGenerator* copy() const override; - virtual void updateForShaderBasedRendering(cvf::Effect* effect) const; - virtual void updateForFixedFunctionRendering(cvf::Effect* effect) const; + void updateForShaderBasedRendering(cvf::Effect* effect) const override; + void updateForFixedFunctionRendering(cvf::Effect* effect) const override; }; } diff --git a/Fwk/AppFwk/CommonCode/cafLog.cpp b/Fwk/AppFwk/CommonCode/cafLog.cpp index 523a80e40b..3c295b3de3 100644 --- a/Fwk/AppFwk/CommonCode/cafLog.cpp +++ b/Fwk/AppFwk/CommonCode/cafLog.cpp @@ -95,10 +95,10 @@ void Log::infoMultiLine(const QString& line1, const QString& line2Etc) if (generateTrace) { - cvf::Trace::show("INF: %s", (const char*)line1.toAscii()); + cvf::Trace::show("INF: %s", (const char*)line1.toLatin1()); if (!line2Etc.isEmpty()) { - cvf::Trace::show((const char*)Utils::indentString(5, line2Etc).toAscii()); + cvf::Trace::show((const char*)Utils::indentString(5, line2Etc).toLatin1()); } } } @@ -127,10 +127,10 @@ void Log::warningMultiLine(const QString& line1, const QString& line2Etc) if (generateTrace) { - cvf::Trace::show("WRN: %s", (const char*)line1.toAscii()); + cvf::Trace::show("WRN: %s", (const char*)line1.toLatin1()); if (!line2Etc.isEmpty()) { - cvf::Trace::show((const char*)Utils::indentString(5, line2Etc).toAscii()); + cvf::Trace::show((const char*)Utils::indentString(5, line2Etc).toLatin1()); } } } @@ -186,10 +186,10 @@ bool Log::errorMultiLine(const QString& line1, const QString& line2Etc) if (generateTrace) { - cvf::Trace::show("\nERR: %s", (const char*)line1.toAscii()); + cvf::Trace::show("\nERR: %s", (const char*)line1.toLatin1()); if (!line2Etc.isEmpty()) { - cvf::Trace::show((const char*)Utils::indentString(5, line2Etc).toAscii()); + cvf::Trace::show((const char*)Utils::indentString(5, line2Etc).toLatin1()); } } diff --git a/Fwk/AppFwk/CommonCode/cafMessagePanel.cpp b/Fwk/AppFwk/CommonCode/cafMessagePanel.cpp index b6945ef7da..34866aa354 100644 --- a/Fwk/AppFwk/CommonCode/cafMessagePanel.cpp +++ b/Fwk/AppFwk/CommonCode/cafMessagePanel.cpp @@ -37,10 +37,10 @@ #include "cafMessagePanel.h" -#include -#include -#include -#include +#include +#include +#include +#include namespace caf { diff --git a/Fwk/AppFwk/CommonCode/cafMessagePanel.h b/Fwk/AppFwk/CommonCode/cafMessagePanel.h index 57806df71e..fed05b7131 100644 --- a/Fwk/AppFwk/CommonCode/cafMessagePanel.h +++ b/Fwk/AppFwk/CommonCode/cafMessagePanel.h @@ -37,7 +37,7 @@ #pragma once -#include +#include class QDockWidget; class QTextEdit; @@ -63,7 +63,7 @@ class MessagePanel : public QWidget void showWarning(QString warn); void showError(QString error); - virtual QSize sizeHint () const; + QSize sizeHint () const override; bool isVisibleToUser(); private: diff --git a/Fwk/AppFwk/CommonCode/cafMouseState.cpp b/Fwk/AppFwk/CommonCode/cafMouseState.cpp index da4f6ccf64..0b4d930f8a 100644 --- a/Fwk/AppFwk/CommonCode/cafMouseState.cpp +++ b/Fwk/AppFwk/CommonCode/cafMouseState.cpp @@ -42,7 +42,7 @@ #include #include -#include +#include namespace caf { diff --git a/Fwk/AppFwk/CommonCode/cafUtils.cpp b/Fwk/AppFwk/CommonCode/cafUtils.cpp index e531f34338..04876063b8 100644 --- a/Fwk/AppFwk/CommonCode/cafUtils.cpp +++ b/Fwk/AppFwk/CommonCode/cafUtils.cpp @@ -40,7 +40,7 @@ #include #include -#include +#include #include diff --git a/Fwk/AppFwk/CommonCode/cvfStructGridGeometryGenerator.h b/Fwk/AppFwk/CommonCode/cvfStructGridGeometryGenerator.h index 2308348b76..ade37fbdbc 100644 --- a/Fwk/AppFwk/CommonCode/cvfStructGridGeometryGenerator.h +++ b/Fwk/AppFwk/CommonCode/cvfStructGridGeometryGenerator.h @@ -165,7 +165,7 @@ class StructGridGeometryGenerator : public Object { public: explicit StructGridGeometryGenerator(const StructGridInterface* grid, bool useOpenMP); - ~StructGridGeometryGenerator(); + ~StructGridGeometryGenerator() override; // Setup methods diff --git a/Fwk/AppFwk/cafAnimControl/CMakeLists.txt b/Fwk/AppFwk/cafAnimControl/CMakeLists.txt index 5e016e8180..bcefe1d8dc 100644 --- a/Fwk/AppFwk/cafAnimControl/CMakeLists.txt +++ b/Fwk/AppFwk/cafAnimControl/CMakeLists.txt @@ -3,17 +3,25 @@ cmake_minimum_required (VERSION 2.8.12) project (cafAnimControl) # Qt -find_package ( Qt4 COMPONENTS QtCore QtGui QtMain ) -include (${QT_USE_FILE}) +if (CAF_USE_QT5) + find_package(Qt5 COMPONENTS Core Gui OpenGL Widgets REQUIRED) +else() + find_package(Qt4 COMPONENTS QtCore QtGui QtMain REQUIRED) + include(${QT_USE_FILE}) +endif(CAF_USE_QT5) -set( QOBJECT_HEADERS + +set( MOC_HEADER_FILES cafFrameAnimationControl.h cafAnimationToolBar.h + cafPopupMenuButton.h ) -if ( NOT CMAKE_AUTOMOC ) - qt4_wrap_cpp( MOC_FILES_CPP ${QOBJECT_HEADERS} ) -endif() +if (CAF_USE_QT5) + qt5_wrap_cpp(MOC_SOURCE_FILES ${MOC_HEADER_FILES} ) +else() + qt4_wrap_cpp(MOC_SOURCE_FILES ${MOC_HEADER_FILES} ) +endif(CAF_USE_QT5) # NOTE! Resources in this subfolder appends to the variable QRC_FILES in parent scope # CMakeList.txt in the application folder (parent scope) must use the following syntax @@ -35,11 +43,13 @@ set( PROJECT_FILES cafFrameAnimationControl.cpp cafAnimationToolBar.h cafAnimationToolBar.cpp + cafPopupMenuButton.h + cafPopupMenuButton.cpp ) add_library( ${PROJECT_NAME} ${PROJECT_FILES} - ${MOC_FILES_CPP} + ${MOC_SOURCE_FILES} ) target_include_directories(${PROJECT_NAME} @@ -47,6 +57,12 @@ target_include_directories(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR} ) +if (CAF_USE_QT5) + set(QT_LIBRARIES Qt5::Core Qt5::Gui Qt5::Widgets) +endif(CAF_USE_QT5) + +target_link_libraries(${PROJECT_NAME} ${QT_LIBRARIES}) + if (MSVC) set_target_properties(${PROJECT_NAME} PROPERTIES COMPILE_FLAGS "/W4 /wd4127") endif() diff --git a/Fwk/AppFwk/cafAnimControl/Resources/FastHorizontal.png b/Fwk/AppFwk/cafAnimControl/Resources/FastHorizontal.png new file mode 100644 index 0000000000..a1bcf4fb4c Binary files /dev/null and b/Fwk/AppFwk/cafAnimControl/Resources/FastHorizontal.png differ diff --git a/Fwk/AppFwk/cafAnimControl/Resources/Play.png b/Fwk/AppFwk/cafAnimControl/Resources/Play.png index 658ae204df..9ccc5952d1 100644 Binary files a/Fwk/AppFwk/cafAnimControl/Resources/Play.png and b/Fwk/AppFwk/cafAnimControl/Resources/Play.png differ diff --git a/Fwk/AppFwk/cafAnimControl/Resources/SlowHorizontal.png b/Fwk/AppFwk/cafAnimControl/Resources/SlowHorizontal.png new file mode 100644 index 0000000000..5fa1d46b8f Binary files /dev/null and b/Fwk/AppFwk/cafAnimControl/Resources/SlowHorizontal.png differ diff --git a/Fwk/AppFwk/cafAnimControl/Resources/Speed.png b/Fwk/AppFwk/cafAnimControl/Resources/Speed.png new file mode 100644 index 0000000000..6ce81bbd44 Binary files /dev/null and b/Fwk/AppFwk/cafAnimControl/Resources/Speed.png differ diff --git a/Fwk/AppFwk/cafAnimControl/Resources/cafAnimControl.qrc b/Fwk/AppFwk/cafAnimControl/Resources/cafAnimControl.qrc index f599c5919c..33024f7e8e 100644 --- a/Fwk/AppFwk/cafAnimControl/Resources/cafAnimControl.qrc +++ b/Fwk/AppFwk/cafAnimControl/Resources/cafAnimControl.qrc @@ -12,5 +12,8 @@ PlayBwd.png Slow.png Fast.png + SlowHorizontal.png + FastHorizontal.png + Speed.png
diff --git a/Fwk/AppFwk/cafAnimControl/cafAnimationToolBar.cpp b/Fwk/AppFwk/cafAnimControl/cafAnimationToolBar.cpp index 0ad39ec519..fe37b4c74b 100644 --- a/Fwk/AppFwk/cafAnimControl/cafAnimationToolBar.cpp +++ b/Fwk/AppFwk/cafAnimControl/cafAnimationToolBar.cpp @@ -37,11 +37,13 @@ #include "cafAnimationToolBar.h" +#include "cafPopupMenuButton.h" + #include #include #include #include - +#include namespace caf { @@ -50,7 +52,7 @@ namespace caf /// //-------------------------------------------------------------------------------------------------- AnimationToolBar::AnimationToolBar(QWidget *parent /*= 0*/) - : QToolBar (parent) + : QToolBar (parent) { setObjectName("AnimationToolBar"); init(); @@ -78,33 +80,43 @@ void AnimationToolBar::init() // Create actions and widgets m_animSkipToStartAction = new QAction(QIcon(":/cafAnimControl/SkipToStart.png"), tr("Skip to Start"), this); m_animStepBackwardAction = new QAction(QIcon(":/cafAnimControl/StepBwd.png"), tr("Step Backward"), this); - m_animPlayBwdAction = new QAction(QIcon(":/cafAnimControl/PlayBwd.png"), tr("Play Backwards"), this); - m_animStopAction = new QAction(QIcon(":/cafAnimControl/Stop.png"), tr("Stop"), this); m_animPauseAction = new QAction(QIcon(":/cafAnimControl/Pause.png"), tr("Pause"), this); m_animPlayAction = new QAction(QIcon(":/cafAnimControl/Play.png"), tr("Play"), this); + m_animPlayPauseButton = new QToolButton(this); + m_animPlayPauseButton->setIcon(m_animPlayAction->icon()); + m_animPlayPauseButton->setToolTip(m_animPlayAction->toolTip()); + QObject::connect(m_animPlayPauseButton, SIGNAL(clicked()), this, SLOT(playPauseChanged())); + m_animStepForwardAction = new QAction(QIcon(":/cafAnimControl/StepFwd.png"), tr("Step Forward"), this); m_animSkipToEndAction = new QAction(QIcon(":/cafAnimControl/SkipToEnd.png"), tr("Skip to End"), this); m_animRepeatFromStartAction = new QAction(QIcon(":/cafAnimControl/RepeatFromStart.png"), tr("Repeat From start"), this); m_animRepeatFromStartAction->setCheckable(true); - m_animRepeatFwdBwdAction = new QAction(QIcon(":/cafAnimControl/RepeatFwdBwd.png"), tr("Repeat Forward/Backward"), this); - m_animRepeatFwdBwdAction->setCheckable(true); - m_timestepCombo = new QComboBox(this); - m_timestepCombo->setSizeAdjustPolicy(QComboBox::AdjustToContents); - m_timestepCombo->setToolTip(tr("Current Time Step")); + m_animSpeedButton = new PopupMenuButton(this); + m_animSpeedButton->setIcon(QIcon(":/cafAnimControl/Speed.png")); + m_animSpeedButton->setToolTip("Adjust Animation Speed"); + + m_frameRateSlowLabel = new QLabel(this); + m_frameRateSlowLabel->setPixmap(QPixmap(":/cafAnimControl/SlowHorizontal.png")); + m_frameRateSlowLabel->setToolTip(tr("Slow")); - QLabel* slowLabel = new QLabel ( this); - slowLabel->setPixmap(QPixmap(":/cafAnimControl/Slow.png")); - slowLabel->setToolTip(tr("Slow")); - QLabel* fastLabel = new QLabel(this); - fastLabel->setPixmap(QPixmap(":/cafAnimControl/Fast.png")); - fastLabel->setAlignment(Qt::AlignRight); - fastLabel->setToolTip(tr("Fast")); + m_frameRateFastLabel = new QLabel(this); + m_frameRateFastLabel->setPixmap(QPixmap(":/cafAnimControl/FastHorizontal.png")); + m_frameRateFastLabel->setToolTip(tr("Fast")); + m_frameRateFastLabel->setAlignment(Qt::AlignRight | Qt::AlignVCenter); m_frameRateSlider = new QSlider(Qt::Horizontal, this); - m_frameRateSlider->setMaximumWidth(75); m_frameRateSlider->setToolTip(tr("Animation speed")); + m_frameRateSlider->setMinimumWidth(100); + + m_animSpeedButton->addWidget(m_frameRateSlowLabel); + m_animSpeedButton->addWidget(m_frameRateSlider); + m_animSpeedButton->addWidget(m_frameRateFastLabel); + + m_timestepCombo = new QComboBox(this); + m_timestepCombo->setSizeAdjustPolicy(QComboBox::AdjustToContents); + m_timestepCombo->setToolTip(tr("Current Time Step")); QAction* separator1 = new QAction(this); separator1->setSeparator(true); @@ -116,28 +128,58 @@ void AnimationToolBar::init() // Add actions and widgets to animation toolbar addAction(m_animSkipToStartAction); addAction(m_animStepBackwardAction); - addAction(m_animPlayBwdAction ); - //addAction(m_animStopAction); - addAction(m_animPauseAction); - addAction(m_animPlayAction); + addWidget(m_animPlayPauseButton); addAction(m_animStepForwardAction); addAction(m_animSkipToEndAction); addAction(separator1); addAction(m_animRepeatFromStartAction ); - addAction(m_animRepeatFwdBwdAction ); addAction(separator2); - - addWidget(slowLabel); - addWidget(m_frameRateSlider); - addWidget(fastLabel); + + addWidget(m_animSpeedButton); addAction(separator3); addWidget(m_timestepCombo); + updateAnimationButtons(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void AnimationToolBar::updateAnimationButtons() +{ + bool isPlaying = m_activeAnimationControl && m_activeAnimationControl->isActive(); + + if (isPlaying) + { + m_animPlayPauseButton->setIcon(m_animPauseAction->icon()); + m_animPlayPauseButton->setToolTip(m_animPauseAction->toolTip()); + } + else + { + m_animPlayPauseButton->setIcon(m_animPlayAction->icon()); + m_animPlayPauseButton->setToolTip(m_animPlayAction->toolTip()); + } + + bool isAtStart = m_timestepCombo->count() == 0 || m_timestepCombo->currentIndex() == 0; + bool isAtEnd = m_timestepCombo->count() > 0 && m_timestepCombo->currentIndex() == m_timestepCombo->count() - 1; + + // Going backwards actions disabled when we're stopped at the start + m_animSkipToStartAction->setEnabled(isPlaying || !isAtStart); + m_animStepBackwardAction->setEnabled(isPlaying || !isAtStart); + + bool isRepeat = m_activeAnimationControl && + m_activeAnimationControl->isRepeatingFromStart(); + + // Going forwards actions disabled when we're stopped at the end + m_animStepForwardAction->setEnabled(isPlaying || !isAtEnd); + m_animSkipToEndAction->setEnabled(isPlaying || !isAtEnd); + // ... however we allow playing if we have repeat on + m_animPlayPauseButton->setEnabled(isPlaying || isRepeat || !isAtEnd); } //-------------------------------------------------------------------------------------------------- @@ -148,7 +190,7 @@ void AnimationToolBar::connectAnimationControl(caf::FrameAnimationControl* anima // Animation action connections if (m_activeAnimationControl) { - m_activeAnimationControl->disconnect(this, SLOT(slotUpdateComboBoxIndex(int))); + m_activeAnimationControl->disconnect(this, SLOT(slotUpdateAnimationGuiFromFrameIndex(int))); m_activeAnimationControl->disconnect(this, SLOT(slotUpdateTimestepList(int))); } @@ -156,15 +198,12 @@ void AnimationToolBar::connectAnimationControl(caf::FrameAnimationControl* anima m_animSkipToStartAction->disconnect(); m_animStepBackwardAction->disconnect(); - m_animStopAction->disconnect(); m_animPauseAction->disconnect(); m_animPlayAction->disconnect(); m_animStepForwardAction->disconnect(); m_animSkipToEndAction->disconnect(); - m_animPlayBwdAction ->disconnect(); m_animRepeatFromStartAction->disconnect(); - m_animRepeatFwdBwdAction ->disconnect(); m_timestepCombo->disconnect(); m_frameRateSlider->disconnect(); @@ -173,34 +212,25 @@ void AnimationToolBar::connectAnimationControl(caf::FrameAnimationControl* anima { connect(m_animSkipToStartAction, SIGNAL(triggered()), animationControl, SLOT(slotSkipToStart())); connect(m_animStepBackwardAction, SIGNAL(triggered()), animationControl, SLOT(slotStepBackward())); - connect(m_animStopAction, SIGNAL(triggered()), animationControl, SLOT(slotStop())); connect(m_animPauseAction, SIGNAL(triggered()), animationControl, SLOT(slotPause())); connect(m_animPlayAction, SIGNAL(triggered()), animationControl, SLOT(slotPlayFwd())); connect(m_animStepForwardAction, SIGNAL(triggered()), animationControl, SLOT(slotStepForward())); connect(m_animSkipToEndAction, SIGNAL(triggered()), animationControl, SLOT(slotSkipToEnd())); - connect(m_animPlayBwdAction ,SIGNAL(triggered()), animationControl, SLOT(slotPlayBwd())); - m_animRepeatFromStartAction->setChecked(animationControl->isRepeatingFromStart()); - m_animRepeatFwdBwdAction->setChecked(animationControl->isRepeatingFwdBwd()); connect(m_animRepeatFromStartAction,SIGNAL(triggered(bool)), animationControl, SLOT(slotRepeatFromStart(bool))); - connect(m_animRepeatFwdBwdAction ,SIGNAL(triggered(bool)), animationControl, SLOT(slotRepeatFwdBwd(bool))); - - connect(m_animRepeatFromStartAction,SIGNAL(triggered(bool)), this, SLOT(slotFromStartModeToggled(bool))); - connect(m_animRepeatFwdBwdAction ,SIGNAL(triggered(bool)), this, SLOT(slotFwdBwdModeToggled(bool))); connect(m_timestepCombo, SIGNAL(currentIndexChanged(int)), animationControl, SLOT(setCurrentFrame(int))); connect(m_frameRateSlider, SIGNAL(valueChanged(int)), this, SLOT(slotFrameRateSliderChanged(int))); - connect(animationControl, SIGNAL(changeFrame(int)), this, SLOT(slotUpdateComboBoxIndex(int))); + connect(animationControl, SIGNAL(changeFrame(int)), this, SLOT(slotUpdateAnimationGuiFromFrameIndex(int))); connect(animationControl, SIGNAL(frameCountChanged(int)), this, SLOT(slotUpdateTimestepList(int))); int timeout = animationControl->timeout(); double initialFrameRate = 1000; if (timeout > 0) initialFrameRate = 1000.0/timeout; - setFrameRate(initialFrameRate); - + setFrameRate(initialFrameRate); } } @@ -250,6 +280,7 @@ void AnimationToolBar::setCurrentTimeStepIndex(int index) { m_timestepCombo->blockSignals(true); m_timestepCombo->setCurrentIndex(index); + updateAnimationButtons(); m_timestepCombo->blockSignals(false); } @@ -311,45 +342,38 @@ void AnimationToolBar::slotUpdateTimestepList(int frameCount) m_timestepCombo->clear(); m_timestepCombo->addItems(timeStepNames); + updateAnimationButtons(); m_timestepCombo->blockSignals(false); } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- -void AnimationToolBar::slotFromStartModeToggled(bool on) +void AnimationToolBar::playPauseChanged() { - if (on) + if (m_activeAnimationControl->isActive()) { - m_animRepeatFwdBwdAction->blockSignals(true); - m_animRepeatFwdBwdAction->setChecked(false); - m_animRepeatFwdBwdAction->blockSignals(false); + m_animPauseAction->trigger(); + updateAnimationButtons(); } -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void AnimationToolBar::slotFwdBwdModeToggled(bool on) -{ - if (on) + else { - m_animRepeatFromStartAction->blockSignals(true); - m_animRepeatFromStartAction->setChecked(false); - m_animRepeatFromStartAction->blockSignals(false); + m_animPlayAction->trigger(); + updateAnimationButtons(); } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void AnimationToolBar::slotUpdateComboBoxIndex(int value) +void AnimationToolBar::slotUpdateAnimationGuiFromFrameIndex(int value) { // Update only the combo box index, but do not set current frame // Disconnect the signal temporarily when updating UI disconnect(m_timestepCombo, SIGNAL(currentIndexChanged(int)), m_activeAnimationControl, SLOT(setCurrentFrame(int))); m_timestepCombo->setCurrentIndex(value); + updateAnimationButtons(); connect(m_timestepCombo, SIGNAL(currentIndexChanged(int)), m_activeAnimationControl, SLOT(setCurrentFrame(int))); } diff --git a/Fwk/AppFwk/cafAnimControl/cafAnimationToolBar.h b/Fwk/AppFwk/cafAnimControl/cafAnimationToolBar.h index 8f15eb0d15..aefe8db583 100644 --- a/Fwk/AppFwk/cafAnimControl/cafAnimationToolBar.h +++ b/Fwk/AppFwk/cafAnimControl/cafAnimationToolBar.h @@ -37,8 +37,8 @@ #pragma once -#include #include +#include #include "cafFrameAnimationControl.h" @@ -46,9 +46,11 @@ class QComboBox; class QLabel; class QLineEdit; class QSlider; +class QToolButton; namespace caf { +class PopupMenuButton; //================================================================================================== /// @@ -73,32 +75,32 @@ class AnimationToolBar : public QToolBar public slots: void slotUpdateTimestepList(int frameCount); + void playPauseChanged(); private slots: void slotFrameRateSliderChanged(int value); - void slotFromStartModeToggled(bool on); - void slotFwdBwdModeToggled(bool on); - void slotUpdateComboBoxIndex(int value); + void slotUpdateAnimationGuiFromFrameIndex(int value); private: void init(); - + void updateAnimationButtons(); private: - QAction* m_animSkipToStartAction; - QAction* m_animStepBackwardAction; - QAction* m_animPlayBwdAction; - QAction* m_animStopAction; - QAction* m_animPauseAction; - QAction* m_animPlayAction; - QAction* m_animStepForwardAction; - QAction* m_animSkipToEndAction; - - QAction* m_animRepeatFromStartAction; - QAction* m_animRepeatFwdBwdAction; - - QSlider* m_frameRateSlider; - - QComboBox* m_timestepCombo; + QAction* m_animSkipToStartAction; + QAction* m_animStepBackwardAction; + QToolButton* m_animPlayPauseButton; + QAction* m_animPauseAction; + QAction* m_animPlayAction; + QAction* m_animStepForwardAction; + QAction* m_animSkipToEndAction; + + QAction* m_animRepeatFromStartAction; + + PopupMenuButton* m_animSpeedButton; + QLabel* m_frameRateFastLabel; + QLabel* m_frameRateSlowLabel; + QSlider* m_frameRateSlider; + + QComboBox* m_timestepCombo; QPointer m_activeAnimationControl; diff --git a/Fwk/AppFwk/cafAnimControl/cafPopupMenuButton.cpp b/Fwk/AppFwk/cafAnimControl/cafPopupMenuButton.cpp new file mode 100644 index 0000000000..58fbbe15f0 --- /dev/null +++ b/Fwk/AppFwk/cafAnimControl/cafPopupMenuButton.cpp @@ -0,0 +1,76 @@ +//################################################################################################## +// +// Custom Visualization Core library +// Copyright (C) 2019- Ceetron Solutions AS +// +// This library may be used under the terms of either the GNU General Public License or +// the GNU Lesser General Public License as follows: +// +// GNU General Public License Usage +// This library 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 3 of the License, or +// (at your option) any later version. +// +// This library 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 at <> +// for more details. +// +// GNU Lesser General Public License Usage +// This library 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.1 of the License, or +// (at your option) any later version. +// +// This library 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 at <> +// for more details. +// +//################################################################################################## +#include "cafPopupMenuButton.h" + +#include +#include +#include + +using namespace caf; +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- + +PopupMenuButton::PopupMenuButton(QWidget* parentWidget, + Qt::Orientation orientation /*= Qt::Horizontal*/, + ToolButtonPopupMode popupMode /*=InstantPopup*/) + : QToolButton(parentWidget) +{ + if (orientation == Qt::Horizontal) + { + m_layout = new QHBoxLayout(this); + } + else + { + m_layout = new QVBoxLayout(this); + } + m_layout->setContentsMargins(QMargins(2, 2, 2, 2)); + + QMenu* menu = new QMenu(this); + menu->setLayout(m_layout); + setMenu(menu); + + setCheckable(true); + setPopupMode(popupMode); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void caf::PopupMenuButton::addWidget(QWidget* widget, int stretch, Qt::Alignment alignment) +{ + m_layout->addWidget(widget, stretch, alignment); +} diff --git a/Fwk/AppFwk/cafAnimControl/cafPopupMenuButton.h b/Fwk/AppFwk/cafAnimControl/cafPopupMenuButton.h new file mode 100644 index 0000000000..ea6daf103c --- /dev/null +++ b/Fwk/AppFwk/cafAnimControl/cafPopupMenuButton.h @@ -0,0 +1,63 @@ +//################################################################################################## +// +// Custom Visualization Core library +// Copyright (C) 2019- Ceetron Solutions AS +// +// This library may be used under the terms of either the GNU General Public License or +// the GNU Lesser General Public License as follows: +// +// GNU General Public License Usage +// This library 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 3 of the License, or +// (at your option) any later version. +// +// This library 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 at <> +// for more details. +// +// GNU Lesser General Public License Usage +// This library 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.1 of the License, or +// (at your option) any later version. +// +// This library 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 at <> +// for more details. +// +//################################################################################################## +#pragma once +#include +#include + +class QBoxLayout; +class QToolButton; + +namespace caf +{ +//================================================================================================== +/// +//================================================================================================== +class PopupMenuButton : public QToolButton +{ + Q_OBJECT + +public: + PopupMenuButton(QWidget* parentWidget, + Qt::Orientation orientation = Qt::Horizontal, + ToolButtonPopupMode popupMode = InstantPopup); + + void addWidget(QWidget* widget, int stretch = 0, Qt::Alignment alignment = Qt::Alignment()); + +private: + QPointer m_layout; +}; + +} diff --git a/Fwk/AppFwk/cafCommand/CMakeLists.txt b/Fwk/AppFwk/cafCommand/CMakeLists.txt index d4e2656877..67e76d35d2 100644 --- a/Fwk/AppFwk/cafCommand/CMakeLists.txt +++ b/Fwk/AppFwk/cafCommand/CMakeLists.txt @@ -1,21 +1,28 @@ cmake_minimum_required (VERSION 2.8.12) # Qt -find_package ( Qt4 COMPONENTS QtCore QtGui QtMain ) -include (${QT_USE_FILE}) +if (CAF_USE_QT5) + find_package(Qt5 COMPONENTS Core Gui OpenGL Widgets REQUIRED) +else() + find_package(Qt4 COMPONENTS QtCore QtGui QtMain REQUIRED) + include(${QT_USE_FILE}) +endif(CAF_USE_QT5) project (cafCommand) # These headers need to go through Qt's MOC compiler -set( QOBJECT_HEADERS +set (MOC_HEADER_FILES cafCmdFeature.h cafCmdFeatureManager.h ) -if ( NOT CMAKE_AUTOMOC ) - qt4_wrap_cpp( MOC_FILES_CPP ${QOBJECT_HEADERS} ) -endif() +if (CAF_USE_QT5) + qt5_wrap_cpp(MOC_SOURCE_FILES ${MOC_HEADER_FILES} ) + set(QT_LIBRARIES Qt5::Core Qt5::Gui Qt5::Widgets) +else() + qt4_wrap_cpp(MOC_SOURCE_FILES ${MOC_HEADER_FILES} ) +endif(CAF_USE_QT5) set( PROJECT_FILES @@ -58,7 +65,7 @@ set( PROJECT_FILES add_library( ${PROJECT_NAME} ${PROJECT_FILES} - ${MOC_FILES_CPP} + ${MOC_SOURCE_FILES} ) target_include_directories(${PROJECT_NAME} @@ -68,6 +75,7 @@ target_include_directories(${PROJECT_NAME} target_link_libraries ( ${PROJECT_NAME} cafProjectDataModel + ${QT_LIBRARIES} ) if (MSVC) @@ -75,3 +83,8 @@ if (MSVC) endif() source_group("" FILES ${PROJECT_FILES}) + +# cotire +if (COMMAND caf_apply_cotire) + caf_apply_cotire("${PROJECT_NAME}") +endif() diff --git a/Fwk/AppFwk/cafCommand/cafCmdFeature.cpp b/Fwk/AppFwk/cafCommand/cafCmdFeature.cpp index 5eaa86f56f..d1133284ca 100644 --- a/Fwk/AppFwk/cafCommand/cafCmdFeature.cpp +++ b/Fwk/AppFwk/cafCommand/cafCmdFeature.cpp @@ -155,6 +155,20 @@ bool CmdFeature::canFeatureBeExecuted() return this->isCommandEnabled(); } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void CmdFeature::applyShortcutWithHintToAction(QAction* action, const QKeySequence& keySequence) +{ + action->setShortcut(keySequence); + +#if (QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)) + // Qt made keyboard shortcuts in context menus platform dependent in Qt 5.10 + // With no global way of removing it. + action->setShortcutVisibleInContextMenu(true); +#endif +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- diff --git a/Fwk/AppFwk/cafCommand/cafCmdFeature.h b/Fwk/AppFwk/cafCommand/cafCmdFeature.h index d1b905f575..ad24e3444b 100644 --- a/Fwk/AppFwk/cafCommand/cafCmdFeature.h +++ b/Fwk/AppFwk/cafCommand/cafCmdFeature.h @@ -46,6 +46,7 @@ class QAction; class QIcon; +class QKeySequence; class QString; #define CAF_CMD_HEADER_INIT \ @@ -84,6 +85,8 @@ class CmdFeature : public QObject bool canFeatureBeExecuted(); + static void applyShortcutWithHintToAction(QAction* action, const QKeySequence& keySequence); + public slots: void actionTriggered(bool isChecked); diff --git a/Fwk/AppFwk/cafCommand/cafCmdFeatureManager.cpp b/Fwk/AppFwk/cafCommand/cafCmdFeatureManager.cpp index d90c1cad7a..445ac8553f 100644 --- a/Fwk/AppFwk/cafCommand/cafCmdFeatureManager.cpp +++ b/Fwk/AppFwk/cafCommand/cafCmdFeatureManager.cpp @@ -45,6 +45,7 @@ #include "defaultfeatures/cafCmdAddItemFeature.h" #include +#include namespace caf { @@ -313,4 +314,27 @@ std::vector CmdFeatureManager::commandFeaturesMatchingSubString(con return matches; } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector CmdFeatureManager::commandFeaturesMatchingKeyboardShortcut(const QKeySequence& keySequence) const +{ + std::vector matches; + + std::vector keys = CommandFeatureFactory::instance()->allKeys(); + for (size_t i = 0; i < keys.size(); i++) + { + caf::CmdFeature* cmdFeature = commandFeature(keys[i]); + if (cmdFeature) + { + if (cmdFeature->action()->shortcut().matches(keySequence) == QKeySequence::ExactMatch) + { + matches.push_back(cmdFeature); + } + } + } + + return matches; +} + } // end namespace caf diff --git a/Fwk/AppFwk/cafCommand/cafCmdFeatureManager.h b/Fwk/AppFwk/cafCommand/cafCmdFeatureManager.h index db3bb6a605..76fe9cc931 100644 --- a/Fwk/AppFwk/cafCommand/cafCmdFeatureManager.h +++ b/Fwk/AppFwk/cafCommand/cafCmdFeatureManager.h @@ -45,6 +45,7 @@ #include class QAction; +class QKeySequence; namespace caf { @@ -72,7 +73,7 @@ class CmdFeatureManager : public QObject CmdFeature* getCommandFeature(const std::string& commandId); std::vector commandFeaturesMatchingSubString(const std::string& subString) const; - + std::vector commandFeaturesMatchingKeyboardShortcut(const QKeySequence& keySequence) const; private: CmdFeatureManager(); diff --git a/Fwk/AppFwk/cafCommand/cafCmdFeatureMenuBuilder.cpp b/Fwk/AppFwk/cafCommand/cafCmdFeatureMenuBuilder.cpp index fbd46bdb02..80086e92a3 100644 --- a/Fwk/AppFwk/cafCommand/cafCmdFeatureMenuBuilder.cpp +++ b/Fwk/AppFwk/cafCommand/cafCmdFeatureMenuBuilder.cpp @@ -236,4 +236,12 @@ bool CmdFeatureMenuBuilder::isCmdFeatureAdded(const QString &commandId) return false; } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +size_t CmdFeatureMenuBuilder::itemCount() const +{ + return m_items.size(); +} + } // end namespace caf diff --git a/Fwk/AppFwk/cafCommand/cafCmdFeatureMenuBuilder.h b/Fwk/AppFwk/cafCommand/cafCmdFeatureMenuBuilder.h index d0b8c185b8..dfd03fcfcd 100644 --- a/Fwk/AppFwk/cafCommand/cafCmdFeatureMenuBuilder.h +++ b/Fwk/AppFwk/cafCommand/cafCmdFeatureMenuBuilder.h @@ -70,7 +70,7 @@ class CmdFeatureMenuBuilder void appendToMenu(QMenu* menu); bool isCmdFeatureAdded(const QString &commandId); - + size_t itemCount() const; private: struct MenuItem { diff --git a/Fwk/AppFwk/cafCommand/defaultfeatures/cafCmdDeleteItemFeature.cpp b/Fwk/AppFwk/cafCommand/defaultfeatures/cafCmdDeleteItemFeature.cpp index 1901fd9e7d..7b9ebc510d 100644 --- a/Fwk/AppFwk/cafCommand/defaultfeatures/cafCmdDeleteItemFeature.cpp +++ b/Fwk/AppFwk/cafCommand/defaultfeatures/cafCmdDeleteItemFeature.cpp @@ -140,6 +140,7 @@ void CmdDeleteItemFeature::onActionTriggered(bool isChecked) void CmdDeleteItemFeature::setupActionLook(QAction* actionToSetup) { actionToSetup->setText("Delete object"); + applyShortcutWithHintToAction(actionToSetup, QKeySequence::Delete); } } // end namespace caf diff --git a/Fwk/AppFwk/cafPdmCvf/CMakeLists.txt b/Fwk/AppFwk/cafPdmCvf/CMakeLists.txt index bafd45477d..b5723987c4 100644 --- a/Fwk/AppFwk/cafPdmCvf/CMakeLists.txt +++ b/Fwk/AppFwk/cafPdmCvf/CMakeLists.txt @@ -3,8 +3,14 @@ cmake_minimum_required (VERSION 2.8.12) project (cafPdmCvf) # Qt -find_package ( Qt4 COMPONENTS QtCore QtGui QtMain ) -include (${QT_USE_FILE}) +if (CAF_USE_QT5) + find_package(Qt5 COMPONENTS Core Gui Widgets REQUIRED) +else() + find_package(Qt4 COMPONENTS QtCore QtGui QtMain REQUIRED) + include(${QT_USE_FILE}) +endif(CAF_USE_QT5) + +add_definitions(-DCVF_USING_CMAKE) add_library( ${PROJECT_NAME} cafPdmCoreColor3f.h @@ -34,6 +40,11 @@ target_include_directories(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR} ) +if (CAF_USE_QT5) + set(QT_LIBRARIES Qt5::Core Qt5::Gui Qt5::Widgets) +endif(CAF_USE_QT5) + + target_link_libraries ( ${PROJECT_NAME} cafUserInterface LibCore diff --git a/Fwk/AppFwk/cafPdmCvf/cafPdmCvf_UnitTests/CMakeLists.txt b/Fwk/AppFwk/cafPdmCvf/cafPdmCvf_UnitTests/CMakeLists.txt index 8f95b1daf8..693c8c50fa 100644 --- a/Fwk/AppFwk/cafPdmCvf/cafPdmCvf_UnitTests/CMakeLists.txt +++ b/Fwk/AppFwk/cafPdmCvf/cafPdmCvf_UnitTests/CMakeLists.txt @@ -1,7 +1,12 @@ -cmake_minimum_required (VERSION 2.8) +cmake_minimum_required (VERSION 2.8.12) -find_package ( Qt4 COMPONENTS QtCore ) -include (${QT_USE_FILE}) +find_package(Qt5 CONFIG COMPONENTS Core) +if (Qt5Core_FOUND) + find_package(Qt5 CONFIG REQUIRED Core) +else() + find_package(Qt4 COMPONENTS QtCore REQUIRED) + include(${QT_USE_FILE}) +endif(Qt5Core_FOUND) project ( cafPdmCvf_UnitTests ) @@ -30,9 +35,11 @@ add_executable (${PROJECT_NAME} ${PROJECT_FILES} ) -source_group("" FILES ${PROJECT_FILES}) +if (Qt5Core_FOUND) + set(QT_LIBRARIES Qt5::Core) +endif() -message(STATUS ${PROJECT_NAME}" - Qt includes : " ${QT_LIBRARIES}) +source_group("" FILES ${PROJECT_FILES}) target_link_libraries ( ${PROJECT_NAME} cafPdmCore @@ -43,14 +50,24 @@ target_link_libraries ( ${PROJECT_NAME} ) # Copy Qt Dlls -if (MSVC) - set (QTLIBLIST QtCore QtGui) - foreach (qtlib ${QTLIBLIST}) - - # Debug - execute_process(COMMAND cmake -E copy_if_different ${QT_BINARY_DIR}/${qtlib}d4.dll ${CMAKE_CURRENT_BINARY_DIR}/Debug/${qtlib}d4.dll) - - # Release - execute_process(COMMAND cmake -E copy_if_different ${QT_BINARY_DIR}/${qtlib}4.dll ${CMAKE_CURRENT_BINARY_DIR}/Release/${qtlib}4.dll) - endforeach( qtlib ) -endif(MSVC) +if (Qt5Core_FOUND) + foreach (qtlib ${QT_LIBRARIES}) + add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_if_different $ $ + ) + endforeach(qtlib) + # Copy Qt Dlls +else() + # Copy Qt Dlls + if (MSVC) + set (QTLIBLIST QtCore) + foreach (qtlib ${QTLIBLIST}) + + # Debug + execute_process(COMMAND cmake -E copy_if_different ${QT_BINARY_DIR}/${qtlib}d4.dll ${CMAKE_BINARY_DIR}/Debug/${qtlib}d4.dll) + + # Release + execute_process(COMMAND cmake -E copy_if_different ${QT_BINARY_DIR}/${qtlib}4.dll ${CMAKE_BINARY_DIR}/Release/${qtlib}4.dll) + endforeach( qtlib ) + endif(MSVC) +endif(Qt5Core_FOUND) \ No newline at end of file diff --git a/Fwk/AppFwk/cafProjectDataModel/CMakeLists.txt b/Fwk/AppFwk/cafProjectDataModel/CMakeLists.txt index 107983a970..2158d47e6e 100644 --- a/Fwk/AppFwk/cafProjectDataModel/CMakeLists.txt +++ b/Fwk/AppFwk/cafProjectDataModel/CMakeLists.txt @@ -1,10 +1,14 @@ -cmake_minimum_required (VERSION 2.8) +cmake_minimum_required (VERSION 2.8.12) project (cafProjectDataModel) # Qt -find_package ( Qt4 COMPONENTS QtCore QtGui ) -include (${QT_USE_FILE}) +if (CAF_USE_QT5) + find_package(Qt5 COMPONENTS Core Gui Widgets REQUIRED) +else() + find_package(Qt4 COMPONENTS QtCore QtGui REQUIRED) + include(${QT_USE_FILE}) +endif(CAF_USE_QT5) set( PROJECT_FILES cafFactory.h @@ -21,9 +25,14 @@ add_library( ${PROJECT_NAME} ${PROJECT_FILES} ) +if (CAF_USE_QT5) + set(QT_LIBRARIES Qt5::Core Qt5::Gui Qt5::Widgets) +endif(CAF_USE_QT5) + target_link_libraries ( ${PROJECT_NAME} cafPdmUiCore cafPdmXml + ${QT_LIBRARIES} ) target_include_directories(${PROJECT_NAME} @@ -36,3 +45,8 @@ if (MSVC) endif() source_group("" FILES ${PROJECT_FILES}) + +# cotire +if (COMMAND caf_apply_cotire) + caf_apply_cotire("${PROJECT_NAME}") +endif() diff --git a/Fwk/AppFwk/cafProjectDataModel/PdmCore.plantuml b/Fwk/AppFwk/cafProjectDataModel/PdmCore.plantuml index 2cf0221beb..aef25defb0 100644 --- a/Fwk/AppFwk/cafProjectDataModel/PdmCore.plantuml +++ b/Fwk/AppFwk/cafProjectDataModel/PdmCore.plantuml @@ -1,6 +1,6 @@ @startuml -class PdmObject { +class PdmObjectHandle { name() fields(); referencingFields(); @@ -14,16 +14,16 @@ class PdmObject { } -PdmObject --* "n" PdmObjectCapability +PdmObjectHandle --* "n" PdmObjectCapability class PdmUiItem{ } -PdmObjectCapability <|- PdmUiObject -PdmUiItem <|- PdmUiObject +PdmObjectCapability <|- PdmUiObjectHandle +PdmUiItem <|- PdmUiObjectHandle -class PdmUiObject{ +class PdmUiObjectHandle { uiOrdering() = ?; uiTreeOrdering() = ? ; editorAttribute() = ?; @@ -41,24 +41,24 @@ class PdmUiObject{ m_objectToggleField; } -PdmUiObject <|-- PdmCompleteObject -PdmObject <|-- PdmCompleteObject -PdmXmlSerializable <|-- PdmCompleteObject +PdmUiObjectHandle <|-- PdmObject +PdmObjectHandle <|-- PdmObject +PdmXmlObjectHandle <|-- PdmObject -class PdmXmlSerializable { +class PdmXmlObjectHandle { classKeyword() = 0; readFields (); writeFields(); } -PdmObjectCapability <|- PdmXmlSerializable +PdmObjectCapability <|- PdmXmlObjectHandle package FieldHandle{ -PdmObject --> "n" PdmFieldHandle +PdmObjectHandle --> "n" PdmFieldHandle class PdmFieldHandle{ name() @@ -107,56 +107,53 @@ class PdmXmlFieldHandle { PdmFieldCapability <|- PdmXmlFieldHandle -PdmFieldHandle <|-- PdmCompleteFieldHandle -PdmUiFieldHandle <|-- PdmCompleteFieldHandle -PdmXmlFieldHandle <|-- PdmCompleteFieldHandle } package ToDoFields{ -class "PdmFieldXmlCap>"{ +class "InternalPdmXmlFieldCapability>"{ } } package SplittedFields{ PdmFieldHandle <|--- "PdmField" -"PdmField" --> "PdmFieldUiCap" -"PdmField" --> "PdmFieldXmlCap" +"PdmField" --> "InternalPdmUiFieldCapability" +"PdmField" --> "InternalPdmXmlFieldCapability" PdmFieldHandle <|--- "PdmProxyField" -"PdmProxyField" --> "PdmFieldUiCap" -"PdmProxyField" --> "PdmFieldXmlCap" +"PdmProxyField" --> "InternalPdmUiFieldCapability" +"PdmProxyField" --> "InternalPdmXmlFieldCapability" -PdmUiFieldHandle <|--- "PdmFieldUiCap" -PdmXmlFieldHandle <|--- "PdmFieldXmlCap" +PdmUiFieldHandle <|--- "InternalPdmUiFieldCapability" +PdmXmlFieldHandle <|--- "InternalPdmXmlFieldCapability" PdmFieldHandle <|--- "PdmPtrField" -"PdmPtrField" --> "PdmFieldUiCap" -"PdmPtrField" --> "PdmFieldXmlCap" -"PdmPtrField" ..> "Todo" "PdmFieldXmlCap>" +"PdmPtrField" --> "InternalPdmUiFieldCapability" +"PdmPtrField" --> "InternalPdmXmlFieldCapability" +"PdmPtrField" ..> "Todo" "InternalPdmXmlFieldCapability>" PdmFieldHandle <|--- "PdmChildField" -"PdmChildField"--> "PdmFieldUiCap>" -"PdmChildField"--> "PdmFieldXmlCap>" +"PdmChildField"--> "InternalPdmUiFieldCapability>" +"PdmChildField"--> "InternalPdmXmlFieldCapability>" PdmFieldHandle <|--- "PdmChildArrayField" -"PdmChildArrayField"--> "PdmFieldUiCap>" -"PdmChildArrayField"--> "PdmFieldXmlCap>" +"PdmChildArrayField"--> "InternalPdmUiFieldCapability>" +"PdmChildArrayField"--> "InternalPdmXmlFieldCapability>" } package ToDoFields{ PdmFieldHandle <|-- "PdmProxyPtrField" -"PdmProxyPtrField" --> "PdmFieldUiCap" -"PdmProxyPtrField" ..> "Todo" "PdmFieldXmlCap>" +"PdmProxyPtrField" --> "InternalPdmUiFieldCapability" +"PdmProxyPtrField" ..> "Todo" "InternalPdmXmlFieldCapability>" PdmFieldHandle <|-- "PdmProxyChildField" -"PdmProxyChildField"--> "PdmFieldUiCap>" -"PdmProxyChildField"--> "PdmFieldXmlCap>" +"PdmProxyChildField"--> "InternalPdmUiFieldCapability>" +"PdmProxyChildField"--> "InternalPdmXmlFieldCapability>" PdmFieldHandle <|-- "PdmProxyChildArrayField" -"PdmProxyChildArrayField"--> "PdmFieldUiCap>" -"PdmProxyChildArrayField"--> "PdmFieldXmlCap>" +"PdmProxyChildArrayField"--> "InternalPdmUiFieldCapability>" +"PdmProxyChildArrayField"--> "InternalPdmXmlFieldCapability>" } diff --git a/Fwk/AppFwk/cafProjectDataModel/PdmCoreNewNames.plantuml b/Fwk/AppFwk/cafProjectDataModel/PdmCoreNewNames.plantuml deleted file mode 100644 index aef25defb0..0000000000 --- a/Fwk/AppFwk/cafProjectDataModel/PdmCoreNewNames.plantuml +++ /dev/null @@ -1,163 +0,0 @@ -@startuml - -class PdmObjectHandle { - name() - fields(); - referencingFields(); - parentField(); - template capability() - void addCapability() - ---- - std::vector m_fields; - std::vector m_capabilities; -} - - -PdmObjectHandle --* "n" PdmObjectCapability - -class PdmUiItem{ - -} - -PdmObjectCapability <|- PdmUiObjectHandle -PdmUiItem <|- PdmUiObjectHandle - -class PdmUiObjectHandle { - uiOrdering() = ?; - uiTreeOrdering() = ? ; - editorAttribute() = ?; - - objectEditorAttribute() = ? ; - - userDescriptionField(); - objectToggleField() - - calculateValueOptions() = ?; - - fieldChangedByUi() = 0; - --- - m_descriptionField; - m_objectToggleField; -} - -PdmUiObjectHandle <|-- PdmObject -PdmObjectHandle <|-- PdmObject -PdmXmlObjectHandle <|-- PdmObject - - -class PdmXmlObjectHandle { - classKeyword() = 0; - readFields (); - writeFields(); -} - -PdmObjectCapability <|- PdmXmlObjectHandle - - - -package FieldHandle{ - -PdmObjectHandle --> "n" PdmFieldHandle - -class PdmFieldHandle{ - name() - - setOwnerObject(); - ownerObject(); - - hasChildObjects() = 0; - childObjects( ) = 0; - --- - std::vector m_attributes; -} - - -PdmFieldHandle --* "n" PdmFieldCapability - -class PdmUiFieldHandle{ - - uiValue() - setValueFromUi() - - valueOptions( ) = 0; - -} - -PdmFieldCapability <|- PdmUiFieldHandle -PdmUiItem <|- PdmUiFieldHandle - - -class PdmXmlFieldHandle { - setKeyword(); - keyword(); - - readFieldData() = 0; - writeFieldData() = 0; - - isIOReadable() - isIOWritable() - setIOWritable() - setIOReadable() ---- - bool m_isReadable; - bool m_isWritable; -} - -PdmFieldCapability <|- PdmXmlFieldHandle - - - -} - -package ToDoFields{ -class "InternalPdmXmlFieldCapability>"{ -} -} - -package SplittedFields{ - -PdmFieldHandle <|--- "PdmField" -"PdmField" --> "InternalPdmUiFieldCapability" -"PdmField" --> "InternalPdmXmlFieldCapability" - -PdmFieldHandle <|--- "PdmProxyField" -"PdmProxyField" --> "InternalPdmUiFieldCapability" -"PdmProxyField" --> "InternalPdmXmlFieldCapability" - -PdmUiFieldHandle <|--- "InternalPdmUiFieldCapability" -PdmXmlFieldHandle <|--- "InternalPdmXmlFieldCapability" - -PdmFieldHandle <|--- "PdmPtrField" -"PdmPtrField" --> "InternalPdmUiFieldCapability" -"PdmPtrField" --> "InternalPdmXmlFieldCapability" -"PdmPtrField" ..> "Todo" "InternalPdmXmlFieldCapability>" - -PdmFieldHandle <|--- "PdmChildField" -"PdmChildField"--> "InternalPdmUiFieldCapability>" -"PdmChildField"--> "InternalPdmXmlFieldCapability>" -PdmFieldHandle <|--- "PdmChildArrayField" -"PdmChildArrayField"--> "InternalPdmUiFieldCapability>" -"PdmChildArrayField"--> "InternalPdmXmlFieldCapability>" - -} - - -package ToDoFields{ -PdmFieldHandle <|-- "PdmProxyPtrField" -"PdmProxyPtrField" --> "InternalPdmUiFieldCapability" -"PdmProxyPtrField" ..> "Todo" "InternalPdmXmlFieldCapability>" - -PdmFieldHandle <|-- "PdmProxyChildField" -"PdmProxyChildField"--> "InternalPdmUiFieldCapability>" -"PdmProxyChildField"--> "InternalPdmXmlFieldCapability>" -PdmFieldHandle <|-- "PdmProxyChildArrayField" -"PdmProxyChildArrayField"--> "InternalPdmUiFieldCapability>" -"PdmProxyChildArrayField"--> "InternalPdmXmlFieldCapability>" - -} - - - -@enduml - \ No newline at end of file diff --git a/Fwk/AppFwk/cafProjectDataModel/PdmCoreUserOverviewCondensed.plantuml b/Fwk/AppFwk/cafProjectDataModel/PdmCoreUserOverviewCondensed.plantuml deleted file mode 100644 index 1c1de6e1a1..0000000000 --- a/Fwk/AppFwk/cafProjectDataModel/PdmCoreUserOverviewCondensed.plantuml +++ /dev/null @@ -1,17 +0,0 @@ -@startuml -title Simplified Overview of Pdm classes - -PdmUiItem <|---- PdmUiObjectHandle -PdmUiObjectHandle <|-- PdmObject -PdmObject <|-- YourClass - -PdmUiItem <|-- PdmUiFieldHandle -PdmFieldHandle -* PdmUiFieldHandle -PdmFieldHandle <|--- "PdmField" -PdmFieldHandle <|--- "PdmProxyField" -PdmFieldHandle <|--- "PdmPtrField" -PdmFieldHandle <|--- "PdmChildField" -PdmFieldHandle <|--- "PdmChildArrayField" - -@enduml - \ No newline at end of file diff --git a/Fwk/AppFwk/cafProjectDataModel/PdmModularization.plantuml b/Fwk/AppFwk/cafProjectDataModel/PdmModularization.plantuml deleted file mode 100644 index af982b8471..0000000000 --- a/Fwk/AppFwk/cafProjectDataModel/PdmModularization.plantuml +++ /dev/null @@ -1,135 +0,0 @@ -@startuml - -class PdmObjectHandle { - name() - fields(); - referencingFields(); - parentField(); - template capability() - void addCapability() - ---- - std::vector m_fields; - std::vector m_capabilities; -} - - -PdmObjectHandle --* "n" PdmObjectCapability - -class PdmUiItem{ - -} - -PdmObjectCapability <|- PdmUiObjectHandle -PdmUiItem <|- PdmUiObjectHandle - -class PdmUiObjectHandle { - uiOrdering() = ?; - uiTreeOrdering() = ? ; - editorAttribute() = ?; - - objectEditorAttribute() = ? ; - - userDescriptionField(); - objectToggleField() - - calculateValueOptions() = ?; - - fieldChangedByUi() = 0; - --- - m_descriptionField; - m_objectToggleField; -} - -PdmUiObjectHandle <|-- PdmObject -PdmObjectHandle <|-- PdmObject -PdmXmlObjectHandle <|-- PdmObject - - -class PdmXmlObjectHandle { - classKeyword() = 0; - readFields (); - writeFields(); -} - -PdmObjectCapability <|- PdmXmlObjectHandle - - - -package FieldHandle{ - -PdmObjectHandle --> "n" PdmFieldHandle - -class PdmFieldHandle{ - name() - - setOwnerObject(); - ownerObject(); - - hasChildObjects() = 0; - childObjects( ) = 0; - --- - std::vector m_attributes; -} - - -PdmFieldHandle --* "n" PdmFieldCapability - -class PdmUiFieldHandle{ - - uiValue() - setValueFromUi() - - valueOptions( ) = 0; - -} - -PdmFieldCapability <|- PdmUiFieldHandle -PdmUiItem <|- PdmUiFieldHandle - - -class PdmXmlFieldHandle { - setKeyword(); - keyword(); - - readFieldData() = 0; - writeFieldData() = 0; - - isIOReadable() - isIOWritable() - setIOWritable() - setIOReadable() ---- - bool m_isReadable; - bool m_isWritable; -} - -PdmFieldCapability <|- PdmXmlFieldHandle - - - -} - - - -PdmFieldHandle <|- "PdmPtrField" -PdmFieldHandle <|- "PdmChildField" - -PdmFieldHandle <|- PdmValueField -PdmValueField <|-- "PdmDataValueField" -PdmValueField <|-- "PdmProxyValueField" - -PdmFieldHandle <|- PdmChildArrayFieldHandle -PdmChildArrayFieldHandle <|-- "PdmChildArrayField" - -PdmField ..u.. PdmValueField - -class PdmField { - Macro used to replace - PdmField with PdmValueField (used in ResInsight) -} - - - -@enduml - \ No newline at end of file diff --git a/Fwk/AppFwk/cafProjectDataModel/PdmOverview.plantuml b/Fwk/AppFwk/cafProjectDataModel/PdmOverview.plantuml index fac1502557..48b24a5369 100644 --- a/Fwk/AppFwk/cafProjectDataModel/PdmOverview.plantuml +++ b/Fwk/AppFwk/cafProjectDataModel/PdmOverview.plantuml @@ -3,21 +3,24 @@ left to right direction component cafProjectDataModel note right of [cafProjectDataModel] - Templated factory class - Multithreaded mutex - Aggreagated class PdmObject, inherits Core, Ui, Xml - Helper macro to be able to use PdmField(macro for replacing with PdmValueField) - PdmObjectGroup - collection of PdmObjects +-- Top Level Directory -- + - PdmObject and PdmField : Convenienece classes used when + using all the intrinsic capabilities: Xml, Ui and Introspection + Some utility classes: + - Templated factory class + - Multithreaded mutex + - PdmObjectGroup - collection of PdmObjects end note -component cafPdmCore +component cafPdmCore note right of [cafPdmCore] cafAppEnum Classes derived from cafPdmFieldHandle cafPdmPointer end note + component cafPdmUiCore note right of [cafPdmUiCore] Object editor handle @@ -69,7 +72,20 @@ note right of [cafPdmCvf] Mat4d end note +cafPdmCore --> cafPdmUiCore +cafPdmCore --> cafPdmXml +cafPdmCore --> cafProjectDataModel + +cafPdmUiCore --> cafProjectDataModel +cafPdmXml --> cafProjectDataModel + + +cafProjectDataModel --> cafUserInterface +cafProjectDataModel --> cafCommand +cafAnimControl --> cafViewer + +cafProjectDataModel --> cafPdmCvf @enduml diff --git a/Fwk/AppFwk/cafProjectDataModel/cafFactory.h b/Fwk/AppFwk/cafProjectDataModel/cafFactory.h index 2b291a5b3f..dc7b4496b1 100644 --- a/Fwk/AppFwk/cafProjectDataModel/cafFactory.h +++ b/Fwk/AppFwk/cafProjectDataModel/cafFactory.h @@ -178,7 +178,7 @@ namespace caf class ObjectCreator : public ObjectCreatorBase { public: - virtual BaseType * create() { return new TypeToCreate(); } + BaseType * create() override { return new TypeToCreate(); } }; // Map to store factory diff --git a/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/CMakeLists.txt b/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/CMakeLists.txt index cd5797cb83..a7ed64a1a3 100644 --- a/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/CMakeLists.txt +++ b/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/CMakeLists.txt @@ -3,8 +3,12 @@ cmake_minimum_required (VERSION 2.8.12) project (cafPdmCore) # Qt -find_package ( Qt4 COMPONENTS QtCore ) -include (${QT_USE_FILE}) +if (CAF_USE_QT5) + find_package(Qt5 COMPONENTS Core REQUIRED) +else() + find_package(Qt4 COMPONENTS QtCore REQUIRED) + include(${QT_USE_FILE}) +endif(CAF_USE_QT5) set( PROJECT_FILES @@ -60,8 +64,19 @@ target_include_directories(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR} ) +if (CAF_USE_QT5) + set(QT_LIBRARIES Qt5::Core Qt5::Gui Qt5::Widgets) +endif(CAF_USE_QT5) + +target_link_libraries(${PROJECT_NAME} ${QT_LIBRARIES}) + if (MSVC) set_target_properties(${PROJECT_NAME} PROPERTIES COMPILE_FLAGS "/W4 /wd4100 /wd4127") endif() source_group("" FILES ${PROJECT_FILES}) + +# cotire +if (COMMAND caf_apply_cotire) + caf_apply_cotire("${PROJECT_NAME}") +endif() diff --git a/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafFilePath.h b/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafFilePath.h index e859bfe079..45ede5f64d 100644 --- a/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafFilePath.h +++ b/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafFilePath.h @@ -1,6 +1,7 @@ #pragma once #include +#include class QTextStream; diff --git a/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafPdmCore_UnitTests/CMakeLists.txt b/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafPdmCore_UnitTests/CMakeLists.txt index ca70e46c3e..f5c9d39c1d 100644 --- a/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafPdmCore_UnitTests/CMakeLists.txt +++ b/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafPdmCore_UnitTests/CMakeLists.txt @@ -1,10 +1,21 @@ cmake_minimum_required (VERSION 2.8.12) -find_package ( Qt4 COMPONENTS QtCore QtGui ) -include (${QT_USE_FILE}) - project ( cafPdmCore_UnitTests ) +find_package(Qt5Core CONFIG QUIET) +if (Qt5Core_FOUND) + find_package(Qt5 CONFIG REQUIRED Core Gui Widgets) +else() + find_package(Qt4 COMPONENTS QtCore QtGui REQUIRED) + include(${QT_USE_FILE}) +endif(Qt5Core_FOUND) + +if (MSVC AND (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 19.11)) + # VS 2017 : Disable warnings from from gtest code, using deprecated code related to TR1 + add_definitions(-D_SILENCE_TR1_NAMESPACE_DEPRECATION_WARNING) + message(STATUS "Add flag to disable warings from gtest - _SILENCE_TR1_NAMESPACE_DEPRECATION_WARNING") +endif() + include_directories ( ${CMAKE_CURRENT_SOURCE_DIR} # required for gtest-all.cpp ) @@ -34,7 +45,10 @@ add_executable (${PROJECT_NAME} source_group("" FILES ${PROJECT_FILES}) -message(STATUS ${PROJECT_NAME}" - Qt includes : " ${QT_LIBRARIES}) + +if (Qt5Core_FOUND) + set(QT_LIBRARIES Qt5::Core Qt5::Gui Qt5::Widgets) +endif() target_link_libraries ( ${PROJECT_NAME} cafPdmCore @@ -42,16 +56,25 @@ target_link_libraries ( ${PROJECT_NAME} ${THREAD_LIBRARY} ) - # Copy Qt Dlls -if (MSVC) - set (QTLIBLIST QtCore ) - foreach (qtlib ${QTLIBLIST}) - - # Debug - execute_process(COMMAND cmake -E copy_if_different ${QT_BINARY_DIR}/${qtlib}d4.dll ${CMAKE_CURRENT_BINARY_DIR}/Debug/${qtlib}d4.dll) - - # Release - execute_process(COMMAND cmake -E copy_if_different ${QT_BINARY_DIR}/${qtlib}4.dll ${CMAKE_CURRENT_BINARY_DIR}/Release/${qtlib}4.dll) - endforeach( qtlib ) -endif(MSVC) +if (Qt5Core_FOUND) + foreach (qtlib ${QT_LIBRARIES}) + add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_if_different $ $ + ) + endforeach(qtlib) + # Copy Qt Dlls +else() + # Copy Qt Dlls + if (MSVC) + set (QTLIBLIST QtCore QtGui ) + foreach (qtlib ${QTLIBLIST}) + + # Debug + execute_process(COMMAND cmake -E copy_if_different ${QT_BINARY_DIR}/${qtlib}d4.dll ${CMAKE_BINARY_DIR}/Debug/${qtlib}d4.dll) + + # Release + execute_process(COMMAND cmake -E copy_if_different ${QT_BINARY_DIR}/${qtlib}4.dll ${CMAKE_BINARY_DIR}/Release/${qtlib}4.dll) + endforeach( qtlib ) + endif(MSVC) +endif(Qt5Core_FOUND) \ No newline at end of file diff --git a/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafPdmCore_UnitTests/cafPdmReferenceHelperTest.cpp b/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafPdmCore_UnitTests/cafPdmReferenceHelperTest.cpp index 8f7826653f..94e312b085 100644 --- a/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafPdmCore_UnitTests/cafPdmReferenceHelperTest.cpp +++ b/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafPdmCore_UnitTests/cafPdmReferenceHelperTest.cpp @@ -129,7 +129,7 @@ TEST(PdmReferenceHelperTest, ReferenceFrommRootToField) QString refString = caf::PdmReferenceHelper::referenceFromRootToField(ihd1, &s3->m_dir); QString expectedString = "m_dir m_simpleObjPtrField 2"; - EXPECT_STREQ(expectedString.toAscii(), refString.toAscii()); + EXPECT_STREQ(expectedString.toLatin1(), refString.toLatin1()); delete ihd1; } @@ -160,7 +160,7 @@ TEST(PdmReferenceHelperTest, ReferenceFrommRootToObject) QString refString = caf::PdmReferenceHelper::referenceFromRootToObject(ihd1, s3); QString expectedString = "m_simpleObjPtrField 2"; - EXPECT_STREQ(expectedString.toAscii(), refString.toAscii()); + EXPECT_STREQ(expectedString.toLatin1(), refString.toLatin1()); ReferenceSimpleObj* ihd2 = new ReferenceSimpleObj; SimpleObj* s4 = new SimpleObj; diff --git a/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafPdmDataValueField.h b/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafPdmDataValueField.h index 9a45fb4898..a3283fdfed 100644 --- a/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafPdmDataValueField.h +++ b/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafPdmDataValueField.h @@ -66,7 +66,7 @@ class PdmDataValueField : public PdmValueField PdmDataValueField() {} PdmDataValueField(const PdmDataValueField& other) { m_fieldValue = other.m_fieldValue; } explicit PdmDataValueField(const DataType& fieldValue) { m_fieldValue = fieldValue; } - virtual ~PdmDataValueField() {} + ~PdmDataValueField() override {} // Assignment @@ -81,9 +81,9 @@ class PdmDataValueField : public PdmValueField // Implementation of PdmValueField interface - virtual QVariant toQVariant() const { CAF_ASSERT(isInitializedByInitFieldMacro()); return PdmValueFieldSpecialization::convert(m_fieldValue); } - virtual void setFromQVariant(const QVariant& variant) { CAF_ASSERT(isInitializedByInitFieldMacro()); PdmValueFieldSpecialization::setFromVariant(variant, m_fieldValue); } - virtual bool isReadOnly() const { return false; } + QVariant toQVariant() const override { CAF_ASSERT(isInitializedByInitFieldMacro()); return PdmValueFieldSpecialization::convert(m_fieldValue); } + void setFromQVariant(const QVariant& variant) override { CAF_ASSERT(isInitializedByInitFieldMacro()); PdmValueFieldSpecialization::setFromVariant(variant, m_fieldValue); } + bool isReadOnly() const override { return false; } // Access operators diff --git a/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafPdmProxyValueField.h b/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafPdmProxyValueField.h index 0927ccd91b..1e2b1f9a63 100644 --- a/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafPdmProxyValueField.h +++ b/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafPdmProxyValueField.h @@ -23,7 +23,7 @@ class PdmProxyValueField : public PdmValueField public: typedef DataType FieldDataType; PdmProxyValueField() { m_valueSetter = NULL; m_valueGetter = NULL; } - virtual ~PdmProxyValueField() { if (m_valueSetter) delete m_valueSetter; if (m_valueGetter) delete m_valueGetter; } + ~PdmProxyValueField() override { if (m_valueSetter) delete m_valueSetter; if (m_valueGetter) delete m_valueGetter; } // Assignment @@ -36,9 +36,9 @@ class PdmProxyValueField : public PdmValueField // Implementation of PdmValueField interface - virtual QVariant toQVariant() const { DataType val = value(); return PdmValueFieldSpecialization::convert(val); } - virtual void setFromQVariant(const QVariant& variant) { DataType val; PdmValueFieldSpecialization::setFromVariant(variant, val); setValue(val); } - virtual bool isReadOnly() const { if (!m_valueSetter) { return true; } else { return false; } } + QVariant toQVariant() const override { DataType val = value(); return PdmValueFieldSpecialization::convert(val); } + void setFromQVariant(const QVariant& variant) override { DataType val; PdmValueFieldSpecialization::setFromVariant(variant, val); setValue(val); } + bool isReadOnly() const override { if (!m_valueSetter) { return true; } else { return false; } } // Access operators diff --git a/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafPdmPtrField.h b/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafPdmPtrField.h index 5ac6e0c879..68f4149be8 100644 --- a/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafPdmPtrField.h +++ b/Fwk/AppFwk/cafProjectDataModel/cafPdmCore/cafPdmPtrField.h @@ -39,7 +39,7 @@ class PdmPtrField : public PdmValueField PdmPtrField() : m_isResolved(false) { } explicit PdmPtrField(const DataTypePtr& fieldValue); - virtual ~PdmPtrField(); + ~PdmPtrField() override; // Assignment @@ -52,9 +52,9 @@ class PdmPtrField : public PdmValueField void setValue(const DataTypePtr& fieldValue); // QVariant access - virtual QVariant toQVariant() const override; - virtual void setFromQVariant(const QVariant& variant) override; - virtual bool isReadOnly() const override { return false; } + QVariant toQVariant() const override; + void setFromQVariant(const QVariant& variant) override; + bool isReadOnly() const override { return false; } // Access operators @@ -66,7 +66,7 @@ class PdmPtrField : public PdmValueField // Ptr referenced objects - virtual void ptrReferencedObjects(std::vector* objectsToFill); + void ptrReferencedObjects(std::vector* objectsToFill) override; private: diff --git a/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/CMakeLists.txt b/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/CMakeLists.txt index 5d5ccd9094..c400014550 100644 --- a/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/CMakeLists.txt +++ b/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/CMakeLists.txt @@ -1,23 +1,35 @@ -cmake_minimum_required (VERSION 2.8) +cmake_minimum_required (VERSION 2.8.12) project (cafPdmUiCore) # Qt -find_package ( Qt4 COMPONENTS QtCore QtGui ) -include (${QT_USE_FILE}) +if (CAF_USE_QT5) + find_package(Qt5 COMPONENTS Core Gui Widgets REQUIRED) +else() + find_package(Qt4 COMPONENTS QtCore QtGui REQUIRED) + include(${QT_USE_FILE}) +endif(CAF_USE_QT5) + include_directories ( .. ) # These headers need to go through Qt's MOC compiler -set( QOBJECT_HEADERS +set (MOC_HEADER_FILES + cafPdmUiEditorHandle.h cafPdmUiFieldEditorHandle.h + cafPdmUiSelection3dEditorVisualizer.h + cafQShortenedLabel.h ) -if ( NOT CMAKE_AUTOMOC ) - qt4_wrap_cpp( MOC_FILES_CPP ${QOBJECT_HEADERS} ) -endif() +# Run MOC on the headers +add_definitions(-DCVF_USING_CMAKE) +if (CAF_USE_QT5) + qt5_wrap_cpp(MOC_SOURCE_FILES ${MOC_HEADER_FILES} ) +else() + qt4_wrap_cpp(MOC_SOURCE_FILES ${MOC_HEADER_FILES} ) +endif(CAF_USE_QT5) set( PROJECT_FILES @@ -39,6 +51,10 @@ set( PROJECT_FILES cafPdmUiModelChangeDetector.h cafPdmUiObjectEditorHandle.cpp cafPdmUiObjectEditorHandle.h + cafPdmUiWidgetObjectEditorHandle.cpp + cafPdmUiWidgetObjectEditorHandle.h + cafPdmUi3dObjectEditorHandle.cpp + cafPdmUi3dObjectEditorHandle.h cafPdmUiObjectHandle.cpp cafPdmUiObjectHandle.h cafPdmUiOrdering.cpp @@ -56,15 +72,25 @@ set( PROJECT_FILES cafSelectionChangedReceiver.h cafSelectionChangedReceiver.cpp cafSelectionManagerTools.h + cafPdmUiSelection3dEditorVisualizer.h + cafPdmUiSelection3dEditorVisualizer.cpp + cafQShortenedLabel.cpp + cafQShortenedLabel.h + ) add_library( ${PROJECT_NAME} ${PROJECT_FILES} - ${MOC_FILES_CPP} + ${MOC_SOURCE_FILES} ) +if (CAF_USE_QT5) + set(QT_LIBRARIES Qt5::Core Qt5::Gui Qt5::Widgets) +endif(CAF_USE_QT5) + target_link_libraries ( ${PROJECT_NAME} cafPdmCore + ${QT_LIBRARIES} ) target_include_directories(${PROJECT_NAME} @@ -77,3 +103,8 @@ if (MSVC) endif() source_group("" FILES ${PROJECT_FILES}) + +# cotire +if (COMMAND caf_apply_cotire) + caf_apply_cotire("${PROJECT_NAME}") +endif() diff --git a/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafPdmUi3dObjectEditorHandle.cpp b/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafPdmUi3dObjectEditorHandle.cpp new file mode 100644 index 0000000000..7c5b63fe31 --- /dev/null +++ b/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafPdmUi3dObjectEditorHandle.cpp @@ -0,0 +1,72 @@ +//################################################################################################## +// +// Custom Visualization Core library +// Copyright (C) Ceetron Solutions AS +// +// This library may be used under the terms of either the GNU General Public License or +// the GNU Lesser General Public License as follows: +// +// GNU General Public License Usage +// This library 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 3 of the License, or +// (at your option) any later version. +// +// This library 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 at <> +// for more details. +// +// GNU Lesser General Public License Usage +// This library 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.1 of the License, or +// (at your option) any later version. +// +// This library 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 at <> +// for more details. +// +//################################################################################################## + +#include "cafPdmUi3dObjectEditorHandle.h" + +//================================================================================================== +/// +/// +/// +//================================================================================================== +namespace caf +{ +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +PdmUi3dObjectEditorHandle::PdmUi3dObjectEditorHandle() +{ + +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +PdmUi3dObjectEditorHandle::~PdmUi3dObjectEditorHandle() +{ + +} + +//-------------------------------------------------------------------------------------------------- +/// The viewer widget set here is provided by the PdmUiSelection3dEditorVisualizer and is expected +/// to be cast able to whatever is needed in subclasses. +/// Not allowed to change. Should be constructor argument, but makes factory stuff difficult. +//-------------------------------------------------------------------------------------------------- +void PdmUi3dObjectEditorHandle::setViewer(QWidget* ownerViewer) +{ + CAF_ASSERT(m_ownerViewer.isNull()); + m_ownerViewer = ownerViewer; +} +} \ No newline at end of file diff --git a/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafPdmUi3dObjectEditorHandle.h b/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafPdmUi3dObjectEditorHandle.h new file mode 100644 index 0000000000..2c387321fb --- /dev/null +++ b/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafPdmUi3dObjectEditorHandle.h @@ -0,0 +1,89 @@ +//################################################################################################## +// +// Custom Visualization Core library +// Copyright (C) Ceetron Solutions AS +// +// This library may be used under the terms of either the GNU General Public License or +// the GNU Lesser General Public License as follows: +// +// GNU General Public License Usage +// This library 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 3 of the License, or +// (at your option) any later version. +// +// This library 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 at <> +// for more details. +// +// GNU Lesser General Public License Usage +// This library 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.1 of the License, or +// (at your option) any later version. +// +// This library 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 at <> +// for more details. +// +//################################################################################################## +#pragma once + +#include "cafPdmUiObjectEditorHandle.h" + +#include "cafFactory.h" + +#include +#include + +// PdmUiObjectEditorHandle -<| PdmUiWidgetObjectEditorHandle --<| PdmUiFormLayoutObjectEditor +// -<| PdmUi3dObjectEditorHandle +namespace caf +{ + +//================================================================================================== +/// Macros helping in development of PDM UI 3d editors +//================================================================================================== + +/// CAF_PDM_UI_3D_OBJECT_EDITOR_HEADER_INIT assists the factory used when creating editors +/// Place this in the header file inside the class definition of your PdmUiEditor + +#define CAF_PDM_UI_3D_OBJECT_EDITOR_HEADER_INIT \ +public: \ + static QString uiEditorTypeName() + +/// CAF_PDM_UI_3D_OBJECT_EDITOR_SOURCE_INIT implements editorTypeName() and registers the field editor in the field editor factory +/// Place this in the cpp file, preferably above the constructor + +#define CAF_PDM_UI_3D_OBJECT_EDITOR_SOURCE_INIT(EditorClassName) \ + QString EditorClassName::uiEditorTypeName() { return #EditorClassName; } \ + CAF_FACTORY_REGISTER(caf::PdmUi3dObjectEditorHandle, EditorClassName, QString, EditorClassName::uiEditorTypeName()) + +//================================================================================================== +/// Abstract class for 3D editors editing complete PdmObjects +//================================================================================================== + +class PdmUi3dObjectEditorHandle : public caf::PdmUiObjectEditorHandle +{ +public: + PdmUi3dObjectEditorHandle(); + ~PdmUi3dObjectEditorHandle() override; + + void setViewer(QWidget* ownerViewer); + +protected: + QWidget* ownerViewer() const { return m_ownerViewer;} + +private: + + QPointer m_ownerViewer; +}; + +} + diff --git a/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafPdmUiEditorHandle.cpp b/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafPdmUiEditorHandle.cpp index cc3153de1e..7c23842082 100644 --- a/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafPdmUiEditorHandle.cpp +++ b/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafPdmUiEditorHandle.cpp @@ -68,6 +68,8 @@ void PdmUiEditorHandle::updateUi(const QString& uiConfigName) m_currentConfigName = uiConfigName; this->configureAndUpdateUi(uiConfigName); m_isConfiguringUi = false; + + emit uiUpdated(); } //-------------------------------------------------------------------------------------------------- @@ -79,6 +81,8 @@ void PdmUiEditorHandle::updateUi() m_isConfiguringUi = true; this->configureAndUpdateUi(m_currentConfigName); m_isConfiguringUi = false; + + emit uiUpdated(); } //-------------------------------------------------------------------------------------------------- diff --git a/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafPdmUiEditorHandle.h b/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafPdmUiEditorHandle.h index f3641e40d5..2cbd04aa0a 100644 --- a/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafPdmUiEditorHandle.h +++ b/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafPdmUiEditorHandle.h @@ -52,13 +52,17 @@ class PdmUiItem; class PdmUiEditorHandle : public QObject { + Q_OBJECT public: PdmUiEditorHandle(); ~PdmUiEditorHandle() override; public: void updateUi(const QString& uiConfigName);; - void updateUi();; + void updateUi(); + +signals: + void uiUpdated(); protected: // Interface to override: @@ -81,34 +85,5 @@ class PdmUiEditorHandle : public QObject bool m_isConfiguringUi; }; - -//================================================================================================== -/// Proxy editor handle used to propagate updates to the editor responsible for the UI for this object -/// -/// A tree view control is connected to the root item, and all nodes in the tree will have a proxy editor -/// pointing to the root node editor controlling the UI for the whole tree -//================================================================================================== -class PdmUiProxyEditorHandle: public PdmUiEditorHandle -{ -public: - explicit PdmUiProxyEditorHandle(PdmUiEditorHandle* mainEditorHandle) : PdmUiEditorHandle() { m_mainEditorHandle = mainEditorHandle; } - ~PdmUiProxyEditorHandle() override {}; - -protected: // Interface to override: - - /// Supposed to update all parts of the widgets, both visibility, sensitivity, decorations and field data - void configureAndUpdateUi(const QString& uiConfigName) override - { - if (m_mainEditorHandle) - { - m_mainEditorHandle->updateUi(uiConfigName); - } - }; - -private: - PdmUiEditorHandle* m_mainEditorHandle; -}; - - } // End of namespace caf diff --git a/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafPdmUiFieldEditorHandle.cpp b/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafPdmUiFieldEditorHandle.cpp index 6aae177baf..ea7760cc9a 100644 --- a/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafPdmUiFieldEditorHandle.cpp +++ b/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafPdmUiFieldEditorHandle.cpp @@ -112,6 +112,10 @@ void PdmUiFieldEditorHandle::createWidgets(QWidget * parent) { connect(m_editorWidget, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(customMenuRequested(QPoint))); } + if (m_labelWidget) + { + m_labelWidget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed); + } } //-------------------------------------------------------------------------------------------------- @@ -122,6 +126,14 @@ QMargins PdmUiFieldEditorHandle::labelContentMargins() const return calculateLabelContentMargins(); } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +int PdmUiFieldEditorHandle::rowStretchFactor() const +{ + return isMultiRowEditor() ? 1 : 0; +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -133,7 +145,7 @@ void PdmUiFieldEditorHandle::setValueToField(const QVariant& newUiValue) //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void PdmUiFieldEditorHandle::updateLabelFromField(QLabel* label, const QString& uiConfigName) const +void PdmUiFieldEditorHandle::updateLabelFromField(QShortenedLabel* label, const QString& uiConfigName /*= ""*/) const { CAF_ASSERT(label); @@ -165,6 +177,14 @@ QMargins PdmUiFieldEditorHandle::calculateLabelContentMargins() const return m_labelWidget->contentsMargins(); } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool PdmUiFieldEditorHandle::isMultiRowEditor() const +{ + return false; +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- diff --git a/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafPdmUiFieldEditorHandle.h b/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafPdmUiFieldEditorHandle.h index b2c220f794..763c3746ad 100644 --- a/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafPdmUiFieldEditorHandle.h +++ b/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafPdmUiFieldEditorHandle.h @@ -35,9 +35,10 @@ //################################################################################################## #pragma once +#include "cafClassTypeName.h" #include "cafFactory.h" #include "cafPdmUiEditorHandle.h" -#include "cafClassTypeName.h" +#include "cafQShortenedLabel.h" #include @@ -98,7 +99,7 @@ class PdmUiFieldEditorHandle : public PdmUiEditorHandle QWidget* editorWidget() { return m_editorWidget; } QWidget* labelWidget() { return m_labelWidget; } QMargins labelContentMargins() const; - + int rowStretchFactor() const; protected: // Virtual interface to override /// Implement one of these, or both editor and label. The widgets will be used in the parent layout according to /// being "Label" Editor" or a single combined widget. @@ -109,8 +110,9 @@ class PdmUiFieldEditorHandle : public PdmUiEditorHandle void setValueToField(const QVariant& value); - void updateLabelFromField(QLabel* label, const QString& uiConfigName = "") const; + void updateLabelFromField(QShortenedLabel* label, const QString& uiConfigName = "") const; virtual QMargins calculateLabelContentMargins() const; + virtual bool isMultiRowEditor() const; private slots: void customMenuRequested(QPoint pos); diff --git a/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafPdmUiFieldHandle.cpp b/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafPdmUiFieldHandle.cpp index 0cb0e16e0b..ba6f09c866 100644 --- a/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafPdmUiFieldHandle.cpp +++ b/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafPdmUiFieldHandle.cpp @@ -58,11 +58,27 @@ void PdmUiFieldHandle::notifyFieldChanged(const QVariant& oldFieldValue, const Q PdmFieldHandle* fieldHandle = this->fieldHandle(); CAF_ASSERT(fieldHandle && fieldHandle->ownerObject()); - PdmUiObjectHandle* uiObjHandle = uiObj(fieldHandle->ownerObject()); - if (uiObjHandle) + PdmObjectHandle* ownerObjectHandle = fieldHandle->ownerObject(); + + { + PdmUiObjectHandle* uiObjHandle = uiObj(ownerObjectHandle); + if (uiObjHandle) + { + uiObjHandle->fieldChangedByUi(fieldHandle, oldFieldValue, newFieldValue); + uiObjHandle->updateConnectedEditors(); + + } + } + + if (ownerObjectHandle->parentField() && ownerObjectHandle->parentField()->ownerObject()) { - uiObjHandle->fieldChangedByUi(fieldHandle, oldFieldValue, newFieldValue); - uiObjHandle->updateConnectedEditors(); + PdmUiObjectHandle* uiObjHandle = uiObj(ownerObjectHandle->parentField()->ownerObject()); + if (uiObjHandle) + { + uiObjHandle->childFieldChangedByUi(ownerObjectHandle->parentField()); + + // If updateConnectedEditors() is required, this has to be called in childFieldChangedByUi() + } } // Update field editors diff --git a/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafPdmUiItem.cpp b/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafPdmUiItem.cpp index 7b2a30549a..cca07972ea 100644 --- a/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafPdmUiItem.cpp +++ b/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafPdmUiItem.cpp @@ -418,6 +418,30 @@ void PdmUiItem::setUiEditorTypeName(const QString& editorTypeName, const QString m_configItemInfos[uiConfigName].m_editorTypeName = editorTypeName; } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString PdmUiItem::ui3dEditorTypeName(const QString& uiConfigName) const +{ + const PdmUiItemInfo* conInfo = configInfo(uiConfigName); + const PdmUiItemInfo* defInfo = defaultInfo(); + const PdmUiItemInfo* sttInfo = m_staticItemInfo; + + if (conInfo && !(conInfo->m_3dEditorTypeName.isEmpty())) return conInfo->m_3dEditorTypeName; + if (defInfo && !(defInfo->m_3dEditorTypeName.isEmpty())) return defInfo->m_3dEditorTypeName; + if (sttInfo && !(sttInfo->m_3dEditorTypeName.isEmpty())) return sttInfo->m_3dEditorTypeName; + + return QString(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void PdmUiItem::setUi3dEditorTypeName(const QString& editorTypeName, const QString& uiConfigName /*= ""*/) +{ + m_configItemInfos[uiConfigName].m_3dEditorTypeName = editorTypeName; +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- diff --git a/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafPdmUiItem.h b/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafPdmUiItem.h index 9b67ecfd25..f1bcc325fa 100644 --- a/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafPdmUiItem.h +++ b/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafPdmUiItem.h @@ -56,12 +56,26 @@ class PdmUiItemInfo { public: PdmUiItemInfo() - : m_editorTypeName(""), m_isHidden(-1), m_isTreeChildrenHidden(-1), m_isReadOnly(-1), m_labelAlignment(LEFT), m_isCustomContextMenuEnabled(-1) + : m_editorTypeName("") + , m_isHidden(-1) + , m_isTreeChildrenHidden(-1) + , m_isReadOnly(-1) + , m_labelAlignment(LEFT) + , m_isCustomContextMenuEnabled(-1) {} PdmUiItemInfo(const QString& uiName, QIcon icon = QIcon(), QString toolTip = "", QString whatsThis = "", QString extraDebugText = "") - : m_uiName(uiName), m_icon(icon), m_toolTip(toolTip), m_whatsThis(whatsThis), m_extraDebugText(extraDebugText), - m_editorTypeName(""), m_isHidden(false), m_isTreeChildrenHidden(false), m_isReadOnly(false), m_labelAlignment(LEFT), m_isCustomContextMenuEnabled(false) + : m_uiName(uiName) + , m_icon(icon) + , m_toolTip(toolTip) + , m_whatsThis(whatsThis) + , m_extraDebugText(extraDebugText) + , m_editorTypeName("") + , m_isHidden(false) + , m_isTreeChildrenHidden(false) + , m_isReadOnly(false) + , m_labelAlignment(LEFT) + , m_isCustomContextMenuEnabled(false) { } enum LabelPosType { LEFT, TOP, HIDDEN }; @@ -75,6 +89,7 @@ class PdmUiItemInfo QString m_whatsThis; QString m_extraDebugText; QString m_editorTypeName; ///< Use this exact type of editor to edit this UiItem + QString m_3dEditorTypeName; ///< If set, use this editor type to edit this UiItem in 3D int m_isHidden; ///< UiItem should be hidden. -1 means not set int m_isTreeChildrenHidden; ///< Children of UiItem should be hidden. -1 means not set int m_isReadOnly; ///< UiItem should be insensitive, or read only. -1 means not set. @@ -236,6 +251,9 @@ class PdmUiItem QString uiEditorTypeName(const QString& uiConfigName) const; void setUiEditorTypeName(const QString& editorTypeName, const QString& uiConfigName = ""); + QString ui3dEditorTypeName(const QString& uiConfigName) const; + void setUi3dEditorTypeName(const QString& editorTypeName, const QString& uiConfigName = ""); + virtual bool isUiGroup() const; /// Intended to be called when fields in an object has been changed diff --git a/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafPdmUiObjectEditorHandle.cpp b/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafPdmUiObjectEditorHandle.cpp index 711ad73a91..269def0c2e 100644 --- a/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafPdmUiObjectEditorHandle.cpp +++ b/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafPdmUiObjectEditorHandle.cpp @@ -34,10 +34,8 @@ // //################################################################################################## - #include "cafPdmUiObjectEditorHandle.h" -#include "cafPdmObjectHandle.h" #include "cafPdmUiObjectHandle.h" namespace caf @@ -61,26 +59,6 @@ PdmUiObjectEditorHandle::~PdmUiObjectEditorHandle() m_sRegisteredObjectEditors.erase(this); } -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -QWidget* PdmUiObjectEditorHandle::getOrCreateWidget(QWidget* parent) -{ - if (m_widget.isNull()) - { - m_widget = this->createWidget(parent); - } - return m_widget; -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -QWidget* PdmUiObjectEditorHandle::widget() const -{ - return m_widget; -} - //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- diff --git a/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafPdmUiObjectEditorHandle.h b/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafPdmUiObjectEditorHandle.h index e6a481219f..1e237bbdfa 100644 --- a/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafPdmUiObjectEditorHandle.h +++ b/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafPdmUiObjectEditorHandle.h @@ -2,6 +2,7 @@ // // Custom Visualization Core library // Copyright (C) 2011-2013 Ceetron AS +// Copyright (C) Ceetron Solutions AS // // This library may be used under the terms of either the GNU General Public License or // the GNU Lesser General Public License as follows: @@ -41,10 +42,6 @@ #include "cafPdmPointer.h" #include -#include -#include - -#include namespace caf { @@ -60,9 +57,6 @@ class PdmUiObjectEditorHandle : public PdmUiEditorHandle public: PdmUiObjectEditorHandle(); ~PdmUiObjectEditorHandle() override; - - QWidget* getOrCreateWidget(QWidget* parent); - QWidget* widget() const; void setPdmObject(PdmObjectHandle* object); PdmObjectHandle* pdmObject(); @@ -72,18 +66,12 @@ class PdmUiObjectEditorHandle : public PdmUiEditorHandle static void updateUiAllObjectEditors(); protected: - /// Supposed to create the top level widget of the editor with a suitable QLayout - virtual QWidget* createWidget(QWidget* parent) = 0; - virtual void cleanupBeforeSettingPdmObject() {}; private: - QPointer m_widget; static std::set> m_sRegisteredObjectEditors; }; - - } // End of namespace caf diff --git a/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafPdmUiObjectHandle.h b/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafPdmUiObjectHandle.h index 7818894f66..c7cc5165fd 100644 --- a/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafPdmUiObjectHandle.h +++ b/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafPdmUiObjectHandle.h @@ -58,6 +58,9 @@ class PdmUiObjectHandle : public PdmUiItem, public PdmObjectCapability /// Method to reimplement to catch when the field has changed due to setUiValue() virtual void fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue) {} + /// Method to reimplement to catch when a field in a contained object has changed due to setUiValue() + virtual void childFieldChangedByUi(const caf::PdmFieldHandle* changedChildField) {} + /// Method to re-implement to supply option values for a specific field virtual QList calculateValueOptions(const caf::PdmFieldHandle* fieldNeedingOptions, bool* useOptionsOnly) { return QList(); } diff --git a/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafPdmUiOrdering.cpp b/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafPdmUiOrdering.cpp index 2a0490b87c..f8dcf40dc7 100644 --- a/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafPdmUiOrdering.cpp +++ b/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafPdmUiOrdering.cpp @@ -311,35 +311,105 @@ const std::vector& PdmUiOrdering::uiItemsWithLayo //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -int PdmUiOrdering::nrOfColumns() const +PdmUiOrdering::TableLayout PdmUiOrdering::calculateTableLayout(const QString& uiConfigName) const { - int maxColumns = 0; - int currentRowColumns = 0; - for (const FieldAndLayout& itemAndLayout : m_ordering) + TableLayout tableLayout; + + for (size_t i = 0; i < m_ordering.size(); ++i) { - int currentColumnSpan = itemAndLayout.second.totalColumnSpan; - if (currentColumnSpan == LayoutOptions::MAX_COLUMN_SPAN) - { - int minimumFieldColumnSpan = 1; - int minimumLabelColumnSpan = 0; - if (itemAndLayout.first->uiLabelPosition() == PdmUiItemInfo::LEFT) - { - minimumLabelColumnSpan = 1; - } - currentColumnSpan = minimumLabelColumnSpan + minimumFieldColumnSpan; - } + if (m_ordering[i].first->isUiHidden(uiConfigName)) continue; - if (itemAndLayout.second.newRow) + if (m_ordering[i].second.newRow || i == 0u) { - currentRowColumns = currentColumnSpan; + tableLayout.push_back(RowLayout()); } - else + tableLayout.back().push_back(m_ordering[i]); + } + return tableLayout; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +int PdmUiOrdering::nrOfColumns(const TableLayout& tableLayout) const +{ + int maxNrOfColumns = 0; + + for (const auto& rowContent : tableLayout) + { + maxNrOfColumns = std::max(maxNrOfColumns, nrOfRequiredColumnsInRow(rowContent)); + } + + return maxNrOfColumns; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +int PdmUiOrdering::nrOfRequiredColumnsInRow(const RowLayout& rowItems) const +{ + int totalColumns = 0; + for (const FieldAndLayout& item : rowItems) + { + int totalItemColumns = 0, labelItemColumns = 0, fieldItemColumns = 0; + nrOfColumnsRequiredForItem(item, &totalItemColumns, &labelItemColumns, &fieldItemColumns); + totalColumns += totalItemColumns; + } + return totalColumns; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +int PdmUiOrdering::nrOfExpandingItemsInRow(const RowLayout& rowItems) const +{ + int nrOfExpandingItems = 0; + for (const FieldAndLayout& item : rowItems) + { + if (item.second.totalColumnSpan == LayoutOptions::MAX_COLUMN_SPAN) + nrOfExpandingItems++; + } + return nrOfExpandingItems; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void PdmUiOrdering::nrOfColumnsRequiredForItem(const FieldAndLayout& fieldAndLayout, + int* totalColumnsRequired, + int* labelColumnsRequired, + int* fieldColumnsRequired) const +{ + const PdmUiItem* uiItem = fieldAndLayout.first; + CAF_ASSERT(uiItem && totalColumnsRequired && labelColumnsRequired && fieldColumnsRequired); + + LayoutOptions layoutOption = fieldAndLayout.second; + + if (uiItem->isUiGroup()) + { + *totalColumnsRequired = 1; + *labelColumnsRequired = 0; + *fieldColumnsRequired = 0; + } + else + { + *fieldColumnsRequired = 1; + *labelColumnsRequired = 0; + if (uiItem->uiLabelPosition() == PdmUiItemInfo::LEFT) { - currentRowColumns += currentColumnSpan; + *labelColumnsRequired = 1; + if (layoutOption.leftLabelColumnSpan != LayoutOptions::MAX_COLUMN_SPAN) + { + *labelColumnsRequired = layoutOption.leftLabelColumnSpan; + } } - maxColumns = std::max(maxColumns, currentRowColumns); + *totalColumnsRequired = *labelColumnsRequired + *fieldColumnsRequired; + } + + if (layoutOption.totalColumnSpan != LayoutOptions::MAX_COLUMN_SPAN) + { + *totalColumnsRequired = layoutOption.totalColumnSpan; } - return maxColumns; } //-------------------------------------------------------------------------------------------------- diff --git a/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafPdmUiOrdering.h b/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafPdmUiOrdering.h index 9dce113c9a..052ee0a0ba 100644 --- a/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafPdmUiOrdering.h +++ b/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafPdmUiOrdering.h @@ -67,6 +67,8 @@ class PdmUiOrdering int leftLabelColumnSpan; }; typedef std::pair FieldAndLayout; + typedef std::vector RowLayout; + typedef std::vector TableLayout; PdmUiOrdering(): m_skipRemainingFields(false) { }; virtual ~PdmUiOrdering(); @@ -92,10 +94,18 @@ class PdmUiOrdering void skipRemainingFields(bool doSkip = true); // Pdm internal methods - - const std::vector uiItems() const; - const std::vector& uiItemsWithLayout() const; - int nrOfColumns() const; + + const std::vector uiItems() const; + const std::vector& uiItemsWithLayout() const; + + std::vector> calculateTableLayout(const QString& uiConfigName) const; + int nrOfColumns(const TableLayout& tableLayout) const; + int nrOfRequiredColumnsInRow(const RowLayout& rowItems) const; + int nrOfExpandingItemsInRow(const RowLayout& rowItems) const; + void nrOfColumnsRequiredForItem(const FieldAndLayout& fieldAndLayout, + int* totalColumnsRequired, + int* labelColumnsRequired, + int* fieldColumnsRequired) const; bool contains(const PdmUiItem* item) const; bool isIncludingRemainingFields() const; diff --git a/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafPdmUiSelection3dEditorVisualizer.cpp b/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafPdmUiSelection3dEditorVisualizer.cpp new file mode 100644 index 0000000000..d3947501b5 --- /dev/null +++ b/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafPdmUiSelection3dEditorVisualizer.cpp @@ -0,0 +1,127 @@ +//################################################################################################## +// +// Custom Visualization Core library +// Copyright (C) Ceetron Solutions AS +// +// This library may be used under the terms of either the GNU General Public License or +// the GNU Lesser General Public License as follows: +// +// GNU General Public License Usage +// This library 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 3 of the License, or +// (at your option) any later version. +// +// This library 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 at <> +// for more details. +// +// GNU Lesser General Public License Usage +// This library 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.1 of the License, or +// (at your option) any later version. +// +// This library 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 at <> +// for more details. +// +//################################################################################################## + +#include "cafPdmUiSelection3dEditorVisualizer.h" + +//================================================================================================== +/// +/// +/// +//================================================================================================== + +#include "cafSelectionManager.h" + +namespace caf +{ + +//-------------------------------------------------------------------------------------------------- +/// The ownerViewer will take over ownership of this class. The ownerViewer is also the viewer distributed to +/// the 3dEditors created by this class to make them know where to exist. +//-------------------------------------------------------------------------------------------------- +PdmUiSelection3dEditorVisualizer::PdmUiSelection3dEditorVisualizer(QWidget* ownerViewer) + : m_ownerViewer(ownerViewer) +{ + this->setParent(ownerViewer); // Makes this owned by the viewer. +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +PdmUiSelection3dEditorVisualizer::~PdmUiSelection3dEditorVisualizer() +{ + for (const auto& editor: m_active3DEditors) + { + delete editor; + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void PdmUiSelection3dEditorVisualizer::updateVisibleEditors() +{ + for (const auto& editor: m_active3DEditors) + { + if (editor) editor->updateUi(); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void PdmUiSelection3dEditorVisualizer::onSelectionManagerSelectionChanged( const std::set& changedSelectionLevels ) +{ + if (!changedSelectionLevels.count(0)) return; + + for (const auto& editor: m_active3DEditors) + { + delete editor; + } + + m_active3DEditors.clear(); + + if (!m_ownerViewer) return; + + std::set totalSelection; + for ( int selLevel: changedSelectionLevels ) + { + std::vector items; + caf::SelectionManager::instance()->selectedItems(items, selLevel ); + totalSelection.insert(items.begin(), items.end()); + } + + for (PdmUiItem* item: totalSelection) + { + QString editor3dTypeName = item->ui3dEditorTypeName(m_configName); + if (!editor3dTypeName.isEmpty()) + { + PdmObjectHandle* itemObject = dynamic_cast(item); + if (itemObject) + { + PdmUi3dObjectEditorHandle* editor3d = caf::Factory::instance()->create(editor3dTypeName); + editor3d->setViewer(m_ownerViewer); + editor3d->setPdmObject(itemObject); + m_active3DEditors.emplace_back(editor3d); + editor3d->updateUi(); + } + } + } + + m_ownerViewer->update(); +} + +} // end namespace caf + diff --git a/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafPdmUiSelection3dEditorVisualizer.h b/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafPdmUiSelection3dEditorVisualizer.h new file mode 100644 index 0000000000..249090f02e --- /dev/null +++ b/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafPdmUiSelection3dEditorVisualizer.h @@ -0,0 +1,77 @@ +//################################################################################################## +// +// Custom Visualization Core library +// Copyright (C) Ceetron Solutions AS +// +// This library may be used under the terms of either the GNU General Public License or +// the GNU Lesser General Public License as follows: +// +// GNU General Public License Usage +// This library 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 3 of the License, or +// (at your option) any later version. +// +// This library 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 at <> +// for more details. +// +// GNU Lesser General Public License Usage +// This library 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.1 of the License, or +// (at your option) any later version. +// +// This library 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 at <> +// for more details. +// +//################################################################################################## +#pragma once + +#include "cafSelectionChangedReceiver.h" +#include "cafPdmUi3dObjectEditorHandle.h" + +#include +#include +#include + +#include + +namespace caf +{ + +//================================================================================================== +/// +/// +/// +//================================================================================================== + +// Selected object 3D editor visualizer +class PdmUiSelection3dEditorVisualizer : public QObject, caf::SelectionChangedReceiver +{ + Q_OBJECT +public: + PdmUiSelection3dEditorVisualizer(QWidget* ownerViewer); + ~PdmUiSelection3dEditorVisualizer() override; + + void setConfigName(const QString& configName) { m_configName = configName; } + + void updateVisibleEditors(); + +private: + void onSelectionManagerSelectionChanged( const std::set& changedSelectionLevels ) override; + + std::vector< QPointer > m_active3DEditors; + QPointer m_ownerViewer; + QString m_configName; +}; + + +} diff --git a/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafPdmUiWidgetObjectEditorHandle.cpp b/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafPdmUiWidgetObjectEditorHandle.cpp new file mode 100644 index 0000000000..8f4b3bc18d --- /dev/null +++ b/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafPdmUiWidgetObjectEditorHandle.cpp @@ -0,0 +1,80 @@ +//################################################################################################## +// +// Custom Visualization Core library +// Copyright (C) Ceetron Solutions AS +// +// This library may be used under the terms of either the GNU General Public License or +// the GNU Lesser General Public License as follows: +// +// GNU General Public License Usage +// This library 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 3 of the License, or +// (at your option) any later version. +// +// This library 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 at <> +// for more details. +// +// GNU Lesser General Public License Usage +// This library 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.1 of the License, or +// (at your option) any later version. +// +// This library 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 at <> +// for more details. +// +//################################################################################################## + +#include "cafPdmUiWidgetObjectEditorHandle.h" + +namespace caf +{ + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +PdmUiWidgetObjectEditorHandle::PdmUiWidgetObjectEditorHandle() +{ + +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +PdmUiWidgetObjectEditorHandle::~PdmUiWidgetObjectEditorHandle() +{ + +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QWidget* PdmUiWidgetObjectEditorHandle::getOrCreateWidget(QWidget* parent) +{ + if (m_widget.isNull()) + { + m_widget = this->createWidget(parent); + } + return m_widget; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QWidget* PdmUiWidgetObjectEditorHandle::widget() const +{ + return m_widget; +} + + +} //End of namespace caf + diff --git a/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafPdmUiWidgetObjectEditorHandle.h b/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafPdmUiWidgetObjectEditorHandle.h new file mode 100644 index 0000000000..58a50487d8 --- /dev/null +++ b/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafPdmUiWidgetObjectEditorHandle.h @@ -0,0 +1,70 @@ +//################################################################################################## +// +// Custom Visualization Core library +// Copyright (C) Ceetron Solutions AS +// +// This library may be used under the terms of either the GNU General Public License or +// the GNU Lesser General Public License as follows: +// +// GNU General Public License Usage +// This library 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 3 of the License, or +// (at your option) any later version. +// +// This library 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 at <> +// for more details. +// +// GNU Lesser General Public License Usage +// This library 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.1 of the License, or +// (at your option) any later version. +// +// This library 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 at <> +// for more details. +// +//################################################################################################## +#pragma once + +#include "cafPdmUiObjectEditorHandle.h" + +#include +#include + +namespace caf +{ + +//================================================================================================== +/// Abstract class to handle widget based editors for complete PdmObjects +//================================================================================================== + +class PdmUiWidgetObjectEditorHandle : public PdmUiObjectEditorHandle +{ +public: + PdmUiWidgetObjectEditorHandle(); + ~PdmUiWidgetObjectEditorHandle() override; + + QWidget* getOrCreateWidget(QWidget* parent); + QWidget* widget() const; + +protected: + /// Supposed to create the top level widget of the editor with a suitable QLayout + virtual QWidget* createWidget(QWidget* parent) = 0; + +private: + QPointer m_widget; +}; + + + +} // End of namespace caf + diff --git a/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafQShortenedLabel.cpp b/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafQShortenedLabel.cpp new file mode 100644 index 0000000000..4145eff9a4 --- /dev/null +++ b/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafQShortenedLabel.cpp @@ -0,0 +1,179 @@ +//################################################################################################## +// +// Custom Visualization Core library +// Copyright (C) 2019- Ceetron Solutions AS +// +// This library may be used under the terms of either the GNU General Public License or +// the GNU Lesser General Public License as follows: +// +// GNU General Public License Usage +// This library 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 3 of the License, or +// (at your option) any later version. +// +// This library 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 at <> +// for more details. +// +// GNU Lesser General Public License Usage +// This library 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.1 of the License, or +// (at your option) any later version. +// +// This library 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 at <> +// for more details. +// +//################################################################################################## +#include "cafQShortenedLabel.h" + +#include +#include +#include +#include + +using namespace caf; + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QShortenedLabel::QShortenedLabel(QWidget* parent /*= nullptr*/, Qt::WindowFlags f /*= Qt::WindowFlags()*/) + : QLabel(parent, f) +{ +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void QShortenedLabel::setText(const QString& text) +{ + bool textHasChanged = m_fullLengthText != text; + + m_fullLengthText = text; + setDisplayText(text); + + if (textHasChanged) + { + adjustSize(); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString QShortenedLabel::fullText() const +{ + return m_fullLengthText; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QSize QShortenedLabel::minimumSizeHint() const +{ + int minimumWidth = 20; + + QFontMetrics fontMetrics = QApplication::fontMetrics(); + QString fullLabelText = fullText(); + + if (!fullLabelText.isEmpty()) + { + int maxLineWidth = 0; + int maxFirstWordWidth = 0; + + QStringList labelLines = fullLabelText.split("\n"); + for (QString line : labelLines) + { + int lineWidth = fontMetrics.width(line); + maxLineWidth = std::max(maxLineWidth, lineWidth); + QStringList words = line.split(" "); + if (!words.empty()) + { + int wordWidth = fontMetrics.width(words.front() + "..."); + maxFirstWordWidth = std::max(maxFirstWordWidth, wordWidth); + } + } + int minimumTextWidth = std::min(maxLineWidth, maxFirstWordWidth); + minimumWidth = std::max(minimumWidth, minimumTextWidth); + } + QSize minimumSize = QLabel::minimumSizeHint(); + minimumSize.setWidth(minimumWidth); + return minimumSize; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QSize QShortenedLabel::sizeHint() const +{ + QFontMetrics fontMetrics = QApplication::fontMetrics(); + QString labelText = fullText(); + + QStringList labelLines = labelText.split("\n"); + int maxLineWidth = 0; + for (const QString& line : labelLines) + { + maxLineWidth = std::max(maxLineWidth, fontMetrics.width(line)); + } + + return QSize(maxLineWidth, QLabel::sizeHint().height()); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void QShortenedLabel::resizeEvent(QResizeEvent* event) +{ + QSize paintSize = event->size(); + resizeText(paintSize); + QLabel::resizeEvent(event); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void caf::QShortenedLabel::resizeText(QSize paintSize) +{ + QString labelText = fullText(); + QFontMetrics fontMetrics = QApplication::fontMetrics(); + + QStringList labelLines = labelText.split("\n"); + int maxLineWidth = 0; + for (const QString& line : labelLines) + { + maxLineWidth += fontMetrics.width(line); + } + + if (maxLineWidth < paintSize.width()) + { + setDisplayText(labelText); + } + else + { + int limitWidth = std::max(minimumSizeHint().width(), paintSize.width()); + + QStringList elidedLines; + for (const QString& line : labelLines) + { + QString elidedLine = fontMetrics.elidedText(line, Qt::ElideRight, limitWidth); + elidedLines.push_back(elidedLine); + } + setDisplayText(elidedLines.join("\n")); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void QShortenedLabel::setDisplayText(const QString& displayText) +{ + QLabel::setText(displayText); +} diff --git a/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafQShortenedLabel.h b/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafQShortenedLabel.h new file mode 100644 index 0000000000..b233b36331 --- /dev/null +++ b/Fwk/AppFwk/cafProjectDataModel/cafPdmUiCore/cafQShortenedLabel.h @@ -0,0 +1,61 @@ +//################################################################################################## +// +// Custom Visualization Core library +// Copyright (C) 2019- Ceetron Solutions AS +// +// This library may be used under the terms of either the GNU General Public License or +// the GNU Lesser General Public License as follows: +// +// GNU General Public License Usage +// This library 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 3 of the License, or +// (at your option) any later version. +// +// This library 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 at <> +// for more details. +// +// GNU Lesser General Public License Usage +// This library 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.1 of the License, or +// (at your option) any later version. +// +// This library 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 at <> +// for more details. +// +//################################################################################################## +#pragma once + +#include + +namespace caf +{ +class QShortenedLabel : public QLabel +{ + Q_OBJECT +public: + explicit QShortenedLabel(QWidget *parent = nullptr, Qt::WindowFlags f = Qt::WindowFlags()); + + void setText(const QString& text); + QString fullText() const; + + QSize minimumSizeHint() const override; + QSize sizeHint() const override; +protected: + void resizeEvent(QResizeEvent *event) override; + void resizeText(QSize paintSize); + void setDisplayText(const QString& shortText); +private: + QString m_fullLengthText; +}; +} + diff --git a/Fwk/AppFwk/cafProjectDataModel/cafPdmXml/CMakeLists.txt b/Fwk/AppFwk/cafProjectDataModel/cafPdmXml/CMakeLists.txt index 95b987c4b7..a734681847 100644 --- a/Fwk/AppFwk/cafProjectDataModel/cafPdmXml/CMakeLists.txt +++ b/Fwk/AppFwk/cafProjectDataModel/cafPdmXml/CMakeLists.txt @@ -1,10 +1,14 @@ -cmake_minimum_required (VERSION 2.8) +cmake_minimum_required (VERSION 2.8.12) project (cafPdmXml) # Qt -find_package ( Qt4 COMPONENTS QtCore ) -include (${QT_USE_FILE}) +if (CAF_USE_QT5) + find_package(Qt5 COMPONENTS Core Xml REQUIRED) +else() + find_package(Qt4 COMPONENTS QtCore QtXml REQUIRED) + include(${QT_USE_FILE}) +endif(CAF_USE_QT5) include_directories ( .. @@ -44,8 +48,13 @@ add_library( ${PROJECT_NAME} ${PROJECT_FILES} ) +if (CAF_USE_QT5) + set(QT_LIBRARIES Qt5::Core Qt5::Xml) +endif(CAF_USE_QT5) + target_link_libraries ( ${PROJECT_NAME} cafPdmCore + ${QT_LIBRARIES} ) target_include_directories(${PROJECT_NAME} @@ -58,3 +67,8 @@ if (MSVC) endif() source_group("" FILES ${PROJECT_FILES}) + +# cotire +if (COMMAND caf_apply_cotire) + caf_apply_cotire("${PROJECT_NAME}") +endif() diff --git a/Fwk/AppFwk/cafProjectDataModel/cafPdmXml/cafInternalPdmXmlFieldCapability.h b/Fwk/AppFwk/cafProjectDataModel/cafPdmXml/cafInternalPdmXmlFieldCapability.h index 27582b60fd..b3e9d09f01 100644 --- a/Fwk/AppFwk/cafProjectDataModel/cafPdmXml/cafInternalPdmXmlFieldCapability.h +++ b/Fwk/AppFwk/cafProjectDataModel/cafPdmXml/cafInternalPdmXmlFieldCapability.h @@ -16,6 +16,8 @@ class PdmFieldXmlCap : public PdmXmlFieldHandle public: void readFieldData(QXmlStreamReader& xmlStream, PdmObjectFactory* objectFactory) override; void writeFieldData(QXmlStreamWriter& xmlStream) const override; + bool resolveReferences() override; + private: FieldType* m_field; }; @@ -40,7 +42,7 @@ class PdmFieldXmlCap< PdmPtrField > : public PdmXmlFieldHandle public: void readFieldData(QXmlStreamReader& xmlStream, PdmObjectFactory* objectFactory) override; void writeFieldData(QXmlStreamWriter& xmlStream) const override; - void resolveReferences() override; + bool resolveReferences() override; private: FieldType* m_field; @@ -69,7 +71,7 @@ class PdmFieldXmlCap< PdmPtrArrayField >: public PdmXmlFieldHandle public: void readFieldData(QXmlStreamReader& xmlStream, PdmObjectFactory* objectFactory) override; void writeFieldData(QXmlStreamWriter& xmlStream) const override; - void resolveReferences() override; + bool resolveReferences() override; private: FieldType* m_field; @@ -93,6 +95,8 @@ class PdmFieldXmlCap< PdmChildField > : public PdmXmlFieldHandle public: void readFieldData(QXmlStreamReader& xmlStream, PdmObjectFactory* objectFactory) override; void writeFieldData(QXmlStreamWriter& xmlStream) const override; + bool resolveReferences() override; + private: FieldType* m_field; }; @@ -111,6 +115,7 @@ class PdmFieldXmlCap< PdmChildArrayField > : public PdmXmlFieldHandle public: void readFieldData(QXmlStreamReader& xmlStream, PdmObjectFactory* objectFactory) override; void writeFieldData(QXmlStreamWriter& xmlStream) const override; + bool resolveReferences() override; private: FieldType* m_field; }; diff --git a/Fwk/AppFwk/cafProjectDataModel/cafPdmXml/cafInternalPdmXmlFieldCapability.inl b/Fwk/AppFwk/cafProjectDataModel/cafPdmXml/cafInternalPdmXmlFieldCapability.inl index 6e9a567ae1..3bcb3dea4c 100644 --- a/Fwk/AppFwk/cafProjectDataModel/cafPdmXml/cafInternalPdmXmlFieldCapability.inl +++ b/Fwk/AppFwk/cafProjectDataModel/cafPdmXml/cafInternalPdmXmlFieldCapability.inl @@ -38,6 +38,16 @@ void caf::PdmFieldXmlCap::writeFieldData(QXmlStreamWriter& xmlStream) PdmFieldWriter::writeFieldData(m_field->value(), xmlStream); } + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +template < typename FieldType> +bool caf::PdmFieldXmlCap::resolveReferences() +{ + return true; +} + //================================================================================================== /// XML Implementation for PdmPtrField<> //================================================================================================== @@ -97,14 +107,16 @@ void caf::PdmFieldXmlCap::writeFieldData(QXmlStreamWriter& xmlStream) /// //-------------------------------------------------------------------------------------------------- template < typename DataType> - void caf::PdmFieldXmlCap< PdmPtrField >::resolveReferences() + bool caf::PdmFieldXmlCap< PdmPtrField >::resolveReferences() { - if (m_isResolved) return; - if (m_referenceString.isEmpty()) return; + if (m_isResolved) return true; + if (m_referenceString.isEmpty()) return true; PdmObjectHandle* objHandle = PdmReferenceHelper::objectFromFieldReference(this->fieldHandle(), m_referenceString); m_field->setRawPtr(objHandle); m_isResolved = true; + + return objHandle != nullptr; } //================================================================================================== @@ -163,20 +175,29 @@ void caf::PdmFieldXmlCap::writeFieldData(QXmlStreamWriter& xmlStream) /// //-------------------------------------------------------------------------------------------------- template < typename DataType> - void caf::PdmFieldXmlCap< PdmPtrArrayField >::resolveReferences() + bool caf::PdmFieldXmlCap< PdmPtrArrayField >::resolveReferences() { - if(m_isResolved) return; - if(m_referenceString.isEmpty()) return; + if(m_isResolved) return true; + if(m_referenceString.isEmpty()) return true; m_field->clear(); + + bool foundValidObjectFromString = true; QStringList tokens = m_referenceString.split('|'); for(int i = 0; i < tokens.size(); ++i) { PdmObjectHandle* objHandle = PdmReferenceHelper::objectFromFieldReference(this->fieldHandle(), tokens[i]); + if (!tokens[i].isEmpty() && !objHandle) + { + foundValidObjectFromString = false; + } + m_field->m_pointers.push_back(NULL); m_field->m_pointers.back().setRawPtr(objHandle); } m_isResolved = true; + + return foundValidObjectFromString; } @@ -281,6 +302,15 @@ void caf::PdmFieldXmlCap< caf::PdmChildField >::writeFieldData(QXmlSt } } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +template < typename DataType> +bool caf::PdmFieldXmlCap>::resolveReferences() +{ + return true; +} + //================================================================================================== /// XML Implementation for PdmChildArrayField<> //================================================================================================== @@ -373,4 +403,14 @@ void caf::PdmFieldXmlCap< caf::PdmChildArrayField >::readFieldData(QX } } + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +template < typename DataType> +bool caf::PdmFieldXmlCap>::resolveReferences() +{ + return true; +} + } // End namespace caf diff --git a/Fwk/AppFwk/cafProjectDataModel/cafPdmXml/cafPdmXmlFieldHandle.h b/Fwk/AppFwk/cafProjectDataModel/cafPdmXml/cafPdmXmlFieldHandle.h index 91ca4b9d9b..4f488d61b9 100644 --- a/Fwk/AppFwk/cafProjectDataModel/cafPdmXml/cafPdmXmlFieldHandle.h +++ b/Fwk/AppFwk/cafProjectDataModel/cafPdmXml/cafPdmXmlFieldHandle.h @@ -40,7 +40,7 @@ class PdmXmlFieldHandle : public PdmFieldCapability virtual void readFieldData(QXmlStreamReader& xmlStream, PdmObjectFactory* objectFactory) = 0; virtual void writeFieldData(QXmlStreamWriter& xmlStream) const = 0; - virtual void resolveReferences() { }; + virtual bool resolveReferences() = 0; protected: bool assertValid() const; diff --git a/Fwk/AppFwk/cafProjectDataModel/cafPdmXml/cafPdmXmlObjectHandle.cpp b/Fwk/AppFwk/cafProjectDataModel/cafPdmXml/cafPdmXmlObjectHandle.cpp index fc0847a032..94ca39dc76 100644 --- a/Fwk/AppFwk/cafProjectDataModel/cafPdmXml/cafPdmXmlObjectHandle.cpp +++ b/Fwk/AppFwk/cafProjectDataModel/cafPdmXml/cafPdmXmlObjectHandle.cpp @@ -299,7 +299,7 @@ void PdmXmlObjectHandle::initAfterReadRecursively(PdmObjectHandle* object) //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void PdmXmlObjectHandle::resolveReferencesRecursively(PdmObjectHandle* object) +void PdmXmlObjectHandle::resolveReferencesRecursively(PdmObjectHandle* object, std::vector* fieldWithFailingResolve) { if (object == nullptr) return; @@ -315,14 +315,35 @@ void PdmXmlObjectHandle::resolveReferencesRecursively(PdmObjectHandle* object) { field->childObjects(&children); - field->xmlCapability()->resolveReferences(); + bool resolvedOk = field->xmlCapability()->resolveReferences(); + if (fieldWithFailingResolve && !resolvedOk) + { + fieldWithFailingResolve->push_back(field); + } } } size_t cIdx; for (cIdx = 0; cIdx < children.size(); ++cIdx) { - resolveReferencesRecursively(children[cIdx]); + resolveReferencesRecursively(children[cIdx], fieldWithFailingResolve); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void PdmXmlObjectHandle::resolveReferencesRecursively(std::vector* fieldWithFailingResolve /*= nullptr*/) +{ + std::vector tempFields; + resolveReferencesRecursively(this->m_owner, &tempFields); + + if (fieldWithFailingResolve) + { + for (auto f : tempFields) + { + fieldWithFailingResolve->push_back(f); + } } } diff --git a/Fwk/AppFwk/cafProjectDataModel/cafPdmXml/cafPdmXmlObjectHandle.h b/Fwk/AppFwk/cafProjectDataModel/cafPdmXml/cafPdmXmlObjectHandle.h index 8daba8e57d..8842527047 100644 --- a/Fwk/AppFwk/cafProjectDataModel/cafPdmXml/cafPdmXmlObjectHandle.h +++ b/Fwk/AppFwk/cafProjectDataModel/cafPdmXml/cafPdmXmlObjectHandle.h @@ -4,6 +4,8 @@ #include +#include + class QXmlStreamReader; class QXmlStreamWriter; @@ -15,6 +17,7 @@ class PdmXmlFieldHandle; class PdmObjectHandle; class PdmObjectFactory; class PdmReferenceHelper; +class PdmFieldHandle; //================================================================================================== @@ -51,7 +54,8 @@ class PdmXmlObjectHandle : public PdmObjectCapability void initAfterReadRecursively() { initAfterReadRecursively(this->m_owner); }; void setupBeforeSaveRecursively() { setupBeforeSaveRecursively(this->m_owner); }; - void resolveReferencesRecursively() { resolveReferencesRecursively(this->m_owner); }; + + void resolveReferencesRecursively(std::vector* fieldWithFailingResolve = nullptr); protected: // Virtual /// Method gets called from PdmDocument after all objects are read. @@ -68,7 +72,7 @@ class PdmXmlObjectHandle : public PdmObjectCapability private: void initAfterReadRecursively(PdmObjectHandle* object); void setupBeforeSaveRecursively(PdmObjectHandle * object); - void resolveReferencesRecursively(PdmObjectHandle* object); + void resolveReferencesRecursively(PdmObjectHandle* object, std::vector* fieldWithFailingResolve); private: friend class PdmObjectHandle ; // Only temporary for void PdmObject::addFieldNoDefault( ) accessing findField diff --git a/Fwk/AppFwk/cafProjectDataModel/cafPdmXml/cafPdmXml_UnitTests/CMakeLists.txt b/Fwk/AppFwk/cafProjectDataModel/cafPdmXml/cafPdmXml_UnitTests/CMakeLists.txt index 04b8e830cc..e39d304012 100644 --- a/Fwk/AppFwk/cafProjectDataModel/cafPdmXml/cafPdmXml_UnitTests/CMakeLists.txt +++ b/Fwk/AppFwk/cafProjectDataModel/cafPdmXml/cafPdmXml_UnitTests/CMakeLists.txt @@ -1,10 +1,21 @@ cmake_minimum_required (VERSION 2.8.12) -find_package ( Qt4 COMPONENTS QtCore ) -include (${QT_USE_FILE}) - project ( cafPdmXml_UnitTests ) +find_package(Qt5Core CONFIG QUIET) +if (Qt5Core_FOUND) + find_package(Qt5 CONFIG REQUIRED Core Xml) +else() + find_package(Qt4 COMPONENTS QtCore QtXml REQUIRED) + include(${QT_USE_FILE}) +endif(Qt5Core_FOUND) + +if (MSVC AND (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 19.11)) + # VS 2017 : Disable warnings from from gtest code, using deprecated code related to TR1 + add_definitions(-D_SILENCE_TR1_NAMESPACE_DEPRECATION_WARNING) + message(STATUS "Add flag to disable warings from gtest - _SILENCE_TR1_NAMESPACE_DEPRECATION_WARNING") +endif() + include_directories ( ${CMAKE_CURRENT_SOURCE_DIR} # required for gtest-all.cpp ) @@ -18,7 +29,10 @@ add_executable (${PROJECT_NAME} cafPdmAdvancedTemplateTest.cpp cafPdmXmlNumberTest.cpp ) -message(STATUS ${PROJECT_NAME}" - Qt includes : " ${QT_LIBRARIES}) + +if (Qt5Core_FOUND) + set(QT_LIBRARIES Qt5::Core Qt5::Xml) +endif() target_link_libraries ( ${PROJECT_NAME} cafPdmXml @@ -29,14 +43,24 @@ target_link_libraries ( ${PROJECT_NAME} source_group("" FILES ${PROJECT_FILES}) # Copy Qt Dlls -if (MSVC) - set (QTLIBLIST QtCore ) - foreach (qtlib ${QTLIBLIST}) - - # Debug - execute_process(COMMAND cmake -E copy_if_different ${QT_BINARY_DIR}/${qtlib}d4.dll ${CMAKE_CURRENT_BINARY_DIR}/Debug/${qtlib}d4.dll) - - # Release - execute_process(COMMAND cmake -E copy_if_different ${QT_BINARY_DIR}/${qtlib}4.dll ${CMAKE_CURRENT_BINARY_DIR}/Release/${qtlib}4.dll) - endforeach( qtlib ) -endif(MSVC) +if (Qt5Core_FOUND) + foreach (qtlib ${QT_LIBRARIES}) + add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_if_different $ $ + ) + endforeach(qtlib) + # Copy Qt Dlls +else() + # Copy Qt Dlls + if (MSVC) + set (QTLIBLIST QtCore) + foreach (qtlib ${QTLIBLIST}) + + # Debug + execute_process(COMMAND cmake -E copy_if_different ${QT_BINARY_DIR}/${qtlib}d4.dll ${CMAKE_BINARY_DIR}/Debug/${qtlib}d4.dll) + + # Release + execute_process(COMMAND cmake -E copy_if_different ${QT_BINARY_DIR}/${qtlib}4.dll ${CMAKE_BINARY_DIR}/Release/${qtlib}4.dll) + endforeach( qtlib ) + endif(MSVC) +endif(Qt5Core_FOUND) \ No newline at end of file diff --git a/Fwk/AppFwk/cafProjectDataModel/cafPdmXml/cafPdmXml_UnitTests/cafPdmAdvancedTemplateTest.cpp b/Fwk/AppFwk/cafProjectDataModel/cafPdmXml/cafPdmXml_UnitTests/cafPdmAdvancedTemplateTest.cpp index ea0be7c31b..415be9d61e 100644 --- a/Fwk/AppFwk/cafProjectDataModel/cafPdmXml/cafPdmXml_UnitTests/cafPdmAdvancedTemplateTest.cpp +++ b/Fwk/AppFwk/cafProjectDataModel/cafPdmXml/cafPdmXml_UnitTests/cafPdmAdvancedTemplateTest.cpp @@ -205,3 +205,64 @@ TEST(AdvancedObjectTest, FieldWrite) } } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +TEST(AdvancedObjectTest, CopyOfObjects) +{ + ContainerPdmObject* root = new ContainerPdmObject; + ContainerPdmObject* container = new ContainerPdmObject; + ContainerPdmObject* sibling = new ContainerPdmObject; + root->m_containers.push_back(container); + root->m_containers.push_back(sibling); + + { + ItemPdmObject* item = new ItemPdmObject(); + item->m_name = "Obj A"; + + container->m_items.push_back(item); + } + { + ItemPdmObject* item = new ItemPdmObject(); + item->m_name = "Obj B"; + + container->m_items.push_back(item); + } + + { + ItemPdmObject* item = new ItemPdmObject(); + item->m_name = "Obj C"; + + container->m_items.push_back(item); + + { + { + DemoPdmObjectA* a = new DemoPdmObjectA; + sibling->m_demoObjs.push_back(a); + + a->m_pointerToItem = container->m_items[1]; + + { + auto* objCopy = dynamic_cast(a->xmlCapability()->copyByXmlSerialization(caf::PdmDefaultObjectFactory::instance())); + std::vector fieldWithFailingResolve; + objCopy->resolveReferencesRecursively(&fieldWithFailingResolve); + ASSERT_FALSE(fieldWithFailingResolve.empty()); + delete objCopy; + } + + + { + auto* objCopy = dynamic_cast(a->xmlCapability()->copyByXmlSerialization(caf::PdmDefaultObjectFactory::instance())); + + sibling->m_demoObjs.push_back(objCopy); + + std::vector fieldWithFailingResolve; + objCopy->resolveReferencesRecursively(&fieldWithFailingResolve); + ASSERT_TRUE(fieldWithFailingResolve.empty()); + delete objCopy; + } + } + } + } +} + diff --git a/Fwk/AppFwk/cafProjectDataModel/cafPdmXml/cafPdmXml_UnitTests/cafPdmXmlBasicTest.cpp b/Fwk/AppFwk/cafProjectDataModel/cafPdmXml/cafPdmXml_UnitTests/cafPdmXmlBasicTest.cpp index 00507bb0b0..20bf46270e 100644 --- a/Fwk/AppFwk/cafProjectDataModel/cafPdmXml/cafPdmXml_UnitTests/cafPdmXmlBasicTest.cpp +++ b/Fwk/AppFwk/cafProjectDataModel/cafPdmXml/cafPdmXml_UnitTests/cafPdmXmlBasicTest.cpp @@ -266,7 +266,7 @@ TEST(BaseTest, PdmReferenceHelper) { QString refString = caf::PdmReferenceHelper::referenceFromRootToObject(ihd1, s3); QString expectedString = ihd1->m_childArrayField.keyword() + " 3"; - EXPECT_STREQ(refString.toAscii(), expectedString.toAscii()); + EXPECT_STREQ(refString.toLatin1(), expectedString.toLatin1()); caf::PdmObjectHandle* fromRef = caf::PdmReferenceHelper::objectFromReference(ihd1, refString); EXPECT_TRUE(fromRef == s3); diff --git a/Fwk/AppFwk/cafProjectDataModel/cafProjectDataModel_UnitTests/CMakeLists.txt b/Fwk/AppFwk/cafProjectDataModel/cafProjectDataModel_UnitTests/CMakeLists.txt index e1e29599ee..d675cf7e2f 100644 --- a/Fwk/AppFwk/cafProjectDataModel/cafProjectDataModel_UnitTests/CMakeLists.txt +++ b/Fwk/AppFwk/cafProjectDataModel/cafProjectDataModel_UnitTests/CMakeLists.txt @@ -1,10 +1,21 @@ cmake_minimum_required (VERSION 2.8.12) -find_package ( Qt4 COMPONENTS QtCore QtGui ) -include (${QT_USE_FILE}) - project ( cafProjectDataModel_UnitTests ) +find_package(Qt5Core CONFIG QUIET) +if (Qt5Core_FOUND) + find_package(Qt5 CONFIG REQUIRED Core Xml) +else() + find_package(Qt4 COMPONENTS QtCore QtXml REQUIRED) + include(${QT_USE_FILE}) +endif(Qt5Core_FOUND) + +if (MSVC AND (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 19.11)) + # VS 2017 : Disable warnings from from gtest code, using deprecated code related to TR1 + add_definitions(-D_SILENCE_TR1_NAMESPACE_DEPRECATION_WARNING) + message(STATUS "Add flag to disable warings from gtest - _SILENCE_TR1_NAMESPACE_DEPRECATION_WARNING") +endif() + include_directories ( ${CMAKE_CURRENT_SOURCE_DIR} # required for gtest-all.cpp ) @@ -22,7 +33,10 @@ add_executable (${PROJECT_NAME} ${PROJECT_FILES} gtest/gtest-all.cpp ) -message(${PROJECT_NAME}" - Qt includes : " ${QT_LIBRARIES}) + +if (Qt5Core_FOUND) + set(QT_LIBRARIES Qt5::Core Qt5::Xml) +endif() target_link_libraries ( ${PROJECT_NAME} cafProjectDataModel @@ -33,14 +47,24 @@ target_link_libraries ( ${PROJECT_NAME} source_group("" FILES ${PROJECT_FILES}) # Copy Qt Dlls -if (MSVC) - set (QTLIBLIST QtCore QtGui ) - foreach (qtlib ${QTLIBLIST}) - - # Debug - execute_process(COMMAND cmake -E copy_if_different ${QT_BINARY_DIR}/${qtlib}d4.dll ${CMAKE_CURRENT_BINARY_DIR}/Debug/${qtlib}d4.dll) - - # Release - execute_process(COMMAND cmake -E copy_if_different ${QT_BINARY_DIR}/${qtlib}4.dll ${CMAKE_CURRENT_BINARY_DIR}/Release/${qtlib}4.dll) - endforeach( qtlib ) -endif(MSVC) +if (Qt5Core_FOUND) + foreach (qtlib ${QT_LIBRARIES}) + add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_if_different $ $ + ) + endforeach(qtlib) + # Copy Qt Dlls +else() + # Copy Qt Dlls + if (MSVC) + set (QTLIBLIST QtCore QtGui) + foreach (qtlib ${QTLIBLIST}) + + # Debug + execute_process(COMMAND cmake -E copy_if_different ${QT_BINARY_DIR}/${qtlib}d4.dll ${CMAKE_BINARY_DIR}/Debug/${qtlib}d4.dll) + + # Release + execute_process(COMMAND cmake -E copy_if_different ${QT_BINARY_DIR}/${qtlib}4.dll ${CMAKE_BINARY_DIR}/Release/${qtlib}4.dll) + endforeach( qtlib ) + endif(MSVC) +endif(Qt5Core_FOUND) \ No newline at end of file diff --git a/Fwk/AppFwk/cafProjectDataModel/cafProjectDataModel_UnitTests/cafPdmBasicTest.cpp b/Fwk/AppFwk/cafProjectDataModel/cafProjectDataModel_UnitTests/cafPdmBasicTest.cpp index 8c53376a39..fd63e90882 100644 --- a/Fwk/AppFwk/cafProjectDataModel/cafProjectDataModel_UnitTests/cafPdmBasicTest.cpp +++ b/Fwk/AppFwk/cafProjectDataModel/cafProjectDataModel_UnitTests/cafPdmBasicTest.cpp @@ -968,7 +968,7 @@ TEST(BaseTest, PdmReferenceHelper) refString = caf::PdmReferenceHelper::referenceFromRootToObject(ihd1, s3); QString expectedString = ihd1->m_simpleObjectsField.keyword() + " 3"; - EXPECT_STREQ(refString.toAscii(), expectedString.toAscii()); + EXPECT_STREQ(refString.toLatin1(), expectedString.toLatin1()); caf::PdmObjectHandle* fromRef = caf::PdmReferenceHelper::objectFromReference(ihd1, refString); EXPECT_TRUE(fromRef == s3); diff --git a/Fwk/AppFwk/cafTensor/cafTensor3.inl b/Fwk/AppFwk/cafTensor/cafTensor3.inl index 2bfe705b08..5b251b3c1e 100644 --- a/Fwk/AppFwk/cafTensor/cafTensor3.inl +++ b/Fwk/AppFwk/cafTensor/cafTensor3.inl @@ -22,7 +22,7 @@ #include "cvfSystem.h" #include #include "cvfMatrix3.h" -#include +#include namespace caf { diff --git a/Fwk/AppFwk/cafTests/cafTestApplication/CMakeLists.txt b/Fwk/AppFwk/cafTests/cafTestApplication/CMakeLists.txt index b1fa180561..4a79920601 100644 --- a/Fwk/AppFwk/cafTests/cafTestApplication/CMakeLists.txt +++ b/Fwk/AppFwk/cafTests/cafTestApplication/CMakeLists.txt @@ -1,26 +1,39 @@ cmake_minimum_required (VERSION 2.8.12) +project ( cafTestApplication ) + +# Open GL +find_package( OpenGL ) + # Qt -find_package ( Qt4 COMPONENTS QtCore QtGui QtMain QtOpenGl ) -include (${QT_USE_FILE}) +find_package(Qt5Core CONFIG QUIET) +if (Qt5Core_FOUND) + find_package(Qt5 CONFIG REQUIRED Core Gui OpenGL Widgets) +else() + find_package(Qt4 COMPONENTS QtCore QtGui QtMain QtOpenGl REQUIRED) + include(${QT_USE_FILE}) +endif(Qt5Core_FOUND) + -project ( cafTestApplication ) option(USE_COMMAND_FRAMEWORK "Use Caf Command Framework" ON) # Qt MOC -set ( QT_MOC_HEADERS +set (MOC_HEADER_FILES MainWindow.h WidgetLayoutTest.h - ManyGroups.h CustomObjectEditor.h MenuItemProducer.h ) -qt4_wrap_cpp( MOC_FILES_CPP - ${QT_MOC_HEADERS} -) +if ( NOT CMAKE_AUTOMOC ) + if (Qt5Core_FOUND) + qt5_wrap_cpp(MOC_SOURCE_FILES ${MOC_HEADER_FILES} ) + else() + qt4_wrap_cpp(MOC_SOURCE_FILES ${MOC_HEADER_FILES} ) + endif() +endif() # Resource file set( QRC_FILES @@ -28,9 +41,11 @@ set( QRC_FILES ) # Runs RCC on specified files -qt4_add_resources( QRC_FILES_CPP - ${QRC_FILES} -) +if (Qt5Core_FOUND) + qt5_add_resources( QRC_FILES_CPP ${QRC_FILES} ) +else() + qt4_add_resources( QRC_FILES_CPP ${QRC_FILES} ) +endif() if (USE_COMMAND_FRAMEWORK) include_directories ( @@ -58,13 +73,16 @@ set( PROJECT_FILES # add the executable add_executable ( ${PROJECT_NAME} ${PROJECT_FILES} - ${MOC_FILES_CPP} + ${MOC_SOURCE_FILES} ${QRC_FILES_CPP} ) +if (Qt5Core_FOUND) + set(QT_LIBRARIES Qt5::Core Qt5::Gui Qt5::OpenGL Qt5::Widgets) +endif() + set (TAP_LINK_LIBRARIES cafUserInterface - ${QT_LIBRARIES} ) if (USE_COMMAND_FRAMEWORK) @@ -77,19 +95,35 @@ endif(USE_COMMAND_FRAMEWORK) target_link_libraries ( ${PROJECT_NAME} ${TAP_LINK_LIBRARIES} + ${QT_LIBRARIES} ) source_group("" FILES ${PROJECT_FILES}) # Copy Qt Dlls -if (MSVC) - set (QTLIBLIST QtCore QtGui QtOpenGl) - foreach (qtlib ${QTLIBLIST}) - - # Debug - execute_process(COMMAND cmake -E copy_if_different ${QT_BINARY_DIR}/${qtlib}d4.dll ${CMAKE_CURRENT_BINARY_DIR}/Debug/${qtlib}d4.dll) - - # Release - execute_process(COMMAND cmake -E copy_if_different ${QT_BINARY_DIR}/${qtlib}4.dll ${CMAKE_CURRENT_BINARY_DIR}/Release/${qtlib}4.dll) - endforeach( qtlib ) -endif(MSVC) +if (Qt5Core_FOUND) + foreach (qtlib ${QT_LIBRARIES}) + add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_if_different $ $ + ) + endforeach(qtlib) + # Copy Qt Dlls +else() + # Copy Qt Dlls + if (MSVC) + set (QTLIBLIST QtCore QtGui QtOpenGl ) + foreach (qtlib ${QTLIBLIST}) + + # Debug + execute_process(COMMAND cmake -E copy_if_different ${QT_BINARY_DIR}/${qtlib}d4.dll ${CMAKE_BINARY_DIR}/Debug/${qtlib}d4.dll) + + # Release + execute_process(COMMAND cmake -E copy_if_different ${QT_BINARY_DIR}/${qtlib}4.dll ${CMAKE_BINARY_DIR}/Release/${qtlib}4.dll) + endforeach( qtlib ) + endif(MSVC) +endif(Qt5Core_FOUND) + +# cotire +if (COMMAND caf_apply_cotire) + caf_apply_cotire("${PROJECT_NAME}") +endif() diff --git a/Fwk/AppFwk/cafTests/cafTestApplication/CustomObjectEditor.cpp b/Fwk/AppFwk/cafTests/cafTestApplication/CustomObjectEditor.cpp index 089d8445eb..50e3f800d5 100644 --- a/Fwk/AppFwk/cafTests/cafTestApplication/CustomObjectEditor.cpp +++ b/Fwk/AppFwk/cafTests/cafTestApplication/CustomObjectEditor.cpp @@ -173,7 +173,7 @@ void CustomObjectEditor::recursivelyConfigureAndUpdateTopLevelUiOrdering(const P std::pair rowCol = rowAndColumn(nextCellId); m_layout->addWidget(groupBox, rowCol.first, rowCol.second, 1, 1); - recursivelyConfigureAndUpdateUiOrderingInGridLayoutColumn(*group, groupBox->contentFrame(), uiConfigName); + recursivelyConfigureAndUpdateUiOrderingInNewGridLayout(*group, groupBox->contentFrame(), uiConfigName); } // NB! Only groups at top level are handled, fields at top level are not added to layout diff --git a/Fwk/AppFwk/cafTests/cafTestApplication/MainWindow.cpp b/Fwk/AppFwk/cafTests/cafTestApplication/MainWindow.cpp index 4b51082a51..fb06147860 100644 --- a/Fwk/AppFwk/cafTests/cafTestApplication/MainWindow.cpp +++ b/Fwk/AppFwk/cafTests/cafTestApplication/MainWindow.cpp @@ -376,6 +376,43 @@ class SmallGridDemoPdmObject : public caf::PdmObject CAF_PDM_SOURCE_INIT(SmallGridDemoPdmObject, "SmallGridDemoPdmObject"); +class SingleEditorPdmObject : public caf::PdmObject +{ + CAF_PDM_HEADER_INIT; + +public: + SingleEditorPdmObject() + { + CAF_PDM_InitObject("Single Editor Object", + "", + "This object is a demo of the CAF framework", + "This object is a demo of the CAF framework"); + + CAF_PDM_InitField(&m_intFieldStandard, + "Standard", + 0, + "Fairly Wide Label", + "", + "Enter some small number here", + "This is a place you can enter a small integer value if you want"); + + } + + // Outside group + caf::PdmField m_intFieldStandard; + +protected: + //-------------------------------------------------------------------------------------------------- + /// + //-------------------------------------------------------------------------------------------------- + void defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering) override + { + uiOrdering.add(&m_intFieldStandard); + } +}; + +CAF_PDM_SOURCE_INIT(SingleEditorPdmObject, "SingleEditorObject"); + class SmallDemoPdmObjectA: public caf::PdmObject { CAF_PDM_HEADER_INIT; @@ -873,6 +910,9 @@ void MainWindow::buildTestModel() SmallGridDemoPdmObject* smallGridObj = new SmallGridDemoPdmObject; m_testRoot->objects.push_back(smallGridObj); + SingleEditorPdmObject* singleEditorObj = new SingleEditorPdmObject; + m_testRoot->objects.push_back(singleEditorObj); + DemoPdmObject* demoObj2 = new DemoPdmObject; demoObject->m_textField = "Mitt Demo Obj"; diff --git a/Fwk/AppFwk/cafTests/cafTestApplication/MainWindow.h b/Fwk/AppFwk/cafTests/cafTestApplication/MainWindow.h index 50e0ec5ce8..a71d571acc 100644 --- a/Fwk/AppFwk/cafTests/cafTestApplication/MainWindow.h +++ b/Fwk/AppFwk/cafTests/cafTestApplication/MainWindow.h @@ -1,6 +1,6 @@ #pragma once -#include +#include #include #include diff --git a/Fwk/AppFwk/cafTests/cafTestApplication/ManyGroups.cpp b/Fwk/AppFwk/cafTests/cafTestApplication/ManyGroups.cpp index a631060d0c..f7562e900b 100644 --- a/Fwk/AppFwk/cafTests/cafTestApplication/ManyGroups.cpp +++ b/Fwk/AppFwk/cafTests/cafTestApplication/ManyGroups.cpp @@ -1,32 +1,57 @@ #include "ManyGroups.h" +#include "cafPdmUiListEditor.h" #include "cafPdmUiTreeSelectionEditor.h" CAF_PDM_SOURCE_INIT(ManyGroups, "LargeObject"); - //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- ManyGroups::ManyGroups() { - CAF_PDM_InitObject("Many Groups", ":/images/win/filenew.png", "This object is a demo of the CAF framework", "This object is a demo of the CAF framework"); - - CAF_PDM_InitField(&m_toggleField, "Toggle", false, "Add Items To Multi Select", "", "Toggle Field tooltip", " Toggle Field whatsthis"); - CAF_PDM_InitField(&m_doubleField, "BigNumber", 0.0, "Big Number", "", "Enter a big number here", "This is a place you can enter a big real value if you want"); - CAF_PDM_InitField(&m_intField, "IntNumber", 0, "Small Number", "", "Enter some small number here", "This is a place you can enter a small integer value if you want"); - CAF_PDM_InitField(&m_textField, "TextField", QString(""), "Text", "", "Text tooltip", "This is a place you can enter a small integer value if you want"); + CAF_PDM_InitObject("Many Groups", + ":/images/win/filenew.png", + "This object is a demo of the CAF framework", + "This object is a demo of the CAF framework"); + + CAF_PDM_InitField( + &m_toggleField, "Toggle", false, "Add Items To Multi Select", "", "Toggle Field tooltip", " Toggle Field whatsthis"); + CAF_PDM_InitField(&m_doubleField, + "BigNumber", + 0.0, + "Big Number", + "", + "Enter a big number here", + "This is a place you can enter a big real value if you want"); + CAF_PDM_InitField(&m_intField, + "IntNumber", + 0, + "Small Number", + "", + "Enter some small number here", + "This is a place you can enter a small integer value if you want"); + CAF_PDM_InitField(&m_textField, + "TextField", + QString(""), + "Text", + "", + "Text tooltip", + "This is a place you can enter a small integer value if you want"); m_proxyDoubleField.registerSetMethod(this, &ManyGroups::setDoubleMember); m_proxyDoubleField.registerGetMethod(this, &ManyGroups::doubleMember); CAF_PDM_InitFieldNoDefault(&m_proxyDoubleField, "ProxyDouble", "Proxy Double", "", "", ""); m_proxyDoubleField = 0; - if (!(m_proxyDoubleField == 3)) { std::cout << "Double is not 3 " << std::endl; } + if (!(m_proxyDoubleField == 3)) + { + std::cout << "Double is not 3 " << std::endl; + } CAF_PDM_InitFieldNoDefault(&m_multiSelectList, "SelectedItems", "Multi Select Field", "", "", ""); m_multiSelectList.uiCapability()->setAutoAddingOptionFromValue(false); - + m_multiSelectList.xmlCapability()->setIOReadable(false); m_multiSelectList.xmlCapability()->setIOWritable(false); m_multiSelectList.uiCapability()->setUiEditorTypeName(caf::PdmUiTreeSelectionEditor::uiEditorTypeName()); @@ -34,10 +59,14 @@ ManyGroups::ManyGroups() m_multiSelectList.v().push_back("First"); m_multiSelectList.v().push_back("Second"); m_multiSelectList.v().push_back("Third"); + + CAF_PDM_InitField( + &m_stringWithMultipleOptions, "m_stringWithMultipleOptions", QString(""), "Text with many items", "", "", ""); + m_stringWithMultipleOptions.uiCapability()->setUiEditorTypeName(caf::PdmUiListEditor::uiEditorTypeName()); } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- caf::PdmFieldHandle* ManyGroups::objectToggleField() { @@ -45,7 +74,7 @@ caf::PdmFieldHandle* ManyGroups::objectToggleField() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void ManyGroups::fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue) { @@ -56,12 +85,25 @@ void ManyGroups::fieldChangedByUi(const caf::PdmFieldHandle* changedField, const } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- -QList ManyGroups::calculateValueOptions(const caf::PdmFieldHandle* fieldNeedingOptions, bool* useOptionsOnly) +QList ManyGroups::calculateValueOptions(const caf::PdmFieldHandle* fieldNeedingOptions, + bool* useOptionsOnly) { QList options; + // Test code used to switch between two lists with different content, but same item count + if (fieldNeedingOptions == &m_stringWithMultipleOptions) + { + for (int i = 0; i < 100; i++) + { + QString text = QString("item %1").arg(i); + options.push_back(caf::PdmOptionItemInfo(text, text)); + } + + return options; + } + // Test code used to switch between two lists with different content, but same item count if (fieldNeedingOptions == &m_multiSelectList) { @@ -96,7 +138,7 @@ QList ManyGroups::calculateValueOptions(const caf::PdmFi options.push_back(caf::PdmOptionItemInfo::createHeader(text, false, QIcon(QString(":/images/win/textbold.png")))); { - text = "Second_a"; + text = "Second_a"; caf::PdmOptionItemInfo itemInfo = caf::PdmOptionItemInfo(text, text, true); itemInfo.setLevel(1); options.push_back(itemInfo); @@ -104,7 +146,8 @@ QList ManyGroups::calculateValueOptions(const caf::PdmFi { text = "Second_b"; - caf::PdmOptionItemInfo itemInfo = caf::PdmOptionItemInfo(text, text, false, QIcon(QString(":/images/win/filenew.png"))); + caf::PdmOptionItemInfo itemInfo = + caf::PdmOptionItemInfo(text, text, false, QIcon(QString(":/images/win/filenew.png"))); itemInfo.setLevel(1); options.push_back(itemInfo); } @@ -112,7 +155,7 @@ QList ManyGroups::calculateValueOptions(const caf::PdmFi int additionalSubItems = 2; for (auto i = 0; i < additionalSubItems; i++) { - text = "Second_b_" + QString::number(i); + text = "Second_b_" + QString::number(i); caf::PdmOptionItemInfo itemInfo = caf::PdmOptionItemInfo(text, text); itemInfo.setLevel(1); options.push_back(itemInfo); @@ -125,7 +168,7 @@ QList ManyGroups::calculateValueOptions(const caf::PdmFi } for (auto i = 0; i < s_additionalSubItems; i++) { - text = "Second_b_" + QString::number(i); + text = "Second_b_" + QString::number(i); caf::PdmOptionItemInfo itemInfo = caf::PdmOptionItemInfo(text, text); itemInfo.setLevel(1); options.push_back(itemInfo); @@ -142,64 +185,66 @@ QList ManyGroups::calculateValueOptions(const caf::PdmFi } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void ManyGroups::defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering) { uiOrdering.add(&m_toggleField); uiOrdering.add(&m_multiSelectList); - -/* - { - caf::PdmUiGroup* group = uiOrdering.addNewGroup("First"); - caf::PdmUiGroup* subGroup = group->addNewGroup("First_Content"); + /* + { + caf::PdmUiGroup* group = uiOrdering.addNewGroup("First"); - subGroup->add(&m_doubleField); - subGroup->add(&m_intField); + caf::PdmUiGroup* subGroup = group->addNewGroup("First_Content"); - caf::PdmUiGroup* subGroup2 = group->addNewGroup("First_Content_2"); + subGroup->add(&m_doubleField); + subGroup->add(&m_intField); - } + caf::PdmUiGroup* subGroup2 = group->addNewGroup("First_Content_2"); - { - caf::PdmUiGroup* group = uiOrdering.addNewGroup("Second"); - caf::PdmUiGroup* subGroup = group->addNewGroup("Second_Content"); - } + } - { - caf::PdmUiGroup* group = uiOrdering.addNewGroup("Third"); - caf::PdmUiGroup* subGroup = group->addNewGroup("Third_Content"); - } + { + caf::PdmUiGroup* group = uiOrdering.addNewGroup("Second"); + caf::PdmUiGroup* subGroup = group->addNewGroup("Second_Content"); + } - { - caf::PdmUiGroup* group = uiOrdering.addNewGroup("Fourth"); - caf::PdmUiGroup* subGroup = group->addNewGroup("Fourth_Content"); + { + caf::PdmUiGroup* group = uiOrdering.addNewGroup("Third"); + caf::PdmUiGroup* subGroup = group->addNewGroup("Third_Content"); + } - subGroup->add(&m_textField); - } + { + caf::PdmUiGroup* group = uiOrdering.addNewGroup("Fourth"); + caf::PdmUiGroup* subGroup = group->addNewGroup("Fourth_Content"); - { - caf::PdmUiGroup* group = uiOrdering.addNewGroup("Fifth"); - caf::PdmUiGroup* subGroup = group->addNewGroup("Fifth_Content"); + subGroup->add(&m_textField); + } - subGroup->add(&m_proxyDoubleField); - } -*/ + { + caf::PdmUiGroup* group = uiOrdering.addNewGroup("Fifth"); + caf::PdmUiGroup* subGroup = group->addNewGroup("Fifth_Content"); + + subGroup->add(&m_proxyDoubleField); + } + */ } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- -void ManyGroups::defineEditorAttribute(const caf::PdmFieldHandle* field, QString uiConfigName, caf::PdmUiEditorAttribute* attribute) +void ManyGroups::defineEditorAttribute(const caf::PdmFieldHandle* field, + QString uiConfigName, + caf::PdmUiEditorAttribute* attribute) { if (field == &m_multiSelectList) { caf::PdmUiTreeSelectionEditorAttribute* myAttr = dynamic_cast(attribute); if (myAttr) { - //myAttr->showTextFilter = false; - //myAttr->showToggleAllCheckbox = false; + // myAttr->showTextFilter = false; + // myAttr->showToggleAllCheckbox = false; } } } diff --git a/Fwk/AppFwk/cafTests/cafTestApplication/ManyGroups.h b/Fwk/AppFwk/cafTests/cafTestApplication/ManyGroups.h index b3e1688ebc..d1204a7e50 100644 --- a/Fwk/AppFwk/cafTests/cafTestApplication/ManyGroups.h +++ b/Fwk/AppFwk/cafTests/cafTestApplication/ManyGroups.h @@ -1,3 +1,4 @@ +#pragma once #include "cafPdmObject.h" #include "cafPdmField.h" @@ -17,6 +18,7 @@ class ManyGroups : public caf::PdmObject caf::PdmProxyValueField m_proxyDoubleField; caf::PdmField > m_multiSelectList; + caf::PdmField m_stringWithMultipleOptions; caf::PdmField m_toggleField; caf::PdmFieldHandle* objectToggleField() override; diff --git a/Fwk/AppFwk/cafTests/cafTestApplication/WidgetLayoutTest.h b/Fwk/AppFwk/cafTests/cafTestApplication/WidgetLayoutTest.h index aaedcc2bb2..3f6a20d64d 100644 --- a/Fwk/AppFwk/cafTests/cafTestApplication/WidgetLayoutTest.h +++ b/Fwk/AppFwk/cafTests/cafTestApplication/WidgetLayoutTest.h @@ -1,6 +1,6 @@ #pragma once -#include +#include class QGridLayout; diff --git a/Fwk/AppFwk/cafTests/cafTestCvfApplication/CMakeLists.txt b/Fwk/AppFwk/cafTests/cafTestCvfApplication/CMakeLists.txt index 5aaa740f70..3109c0531f 100644 --- a/Fwk/AppFwk/cafTests/cafTestCvfApplication/CMakeLists.txt +++ b/Fwk/AppFwk/cafTests/cafTestCvfApplication/CMakeLists.txt @@ -1,8 +1,13 @@ cmake_minimum_required (VERSION 2.8) # Qt -find_package ( Qt4 COMPONENTS QtCore QtGui QtMain QtOpenGl ) -include (${QT_USE_FILE}) +find_package(Qt5 CONFIG COMPONENTS Core) +if (Qt5Core_FOUND) + find_package(Qt5 CONFIG REQUIRED Core Gui OpenGl Widgets) +else() + find_package(Qt4 COMPONENTS QtCore QtGui QtMain QtOpenGl REQUIRED) + include(${QT_USE_FILE}) +endif(Qt5Core_FOUND) project ( cafTestCvfApplication ) @@ -10,14 +15,16 @@ project ( cafTestCvfApplication ) option(USE_COMMAND_FRAMEWORK "Use Caf Command Framework" ON) # Qt MOC -set ( QT_MOC_HEADERS +set ( MOC_HEADER_FILES MainWindow.h WidgetLayoutTest.h ) -qt4_wrap_cpp( MOC_FILES_CPP - ${QT_MOC_HEADERS} -) +if (Qt5Core_FOUND) + qt5_wrap_cpp(MOC_SOURCE_FILES ${MOC_HEADER_FILES} ) +else() + qt4_wrap_cpp(MOC_SOURCE_FILES ${MOC_HEADER_FILES} ) +endif() # Resource file set( QRC_FILES @@ -25,9 +32,15 @@ set( QRC_FILES ) # Runs RCC on specified files -qt4_add_resources( QRC_FILES_CPP - ${QRC_FILES} -) +if (Qt5Core_FOUND) + qt5_add_resources( QRC_FILES_CPP + ${QRC_FILES} + ) +else() + qt4_add_resources( QRC_FILES_CPP + ${QRC_FILES} + ) +endif() include_directories ( ${LibCore_SOURCE_DIR} @@ -69,10 +82,15 @@ set( PROJECT_FILES # add the executable add_executable ( ${PROJECT_NAME} ${PROJECT_FILES} - ${MOC_FILES_CPP} + ${MOC_SOURCE_FILES} ${QRC_FILES_CPP} ) + +if (Qt5Core_FOUND) + set(QT_LIBRARIES Qt5::Core Qt5::Gui Qt5::OpenGl Qt5::Widgets) +endif() + set (TAP_LINK_LIBRARIES cafUserInterface cafPdmXml @@ -95,14 +113,24 @@ target_link_libraries ( ${PROJECT_NAME} source_group("" FILES ${PROJECT_FILES}) # Copy Qt Dlls -if (MSVC) - set (QTLIBLIST QtCore QtGui QtOpenGl) - foreach (qtlib ${QTLIBLIST}) - - # Debug - execute_process(COMMAND cmake -E copy_if_different ${QT_BINARY_DIR}/${qtlib}d4.dll ${CMAKE_CURRENT_BINARY_DIR}/Debug/${qtlib}d4.dll) - - # Release - execute_process(COMMAND cmake -E copy_if_different ${QT_BINARY_DIR}/${qtlib}4.dll ${CMAKE_CURRENT_BINARY_DIR}/Release/${qtlib}4.dll) - endforeach( qtlib ) -endif(MSVC) +if (Qt5Core_FOUND) + foreach (qtlib ${QT_LIBRARIES}) + add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_if_different $ $ + ) + endforeach(qtlib) + # Copy Qt Dlls +else() + # Copy Qt Dlls + if (MSVC) + set (QTLIBLIST QtCore QtGui QtOpenGl ) + foreach (qtlib ${QTLIBLIST}) + + # Debug + execute_process(COMMAND cmake -E copy_if_different ${QT_BINARY_DIR}/${qtlib}d4.dll ${CMAKE_BINARY_DIR}/Debug/${qtlib}d4.dll) + + # Release + execute_process(COMMAND cmake -E copy_if_different ${QT_BINARY_DIR}/${qtlib}4.dll ${CMAKE_BINARY_DIR}/Release/${qtlib}4.dll) + endforeach( qtlib ) + endif(MSVC) +endif(Qt5Core_FOUND) diff --git a/Fwk/AppFwk/cafTests/cafTestCvfApplication/WidgetLayoutTest.h b/Fwk/AppFwk/cafTests/cafTestCvfApplication/WidgetLayoutTest.h index 662765c544..3a9a1f8207 100644 --- a/Fwk/AppFwk/cafTests/cafTestCvfApplication/WidgetLayoutTest.h +++ b/Fwk/AppFwk/cafTests/cafTestCvfApplication/WidgetLayoutTest.h @@ -1,6 +1,6 @@ #pragma once -#include +#include class QGridLayout; diff --git a/Fwk/AppFwk/cafUserInterface/CMakeLists.txt b/Fwk/AppFwk/cafUserInterface/CMakeLists.txt index 0dce881b2c..954afb1457 100644 --- a/Fwk/AppFwk/cafUserInterface/CMakeLists.txt +++ b/Fwk/AppFwk/cafUserInterface/CMakeLists.txt @@ -5,15 +5,18 @@ if (MSVC) add_definitions(-DNOMINMAX) endif (MSVC) -# Qt -find_package ( Qt4 COMPONENTS QtCore QtGui QtMain ) -include (${QT_USE_FILE}) - project (cafUserInterface) +# Qt +if (CAF_USE_QT5) + find_package(Qt5 COMPONENTS Core Gui Widgets REQUIRED) +else() + find_package(Qt4 COMPONENTS QtCore QtGui QtMain REQUIRED) + include(${QT_USE_FILE}) +endif(CAF_USE_QT5) # These headers need to go through Qt's MOC compiler -set( QOBJECT_HEADERS +set (MOC_HEADER_FILES cafPdmUiCheckBoxDelegate.h cafPdmUiCheckBoxEditor.h cafPdmUiCheckBoxTristateEditor.h @@ -41,14 +44,22 @@ set( QOBJECT_HEADERS cafPdmUiTreeViewEditor.h cafUiProcess.h QMinimizePanel.h + cafQStyledProgressBar.h cafPdmUiTreeSelectionEditor.h cafPdmUiTreeSelectionQModel.h cafPdmUiFormLayoutObjectEditor.h cafPdmUiDoubleValueEditor.h + cafPdmUniqueIdValidator.h + cafPdmDoubleStringValidator.h + cafPdmUiPickableLineEditor.h ) if ( NOT CMAKE_AUTOMOC ) - qt4_wrap_cpp( MOC_FILES_CPP ${QOBJECT_HEADERS} ) + if (CAF_USE_QT5) + qt5_wrap_cpp(MOC_SOURCE_FILES ${MOC_HEADER_FILES} ) + else() + qt4_wrap_cpp(MOC_SOURCE_FILES ${MOC_HEADER_FILES} ) + endif(CAF_USE_QT5) endif() @@ -139,17 +150,25 @@ set( PROJECT_FILES cafUiProcess.h QMinimizePanel.cpp QMinimizePanel.h + cafQStyledProgressBar.cpp + cafQStyledProgressBar.h cafQTreeViewStateSerializer.h cafQTreeViewStateSerializer.cpp cafMemoryInspector.h cafMemoryInspector.cpp + cafPdmUniqueIdValidator.cpp + cafPdmDoubleStringValidator.cpp + cafPickEventHandler.h + cafPdmUiPickableLineEditor.cpp + cafStyleSheetTools.h + cafStyleSheetTools.cpp ) add_library( ${PROJECT_NAME} ${PROJECT_FILES} - ${MOC_FILES_CPP} + ${MOC_SOURCE_FILES} ) if (MSVC) @@ -161,19 +180,18 @@ target_include_directories(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR} ) +if (CAF_USE_QT5) + set(QT_LIBRARIES Qt5::Core Qt5::Gui Qt5::Widgets) +endif(CAF_USE_QT5) + target_link_libraries ( ${PROJECT_NAME} cafProjectDataModel ${QT_LIBRARIES} ) -if (COMMAND cotire) - cotire(${PROJECT_NAME}) - - # make sure the unity target is included in the active builds to trigger rebuild before debug - get_target_property(_unityTargetName ${PROJECT_NAME} COTIRE_UNITY_TARGET_NAME) - set_target_properties(${_unityTargetName} PROPERTIES EXCLUDE_FROM_DEFAULT_BUILD FALSE) - set_target_properties(${PROJECT_NAME} PROPERTIES EXCLUDE_FROM_DEFAULT_BUILD TRUE) +source_group("" FILES ${PROJECT_FILES}) +# cotire +if (COMMAND caf_apply_cotire) + caf_apply_cotire("${PROJECT_NAME}") endif() - -source_group("" FILES ${PROJECT_FILES}) diff --git a/Fwk/AppFwk/cafUserInterface/PdmUi.plantuml b/Fwk/AppFwk/cafUserInterface/PdmUi.plantuml index 03f2bd124a..2a0959d01c 100644 --- a/Fwk/AppFwk/cafUserInterface/PdmUi.plantuml +++ b/Fwk/AppFwk/cafUserInterface/PdmUi.plantuml @@ -1,49 +1,71 @@ @startuml +namespace Inheritance{ + +QObject <|-- PdmUiEditorHandle +PdmUiEditorHandle <|-- PdmUiObjectEditorHandle +PdmUiObjectEditorHandle <|-- PdmUiWidgetObjectEditorHandle +PdmUiObjectEditorHandle <|-- PdmUi3dObjectEditorHandle +PdmUiWidgetObjectEditorHandle <|-- PdmUiFormLayoutObjectEditor +PdmUiFormLayoutObjectEditor <|-- PdmUiDefaultObjectEditor +PdmUiFieldEditorHandle <|-- "Tons of field editors" +PdmUiEditorHandle <|-- PdmUiTreeItemEditor +PdmUiEditorHandle <|-- PdmUiTreeEditorHandle +PdmUiEditorHandle <|-- PdmUiToolBarEditor +PdmUiEditorHandle <|-- PdmUiTableRowEditor +PdmUiEditorHandle <|-- PdmUiFieldEditorHandle + +PdmUiTreeEditorHandle <|-- PdmUiTreeViewEditor +} + Namespace TreeView{ QWidget <|-- PdmUiTreeView PdmUiTreeView --* PdmUiTreeViewEditor -PdmUiTreeView --* QTreeView - - -PdmUiTreeViewEditor "N" <--> "1" PdmUiItem<> -PdmUiTreeViewEditor "UpdateUi()" <--> "setValueFromUi()" PdmUiItem<> -PdmUiTreeViewEditor "signals"<--> "confAndUpdate()" QTreeView -PdmUiTreeViewEditor ---* PdmUiTreeViewModel -'PdmUiTreeViewEditor --* "?, N" PdmUiTreeItemEditor +PdmUiTreeViewEditor --* PdmUiTreeViewWidget +PdmUiTreeViewEditor --* PdmUiTreeViewQModel +PdmUiTreeItemEditor --> PdmUiTreeViewEditor +PdmUiTreeViewQModel --* "root" PdmUiTreeOrdering -PdmUiTreeViewModel --> PdmUiTreeItemEditor : "SetValueFromUi()" -PdmUiTreeViewModel <-- PdmUiTreeItemEditor : "UpdatUi()" -PdmUiTreeViewModel --* PdmUiTreeOrdering -'PdmUiTreeViewModel ---* "?, N" PdmUiTreeItemEditor - -PdmUiTreeOrdering "N" <--> "1" PdmUiItem2<> +PdmUiTreeOrdering --> PdmUiItem PdmUiTreeOrdering --* PdmUiTreeItemEditor -PdmUiTreeItemEditor "N" <-- PdmUiItem2<> : UpdateUi(), removeFromList() -PdmUiTreeItemEditor --> "1" PdmUiItem2<> : setValueFromUi() +QTreeView <|-- PdmUiTreeViewWidget } namespace Properties{ + QWidget <|-- PdmUiPropertyView PdmUiPropertyView --* PdmUiDefaultObjectEditor -PdmUiDefaultObjectEditor --* "N" PdmUiFieldEditor -"QWidget3<>" --* "QWidget2<>" +PdmUiDefaultObjectEditor ---* "N" PdmUiFieldEditorHandle -PdmUiPropertyView --* "QWidget3<>" +PdmField --> "N" PdmUiFieldEditorHandle -PdmField --> "N" PdmUiFieldEditor : UpdateUi(), removeFromList() -PdmUiFieldEditor --> "1" PdmField : setValueFromUi() -PdmUiFieldEditor --> "QWidget2<>" : configureAndUpdate() -PdmUiFieldEditor <-- "QWidget2<>" : signals() -PdmUiDefaultObjectEditor "N" <--> "1" PdmObject +PdmUiFieldEditorHandle --> "1" PdmField +PdmUiDefaultObjectEditor "N" <--> "1" edited_PdmObject +edited_PdmObject --* "N" PdmField + +PdmUiFieldEditorHandle --* QWidget_UsedByEditor } +namespace 3DEditors{ + +SomeViewer --* PdmUiSelection3dEditorVisualizer + +PdmUiSelection3dEditorVisualizer --* PdmUi3dObjectEditorHandle : "Creates on SelectionChanged()" + +PdmUi3dObjectEditorHandle --> SomeViewer +PdmUi3dObjectEditorHandle --> 3DVisualizationStuff +PdmUi3dObjectEditorHandle -->edited_PdmObject + +} + + + @enduml \ No newline at end of file diff --git a/Fwk/AppFwk/cafUserInterface/QMinimizePanel.cpp b/Fwk/AppFwk/cafUserInterface/QMinimizePanel.cpp index ca69397c82..89df69165e 100644 --- a/Fwk/AppFwk/cafUserInterface/QMinimizePanel.cpp +++ b/Fwk/AppFwk/cafUserInterface/QMinimizePanel.cpp @@ -39,6 +39,7 @@ #include "QMinimizePanel.h" #include +#include #include #include #include @@ -123,7 +124,7 @@ static const QIcon& expandUpIcon() /// //-------------------------------------------------------------------------------------------------- QMinimizePanel::QMinimizePanel(QWidget* parent/*=0*/) - : QWidget(parent) + : QFrame(parent) { this->initialize(""); } @@ -132,7 +133,7 @@ QMinimizePanel::QMinimizePanel(QWidget* parent/*=0*/) /// //-------------------------------------------------------------------------------------------------- QMinimizePanel::QMinimizePanel(const QString &title, QWidget* parent/*=0*/) - : QWidget(parent) + : QFrame(parent) { this->initialize(title); } @@ -176,42 +177,28 @@ void QMinimizePanel::enableFrame(bool showFrame) { if (showFrame) { + this->setFrameStyle(QFrame::StyledPanel | QFrame::Plain); m_titleFrame->show(); m_titleLabel->show(); m_collapseButton->show(); - m_contentFrame->setFrameStyle(QFrame::StyledPanel | QFrame::Plain); - m_contentFrame->setPalette(m_contentPalette); - m_contentFrame->setAttribute(Qt::WA_SetPalette, true); + m_contentFrame->setObjectName("FramedGroupContent"); } else { + this->setFrameStyle(QFrame::NoFrame); m_titleFrame->hide(); m_titleLabel->hide(); m_collapseButton->hide(); - m_contentFrame->setFrameStyle(QFrame::NoFrame); - if (parentWidget()) - { - m_contentFrame->setPalette(parentWidget()->palette()); - } - m_contentFrame->setAttribute(Qt::WA_SetPalette, false); + m_contentFrame->setObjectName("UnframedGroupContent"); } - QWidget::update(); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -QSize QMinimizePanel::minimumSizeHint() const -{ - return calculateSizeHint(true); } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- -QSize QMinimizePanel::sizeHint() const +bool QMinimizePanel::isExpanded() const { - return calculateSizeHint(false); + return !m_contentFrame->isHidden(); } //-------------------------------------------------------------------------------------------------- @@ -222,7 +209,17 @@ void QMinimizePanel::setExpanded(bool isExpanded) if (m_contentFrame->isHidden() != isExpanded) return; m_contentFrame->setVisible(isExpanded); - isExpanded ? m_collapseButton->setIcon(expandUpIcon()) : m_collapseButton->setIcon(expandDownIcon()); + if (isExpanded) + { + m_collapseButton->setIcon(expandUpIcon()); + this->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); + } + else + { + m_collapseButton->setIcon(expandDownIcon()); + this->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed); + } + this->QWidget::updateGeometry(); emit expandedChanged(isExpanded); @@ -239,113 +236,81 @@ void QMinimizePanel::toggleExpanded() //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void QMinimizePanel::resizeEvent(QResizeEvent *resizeEv ) +void QMinimizePanel::initialize(const QString &title) { - QWidget::updateGeometry(); - - int width = resizeEv->size().width(); - int heigth = resizeEv->size().height(); - int labelHeight = m_titleLabel->sizeHint().height(); - - int titleHeight = labelHeight + 8; - int buttonSize = titleHeight - 2; - - int contentHeightOffset = 0; - if (!m_titleFrame->isHidden()) - { - m_titleFrame->setGeometry(0, 0, width, titleHeight); - m_titleLabel->setGeometry(4, titleHeight - labelHeight - 4, width - 4 - buttonSize - 1, labelHeight); - m_collapseButton->setGeometry(width - buttonSize - 1, 1, buttonSize, buttonSize); - contentHeightOffset = titleHeight - 1; + this->setFrameStyle(QFrame::StyledPanel | QFrame::Plain); + QVBoxLayout* fullLayout = new QVBoxLayout(this); + + fullLayout->setContentsMargins(0, 0, 0, 0); + fullLayout->setSpacing(0); + { // Title + m_titleFrame = new QFrame(); + fullLayout->addWidget(m_titleFrame, 0); + fullLayout->setStretch(0, 0); + m_titleFrame->setObjectName("GroupTitleFrame"); + m_titleFrame->setStyleSheet(titleFrameStyleSheet()); + + QHBoxLayout* titleLayout = new QHBoxLayout(); + titleLayout->setContentsMargins(4, 2, 0, 2); + m_titleFrame->setLayout(titleLayout); + m_titleFrame->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed); + { + m_titleLabel = new QLabel(title); + QPalette titleLabelPalette = m_titleLabel->palette(); + titleLabelPalette.setBrush(QPalette::Foreground, titleLabelPalette.windowText()); + m_titleLabel->setPalette(titleLabelPalette); + titleLayout->addWidget(m_titleLabel, 1, Qt::AlignLeft); + } + { + m_collapseButton = new QPushButton(); + m_collapseButton->setFlat(true); + m_collapseButton->setIcon(expandUpIcon()); + m_collapseButton->setDefault(false); + m_collapseButton->setAutoDefault(false); + m_collapseButton->setIconSize(QSize(16, 16)); + m_collapseButton->setMaximumSize(QSize(16, 16)); + titleLayout->addWidget(m_collapseButton, 0, Qt::AlignRight); + } } - - m_contentFrame->setGeometry(0, contentHeightOffset, width, heigth - contentHeightOffset); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -bool QMinimizePanel::event(QEvent* event) -{ - if (event->type() == QEvent::LayoutRequest) { - this->QWidget::updateGeometry(); + m_contentFrame = new QFrame(); + m_contentFrame->setStyleSheet(contentFrameStyleSheet()); + m_contentFrame->setObjectName("GroupContentFrame"); + fullLayout->addWidget(m_contentFrame, 1); + fullLayout->setStretch(1, 1); } - return this->QWidget::event(event); + connect(m_collapseButton, SIGNAL(clicked()), this, SLOT(toggleExpanded())); } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- -void QMinimizePanel::initialize(const QString &title) +QString QMinimizePanel::titleFrameStyleSheet() { - m_titleFrame = new QFrame(this); - m_titleFrame->setFrameStyle(QFrame::Box | QFrame::Plain); - m_titleFrame->setAutoFillBackground(true); - - m_titleLabel = new QLabel(title, m_titleFrame); - QPalette titleLabelPalette = m_titleLabel->palette(); - titleLabelPalette.setBrush(QPalette::Foreground, titleLabelPalette.windowText()); - - { - QLinearGradient titleGrad(QPointF(0, 0), QPointF(0, 1)); - titleGrad.setCoordinateMode(QGradient::StretchToDeviceMode); - titleGrad.setColorAt(0, QColor(255, 255, 255, 20)); - titleGrad.setColorAt(1, QColor(0, 0, 0, 30)); - - QPalette titleFramePalette = m_titleFrame->palette(); - titleFramePalette.setBrush(QPalette::Window, titleGrad); - titleFramePalette.setBrush(QPalette::Foreground, titleFramePalette.dark()); - m_titleFrame->setPalette(titleFramePalette); - } - - m_titleLabel->setPalette(titleLabelPalette); - - m_collapseButton = new QPushButton(m_titleFrame); - m_collapseButton->setFlat(true); - m_collapseButton->setIcon(expandUpIcon()); - m_collapseButton->setDefault(false); - m_collapseButton->setAutoDefault(false); - - m_contentFrame = new QFrame(this); - m_contentFrame->setFrameStyle(QFrame::StyledPanel | QFrame::Plain); - m_contentFrame->setAutoFillBackground(true); - - m_contentPalette = m_contentFrame->palette(); - m_contentPalette.setBrush(QPalette::Window, QColor(255, 250, 250, 85)); - m_contentFrame->setPalette(m_contentPalette); - - connect(m_collapseButton, SIGNAL(clicked()), this, SLOT(toggleExpanded())); + return QString("QFrame#GroupTitleFrame " + "{" + " border-top: none; border-left: none; border-right: none; border-bottom: none;" + " background: qlineargradient(spread:pad, x1:0 y1:0, x2:0 y2:1," + " stop:0 rgba(150, 150, 150, 20), stop:1 rgba(0, 0, 0, 50));" + "}"); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -QSize QMinimizePanel::calculateSizeHint(bool minimumSizeHint) const +QString QMinimizePanel::contentFrameStyleSheet() { - QSize labelSize = m_titleLabel->sizeHint(); - QSize titleBarHint = labelSize + QSize(4 + labelSize.height() + 8 - 2 + 1, 8); - if (!m_contentFrame->isHidden()) - { - int titleHeight = 0; - if (!m_titleFrame->isHidden()) - { - titleHeight = labelSize.height() + 8; - } - - QSize titleBarMin(0, titleHeight); - QSize contentsMin(minimumSizeHint ? m_contentFrame->minimumSizeHint() : m_contentFrame->sizeHint()); - QSize total = contentsMin.expandedTo(titleBarMin); - total.rheight() += titleBarMin.height(); - - return total; - } - else - { - // Retain width when collapsing the field - QSize contentsMin(minimumSizeHint ? m_contentFrame->minimumSizeHint() : m_contentFrame->sizeHint()); - titleBarHint.rwidth() = std::max(titleBarHint.width(), contentsMin.width()); - return titleBarHint; - } + return QString + ( + "QFrame#FramedGroupContent" + "{" + " border-top: 1px solid darkgray; border-left: none; border-right: none; border-bottom: none; " + " background: rgba(255, 250, 250, 85)" + "}" + "QFrame#UnframedGroupContent" + "{" + " border-top: none; border-left: none; border-right: none; border-bottom: none; " + "}" + ); } diff --git a/Fwk/AppFwk/cafUserInterface/QMinimizePanel.h b/Fwk/AppFwk/cafUserInterface/QMinimizePanel.h index 697e9b9008..3a8b7ed74c 100644 --- a/Fwk/AppFwk/cafUserInterface/QMinimizePanel.h +++ b/Fwk/AppFwk/cafUserInterface/QMinimizePanel.h @@ -36,11 +36,9 @@ #pragma once -#include +#include -class QFrame; class QLabel; -class QPalette; class QPushButton; //================================================================================================== @@ -48,7 +46,7 @@ class QPushButton; // // //================================================================================================== -class QMinimizePanel : public QWidget +class QMinimizePanel : public QFrame { Q_OBJECT public: @@ -60,10 +58,7 @@ class QMinimizePanel : public QWidget void setTitle (const QString& title); QString title() const; void enableFrame(bool showFrame); - - QSize minimumSizeHint() const override; - QSize sizeHint() const override; - + bool isExpanded() const; public slots: void setExpanded(bool isExpanded); void toggleExpanded(); @@ -71,20 +66,17 @@ public slots: signals: void expandedChanged(bool isExpanded); -public: - protected: QFrame* m_titleFrame; QLabel* m_titleLabel; QPushButton* m_collapseButton; QFrame* m_contentFrame; - QPalette m_contentPalette; - - void resizeEvent(QResizeEvent *) override; - bool event(QEvent* event) override; // To catch QEvent::LayoutRequest private: void initialize(const QString &title); - QSize calculateSizeHint(bool minimumSizeHint) const; + + QString titleFrameStyleSheet(); + QString contentFrameStyleSheet(); + }; diff --git a/Fwk/AppFwk/cafUserInterface/cafAboutDialog.cpp b/Fwk/AppFwk/cafUserInterface/cafAboutDialog.cpp index ce5716554c..6c3c5536c0 100644 --- a/Fwk/AppFwk/cafUserInterface/cafAboutDialog.cpp +++ b/Fwk/AppFwk/cafUserInterface/cafAboutDialog.cpp @@ -38,10 +38,10 @@ #include "cafAboutDialog.h" #include "cafAssert.h" -#include -#include -#include -#include +#include +#include +#include +#include #include namespace caf { @@ -199,7 +199,7 @@ void AboutDialog::create() QLabel* appVersionLabel = new QLabel(this); QFont appVersionFont(appVersionLabel->font()); appVersionFont.setPointSize(8); - appVersionFont.setBold(TRUE); + appVersionFont.setBold(true); appVersionLabel->setFont(appVersionFont); appVersionLabel->setText(appVer); appInfoLayout->addWidget(appVersionLabel); @@ -211,7 +211,7 @@ void AboutDialog::create() QLabel* appCopyrightLabel = new QLabel(this); QFont appCopyrightFont(appCopyrightLabel->font()); appCopyrightFont.setPointSize(8); - appCopyrightFont.setBold(TRUE); + appCopyrightFont.setBold(true); appCopyrightLabel->setFont(appCopyrightFont); appCopyrightLabel->setText(m_appCopyright); appInfoLayout->addWidget(appCopyrightLabel); @@ -282,8 +282,8 @@ void AboutDialog::create() bottomLayout->addItem(spacer2); QPushButton* buttonOk = new QPushButton("&OK", this); - buttonOk->setAutoDefault(TRUE); - buttonOk->setDefault(TRUE); + buttonOk->setAutoDefault(true); + buttonOk->setDefault(true); buttonOk->setFocus(); connect(buttonOk, SIGNAL(clicked()), this, SLOT(accept()) ); bottomLayout->addWidget(buttonOk); diff --git a/Fwk/AppFwk/cafUserInterface/cafAboutDialog.h b/Fwk/AppFwk/cafUserInterface/cafAboutDialog.h index e7ff92341f..bd33a267be 100644 --- a/Fwk/AppFwk/cafUserInterface/cafAboutDialog.h +++ b/Fwk/AppFwk/cafUserInterface/cafAboutDialog.h @@ -37,7 +37,7 @@ #pragma once -#include +#include class QGridLayout; diff --git a/Fwk/AppFwk/cafUserInterface/cafMemoryInspector.cpp b/Fwk/AppFwk/cafUserInterface/cafMemoryInspector.cpp index 8499376d50..b766d8666a 100644 --- a/Fwk/AppFwk/cafUserInterface/cafMemoryInspector.cpp +++ b/Fwk/AppFwk/cafUserInterface/cafMemoryInspector.cpp @@ -6,6 +6,10 @@ #include #ifdef _WIN32 +// Define this one to tell windows.h to not define min() and max() as macros +#if defined WIN32 && !defined NOMINMAX +#define NOMINMAX +#endif #include "windows.h" #include "psapi.h" #elif defined (__linux__) diff --git a/Fwk/AppFwk/cafUserInterface/cafPdmDoubleStringValidator.cpp b/Fwk/AppFwk/cafUserInterface/cafPdmDoubleStringValidator.cpp new file mode 100644 index 0000000000..07a42ed8b1 --- /dev/null +++ b/Fwk/AppFwk/cafUserInterface/cafPdmDoubleStringValidator.cpp @@ -0,0 +1,57 @@ +//################################################################################################## +// +// Custom Visualization Core library +// Copyright (C) Ceetron Solutions AS +// +// This library may be used under the terms of either the GNU General Public License or +// the GNU Lesser General Public License as follows: +// +// GNU General Public License Usage +// This library 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 3 of the License, or +// (at your option) any later version. +// +// This library 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 at <> +// for more details. +// +// GNU Lesser General Public License Usage +// This library 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.1 of the License, or +// (at your option) any later version. +// +// This library 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 at <> +// for more details. +// +//################################################################################################## + +#include "cafPdmDoubleStringValidator.h" + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QValidator::State caf::PdmDoubleStringValidator::validate(QString& inputString, int& position) const +{ + if (m_defaultString == inputString) + { + return QValidator::Acceptable; + } + return QDoubleValidator::validate(inputString, position); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void caf::PdmDoubleStringValidator::fixup(QString& inputString) const +{ + inputString = m_defaultString; +} diff --git a/Fwk/AppFwk/cafUserInterface/cafPdmDoubleStringValidator.h b/Fwk/AppFwk/cafUserInterface/cafPdmDoubleStringValidator.h new file mode 100644 index 0000000000..9dad34ec9d --- /dev/null +++ b/Fwk/AppFwk/cafUserInterface/cafPdmDoubleStringValidator.h @@ -0,0 +1,64 @@ +//################################################################################################## +// +// Custom Visualization Core library +// Copyright (C) Ceetron Solutions AS +// +// This library may be used under the terms of either the GNU General Public License or +// the GNU Lesser General Public License as follows: +// +// GNU General Public License Usage +// This library 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 3 of the License, or +// (at your option) any later version. +// +// This library 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 at <> +// for more details. +// +// GNU Lesser General Public License Usage +// This library 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.1 of the License, or +// (at your option) any later version. +// +// This library 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 at <> +// for more details. +// +//################################################################################################## +#pragma once + +#include +#include + +namespace caf +{ +////////////////////////////////////////////////////////////////////////// +/// Class that validates text strings containing double values but allows +/// a default text string that isn't necessarily a double. +/// Example use is the "1*" value in ECLIPSE output files or "N/A". +////////////////////////////////////////////////////////////////////////// +class PdmDoubleStringValidator : public QDoubleValidator +{ + Q_OBJECT +public: + PdmDoubleStringValidator(const QString& defaultString) + : QDoubleValidator(nullptr), m_defaultString(defaultString) + { + } + + State validate(QString& inputString, int& position) const override; + void fixup(QString& inputString) const override; + +private: + QString m_defaultString; +}; +} + diff --git a/Fwk/AppFwk/cafUserInterface/cafPdmUiCheckBoxEditor.cpp b/Fwk/AppFwk/cafUserInterface/cafPdmUiCheckBoxEditor.cpp index 2d8f6c493e..8fc00e324f 100644 --- a/Fwk/AppFwk/cafUserInterface/cafPdmUiCheckBoxEditor.cpp +++ b/Fwk/AppFwk/cafUserInterface/cafPdmUiCheckBoxEditor.cpp @@ -42,6 +42,7 @@ #include "cafPdmObject.h" #include "cafPdmUiFieldEditorHandle.h" #include "cafPdmUiOrdering.h" +#include "cafQShortenedLabel.h" #include "cafFactory.h" @@ -97,7 +98,7 @@ QWidget* PdmUiCheckBoxEditor::createEditorWidget(QWidget* parent) //-------------------------------------------------------------------------------------------------- QWidget* PdmUiCheckBoxEditor::createLabelWidget(QWidget* parent) { - m_label = new QLabel(parent); + m_label = new QShortenedLabel(parent); return m_label; } diff --git a/Fwk/AppFwk/cafUserInterface/cafPdmUiCheckBoxEditor.h b/Fwk/AppFwk/cafUserInterface/cafPdmUiCheckBoxEditor.h index 508b3fcca5..8f9fd4ef8f 100644 --- a/Fwk/AppFwk/cafUserInterface/cafPdmUiCheckBoxEditor.h +++ b/Fwk/AppFwk/cafUserInterface/cafPdmUiCheckBoxEditor.h @@ -81,8 +81,8 @@ protected slots: void slotClicked(bool checked); private: - QPointer m_checkBox; - QPointer m_label; + QPointer m_checkBox; + QPointer m_label; }; diff --git a/Fwk/AppFwk/cafUserInterface/cafPdmUiCheckBoxTristateEditor.cpp b/Fwk/AppFwk/cafUserInterface/cafPdmUiCheckBoxTristateEditor.cpp index 428f461646..9c9f674736 100644 --- a/Fwk/AppFwk/cafUserInterface/cafPdmUiCheckBoxTristateEditor.cpp +++ b/Fwk/AppFwk/cafUserInterface/cafPdmUiCheckBoxTristateEditor.cpp @@ -8,6 +8,7 @@ #include "cafPdmUiFieldEditorHandle.h" #include "cafPdmUiOrdering.h" #include "cafPdmField.h" +#include "cafQShortenedLabel.h" #include "cafFactory.h" #include "cafTristate.h" @@ -66,7 +67,7 @@ QWidget* PdmUiCheckBoxTristateEditor::createEditorWidget(QWidget * parent) //-------------------------------------------------------------------------------------------------- QWidget* PdmUiCheckBoxTristateEditor::createLabelWidget(QWidget * parent) { - m_label = new QLabel(parent); + m_label = new QShortenedLabel(parent); return m_label; } diff --git a/Fwk/AppFwk/cafUserInterface/cafPdmUiCheckBoxTristateEditor.h b/Fwk/AppFwk/cafUserInterface/cafPdmUiCheckBoxTristateEditor.h index 6c340ab223..b5b3c1d961 100644 --- a/Fwk/AppFwk/cafUserInterface/cafPdmUiCheckBoxTristateEditor.h +++ b/Fwk/AppFwk/cafUserInterface/cafPdmUiCheckBoxTristateEditor.h @@ -31,7 +31,7 @@ protected slots: private: QPointer m_checkBox; - QPointer m_label; + QPointer m_label; }; diff --git a/Fwk/AppFwk/cafUserInterface/cafPdmUiColorEditor.cpp b/Fwk/AppFwk/cafUserInterface/cafPdmUiColorEditor.cpp index 287a3bd3f9..e0f6e2f08a 100644 --- a/Fwk/AppFwk/cafUserInterface/cafPdmUiColorEditor.cpp +++ b/Fwk/AppFwk/cafUserInterface/cafPdmUiColorEditor.cpp @@ -43,9 +43,11 @@ #include "cafPdmUiFieldEditorHandle.h" #include "cafPdmUiOrdering.h" #include "cafPdmField.h" +#include "cafQShortenedLabel.h" #include "cafFactory.h" +#include #include #include #include @@ -80,36 +82,74 @@ void PdmUiColorEditor::configureAndUpdateUi(const QString& uiConfigName) if (uiObject) { uiObject->editorAttribute(uiField()->fieldHandle(), uiConfigName, &m_attributes); + + if (m_attributes.showLabel) + { + m_colorTextLabel->show(); + } + else + { + m_colorTextLabel->hide(); + } } QColor col = uiField()->uiValue().value(); setColorOnWidget(col); } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QMargins PdmUiColorEditor::calculateLabelContentMargins() const +{ + QSize editorSize = m_colorSelectionButton->sizeHint(); + QSize labelSize = m_label->sizeHint(); + int heightDiff = editorSize.height() - labelSize.height(); + + QMargins contentMargins = m_label->contentsMargins(); + if (heightDiff > 0) + { + contentMargins.setTop(contentMargins.top() + heightDiff / 2); + contentMargins.setBottom(contentMargins.bottom() + heightDiff / 2); + } + return contentMargins; +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- QWidget* PdmUiColorEditor::createEditorWidget(QWidget * parent) -{ +{ QWidget* placeholder = new QWidget(parent); - QHBoxLayout* layout = new QHBoxLayout(placeholder); layout->setContentsMargins(0,0,0,0); layout->setSpacing(0); - m_colorPixmapLabel = new QLabel(parent); m_colorTextLabel = new QLabel(parent); - QToolButton* button = new QToolButton(parent); - button->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred)); - button->setText(QLatin1String("...")); + m_colorSelectionButton = new QToolButton(parent); + m_colorSelectionButton->setObjectName("ColorSelectionButton"); + m_colorSelectionButton->setSizePolicy(QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred)); + QHBoxLayout* buttonLayout = new QHBoxLayout; + m_colorSelectionButton->setLayout(buttonLayout); + QMargins buttonMargins(3, 3, 3, 3); + buttonLayout->setContentsMargins(buttonMargins); + + m_colorPreviewLabel = new QLabel(m_colorSelectionButton); + m_colorPreviewLabel->setObjectName("ColorPreviewLabel"); + m_colorPreviewLabel->setText(QLatin1String("...")); + m_colorPreviewLabel->setAlignment(Qt::AlignCenter); + + QFontMetrics fontMetrics = QApplication::fontMetrics(); + + buttonLayout->addWidget(m_colorPreviewLabel); + m_colorSelectionButton->setMinimumWidth(fontMetrics.width(m_colorPreviewLabel->text()) + 15); - layout->addWidget(m_colorPixmapLabel); layout->addWidget(m_colorTextLabel); layout->addItem(new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Ignored)); - layout->addWidget(button); - - connect(button, SIGNAL(clicked()), this, SLOT(colorSelectionClicked())); + layout->addWidget(m_colorSelectionButton); + + connect(m_colorSelectionButton, SIGNAL(clicked()), this, SLOT(colorSelectionClicked())); return placeholder; } @@ -119,7 +159,7 @@ QWidget* PdmUiColorEditor::createEditorWidget(QWidget * parent) //-------------------------------------------------------------------------------------------------- QWidget* PdmUiColorEditor::createLabelWidget(QWidget * parent) { - m_label = new QLabel(parent); + m_label = new QShortenedLabel(parent); return m_label; } @@ -134,7 +174,7 @@ void PdmUiColorEditor::colorSelectionClicked() flags |= QColorDialog::ShowAlphaChannel; } - QColor newColor = QColorDialog::getColor(m_color, m_colorPixmapLabel, "Select color", flags); + QColor newColor = QColorDialog::getColor(m_color, m_colorSelectionButton, "Select color", flags); if (newColor.isValid() && newColor != m_color) { setColorOnWidget(newColor); @@ -153,17 +193,19 @@ void PdmUiColorEditor::setColorOnWidget(const QColor& color) { m_color = color; - QPixmap tmp(16, 16); - tmp.fill(m_color); - m_colorPixmapLabel->setPixmap(tmp); - QString colorString; if (!color.isValid()) { colorString = "Undefined"; + m_colorSelectionButton->setStyleSheet(""); } else { + QColor fontColor = getFontColor(m_color); + QString styleTemplate = "QLabel#ColorPreviewLabel { background-color: %1; color: %2; border: 1px solid black; }"; + QString styleSheet = QString(styleTemplate).arg(m_color.name()).arg(fontColor.name()); + + m_colorPreviewLabel->setStyleSheet(styleSheet); colorString = QString("[%1, %2, %3]").arg(QString::number(color.red())).arg(QString::number(color.green())).arg(QString::number(color.blue())); if (m_attributes.showAlpha) @@ -171,11 +213,23 @@ void PdmUiColorEditor::setColorOnWidget(const QColor& color) colorString += QString(" (%4)").arg(QString::number(color.alpha())); } } - - m_colorTextLabel->setText(colorString); + if (m_attributes.showLabel) + { + m_colorTextLabel->setText(colorString); + } } } +//-------------------------------------------------------------------------------------------------- +/// Based on http://www.codeproject.com/cs/media/IdealTextColor.asp +//-------------------------------------------------------------------------------------------------- +QColor PdmUiColorEditor::getFontColor(const QColor& backgroundColor) const +{ + const int THRESHOLD = 105; + int backgroundDelta = (backgroundColor.red() * 0.299) + (backgroundColor.green() * 0.587) + (backgroundColor.blue() * 0.114); + return QColor((255 - backgroundDelta < THRESHOLD) ? Qt::black : Qt::white); +} + } // end namespace caf diff --git a/Fwk/AppFwk/cafUserInterface/cafPdmUiColorEditor.h b/Fwk/AppFwk/cafUserInterface/cafPdmUiColorEditor.h index ed1168b6dd..0123f9cb46 100644 --- a/Fwk/AppFwk/cafUserInterface/cafPdmUiColorEditor.h +++ b/Fwk/AppFwk/cafUserInterface/cafPdmUiColorEditor.h @@ -44,6 +44,7 @@ #include #include #include +#include namespace caf @@ -56,11 +57,13 @@ class PdmUiColorEditorAttribute : public PdmUiEditorAttribute { public: bool showAlpha; + bool showLabel; public: PdmUiColorEditorAttribute() { showAlpha = false; + showLabel = true; } }; @@ -82,19 +85,23 @@ class PdmUiColorEditor : public PdmUiFieldEditorHandle QWidget* createLabelWidget(QWidget * parent) override; void configureAndUpdateUi(const QString& uiConfigName) override; + + QMargins calculateLabelContentMargins() const override; + protected slots: void colorSelectionClicked(); private: void setColorOnWidget(const QColor& c); - + QColor getFontColor(const QColor& backgroundColor) const; private: - QPointer m_label; + QPointer m_label; + + QColor m_color; + QPointer m_colorTextLabel; + QPointer m_colorSelectionButton; + QPointer m_colorPreviewLabel; - QColor m_color; - QPointer m_colorPixmapLabel; - QPointer m_colorTextLabel; - PdmUiColorEditorAttribute m_attributes; }; diff --git a/Fwk/AppFwk/cafUserInterface/cafPdmUiComboBoxEditor.cpp b/Fwk/AppFwk/cafUserInterface/cafPdmUiComboBoxEditor.cpp index 81c805e864..1c898300b8 100644 --- a/Fwk/AppFwk/cafUserInterface/cafPdmUiComboBoxEditor.cpp +++ b/Fwk/AppFwk/cafUserInterface/cafPdmUiComboBoxEditor.cpp @@ -42,6 +42,7 @@ #include "cafPdmField.h" #include "cafFactory.h" +#include "cafQShortenedLabel.h" #include #include @@ -214,6 +215,11 @@ void PdmUiComboBoxEditor::configureAndUpdateUi(const QString& uiConfigName) { m_comboBox->setSizeAdjustPolicy(QComboBox::AdjustToContents); } + else if (attributes.minimumContentsLength > 0) + { + m_comboBox->setSizeAdjustPolicy(QComboBox::AdjustToMinimumContentsLength); + m_comboBox->setMinimumContentsLength(attributes.minimumContentsLength); + } m_comboBox->blockSignals(false); } @@ -382,7 +388,7 @@ QWidget* PdmUiComboBoxEditor::createEditorWidget(QWidget * parent) //-------------------------------------------------------------------------------------------------- QWidget* PdmUiComboBoxEditor::createLabelWidget(QWidget * parent) { - m_label = new QLabel(parent); + m_label = new QShortenedLabel(parent); return m_label; } diff --git a/Fwk/AppFwk/cafUserInterface/cafPdmUiComboBoxEditor.h b/Fwk/AppFwk/cafUserInterface/cafPdmUiComboBoxEditor.h index addd35e0d7..cd9148293d 100644 --- a/Fwk/AppFwk/cafUserInterface/cafPdmUiComboBoxEditor.h +++ b/Fwk/AppFwk/cafUserInterface/cafPdmUiComboBoxEditor.h @@ -58,14 +58,17 @@ class PdmUiComboBoxEditorAttribute : public PdmUiEditorAttribute public: PdmUiComboBoxEditorAttribute() { - adjustWidthToContents = false; + adjustWidthToContents = false; showPreviousAndNextButtons = false; + minimumContentsLength = 8; } public: bool adjustWidthToContents; bool showPreviousAndNextButtons; - + int minimumContentsLength; // The length of string to adjust to if adjustWidthToContents = false. + // Set to <= 0 to ignore and use AdjustToContentsOnFirstShow instead + QString nextButtonText; QString prevButtonText; }; @@ -97,7 +100,7 @@ protected slots: private: QPointer m_comboBox; - QPointer m_label; + QPointer m_label; QPointer m_previousItemButton; QPointer m_nextItemButton; diff --git a/Fwk/AppFwk/cafUserInterface/cafPdmUiDateEditor.cpp b/Fwk/AppFwk/cafUserInterface/cafPdmUiDateEditor.cpp index 1684341c47..a4c719df53 100644 --- a/Fwk/AppFwk/cafUserInterface/cafPdmUiDateEditor.cpp +++ b/Fwk/AppFwk/cafUserInterface/cafPdmUiDateEditor.cpp @@ -44,6 +44,7 @@ #include "cafPdmUiFieldEditorHandle.h" #include "cafPdmUiOrdering.h" #include "cafSelectionManager.h" +#include "cafQShortenedLabel.h" #include #include @@ -106,7 +107,7 @@ QWidget* PdmUiDateEditor::createEditorWidget(QWidget* parent) //-------------------------------------------------------------------------------------------------- QWidget* PdmUiDateEditor::createLabelWidget(QWidget* parent) { - m_label = new QLabel(parent); + m_label = new QShortenedLabel(parent); return m_label; } diff --git a/Fwk/AppFwk/cafUserInterface/cafPdmUiDateEditor.h b/Fwk/AppFwk/cafUserInterface/cafPdmUiDateEditor.h index f3dcd4b7ca..303876cd18 100644 --- a/Fwk/AppFwk/cafUserInterface/cafPdmUiDateEditor.h +++ b/Fwk/AppFwk/cafUserInterface/cafPdmUiDateEditor.h @@ -84,7 +84,7 @@ protected slots: private: QPointer m_dateEdit; - QPointer m_label; + QPointer m_label; PdmUiDateEditorAttribute m_attributes; }; diff --git a/Fwk/AppFwk/cafUserInterface/cafPdmUiDefaultObjectEditor.cpp b/Fwk/AppFwk/cafUserInterface/cafPdmUiDefaultObjectEditor.cpp index 620856af61..033744442f 100644 --- a/Fwk/AppFwk/cafUserInterface/cafPdmUiDefaultObjectEditor.cpp +++ b/Fwk/AppFwk/cafUserInterface/cafPdmUiDefaultObjectEditor.cpp @@ -90,11 +90,7 @@ PdmUiDefaultObjectEditor::~PdmUiDefaultObjectEditor() QWidget* PdmUiDefaultObjectEditor::createWidget(QWidget* parent) { QWidget* widget = new QWidget(parent); - - QGridLayout* gridLayout = new QGridLayout(); - gridLayout->setContentsMargins(0, 0, 0, 0); - widget->setLayout(gridLayout); - + widget->setObjectName("ObjectEditor"); return widget; } @@ -105,7 +101,8 @@ void PdmUiDefaultObjectEditor::recursivelyConfigureAndUpdateTopLevelUiOrdering(c { CAF_ASSERT(this->widget()); - recursivelyConfigureAndUpdateUiOrderingInGridLayoutColumn(topLevelUiOrdering, this->widget(), uiConfigName); + recursivelyConfigureAndUpdateUiOrderingInNewGridLayout(topLevelUiOrdering, this->widget(), uiConfigName); } + } // end namespace caf diff --git a/Fwk/AppFwk/cafUserInterface/cafPdmUiDoubleSliderEditor.cpp b/Fwk/AppFwk/cafUserInterface/cafPdmUiDoubleSliderEditor.cpp index 94a8ae79ea..aeb89f5777 100644 --- a/Fwk/AppFwk/cafUserInterface/cafPdmUiDoubleSliderEditor.cpp +++ b/Fwk/AppFwk/cafUserInterface/cafPdmUiDoubleSliderEditor.cpp @@ -40,6 +40,7 @@ #include "cafPdmField.h" #include "cafPdmUiFieldHandle.h" #include "cafPdmUiObjectHandle.h" +#include "cafQShortenedLabel.h" #include #include @@ -112,6 +113,7 @@ void PdmUiDoubleSliderEditor::configureAndUpdateUi(const QString& uiConfigName) m_lineEdit->setValidator(pdmValidator); m_lineEdit->setText(textValue); + m_sliderValue = doubleValue; updateSliderPosition(doubleValue); } @@ -136,7 +138,7 @@ QWidget* PdmUiDoubleSliderEditor::createEditorWidget(QWidget * parent) layout->addWidget(m_slider); connect(m_slider, SIGNAL(valueChanged(int)), this, SLOT(slotSliderValueChanged(int))); - + connect(m_slider, SIGNAL(sliderReleased()), this, SLOT(slotSliderReleased())); return containerWidget; } @@ -145,7 +147,7 @@ QWidget* PdmUiDoubleSliderEditor::createEditorWidget(QWidget * parent) //-------------------------------------------------------------------------------------------------- QWidget* PdmUiDoubleSliderEditor::createLabelWidget(QWidget * parent) { - m_label = new QLabel(parent); + m_label = new QShortenedLabel(parent); return m_label; } @@ -159,6 +161,7 @@ void PdmUiDoubleSliderEditor::slotEditingFinished() double doubleVal = textValue.toDouble(); doubleVal = qBound(m_attributes.m_minimum, doubleVal, m_attributes.m_maximum); + m_sliderValue = doubleVal; writeValueToField(doubleVal); } @@ -169,8 +172,24 @@ void PdmUiDoubleSliderEditor::slotEditingFinished() void PdmUiDoubleSliderEditor::slotSliderValueChanged(int value) { double newDoubleValue = convertFromSliderValue(value); + m_sliderValue = newDoubleValue; + + if (m_attributes.m_delaySliderUpdateUntilRelease) + { + m_lineEdit->setText(QString("%1").arg(m_sliderValue)); + } + else + { + writeValueToField(m_sliderValue); + } +} - writeValueToField(newDoubleValue); +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void PdmUiDoubleSliderEditor::slotSliderReleased() +{ + writeValueToField(m_sliderValue); } //-------------------------------------------------------------------------------------------------- diff --git a/Fwk/AppFwk/cafUserInterface/cafPdmUiDoubleSliderEditor.h b/Fwk/AppFwk/cafUserInterface/cafPdmUiDoubleSliderEditor.h index f7e102c38e..4a76cdc149 100644 --- a/Fwk/AppFwk/cafUserInterface/cafPdmUiDoubleSliderEditor.h +++ b/Fwk/AppFwk/cafUserInterface/cafPdmUiDoubleSliderEditor.h @@ -61,6 +61,7 @@ class PdmUiDoubleSliderEditorAttribute : public PdmUiEditorAttribute m_maximum = 10; m_decimals = 6; m_sliderTickCount = 2000; + m_delaySliderUpdateUntilRelease = false; } public: @@ -68,6 +69,7 @@ class PdmUiDoubleSliderEditorAttribute : public PdmUiEditorAttribute double m_maximum; int m_decimals; int m_sliderTickCount; + bool m_delaySliderUpdateUntilRelease; }; @@ -91,6 +93,7 @@ class PdmUiDoubleSliderEditor : public PdmUiFieldEditorHandle protected slots: void slotEditingFinished(); void slotSliderValueChanged(int value); + void slotSliderReleased(); private: void updateSliderPosition(double value); @@ -100,9 +103,10 @@ protected slots: double convertFromSliderValue(int sliderValue); private: - QPointer m_lineEdit; - QPointer m_slider; - QPointer m_label; + QPointer m_lineEdit; + QPointer m_slider; + QPointer m_label; + double m_sliderValue; PdmUiDoubleSliderEditorAttribute m_attributes; }; diff --git a/Fwk/AppFwk/cafUserInterface/cafPdmUiDoubleValueEditor.cpp b/Fwk/AppFwk/cafUserInterface/cafPdmUiDoubleValueEditor.cpp index d6c3ff589a..dc5bbca743 100644 --- a/Fwk/AppFwk/cafUserInterface/cafPdmUiDoubleValueEditor.cpp +++ b/Fwk/AppFwk/cafUserInterface/cafPdmUiDoubleValueEditor.cpp @@ -42,6 +42,7 @@ #include "cafPdmUiFieldEditorHandle.h" #include "cafFactory.h" +#include "cafQShortenedLabel.h" #include #include @@ -118,7 +119,7 @@ QWidget* PdmUiDoubleValueEditor::createEditorWidget(QWidget* parent) //-------------------------------------------------------------------------------------------------- QWidget* PdmUiDoubleValueEditor::createLabelWidget(QWidget* parent) { - m_label = new QLabel(parent); + m_label = new QShortenedLabel(parent); return m_label; } diff --git a/Fwk/AppFwk/cafUserInterface/cafPdmUiDoubleValueEditor.h b/Fwk/AppFwk/cafUserInterface/cafPdmUiDoubleValueEditor.h index 3062c34ffb..4b065d0d33 100644 --- a/Fwk/AppFwk/cafUserInterface/cafPdmUiDoubleValueEditor.h +++ b/Fwk/AppFwk/cafUserInterface/cafPdmUiDoubleValueEditor.h @@ -86,8 +86,8 @@ protected slots: void writeValueToField(); private: - QPointer m_lineEdit; - QPointer m_label; + QPointer m_lineEdit; + QPointer m_label; PdmUiDoubleValueEditorAttribute m_attributes; }; diff --git a/Fwk/AppFwk/cafUserInterface/cafPdmUiFilePathEditor.cpp b/Fwk/AppFwk/cafUserInterface/cafPdmUiFilePathEditor.cpp index 49c5ddd022..84cea13657 100644 --- a/Fwk/AppFwk/cafUserInterface/cafPdmUiFilePathEditor.cpp +++ b/Fwk/AppFwk/cafUserInterface/cafPdmUiFilePathEditor.cpp @@ -43,6 +43,7 @@ #include "cafPdmUiDefaultObjectEditor.h" #include "cafPdmUiFieldEditorHandle.h" #include "cafPdmUiOrdering.h" +#include "cafQShortenedLabel.h" #include #include @@ -116,7 +117,7 @@ QWidget* PdmUiFilePathEditor::createEditorWidget(QWidget * parent) //-------------------------------------------------------------------------------------------------- QWidget* PdmUiFilePathEditor::createLabelWidget(QWidget * parent) { - m_label = new QLabel(parent); + m_label = new QShortenedLabel(parent); return m_label; } diff --git a/Fwk/AppFwk/cafUserInterface/cafPdmUiFilePathEditor.h b/Fwk/AppFwk/cafUserInterface/cafPdmUiFilePathEditor.h index 986a6ee349..e7f2a08703 100644 --- a/Fwk/AppFwk/cafUserInterface/cafPdmUiFilePathEditor.h +++ b/Fwk/AppFwk/cafUserInterface/cafPdmUiFilePathEditor.h @@ -60,7 +60,11 @@ class PdmUiFilePathEditorAttribute : public PdmUiEditorAttribute PdmUiFilePathEditorAttribute() { m_selectSaveFileName = false; - m_fileSelectionFilter = "All files (*.* *)"; +#ifdef _WIN32 + m_fileSelectionFilter = "All files (*.*)"; +#else + m_fileSelectionFilter = "All files (*)"; +#endif m_defaultPath = QString(); m_selectDirectory = false; @@ -100,9 +104,9 @@ protected slots: void fileSelectionClicked(); private: - QPointer m_lineEdit; - QPointer m_label; - QPointer m_button; + QPointer m_lineEdit; + QPointer m_label; + QPointer m_button; PdmUiFilePathEditorAttribute m_attributes; }; diff --git a/Fwk/AppFwk/cafUserInterface/cafPdmUiFormLayoutObjectEditor.cpp b/Fwk/AppFwk/cafUserInterface/cafPdmUiFormLayoutObjectEditor.cpp index 3d45b3a4f8..232a09c136 100644 --- a/Fwk/AppFwk/cafUserInterface/cafPdmUiFormLayoutObjectEditor.cpp +++ b/Fwk/AppFwk/cafUserInterface/cafPdmUiFormLayoutObjectEditor.cpp @@ -34,13 +34,13 @@ // //################################################################################################## - #include "cafPdmUiFormLayoutObjectEditor.h" #include "cafPdmObjectHandle.h" #include "cafPdmUiFieldEditorHandle.h" #include "cafPdmUiFieldEditorHelper.h" #include "cafPdmUiFieldHandle.h" +#include "cafPdmUiListEditor.h" #include "cafPdmUiObjectHandle.h" #include "cafPdmUiOrdering.h" #include "cafPdmXmlObjectHandle.h" @@ -49,19 +49,17 @@ #include "QMinimizePanel.h" -#include +#include #include +#include //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- -caf::PdmUiFormLayoutObjectEditor::PdmUiFormLayoutObjectEditor() -{ - -} +caf::PdmUiFormLayoutObjectEditor::PdmUiFormLayoutObjectEditor() {} //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- caf::PdmUiFormLayoutObjectEditor::~PdmUiFormLayoutObjectEditor() { @@ -73,190 +71,244 @@ caf::PdmUiFormLayoutObjectEditor::~PdmUiFormLayoutObjectEditor() //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void caf::PdmUiFormLayoutObjectEditor::recursivelyConfigureAndUpdateUiOrderingInGridLayoutColumn( - const PdmUiOrdering& uiOrdering, - QWidget* containerWidgetWithGridLayout, - const QString& uiConfigName) +void caf::PdmUiFormLayoutObjectEditor::slotScrollToSelectedItemsInFieldEditors() const { + for (auto fieldView : m_fieldViews) + { + auto listEditor = dynamic_cast(fieldView.second); + if (listEditor) + { + listEditor->scrollToSelectedItem(); + } + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool caf::PdmUiFormLayoutObjectEditor::recursivelyConfigureAndUpdateUiOrderingInNewGridLayout(const PdmUiOrdering& uiOrdering, + QWidget* containerWidget, + const QString& uiConfigName) +{ + QSize beforeSize = containerWidget->sizeHint(); + + ensureWidgetContainsEmptyGridLayout(containerWidget); + int stretch = recursivelyConfigureAndUpdateUiOrderingInGridLayout(uiOrdering, containerWidget, uiConfigName); + + QSize afterSize = containerWidget->sizeHint(); + if (beforeSize != afterSize) + { + containerWidget->adjustSize(); + } + + return stretch > 0; +} + +//-------------------------------------------------------------------------------------------------- +/// Add all widgets at a recursion level in the form. +/// Returns the stretch factor that should be applied at the level above. +//-------------------------------------------------------------------------------------------------- +int caf::PdmUiFormLayoutObjectEditor::recursivelyConfigureAndUpdateUiOrderingInGridLayout(const PdmUiOrdering& uiOrdering, + QWidget* containerWidgetWithGridLayout, + const QString& uiConfigName) +{ + int sumRowStretch = 0; CAF_ASSERT(containerWidgetWithGridLayout); - int currentRowIndex = -1; QWidget* previousTabOrderWidget = nullptr; // Currently, only QGridLayout is supported - QGridLayout* parentLayout = dynamic_cast(containerWidgetWithGridLayout->layout()); + QGridLayout* parentLayout = dynamic_cast(containerWidgetWithGridLayout->layout()); CAF_ASSERT(parentLayout); - const std::vector& uiItems = uiOrdering.uiItemsWithLayout(); + PdmUiOrdering::TableLayout tableLayout = uiOrdering.calculateTableLayout(uiConfigName); - int columnsPerRow = uiOrdering.nrOfColumns(); + int totalRows = static_cast(tableLayout.size()); + int totalColumns = uiOrdering.nrOfColumns(tableLayout); - int currentColumn = 0; - int itemsInCurrentRow = 1; - for (size_t i = 0; i < uiItems.size(); ++i) + for (int currentRowIndex = 0; currentRowIndex < totalRows; ++currentRowIndex) { - PdmUiItem* currentItem = uiItems[i].first; - PdmUiOrdering::LayoutOptions currentLayout = uiItems[i].second; - int itemColumnSpan = currentLayout.totalColumnSpan; + int currentColumn = 0; - if (currentRowIndex == -1 || currentLayout.newRow) - { - currentRowIndex++; - parentLayout->setRowStretch(currentRowIndex, 0); + const PdmUiOrdering::RowLayout& uiItemsInRow = tableLayout[currentRowIndex]; - currentColumn = 0; - itemsInCurrentRow = 1; - for (size_t j = i+1; j < uiItems.size(); ++j) - { - if (uiItems[j].second.newRow) break; - itemsInCurrentRow++; - } - } + int columnsRequiredForCurrentRow = uiOrdering.nrOfRequiredColumnsInRow(uiItemsInRow); + int nrOfExpandingItemsInRow = uiOrdering.nrOfExpandingItemsInRow(uiItemsInRow); + int spareColumnsInRow = totalColumns - columnsRequiredForCurrentRow; - if (itemColumnSpan == PdmUiOrdering::LayoutOptions::MAX_COLUMN_SPAN) + std::div_t columnsDiv = {0, 0}; + if (spareColumnsInRow && nrOfExpandingItemsInRow) { - itemColumnSpan = columnsPerRow / itemsInCurrentRow; + columnsDiv = std::div(spareColumnsInRow, nrOfExpandingItemsInRow); } - if (currentItem->isUiHidden(uiConfigName)) continue; - - if (currentItem->isUiGroup()) + for (size_t i = 0; i < uiItemsInRow.size(); ++i) { - PdmUiGroup* group = static_cast(currentItem); - - QMinimizePanel* groupBox = findOrCreateGroupBox(containerWidgetWithGridLayout, group, uiConfigName); + PdmUiItem* currentItem = uiItemsInRow[i].first; + PdmUiOrdering::LayoutOptions currentLayout = uiItemsInRow[i].second; - /// Insert the group box at the correct position of the parent layout - parentLayout->addWidget(groupBox, currentRowIndex, currentColumn, 1, itemColumnSpan); - - recursivelyConfigureAndUpdateUiOrderingInGridLayoutColumn(*group, groupBox->contentFrame(), uiConfigName); + int minimumItemColumnSpan = 0, minimumLabelColumnSpan = 0, minimumFieldColumnSpan = 0; + uiOrdering.nrOfColumnsRequiredForItem( + uiItemsInRow[i], &minimumItemColumnSpan, &minimumLabelColumnSpan, &minimumFieldColumnSpan); + bool isExpandingItem = currentLayout.totalColumnSpan == PdmUiOrdering::LayoutOptions::MAX_COLUMN_SPAN; - currentColumn += itemColumnSpan; - } - else - { - PdmUiFieldHandle* field = dynamic_cast(currentItem); + int spareColumnsToAssign = 0; + if (isExpandingItem) + { + spareColumnsToAssign += columnsDiv.quot; + if (i == 0) spareColumnsToAssign += columnsDiv.rem; + } - PdmUiFieldEditorHandle* fieldEditor = findOrCreateFieldEditor(containerWidgetWithGridLayout, field, uiConfigName); + int itemColumnSpan = minimumItemColumnSpan + spareColumnsToAssign; - if (fieldEditor) + if (currentItem->isUiGroup()) + { + int groupStretchFactor = recursivelyAddGroupToGridLayout(currentItem, + containerWidgetWithGridLayout, + uiConfigName, + parentLayout, + currentRowIndex, + currentColumn, + itemColumnSpan); + parentLayout->setRowStretch(currentRowIndex, groupStretchFactor); + currentColumn += itemColumnSpan; + sumRowStretch += groupStretchFactor; + } + else { - fieldEditor->setUiField(field); + // Also assign required item space that isn't taken up by field and label + spareColumnsToAssign += minimumItemColumnSpan - (minimumLabelColumnSpan + minimumFieldColumnSpan); - // Place the widget(s) into the correct parent and layout - QWidget* fieldCombinedWidget = fieldEditor->combinedWidget(); + PdmUiFieldHandle* field = dynamic_cast(currentItem); - if (fieldCombinedWidget) - { - fieldCombinedWidget->setParent(containerWidgetWithGridLayout); - parentLayout->addWidget(fieldCombinedWidget, currentRowIndex, currentColumn, 1, itemColumnSpan); - } - else + PdmUiFieldEditorHandle* fieldEditor = findOrCreateFieldEditor(containerWidgetWithGridLayout, field, uiConfigName); + + if (fieldEditor) { - PdmUiItemInfo::LabelPosType labelPos = field->uiLabelPosition(uiConfigName); + fieldEditor->setUiField(field); - QWidget* fieldEditorWidget = fieldEditor->editorWidget(); - if (fieldEditorWidget) + // Place the widget(s) into the correct parent and layout + QWidget* fieldCombinedWidget = fieldEditor->combinedWidget(); + + if (fieldCombinedWidget) { - // Hide label - if (labelPos == PdmUiItemInfo::HIDDEN) - { - QWidget* fieldLabelWidget = fieldEditor->labelWidget(); - if (fieldLabelWidget) - { - fieldLabelWidget->hide(); - } + parentLayout->addWidget(fieldCombinedWidget, currentRowIndex, currentColumn, 1, itemColumnSpan); + parentLayout->setRowStretch(currentRowIndex, fieldEditor->rowStretchFactor()); + sumRowStretch += fieldEditor->rowStretchFactor(); + } + else + { + QWidget* fieldEditorWidget = fieldEditor->editorWidget(); + if (!fieldEditorWidget) continue; - fieldEditorWidget->setParent(containerWidgetWithGridLayout); // To make sure this widget has the current group box as parent. - parentLayout->addWidget(fieldEditorWidget, currentRowIndex, currentColumn, 1, itemColumnSpan, Qt::AlignTop); + int fieldColumnSpan = minimumFieldColumnSpan; - currentColumn += itemColumnSpan; - } - else // Add label + QWidget* fieldLabelWidget = fieldEditor->labelWidget(); + PdmUiItemInfo::LabelPosType labelPos = PdmUiItemInfo::HIDDEN; + + if (fieldLabelWidget) { - QWidget* fieldLabelWidget = fieldEditor->labelWidget(); + labelPos = field->uiLabelPosition(uiConfigName); - // For label on top we add another layer of QLayouts to avoid messing with the global rows. - if (labelPos == PdmUiItemInfo::TOP) + if (labelPos == PdmUiItemInfo::HIDDEN) { - QVBoxLayout* labelAndFieldVLayout = new QVBoxLayout(); - parentLayout->addLayout(labelAndFieldVLayout, currentRowIndex, currentColumn, 1, itemColumnSpan, Qt::AlignTop); - if (fieldLabelWidget) - { - labelAndFieldVLayout->addWidget(fieldLabelWidget, 0, Qt::AlignTop); - } - labelAndFieldVLayout->addWidget(fieldEditorWidget, 1, Qt::AlignTop); - + fieldLabelWidget->hide(); + } + else if (labelPos == PdmUiItemInfo::TOP) + { + QVBoxLayout* labelAndFieldVerticalLayout = new QVBoxLayout(); + parentLayout->addLayout( + labelAndFieldVerticalLayout, currentRowIndex, currentColumn, 1, itemColumnSpan, Qt::AlignTop); + labelAndFieldVerticalLayout->addWidget(fieldLabelWidget, 0, Qt::AlignTop); + labelAndFieldVerticalLayout->addWidget(fieldEditorWidget, 1, Qt::AlignTop); + + // Apply margins determined by the editor type + //fieldLabelWidget->setContentsMargins(fieldEditor->labelContentMargins()); currentColumn += itemColumnSpan; } else { - int fieldColumnSpan = currentLayout.totalColumnSpan; - int leftLabelColumnSpan = 0; - if (fieldLabelWidget) + CAF_ASSERT(labelPos == PdmUiItemInfo::LEFT); + int leftLabelColumnSpan = minimumLabelColumnSpan; + if (currentLayout.leftLabelColumnSpan == PdmUiOrdering::LayoutOptions::MAX_COLUMN_SPAN && + currentLayout.totalColumnSpan != PdmUiOrdering::LayoutOptions::MAX_COLUMN_SPAN) { - leftLabelColumnSpan = currentLayout.leftLabelColumnSpan; - if (fieldColumnSpan == PdmUiOrdering::LayoutOptions::MAX_COLUMN_SPAN && - leftLabelColumnSpan == PdmUiOrdering::LayoutOptions::MAX_COLUMN_SPAN) - { - // Rounded up half for field. Rest for left label. - fieldColumnSpan = itemColumnSpan / 2 + itemColumnSpan % 2; - leftLabelColumnSpan = itemColumnSpan - fieldColumnSpan; - } - else if (fieldColumnSpan == PdmUiOrdering::LayoutOptions::MAX_COLUMN_SPAN) - { - fieldColumnSpan = itemColumnSpan - leftLabelColumnSpan; - } - else if (leftLabelColumnSpan == PdmUiOrdering::LayoutOptions::MAX_COLUMN_SPAN) - { - fieldColumnSpan = 1; - leftLabelColumnSpan = itemColumnSpan - fieldColumnSpan; - } - else - { - fieldColumnSpan = itemColumnSpan - leftLabelColumnSpan; - } - CAF_ASSERT(fieldColumnSpan >= 1 && "Need at least one column for the field"); - fieldColumnSpan = std::max(1, fieldColumnSpan); - fieldLabelWidget->setParent(containerWidgetWithGridLayout); - parentLayout->addWidget(fieldLabelWidget, currentRowIndex, currentColumn, 1, leftLabelColumnSpan, Qt::AlignTop); - - // Apply margins determined by the editor type - fieldLabelWidget->setContentsMargins(fieldEditor->labelContentMargins()); + leftLabelColumnSpan += spareColumnsToAssign; + spareColumnsToAssign = 0; + } + else if (currentLayout.leftLabelColumnSpan == PdmUiOrdering::LayoutOptions::MAX_COLUMN_SPAN) + { + leftLabelColumnSpan += spareColumnsToAssign / 2; + spareColumnsToAssign -= spareColumnsToAssign / 2; } - fieldEditorWidget->setParent(containerWidgetWithGridLayout); // To make sure this widget has the current group box as parent. - parentLayout->addWidget(fieldEditorWidget, currentRowIndex, currentColumn + leftLabelColumnSpan, 1, fieldColumnSpan, Qt::AlignTop); - currentColumn += itemColumnSpan; + parentLayout->addWidget( + fieldLabelWidget, currentRowIndex, currentColumn, 1, leftLabelColumnSpan, Qt::AlignTop); + currentColumn += leftLabelColumnSpan; + + // Apply margins determined by the editor type + fieldLabelWidget->setContentsMargins(fieldEditor->labelContentMargins()); } } + if (labelPos != PdmUiItemInfo::TOP) // Already added if TOP + { + fieldColumnSpan += spareColumnsToAssign; + + CAF_ASSERT(fieldColumnSpan >= 1 && "Need at least one column for the field"); + fieldColumnSpan = std::max(1, fieldColumnSpan); + + parentLayout->addWidget( + fieldEditorWidget, currentRowIndex, currentColumn, 1, fieldColumnSpan, Qt::AlignTop); + currentColumn += fieldColumnSpan; + } + if (previousTabOrderWidget) { QWidget::setTabOrder(previousTabOrderWidget, fieldEditorWidget); - } + } + previousTabOrderWidget = fieldEditorWidget; + + parentLayout->setRowStretch(currentRowIndex, fieldEditor->rowStretchFactor()); + sumRowStretch += fieldEditor->rowStretchFactor(); } + fieldEditor->updateUi(uiConfigName); } - fieldEditor->updateUi(uiConfigName); } } - } - // Set last row with content to stretch - if (currentRowIndex >= 0 && currentRowIndex < parentLayout->rowCount()) - { - parentLayout->setRowStretch(currentRowIndex++, 1); + CAF_ASSERT(currentColumn <= totalColumns); } + containerWidgetWithGridLayout->updateGeometry(); + // The magnitude of the stretch should not be sent up, only if there was stretch or not + return sumRowStretch; +} - // Set remaining rows to stretch zero, as we want the row with content to stretch all the way - while (currentRowIndex >= 0 && currentRowIndex < parentLayout->rowCount()) - { - parentLayout->setRowStretch(currentRowIndex++, 0); - } +//-------------------------------------------------------------------------------------------------- +/// Create a group and add widgets. Return true if the containing row needs to be stretched. +//-------------------------------------------------------------------------------------------------- +int caf::PdmUiFormLayoutObjectEditor::recursivelyAddGroupToGridLayout(PdmUiItem* currentItem, + QWidget* containerWidgetWithGridLayout, + const QString& uiConfigName, + QGridLayout* parentLayout, + int currentRowIndex, + int currentColumn, + int itemColumnSpan) +{ + PdmUiGroup* group = static_cast(currentItem); + + QMinimizePanel* groupBox = findOrCreateGroupBox(containerWidgetWithGridLayout, group, uiConfigName); + + int stretch = recursivelyConfigureAndUpdateUiOrderingInGridLayout(*group, groupBox->contentFrame(), uiConfigName); + + /// Insert the group box at the correct position of the parent layout + parentLayout->addWidget(groupBox, currentRowIndex, currentColumn, 1, itemColumnSpan); + + return stretch; } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- bool caf::PdmUiFormLayoutObjectEditor::isUiGroupExpanded(const PdmUiGroup* uiGroup) const { @@ -278,16 +330,16 @@ bool caf::PdmUiFormLayoutObjectEditor::isUiGroupExpanded(const PdmUiGroup* uiGro } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- -QMinimizePanel* caf::PdmUiFormLayoutObjectEditor::findOrCreateGroupBox(QWidget* parent, PdmUiGroup* group, const QString& uiConfigName) +QMinimizePanel* + caf::PdmUiFormLayoutObjectEditor::findOrCreateGroupBox(QWidget* parent, PdmUiGroup* group, const QString& uiConfigName) { - QString groupBoxKey = group->keyword(); - QMinimizePanel* groupBox = nullptr; - QGridLayout* groupBoxLayout = nullptr; + QString groupBoxKey = group->keyword(); + QMinimizePanel* groupBox = nullptr; // Find or create groupBox - std::map >::iterator it; + std::map>::iterator it; it = m_groupBoxes.find(groupBoxKey); if (it == m_groupBoxes.end()) @@ -296,13 +348,6 @@ QMinimizePanel* caf::PdmUiFormLayoutObjectEditor::findOrCreateGroupBox(QWidget* groupBox->enableFrame(group->enableFrame()); groupBox->setTitle(group->uiName(uiConfigName)); groupBox->setObjectName(group->keyword()); - groupBoxLayout = new QGridLayout(); - if (!group->enableFrame()) - { - groupBoxLayout->setContentsMargins(0, 0, 0, 0); - groupBoxLayout->setHorizontalSpacing(0); - } - groupBox->contentFrame()->setLayout(groupBoxLayout); connect(groupBox, SIGNAL(expandedChanged(bool)), this, SLOT(groupBoxExpandedStateToggled(bool))); m_newGroupBoxes[groupBoxKey] = groupBox; @@ -311,24 +356,33 @@ QMinimizePanel* caf::PdmUiFormLayoutObjectEditor::findOrCreateGroupBox(QWidget* { groupBox = it->second; CAF_ASSERT(groupBox); - m_newGroupBoxes[groupBoxKey] = groupBox; } + QMargins contentMargins; + if (group->enableFrame()) + { + contentMargins = QMargins(6, 6, 6, 6); + } + + ensureWidgetContainsEmptyGridLayout(groupBox->contentFrame(), contentMargins); + // Set Expanded state bool isExpanded = isUiGroupExpanded(group); groupBox->setExpanded(isExpanded); // Update the title to be able to support dynamic group names groupBox->setTitle(group->uiName(uiConfigName)); - + groupBox->updateGeometry(); return groupBox; } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- -caf::PdmUiFieldEditorHandle* caf::PdmUiFormLayoutObjectEditor::findOrCreateFieldEditor(QWidget* parent, PdmUiFieldHandle* field, const QString& uiConfigName) +caf::PdmUiFieldEditorHandle* caf::PdmUiFormLayoutObjectEditor::findOrCreateFieldEditor(QWidget* parent, + PdmUiFieldHandle* field, + const QString& uiConfigName) { caf::PdmUiFieldEditorHandle* fieldEditor = nullptr; @@ -354,7 +408,7 @@ caf::PdmUiFieldEditorHandle* caf::PdmUiFormLayoutObjectEditor::findOrCreateField // This assert will trigger for PdmChildArrayField and PdmChildField // Consider to exclude assert or add editors for these types if the assert is reintroduced - //CAF_ASSERT(false); + // CAF_ASSERT(false); } } else @@ -366,14 +420,37 @@ caf::PdmUiFieldEditorHandle* caf::PdmUiFormLayoutObjectEditor::findOrCreateField } //-------------------------------------------------------------------------------------------------- -/// +/// +//-------------------------------------------------------------------------------------------------- +void caf::PdmUiFormLayoutObjectEditor::ensureWidgetContainsEmptyGridLayout(QWidget* containerWidget, QMargins contentMargins) +{ + CAF_ASSERT(containerWidget); + QLayout* layout = containerWidget->layout(); + if (layout != nullptr) + { + // Remove all items from the layout, then reparent the layout to a temporary + // This is because you cannot remove a layout from a widget but it gets moved when reparenting. + QLayoutItem* item; + while ((item = layout->takeAt(0)) != 0) + { + } + QWidget().setLayout(layout); + } + + QGridLayout* gridLayout = new QGridLayout; + gridLayout->setContentsMargins(contentMargins); + containerWidget->setLayout(gridLayout); +} + +//-------------------------------------------------------------------------------------------------- +/// //-------------------------------------------------------------------------------------------------- void caf::PdmUiFormLayoutObjectEditor::groupBoxExpandedStateToggled(bool isExpanded) { if (!this->pdmObject()->xmlCapability()) return; - QString objKeyword = this->pdmObject()->xmlCapability()->classKeyword(); - QMinimizePanel* panel = dynamic_cast(this->sender()); + QString objKeyword = this->pdmObject()->xmlCapability()->classKeyword(); + QMinimizePanel* panel = dynamic_cast(this->sender()); if (!panel) return; @@ -381,7 +458,7 @@ void caf::PdmUiFormLayoutObjectEditor::groupBoxExpandedStateToggled(bool isExpan } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void caf::PdmUiFormLayoutObjectEditor::cleanupBeforeSettingPdmObject() { @@ -395,7 +472,7 @@ void caf::PdmUiFormLayoutObjectEditor::cleanupBeforeSettingPdmObject() m_newGroupBoxes.clear(); - std::map >::iterator groupIt; + std::map>::iterator groupIt; for (groupIt = m_groupBoxes.begin(); groupIt != m_groupBoxes.end(); ++groupIt) { if (!groupIt->second.isNull()) groupIt->second->deleteLater(); @@ -405,7 +482,7 @@ void caf::PdmUiFormLayoutObjectEditor::cleanupBeforeSettingPdmObject() } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- void caf::PdmUiFormLayoutObjectEditor::configureAndUpdateUi(const QString& uiConfigName) { @@ -433,7 +510,7 @@ void caf::PdmUiFormLayoutObjectEditor::configureAndUpdateUi(const QString& uiCon // Remove all fieldViews not mentioned by the configuration from the layout - std::vector< PdmFieldHandle* > fvhToRemoveFromMap; + std::vector fvhToRemoveFromMap; for (it = m_fieldViews.begin(); it != m_fieldViews.end(); ++it) { if (it->second->uiField() == nullptr) @@ -451,8 +528,8 @@ void caf::PdmUiFormLayoutObjectEditor::configureAndUpdateUi(const QString& uiCon // Remove all unmentioned group boxes - std::map >::iterator itOld; - std::map >::iterator itNew; + std::map>::iterator itOld; + std::map>::iterator itNew; for (itOld = m_groupBoxes.begin(); itOld != m_groupBoxes.end(); ++itOld) { @@ -476,16 +553,16 @@ void caf::PdmUiFormLayoutObjectEditor::configureAndUpdateUi(const QString& uiCon //-------------------------------------------------------------------------------------------------- /// Unused. Should probably remove //-------------------------------------------------------------------------------------------------- -void caf::PdmUiFormLayoutObjectEditor::recursiveVerifyUniqueNames(const std::vector& uiItems, - const QString& uiConfigName, - std::set* fieldKeywordNames, - std::set* groupNames) +void caf::PdmUiFormLayoutObjectEditor::recursiveVerifyUniqueNames(const std::vector& uiItems, + const QString& uiConfigName, + std::set* fieldKeywordNames, + std::set* groupNames) { for (size_t i = 0; i < uiItems.size(); ++i) { if (uiItems[i]->isUiGroup()) { - PdmUiGroup* group = static_cast(uiItems[i]); + PdmUiGroup* group = static_cast(uiItems[i]); const std::vector& groupChildren = group->uiItems(); QString groupBoxKey = group->keyword(); @@ -519,4 +596,3 @@ void caf::PdmUiFormLayoutObjectEditor::recursiveVerifyUniqueNames(const std::vec } } } - diff --git a/Fwk/AppFwk/cafUserInterface/cafPdmUiFormLayoutObjectEditor.h b/Fwk/AppFwk/cafUserInterface/cafPdmUiFormLayoutObjectEditor.h index b6c89ac393..586c094059 100644 --- a/Fwk/AppFwk/cafUserInterface/cafPdmUiFormLayoutObjectEditor.h +++ b/Fwk/AppFwk/cafUserInterface/cafPdmUiFormLayoutObjectEditor.h @@ -37,7 +37,7 @@ #pragma once -#include "cafPdmUiObjectEditorHandle.h" +#include "cafPdmUiWidgetObjectEditorHandle.h" #include "cafPdmUiOrdering.h" #include @@ -47,6 +47,7 @@ class QMinimizePanel; class QGridLayout; +class QWidget; namespace caf { @@ -58,26 +59,42 @@ class PdmUiOrdering; //================================================================================================== /// //================================================================================================== -class PdmUiFormLayoutObjectEditor : public PdmUiObjectEditorHandle +class PdmUiFormLayoutObjectEditor : public PdmUiWidgetObjectEditorHandle { Q_OBJECT public: PdmUiFormLayoutObjectEditor(); ~PdmUiFormLayoutObjectEditor() override; +public slots: + void slotScrollToSelectedItemsInFieldEditors() const; + protected: /// When overriding this function, use findOrCreateGroupBox() or findOrCreateFieldEditor() for detailed control /// Use recursivelyConfigureAndUpdateUiItemsInGridLayoutColumn() for automatic layout of group and field widgets virtual void recursivelyConfigureAndUpdateTopLevelUiOrdering(const PdmUiOrdering& topLevelUiOrdering, const QString& uiConfigName) = 0; - void recursivelyConfigureAndUpdateUiOrderingInGridLayoutColumn(const PdmUiOrdering& uiOrdering, - QWidget* containerWidgetWithGridLayout, - const QString& uiConfigName); + bool recursivelyConfigureAndUpdateUiOrderingInNewGridLayout(const PdmUiOrdering& uiOrdering, + QWidget* containerWidget, + const QString& uiConfigName); + int recursivelyConfigureAndUpdateUiOrderingInGridLayout(const PdmUiOrdering& uiOrdering, + QWidget* containerWidgetWithGridLayout, + const QString& uiConfigName); + + int recursivelyAddGroupToGridLayout(PdmUiItem* currentItem, + QWidget* containerWidget, + const QString& uiConfigName, + QGridLayout* parentLayout, + int currentRowIndex, + int currentColumn, + int itemColumnSpan); QMinimizePanel* findOrCreateGroupBox(QWidget* parent, PdmUiGroup* group, const QString& uiConfigName); PdmUiFieldEditorHandle* findOrCreateFieldEditor(QWidget* parent, PdmUiFieldHandle* field, const QString& uiConfigName); + static void ensureWidgetContainsEmptyGridLayout(QWidget* containerWidget, QMargins contentMargins = QMargins()); + private slots: void groupBoxExpandedStateToggled(bool isExpanded); diff --git a/Fwk/AppFwk/cafUserInterface/cafPdmUiLineEditor.cpp b/Fwk/AppFwk/cafUserInterface/cafPdmUiLineEditor.cpp index e827cb193d..e5a777ea80 100644 --- a/Fwk/AppFwk/cafUserInterface/cafPdmUiLineEditor.cpp +++ b/Fwk/AppFwk/cafUserInterface/cafPdmUiLineEditor.cpp @@ -38,11 +38,13 @@ #include "cafPdmUiLineEditor.h" #include "cafFactory.h" +#include "cafQShortenedLabel.h" #include "cafPdmField.h" #include "cafPdmObject.h" #include "cafPdmUiDefaultObjectEditor.h" #include "cafPdmUiFieldEditorHandle.h" #include "cafPdmUiOrdering.h" +#include "cafPdmUniqueIdValidator.h" #include "cafSelectionManager.h" #include @@ -55,101 +57,9 @@ #include #include - - - -class PdmUniqueIdValidator : public QValidator -{ -public: - PdmUniqueIdValidator(const std::set& usedIds, bool multipleSelectionOfSameFieldsSelected, const QString& errorMessage, QObject* parent) - : QValidator(parent), - m_usedIds(usedIds), - m_nextValidValue(0), - m_multipleSelectionOfSameFieldsSelected(multipleSelectionOfSameFieldsSelected), - m_errorMessage(errorMessage) - { - computeNextValidId(); - } - - State validate(QString& currentString, int &) const override - { - if (m_multipleSelectionOfSameFieldsSelected) - { - return QValidator::Invalid; - } - - if (currentString.isEmpty()) - { - return QValidator::Intermediate; - } - - bool isValidInteger = false; - int currentValue = currentString.toInt(&isValidInteger); - - if (!isValidInteger) - { - return QValidator::Invalid; - } - - if (currentValue < 0) - { - return QValidator::Invalid; - } - - if (m_usedIds.find(currentValue) != m_usedIds.end()) - { - foreach(QWidget* widget, QApplication::topLevelWidgets()) - { - if (widget->inherits("QMainWindow")) - { - QMainWindow* mainWindow = qobject_cast(widget); - if (mainWindow && mainWindow->statusBar()) - { - mainWindow->statusBar()->showMessage(m_errorMessage, 3000); - } - } - } - - return QValidator::Intermediate; - } - - return QValidator::Acceptable; - } - - void fixup(QString& editorText) const override - { - editorText = QString::number(m_nextValidValue); - } - -private: - int computeNextValidId() - { - if (!m_usedIds.empty()) - { - m_nextValidValue = *m_usedIds.rbegin(); - } - else - { - m_nextValidValue = 1; - } - - return m_nextValidValue; - } - -private: - std::set m_usedIds; - - int m_nextValidValue; - bool m_multipleSelectionOfSameFieldsSelected; - QString m_errorMessage; -}; - - - namespace caf { -CAF_PDM_UI_FIELD_EDITOR_SOURCE_INIT(PdmUiLineEditor); //-------------------------------------------------------------------------------------------------- /// @@ -168,7 +78,7 @@ QWidget* PdmUiLineEditor::createEditorWidget(QWidget * parent) //-------------------------------------------------------------------------------------------------- QWidget* PdmUiLineEditor::createLabelWidget(QWidget * parent) { - m_label = new QLabel(parent); + m_label = new QShortenedLabel(parent); return m_label; } @@ -209,33 +119,14 @@ void PdmUiLineEditor::configureAndUpdateUi(const QString& uiConfigName) uiObject->editorAttribute(uiField()->fieldHandle(), uiConfigName, &leab); } - if (leab.useRangeValidator) + if (leab.validator) { - m_lineEdit->setValidator(new QIntValidator(leab.minValue, leab.maxValue, this)); + m_lineEdit->setValidator(leab.validator); } m_lineEdit->setAvoidSendingEnterEventToParentWidget(leab.avoidSendingEnterEventToParentWidget); } - { - PdmUiLineEditorAttributeUniqueValues leab; - caf::PdmUiObjectHandle* uiObject = uiObj(uiField()->fieldHandle()->ownerObject()); - if (uiObject) - { - uiObject->editorAttribute(uiField()->fieldHandle(), uiConfigName, &leab); - } - if (leab.usedIds.size() > 0) - { - if (isMultipleFieldsWithSameKeywordSelected(uiField()->fieldHandle())) - { - QMessageBox::information(nullptr, "Invalid operation", "The field you are manipulating is defined to have unique values. A selection of multiple fields is detected. Please select a single item."); - } - - m_lineEdit->setValidator(new PdmUniqueIdValidator(leab.usedIds, isMultipleFieldsWithSameKeywordSelected(uiField()->fieldHandle()), leab.errorMessage, this)); - } - } - - bool fromMenuOnly = true; QList enumNames = uiField()->valueOptions(&fromMenuOnly); CAF_ASSERT(fromMenuOnly); // Not supported @@ -261,7 +152,22 @@ void PdmUiLineEditor::configureAndUpdateUi(const QString& uiConfigName) QString displayString; if (leab.m_displayString.isEmpty()) { +#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) && QT_VERSION < QT_VERSION_CHECK(5, 9, 0)) + bool valueOk = false; + double value = uiField()->uiValue().toDouble(&valueOk); + if (valueOk) + { + // Workaround for issue seen on Qt 5.6.1 on Linux + int precision = 8; + displayString = QString::number(value, 'g', precision); + } + else + { + displayString = uiField()->uiValue().toString(); + } +#else displayString = uiField()->uiValue().toString(); +#endif } else { @@ -368,4 +274,8 @@ void PdmUiLineEdit::keyPressEvent(QKeyEvent * event) } } +// Define at this location to avoid duplicate symbol definitions in 'cafPdmUiDefaultObjectEditor.cpp' in a cotire build. The +// variables defined by the macro are prefixed by line numbers causing a crash if the macro is defined at the same line number. +CAF_PDM_UI_FIELD_EDITOR_SOURCE_INIT(PdmUiLineEditor); + } // end namespace caf diff --git a/Fwk/AppFwk/cafUserInterface/cafPdmUiLineEditor.h b/Fwk/AppFwk/cafUserInterface/cafPdmUiLineEditor.h index 6adf7d30d7..7c1e5947e7 100644 --- a/Fwk/AppFwk/cafUserInterface/cafPdmUiLineEditor.h +++ b/Fwk/AppFwk/cafUserInterface/cafPdmUiLineEditor.h @@ -43,6 +43,7 @@ #include #include #include +#include #include class QGridLayout; @@ -59,31 +60,11 @@ class PdmUiLineEditorAttribute : public PdmUiEditorAttribute PdmUiLineEditorAttribute() { avoidSendingEnterEventToParentWidget = false; - useRangeValidator = false; - minValue = 0; - maxValue = 0; } public: bool avoidSendingEnterEventToParentWidget; - bool useRangeValidator; - int minValue; - int maxValue; -}; - - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -class PdmUiLineEditorAttributeUniqueValues : public PdmUiEditorAttribute -{ -public: - PdmUiLineEditorAttributeUniqueValues() - {} - -public: - std::set usedIds; - QString errorMessage; + QPointer validator; }; //-------------------------------------------------------------------------------------------------- @@ -135,9 +116,9 @@ protected slots: private: bool isMultipleFieldsWithSameKeywordSelected(PdmFieldHandle* editorField) const; -private: - QPointer m_lineEdit; - QPointer m_label; +protected: + QPointer m_lineEdit; + QPointer m_label; }; diff --git a/Fwk/AppFwk/cafUserInterface/cafPdmUiListEditor.cpp b/Fwk/AppFwk/cafUserInterface/cafPdmUiListEditor.cpp index ee55444ca0..b84135d0ed 100644 --- a/Fwk/AppFwk/cafUserInterface/cafPdmUiListEditor.cpp +++ b/Fwk/AppFwk/cafUserInterface/cafPdmUiListEditor.cpp @@ -34,7 +34,6 @@ // //################################################################################################## - #include "cafPdmUiListEditor.h" #include "cafPdmUiDefaultObjectEditor.h" @@ -43,6 +42,7 @@ #include "cafPdmField.h" #include "cafFactory.h" +#include "cafQShortenedLabel.h" #include #include @@ -138,7 +138,8 @@ CAF_PDM_UI_FIELD_EDITOR_SOURCE_INIT(PdmUiListEditor); //-------------------------------------------------------------------------------------------------- PdmUiListEditor::PdmUiListEditor() : m_isEditOperationsAvailable(true), - m_optionItemCount(0) + m_optionItemCount(0), + m_isScrollToItemAllowed(true) { } @@ -149,6 +150,21 @@ PdmUiListEditor::~PdmUiListEditor() { } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void PdmUiListEditor::scrollToSelectedItem() const +{ + if (m_isScrollToItemAllowed) + { + QModelIndex mi = m_listView->currentIndex(); + if (mi.isValid()) + { + m_listView->scrollTo(mi); + } + } +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -190,6 +206,10 @@ void PdmUiListEditor::configureAndUpdateUi(const QString& uiConfigName) m_listView->setPalette(myPalette); m_listView->setHeightHint(attributes.m_heightHint); + if (!attributes.m_allowHorizontalScrollBar) + { + m_listView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + } } MyStringListModel* strListModel = dynamic_cast(m_model.data()); @@ -266,6 +286,8 @@ void PdmUiListEditor::configureAndUpdateUi(const QString& uiConfigName) m_listView->selectionModel()->blockSignals(false); } + + //ensureCurrentItemIsVisible(); } //-------------------------------------------------------------------------------------------------- @@ -295,7 +317,7 @@ QWidget* PdmUiListEditor::createEditorWidget(QWidget * parent) //-------------------------------------------------------------------------------------------------- QWidget* PdmUiListEditor::createLabelWidget(QWidget * parent) { - m_label = new QLabel(parent); + m_label = new QShortenedLabel(parent); return m_label; } @@ -306,6 +328,8 @@ void PdmUiListEditor::slotSelectionChanged(const QItemSelection & selected, cons { if (m_optionItemCount == 0) return; + m_isScrollToItemAllowed = false; + QVariant fieldValue = uiField()->uiValue(); if (fieldValue.type() == QVariant::Int || fieldValue.type() == QVariant::UInt) { @@ -359,6 +383,8 @@ void PdmUiListEditor::slotSelectionChanged(const QItemSelection & selected, cons this->setValueToField(valuesToSetInField); } + + m_isScrollToItemAllowed = true; } //-------------------------------------------------------------------------------------------------- @@ -499,4 +525,12 @@ bool PdmUiListEditor::eventFilter(QObject* object, QEvent * event) return false; } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool PdmUiListEditor::isMultiRowEditor() const +{ + return true; +} + } // end namespace caf diff --git a/Fwk/AppFwk/cafUserInterface/cafPdmUiListEditor.h b/Fwk/AppFwk/cafUserInterface/cafPdmUiListEditor.h index f80dd27473..d2177dfbc8 100644 --- a/Fwk/AppFwk/cafUserInterface/cafPdmUiListEditor.h +++ b/Fwk/AppFwk/cafUserInterface/cafPdmUiListEditor.h @@ -57,6 +57,7 @@ class PdmUiListEditorAttribute : public PdmUiEditorAttribute public: PdmUiListEditorAttribute() : m_heightHint(2000) + , m_allowHorizontalScrollBar(true) { QPalette myPalette; @@ -66,6 +67,7 @@ class PdmUiListEditorAttribute : public PdmUiEditorAttribute public: QColor m_baseColor; int m_heightHint; + bool m_allowHorizontalScrollBar; }; @@ -81,11 +83,14 @@ class PdmUiListEditor : public PdmUiFieldEditorHandle PdmUiListEditor(); ~PdmUiListEditor() override; + void scrollToSelectedItem() const; + protected: QWidget* createEditorWidget(QWidget * parent) override; QWidget* createLabelWidget(QWidget * parent) override; void configureAndUpdateUi(const QString& uiConfigName) override; bool eventFilter ( QObject * listView, QEvent * event ) override; // To catch delete key press in list view. + bool isMultiRowEditor() const override; protected slots: void slotSelectionChanged( const QItemSelection & selected, const QItemSelection & deselected ); @@ -99,11 +104,12 @@ protected slots: private: QPointer m_listView; - QPointer m_label; + QPointer m_label; QPointer m_model; - bool m_isEditOperationsAvailable; - int m_optionItemCount; + bool m_isEditOperationsAvailable; + int m_optionItemCount; + bool m_isScrollToItemAllowed; }; diff --git a/Fwk/AppFwk/cafUserInterface/cafPdmUiListViewEditor.cpp b/Fwk/AppFwk/cafUserInterface/cafPdmUiListViewEditor.cpp index f850ee4482..8d3af86ad3 100644 --- a/Fwk/AppFwk/cafUserInterface/cafPdmUiListViewEditor.cpp +++ b/Fwk/AppFwk/cafUserInterface/cafPdmUiListViewEditor.cpp @@ -200,8 +200,8 @@ void caf::UiListViewModelPdm::setPdmData(PdmObjectCollection* objectGroup, const } computeColumnCount(); - - reset(); + beginResetModel(); + endResetModel(); } diff --git a/Fwk/AppFwk/cafUserInterface/cafPdmUiListViewEditor.h b/Fwk/AppFwk/cafUserInterface/cafPdmUiListViewEditor.h index 50da5bdffa..5b0c0664f8 100644 --- a/Fwk/AppFwk/cafUserInterface/cafPdmUiListViewEditor.h +++ b/Fwk/AppFwk/cafUserInterface/cafPdmUiListViewEditor.h @@ -38,7 +38,7 @@ #pragma once #include "cafPdmUiFieldEditorHandle.h" -#include "cafPdmUiObjectEditorHandle.h" +#include "cafPdmUiWidgetObjectEditorHandle.h" #include #include @@ -103,7 +103,7 @@ class UiListViewModelPdm : public QAbstractTableModel //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -class PdmUiListViewEditor : public PdmUiObjectEditorHandle +class PdmUiListViewEditor : public PdmUiWidgetObjectEditorHandle { public: PdmUiListViewEditor(); diff --git a/Fwk/AppFwk/cafUserInterface/cafPdmUiPickableLineEditor.cpp b/Fwk/AppFwk/cafUserInterface/cafPdmUiPickableLineEditor.cpp new file mode 100644 index 0000000000..5078a5fca1 --- /dev/null +++ b/Fwk/AppFwk/cafUserInterface/cafPdmUiPickableLineEditor.cpp @@ -0,0 +1,91 @@ +//################################################################################################## +// +// Custom Visualization Core library +// Copyright (C) 2019- Ceetron Solutions AS +// +// This library may be used under the terms of either the GNU General Public License or +// the GNU Lesser General Public License as follows: +// +// GNU General Public License Usage +// This library 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 3 of the License, or +// (at your option) any later version. +// +// This library 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 at <> +// for more details. +// +// GNU Lesser General Public License Usage +// This library 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.1 of the License, or +// (at your option) any later version. +// +// This library 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 at <> +// for more details. +// +//################################################################################################## +#include "cafPdmUiPickableLineEditor.h" + +#include "cafPdmField.h" +#include "cafPdmObject.h" +#include "cafPdmUiDefaultObjectEditor.h" +#include "cafPdmUiFieldEditorHandle.h" +#include "cafPickEventHandler.h" + +using namespace caf; + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +caf::PdmUiPickableLineEditor::~PdmUiPickableLineEditor() +{ + if (m_attribute.pickEventHandler) + { + m_attribute.pickEventHandler->unregisterAsPickEventHandler(); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void caf::PdmUiPickableLineEditor::configureAndUpdateUi(const QString& uiConfigName) +{ + PdmUiLineEditor::configureAndUpdateUi(uiConfigName); + + caf::PdmUiObjectHandle* uiObject = uiObj(uiField()->fieldHandle()->ownerObject()); + if (uiObject) + { + uiObject->editorAttribute(uiField()->fieldHandle(), uiConfigName, &m_attribute); + } + + if (m_attribute.pickEventHandler) + { + if (m_attribute.enablePicking) + { + m_attribute.pickEventHandler->registerAsPickEventHandler(); + m_lineEdit->setStyleSheet("QLineEdit {" + "color: #000000;" + "background-color: #FFDCFF;}"); + } + else + { + m_attribute.pickEventHandler->unregisterAsPickEventHandler(); + m_lineEdit->setStyleSheet(""); + } + } + + m_lineEdit->setToolTip(uiField()->uiToolTip(uiConfigName)); +} + +// Define at this location to avoid duplicate symbol definitions in 'cafPdmUiDefaultObjectEditor.cpp' in a cotire build. The +// variables defined by the macro are prefixed by line numbers causing a crash if the macro is defined at the same line number. +CAF_PDM_UI_FIELD_EDITOR_SOURCE_INIT(PdmUiPickableLineEditor); diff --git a/Fwk/AppFwk/cafUserInterface/cafPdmUiPickableLineEditor.h b/Fwk/AppFwk/cafUserInterface/cafPdmUiPickableLineEditor.h new file mode 100644 index 0000000000..53c47f2d8f --- /dev/null +++ b/Fwk/AppFwk/cafUserInterface/cafPdmUiPickableLineEditor.h @@ -0,0 +1,80 @@ +//################################################################################################## +// +// Custom Visualization Core library +// Copyright (C) 2019- Ceetron Solutions AS +// +// This library may be used under the terms of either the GNU General Public License or +// the GNU Lesser General Public License as follows: +// +// GNU General Public License Usage +// This library 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 3 of the License, or +// (at your option) any later version. +// +// This library 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 at <> +// for more details. +// +// GNU Lesser General Public License Usage +// This library 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.1 of the License, or +// (at your option) any later version. +// +// This library 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 at <> +// for more details. +// +//################################################################################################## +#pragma once + +#include "cafPdmUiLineEditor.h" + +#include + +namespace caf +{ +class PickEventHandler; + +//================================================================================================== +/// +//================================================================================================== +class PdmUiPickableLineEditorAttribute : public PdmUiEditorAttribute +{ +public: + PdmUiPickableLineEditorAttribute() : enablePicking(false) {} + +public: + bool enablePicking; + std::shared_ptr pickEventHandler; +}; + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +class PdmUiPickableLineEditor : public PdmUiLineEditor +{ + Q_OBJECT + CAF_PDM_UI_FIELD_EDITOR_HEADER_INIT; + +public: + PdmUiPickableLineEditor() {} + ~PdmUiPickableLineEditor() override; + +protected: + void configureAndUpdateUi(const QString& uiConfigName) override; + +private: + PdmUiPickableLineEditorAttribute m_attribute; +}; + +} // end namespace caf + + diff --git a/Fwk/AppFwk/cafUserInterface/cafPdmUiPropertyView.cpp b/Fwk/AppFwk/cafUserInterface/cafPdmUiPropertyView.cpp index c8b61f693c..0461de05cc 100644 --- a/Fwk/AppFwk/cafUserInterface/cafPdmUiPropertyView.cpp +++ b/Fwk/AppFwk/cafUserInterface/cafPdmUiPropertyView.cpp @@ -34,7 +34,6 @@ // //################################################################################################## - #include "cafPdmUiPropertyView.h" #include "cafPdmObject.h" @@ -42,8 +41,10 @@ #include #include +#include #include #include +#include @@ -59,19 +60,26 @@ QVerticalScrollArea::QVerticalScrollArea(QWidget* parent) : } //-------------------------------------------------------------------------------------------------- -/// +/// //-------------------------------------------------------------------------------------------------- -bool QVerticalScrollArea::eventFilter(QObject* object, QEvent* event) +QSize QVerticalScrollArea::sizeHint() const { - // This works because QScrollArea::setWidget installs an eventFilter on the widget - if (object && object == widget() && event->type() == QEvent::Resize) - { - setMinimumWidth(widget()->minimumSizeHint().width() + verticalScrollBar()->width()); - } - - return QScrollArea::eventFilter(object, event); + QSize widgetSize = widget()->sizeHint(); + QSize scrollSize = QScrollArea::sizeHint(); + scrollSize.setWidth(widgetSize.width() + verticalScrollBar()->width()); + return scrollSize; } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QSize QVerticalScrollArea::minimumSizeHint() const +{ + QSize widgetSize = widget()->minimumSizeHint(); + QSize scrollSize = QScrollArea::minimumSizeHint(); + scrollSize.setWidth(widgetSize.width() + verticalScrollBar()->width()); + return scrollSize; +} namespace caf { @@ -83,12 +91,12 @@ namespace caf PdmUiPropertyView::PdmUiPropertyView(QWidget* parent, Qt::WindowFlags f) : QWidget (parent, f) { - QVerticalScrollArea* scrollArea = new QVerticalScrollArea(this); - scrollArea->setFrameStyle(QFrame::NoFrame); - scrollArea->setWidgetResizable(true); + m_scrollArea = new QVerticalScrollArea(this); + m_scrollArea->setFrameStyle(QFrame::NoFrame); + m_scrollArea->setWidgetResizable(true); m_placeholder = new QWidget(); - scrollArea->setWidget(m_placeholder); + m_scrollArea->setWidget(m_placeholder); m_placeHolderLayout = new QVBoxLayout(); m_placeHolderLayout->setContentsMargins(5,5,5,0); @@ -96,9 +104,9 @@ PdmUiPropertyView::PdmUiPropertyView(QWidget* parent, Qt::WindowFlags f) QVBoxLayout* dummy = new QVBoxLayout(this); dummy->setContentsMargins(0,0,0,0); - dummy->addWidget(scrollArea); + dummy->addWidget(m_scrollArea); - m_currentObjectView = nullptr; + m_defaultObjectEditor = nullptr; } //-------------------------------------------------------------------------------------------------- @@ -106,7 +114,7 @@ PdmUiPropertyView::PdmUiPropertyView(QWidget* parent, Qt::WindowFlags f) //-------------------------------------------------------------------------------------------------- PdmUiPropertyView::~PdmUiPropertyView() { - if (m_currentObjectView) delete m_currentObjectView; + if (m_defaultObjectEditor) delete m_defaultObjectEditor; } //-------------------------------------------------------------------------------------------------- @@ -119,11 +127,11 @@ void PdmUiPropertyView::setUiConfigurationName(QString uiConfigName) { m_uiConfigName = uiConfigName; - if (m_currentObjectView) + if (m_defaultObjectEditor) { - PdmObjectHandle* object = m_currentObjectView->pdmObject(); - delete m_currentObjectView; - m_currentObjectView = nullptr; + PdmObjectHandle* object = m_defaultObjectEditor->pdmObject(); + delete m_defaultObjectEditor; + m_defaultObjectEditor = nullptr; this->showProperties(object); } } @@ -140,13 +148,13 @@ void PdmUiPropertyView::showProperties( PdmObjectHandle* object) bool rebuildWidget = false; - if (!m_currentObjectView) rebuildWidget = true; + if (!m_defaultObjectEditor) rebuildWidget = true; - if (m_currentObjectView && m_currentObjectView->pdmObject()) + if (m_defaultObjectEditor && m_defaultObjectEditor->pdmObject()) { if (object) { - PdmUiObjectHandle* uiObject1 = uiObj(m_currentObjectView->pdmObject()); + PdmUiObjectHandle* uiObject1 = uiObj(m_defaultObjectEditor->pdmObject()); PdmUiObjectHandle* uiObject2 = uiObj(object); if (uiObject1 && uiObject2 && (uiObject1->uiEditorTypeName(m_uiConfigName) != uiObject2->uiEditorTypeName(m_uiConfigName))) @@ -159,21 +167,20 @@ void PdmUiPropertyView::showProperties( PdmObjectHandle* object) if (rebuildWidget) { // Remove Widget from layout - if (m_currentObjectView) + if (m_defaultObjectEditor) { - this->m_placeHolderLayout->removeWidget(m_currentObjectView->widget()); - delete m_currentObjectView; - m_currentObjectView = nullptr; + this->m_placeHolderLayout->removeWidget(m_defaultObjectEditor->widget()); + delete m_defaultObjectEditor; + m_defaultObjectEditor = nullptr; } - if (!m_currentObjectView) + if (!m_defaultObjectEditor) { - PdmUiDefaultObjectEditor* defaultEditor = new PdmUiDefaultObjectEditor(); - m_currentObjectView = defaultEditor; + m_defaultObjectEditor = new PdmUiDefaultObjectEditor(); } // Create widget to handle this - QWidget* propertyWidget = m_currentObjectView->getOrCreateWidget(m_placeholder); + QWidget* propertyWidget = m_defaultObjectEditor->getOrCreateWidget(m_placeholder); CAF_ASSERT(propertyWidget); @@ -183,8 +190,23 @@ void PdmUiPropertyView::showProperties( PdmObjectHandle* object) this->m_placeHolderLayout->insertStretch(-1, 1); } - m_currentObjectView->setPdmObject(object); - m_currentObjectView->updateUi(m_uiConfigName); + m_defaultObjectEditor->setPdmObject(object); + + QObject::connect(m_defaultObjectEditor, SIGNAL(uiUpdated()), this, SLOT(slotScheduleScrollToSelectedItemsInFieldEditors())); + + m_defaultObjectEditor->updateUi(m_uiConfigName); + m_scrollArea->updateGeometry(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void PdmUiPropertyView::slotScheduleScrollToSelectedItemsInFieldEditors() +{ + if (m_defaultObjectEditor) + { + QTimer::singleShot(150, m_defaultObjectEditor, SLOT(slotScrollToSelectedItemsInFieldEditors())); + } } //-------------------------------------------------------------------------------------------------- @@ -192,8 +214,8 @@ void PdmUiPropertyView::showProperties( PdmObjectHandle* object) //-------------------------------------------------------------------------------------------------- PdmObjectHandle* PdmUiPropertyView::currentObject() { - if (!m_currentObjectView) return nullptr; - return m_currentObjectView->pdmObject(); + if (!m_defaultObjectEditor) return nullptr; + return m_defaultObjectEditor->pdmObject(); } @@ -202,12 +224,17 @@ PdmObjectHandle* PdmUiPropertyView::currentObject() //-------------------------------------------------------------------------------------------------- QSize PdmUiPropertyView::sizeHint() const { - if (m_placeholder) - { - return m_placeholder->sizeHint(); - } + QSize scrollSize = m_scrollArea->sizeHint(); + QSize contentSize = m_placeholder->sizeHint(); + return QSize(scrollSize.width(), contentSize.height()); +} - return QWidget::sizeHint(); +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QSize PdmUiPropertyView::minimumSizeHint() const +{ + return m_scrollArea->minimumSizeHint(); } } //End of namespace caf diff --git a/Fwk/AppFwk/cafUserInterface/cafPdmUiPropertyView.h b/Fwk/AppFwk/cafUserInterface/cafPdmUiPropertyView.h index 6b79e932b4..a377eb9208 100644 --- a/Fwk/AppFwk/cafUserInterface/cafPdmUiPropertyView.h +++ b/Fwk/AppFwk/cafUserInterface/cafPdmUiPropertyView.h @@ -37,15 +37,15 @@ #pragma once +#include +#include #include #include -#include class QVBoxLayout; +class QTimer; -#include - //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -54,7 +54,9 @@ class QVerticalScrollArea : public QScrollArea Q_OBJECT public: explicit QVerticalScrollArea(QWidget* parent = nullptr); - bool eventFilter(QObject* object, QEvent* event) override; + + virtual QSize sizeHint() const override; + virtual QSize minimumSizeHint() const override; }; @@ -62,7 +64,7 @@ namespace caf { class PdmObjectHandle; -class PdmUiObjectEditorHandle; +class PdmUiDefaultObjectEditor; //================================================================================================== /// @@ -79,19 +81,19 @@ class PdmUiPropertyView : public QWidget PdmObjectHandle* currentObject(); QSize sizeHint() const override; + QSize minimumSizeHint() const override; public slots: void showProperties(caf::PdmObjectHandle* object); // Signal/Slot system needs caf:: prefix in some cases + void slotScheduleScrollToSelectedItemsInFieldEditors(); private: - PdmUiObjectEditorHandle* m_currentObjectView; - QString m_uiConfigName; - - QPointer m_placeHolderLayout; - QPointer m_placeholder; + PdmUiDefaultObjectEditor* m_defaultObjectEditor; + QString m_uiConfigName; + QPointer m_placeHolderLayout; + QPointer m_placeholder; + QPointer m_scrollArea; }; - - } // End of namespace caf diff --git a/Fwk/AppFwk/cafUserInterface/cafPdmUiPushButtonEditor.cpp b/Fwk/AppFwk/cafUserInterface/cafPdmUiPushButtonEditor.cpp index 4e3596ee2a..d525e7f170 100644 --- a/Fwk/AppFwk/cafUserInterface/cafPdmUiPushButtonEditor.cpp +++ b/Fwk/AppFwk/cafUserInterface/cafPdmUiPushButtonEditor.cpp @@ -45,6 +45,7 @@ #include "cafPdmField.h" #include "cafFactory.h" +#include "cafQShortenedLabel.h" #include @@ -157,7 +158,7 @@ QWidget* PdmUiPushButtonEditor::createEditorWidget(QWidget * parent) //-------------------------------------------------------------------------------------------------- QWidget* PdmUiPushButtonEditor::createLabelWidget(QWidget * parent) { - m_label = new QLabel(parent); + m_label = new QShortenedLabel(parent); return m_label; } diff --git a/Fwk/AppFwk/cafUserInterface/cafPdmUiPushButtonEditor.h b/Fwk/AppFwk/cafUserInterface/cafPdmUiPushButtonEditor.h index b4c73623a6..fe5ce301c5 100644 --- a/Fwk/AppFwk/cafUserInterface/cafPdmUiPushButtonEditor.h +++ b/Fwk/AppFwk/cafUserInterface/cafPdmUiPushButtonEditor.h @@ -80,9 +80,9 @@ protected slots: void slotClicked(bool checked); private: - QPointer m_pushButton; - QPointer m_label; - QPointer m_buttonLayout; + QPointer m_pushButton; + QPointer m_label; + QPointer m_buttonLayout; }; diff --git a/Fwk/AppFwk/cafUserInterface/cafPdmUiSliderEditor.cpp b/Fwk/AppFwk/cafUserInterface/cafPdmUiSliderEditor.cpp index 6ddeff9280..0215e60cba 100644 --- a/Fwk/AppFwk/cafUserInterface/cafPdmUiSliderEditor.cpp +++ b/Fwk/AppFwk/cafUserInterface/cafPdmUiSliderEditor.cpp @@ -43,6 +43,7 @@ #include "cafPdmField.h" #include "cafFactory.h" +#include "cafQShortenedLabel.h" #include #include @@ -125,7 +126,7 @@ QWidget* PdmUiSliderEditor::createEditorWidget(QWidget * parent) //-------------------------------------------------------------------------------------------------- QWidget* PdmUiSliderEditor::createLabelWidget(QWidget * parent) { - m_label = new QLabel(parent); + m_label = new QShortenedLabel(parent); return m_label; } diff --git a/Fwk/AppFwk/cafUserInterface/cafPdmUiSliderEditor.h b/Fwk/AppFwk/cafUserInterface/cafPdmUiSliderEditor.h index c10e35fc4a..c06d16a632 100644 --- a/Fwk/AppFwk/cafUserInterface/cafPdmUiSliderEditor.h +++ b/Fwk/AppFwk/cafUserInterface/cafPdmUiSliderEditor.h @@ -91,9 +91,9 @@ protected slots: void writeValueToField(); private: - QPointer m_spinBox; - QPointer m_slider; - QPointer m_label; + QPointer m_spinBox; + QPointer m_slider; + QPointer m_label; PdmUiSliderEditorAttribute m_attributes; }; diff --git a/Fwk/AppFwk/cafUserInterface/cafPdmUiTableViewDelegate.cpp b/Fwk/AppFwk/cafUserInterface/cafPdmUiTableViewDelegate.cpp index d9eb426441..2d7bb54f6f 100644 --- a/Fwk/AppFwk/cafUserInterface/cafPdmUiTableViewDelegate.cpp +++ b/Fwk/AppFwk/cafUserInterface/cafPdmUiTableViewDelegate.cpp @@ -117,7 +117,11 @@ bool PdmUiTableViewDelegate::isEditorOpen() const //-------------------------------------------------------------------------------------------------- void PdmUiTableViewDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { +#if QT_VERSION_MAJOR > 4 + QStyleOptionViewItem viewItemOption(option); +#else QStyleOptionViewItemV4 viewItemOption(option); +#endif QVariant fgText = index.data(Qt::ForegroundRole); diff --git a/Fwk/AppFwk/cafUserInterface/cafPdmUiTableViewEditor.cpp b/Fwk/AppFwk/cafUserInterface/cafPdmUiTableViewEditor.cpp index 6d651de5d3..3db96aa4ff 100644 --- a/Fwk/AppFwk/cafUserInterface/cafPdmUiTableViewEditor.cpp +++ b/Fwk/AppFwk/cafUserInterface/cafPdmUiTableViewEditor.cpp @@ -43,6 +43,7 @@ #include "cafPdmUiTableViewDelegate.h" #include "cafPdmUiTableViewQModel.h" #include "cafSelectionManager.h" +#include "cafQShortenedLabel.h" #include #include @@ -115,7 +116,7 @@ QWidget* PdmUiTableViewEditor::createLabelWidget(QWidget * parent) { if (m_tableHeading.isNull()) { - m_tableHeading = new QLabel(parent); + m_tableHeading = new QShortenedLabel(parent); } if (m_tableHeadingIcon.isNull()) @@ -231,7 +232,11 @@ void PdmUiTableViewEditor::configureAndUpdateUi(const QString& uiConfigName) } else if (editorAttrib.resizePolicy == PdmUiTableViewEditorAttribute::RESIZE_TO_FILL_CONTAINER) { +#if QT_VERSION >= 0x050000 + m_tableView->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch); +#else m_tableView->horizontalHeader()->setResizeMode(QHeaderView::Stretch); +#endif } } @@ -317,6 +322,13 @@ void PdmUiTableViewEditor::onSelectionManagerSelectionChanged( const std::set @@ -138,6 +137,7 @@ class PdmUiTableViewEditor : public PdmUiFieldEditorHandle, public SelectionChan void configureAndUpdateUi(const QString& uiConfigName) override; void onSelectionManagerSelectionChanged( const std::set& changedSelectionLevels ) override; + bool isMultiRowEditor() const override; private: void selectedUiItems(const QModelIndexList& modelIndexList, std::vector& objects); @@ -153,8 +153,8 @@ private slots: private: friend class FocusEventHandler; - QPointer m_tableHeading; - QPointer m_tableHeadingIcon; + QPointer m_tableHeading; + QPointer m_tableHeadingIcon; QTableView* m_tableView; PdmUiTableViewQModel* m_tableModelPdm; diff --git a/Fwk/AppFwk/cafUserInterface/cafPdmUiTableViewQModel.cpp b/Fwk/AppFwk/cafUserInterface/cafPdmUiTableViewQModel.cpp index c9d71cfaaf..a6162756c9 100644 --- a/Fwk/AppFwk/cafUserInterface/cafPdmUiTableViewQModel.cpp +++ b/Fwk/AppFwk/cafUserInterface/cafPdmUiTableViewQModel.cpp @@ -195,7 +195,7 @@ QVariant PdmUiTableViewQModel::data(const QModelIndex &index, int role /*= Qt::D } else { - return Qt::lightGray; + return QColor(Qt::lightGray); } } else if (textColor.isValid()) diff --git a/Fwk/AppFwk/cafUserInterface/cafPdmUiTextEditor.cpp b/Fwk/AppFwk/cafUserInterface/cafPdmUiTextEditor.cpp index 785bdb2837..8ffd487a4f 100644 --- a/Fwk/AppFwk/cafUserInterface/cafPdmUiTextEditor.cpp +++ b/Fwk/AppFwk/cafUserInterface/cafPdmUiTextEditor.cpp @@ -42,6 +42,7 @@ #include "cafPdmUiDefaultObjectEditor.h" #include "cafPdmUiFieldEditorHandle.h" #include "cafPdmUiOrdering.h" +#include "cafQShortenedLabel.h" #include #include @@ -155,6 +156,14 @@ void PdmUiTextEditor::configureAndUpdateUi(const QString& uiConfigName) } } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool PdmUiTextEditor::isMultiRowEditor() const +{ + return true; +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -187,7 +196,7 @@ QWidget* PdmUiTextEditor::createEditorWidget(QWidget * parent) //-------------------------------------------------------------------------------------------------- QWidget* PdmUiTextEditor::createLabelWidget(QWidget * parent) { - m_label = new QLabel(parent); + m_label = new QShortenedLabel(parent); return m_label; } diff --git a/Fwk/AppFwk/cafUserInterface/cafPdmUiTextEditor.h b/Fwk/AppFwk/cafUserInterface/cafPdmUiTextEditor.h index 5b0efa0279..e242758570 100644 --- a/Fwk/AppFwk/cafUserInterface/cafPdmUiTextEditor.h +++ b/Fwk/AppFwk/cafUserInterface/cafPdmUiTextEditor.h @@ -124,6 +124,7 @@ class PdmUiTextEditor : public PdmUiFieldEditorHandle QWidget* createEditorWidget(QWidget * parent) override; QWidget* createLabelWidget(QWidget * parent) override; void configureAndUpdateUi(const QString& uiConfigName) override; + bool isMultiRowEditor() const override; protected slots: void slotSetValueToField(); @@ -132,9 +133,9 @@ protected slots: QTextOption::WrapMode toQTextOptionWrapMode(PdmUiTextEditorAttribute::WrapMode wrapMode); private: - QPointer m_textEdit; - QPointer m_saveButton; - QPointer m_label; + QPointer m_textEdit; + QPointer m_saveButton; + QPointer m_label; PdmUiTextEditorAttribute::TextMode m_textMode; }; diff --git a/Fwk/AppFwk/cafUserInterface/cafPdmUiTreeSelectionEditor.cpp b/Fwk/AppFwk/cafUserInterface/cafPdmUiTreeSelectionEditor.cpp index 8cf00ac3aa..0dff488240 100644 --- a/Fwk/AppFwk/cafUserInterface/cafPdmUiTreeSelectionEditor.cpp +++ b/Fwk/AppFwk/cafUserInterface/cafPdmUiTreeSelectionEditor.cpp @@ -40,6 +40,7 @@ #include "cafPdmObject.h" #include "cafPdmUiCommandSystemProxy.h" #include "cafPdmUiTreeSelectionQModel.h" +#include "cafQShortenedLabel.h" #include #include @@ -93,7 +94,7 @@ class QTreeViewHeightHint : public QTreeView //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- - void keyPressEvent(QKeyEvent *event) + void keyPressEvent(QKeyEvent *event) override { QTreeView::keyPressEvent(event); @@ -164,7 +165,11 @@ class PlaceholderLineEdit : public QLineEdit QRect r = rect(); QPalette pal = palette(); +#if QT_VERSION_MAJOR > 4 + QStyleOptionFrame panel; +#else QStyleOptionFrameV2 panel; +#endif initStyleOption(&panel); style()->drawPrimitive(QStyle::PE_PanelLineEdit, &panel, &p, this); r = style()->subElementRect(QStyle::SE_LineEditContents, &panel, this); @@ -402,7 +407,7 @@ QWidget* PdmUiTreeSelectionEditor::createEditorWidget(QWidget* parent) //-------------------------------------------------------------------------------------------------- QWidget* PdmUiTreeSelectionEditor::createLabelWidget(QWidget * parent) { - m_label = new QLabel(parent); + m_label = new QShortenedLabel(parent); return m_label; } @@ -423,6 +428,14 @@ QMargins PdmUiTreeSelectionEditor::calculateLabelContentMargins() const return contentMargins; } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool PdmUiTreeSelectionEditor::isMultiRowEditor() const +{ + return true; +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -589,6 +602,16 @@ void PdmUiTreeSelectionEditor::slotTextFilterChanged() //-------------------------------------------------------------------------------------------------- void PdmUiTreeSelectionEditor::slotClicked(const QModelIndex& index) { + QModelIndex lastUncheckedIndex = m_model->indexForLastUncheckedItem(); + m_model->clearIndexForLastUncheckedItem(); + + QModelIndex proxyModelIndex = m_proxyModel->mapFromSource(lastUncheckedIndex); + if (proxyModelIndex == index) + { + // Early return to avoid changing the current item if an item was unchecked + return; + } + if (m_attributes.setCurrentIndexWhenItemIsChecked && index.isValid()) { QModelIndexList selectedIndexes = m_treeView->selectionModel()->selectedIndexes(); diff --git a/Fwk/AppFwk/cafUserInterface/cafPdmUiTreeSelectionEditor.h b/Fwk/AppFwk/cafUserInterface/cafPdmUiTreeSelectionEditor.h index 8d53f83ed6..97a5a883a2 100644 --- a/Fwk/AppFwk/cafUserInterface/cafPdmUiTreeSelectionEditor.h +++ b/Fwk/AppFwk/cafUserInterface/cafPdmUiTreeSelectionEditor.h @@ -99,6 +99,7 @@ class PdmUiTreeSelectionEditor : public PdmUiFieldEditorHandle QWidget* createEditorWidget(QWidget* parent) override; QWidget* createLabelWidget(QWidget* parent) override; QMargins calculateLabelContentMargins() const override; + bool isMultiRowEditor() const override; private slots: void customMenuRequested(const QPoint& pos); @@ -128,7 +129,7 @@ private slots: private: QPointer m_treeView; - QPointer m_label; + QPointer m_label; QPointer m_toggleAllCheckBox; QPointer m_textFilterLineEdit; diff --git a/Fwk/AppFwk/cafUserInterface/cafPdmUiTreeSelectionQModel.cpp b/Fwk/AppFwk/cafUserInterface/cafPdmUiTreeSelectionQModel.cpp index 6dc9496bb0..20ffa0fc81 100644 --- a/Fwk/AppFwk/cafUserInterface/cafPdmUiTreeSelectionQModel.cpp +++ b/Fwk/AppFwk/cafUserInterface/cafPdmUiTreeSelectionQModel.cpp @@ -51,13 +51,14 @@ //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -caf::PdmUiTreeSelectionQModel::PdmUiTreeSelectionQModel(QObject *parent /*= 0*/) - : QAbstractItemModel(parent), - m_uiValueCache(nullptr) +caf::PdmUiTreeSelectionQModel::PdmUiTreeSelectionQModel(QObject* parent /*= 0*/) + : QAbstractItemModel(parent) + , m_uiFieldHandle(nullptr) + , m_uiValueCache(nullptr) + , m_tree(nullptr) + , m_singleSelectionMode(false) + , m_indexForLastUncheckedItem(QModelIndex()) { - m_uiFieldHandle = nullptr; - m_tree = nullptr; - m_singleSelectionMode = false; } //-------------------------------------------------------------------------------------------------- @@ -476,6 +477,8 @@ bool caf::PdmUiTreeSelectionQModel::setData(const QModelIndex &index, const QVar } else { + m_indexForLastUncheckedItem = index; + selectedIndices.erase(std::remove(selectedIndices.begin(), selectedIndices.end(), opIndex), selectedIndices.end()); } @@ -494,6 +497,22 @@ bool caf::PdmUiTreeSelectionQModel::setData(const QModelIndex &index, const QVar return false; } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QModelIndex caf::PdmUiTreeSelectionQModel::indexForLastUncheckedItem() const +{ + return m_indexForLastUncheckedItem; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void caf::PdmUiTreeSelectionQModel::clearIndexForLastUncheckedItem() +{ + m_indexForLastUncheckedItem = QModelIndex(); +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- diff --git a/Fwk/AppFwk/cafUserInterface/cafPdmUiTreeSelectionQModel.h b/Fwk/AppFwk/cafUserInterface/cafPdmUiTreeSelectionQModel.h index c317288b75..dde7d18f3b 100644 --- a/Fwk/AppFwk/cafUserInterface/cafPdmUiTreeSelectionQModel.h +++ b/Fwk/AppFwk/cafUserInterface/cafPdmUiTreeSelectionQModel.h @@ -84,6 +84,9 @@ class PdmUiTreeSelectionQModel : public QAbstractItemModel QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override; + QModelIndex indexForLastUncheckedItem() const; + void clearIndexForLastUncheckedItem(); + // Consider moving these functions to PdmUiFieldHandle static bool isSingleValueField(const QVariant& fieldValue); static bool isMultipleValueField(const QVariant& fieldValue); @@ -107,6 +110,7 @@ class PdmUiTreeSelectionQModel : public QAbstractItemModel TreeItemType* m_tree; bool m_singleSelectionMode; + QModelIndex m_indexForLastUncheckedItem; }; diff --git a/Fwk/AppFwk/cafUserInterface/cafPdmUniqueIdValidator.cpp b/Fwk/AppFwk/cafUserInterface/cafPdmUniqueIdValidator.cpp new file mode 100644 index 0000000000..8844f1a345 --- /dev/null +++ b/Fwk/AppFwk/cafUserInterface/cafPdmUniqueIdValidator.cpp @@ -0,0 +1,132 @@ +//################################################################################################## +// +// Custom Visualization Core library +// Copyright (C) Ceetron Solutions AS +// +// This library may be used under the terms of either the GNU General Public License or +// the GNU Lesser General Public License as follows: +// +// GNU General Public License Usage +// This library 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 3 of the License, or +// (at your option) any later version. +// +// This library 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 at <> +// for more details. +// +// GNU Lesser General Public License Usage +// This library 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.1 of the License, or +// (at your option) any later version. +// +// This library 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 at <> +// for more details. +// +//################################################################################################## + +#include "cafPdmUniqueIdValidator.h" + +#include +#include +#include + +using namespace caf; + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +PdmUniqueIdValidator::PdmUniqueIdValidator(const std::set& usedIds, + bool multipleSelectionOfSameFieldsSelected, + const QString& errorMessage, + QObject* parent) + : QValidator(parent) + , m_usedIds(usedIds) + , m_nextValidValue(0) + , m_multipleSelectionOfSameFieldsSelected(multipleSelectionOfSameFieldsSelected) + , m_errorMessage(errorMessage) +{ + computeNextValidId(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QValidator::State PdmUniqueIdValidator::validate(QString& currentString, int&) const +{ + if (m_multipleSelectionOfSameFieldsSelected) + { + return QValidator::Invalid; + } + + if (currentString.isEmpty()) + { + return QValidator::Intermediate; + } + + bool isValidInteger = false; + int currentValue = currentString.toInt(&isValidInteger); + + if (!isValidInteger) + { + return QValidator::Invalid; + } + + if (currentValue < 0) + { + return QValidator::Invalid; + } + + if (m_usedIds.find(currentValue) != m_usedIds.end()) + { + foreach (QWidget* widget, QApplication::topLevelWidgets()) + { + if (widget->inherits("QMainWindow")) + { + QMainWindow* mainWindow = qobject_cast(widget); + if (mainWindow && mainWindow->statusBar()) + { + mainWindow->statusBar()->showMessage(m_errorMessage, 3000); + } + } + } + + return QValidator::Intermediate; + } + + return QValidator::Acceptable; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void PdmUniqueIdValidator::fixup(QString& editorText) const +{ + editorText = QString::number(m_nextValidValue); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +int PdmUniqueIdValidator::computeNextValidId() +{ + if (!m_usedIds.empty()) + { + m_nextValidValue = *m_usedIds.rbegin(); + } + else + { + m_nextValidValue = 1; + } + + return m_nextValidValue; +} diff --git a/Fwk/AppFwk/cafUserInterface/cafPdmUniqueIdValidator.h b/Fwk/AppFwk/cafUserInterface/cafPdmUniqueIdValidator.h new file mode 100644 index 0000000000..fca050771c --- /dev/null +++ b/Fwk/AppFwk/cafUserInterface/cafPdmUniqueIdValidator.h @@ -0,0 +1,63 @@ +//################################################################################################## +// +// Custom Visualization Core library +// Copyright (C) Ceetron Solutions AS +// +// This library may be used under the terms of either the GNU General Public License or +// the GNU Lesser General Public License as follows: +// +// GNU General Public License Usage +// This library 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 3 of the License, or +// (at your option) any later version. +// +// This library 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 at <> +// for more details. +// +// GNU Lesser General Public License Usage +// This library 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.1 of the License, or +// (at your option) any later version. +// +// This library 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 at <> +// for more details. +// +//################################################################################################## +#pragma once + +#include +#include + +namespace caf +{ +class PdmUniqueIdValidator : public QValidator +{ + Q_OBJECT +public: + PdmUniqueIdValidator(const std::set& usedIds, bool multipleSelectionOfSameFieldsSelected, const QString& errorMessage, QObject* parent); + + State validate(QString& currentString, int &) const override; + + void fixup(QString& editorText) const override; + +private: + int computeNextValidId(); + +private: + std::set m_usedIds; + + int m_nextValidValue; + bool m_multipleSelectionOfSameFieldsSelected; + QString m_errorMessage; +}; +} diff --git a/Fwk/AppFwk/cafUserInterface/cafPickEventHandler.h b/Fwk/AppFwk/cafUserInterface/cafPickEventHandler.h new file mode 100644 index 0000000000..0e64ca667f --- /dev/null +++ b/Fwk/AppFwk/cafUserInterface/cafPickEventHandler.h @@ -0,0 +1,67 @@ +//################################################################################################## +// +// Custom Visualization Core library +// Copyright (C) 2019- Ceetron Solution AS +// +// This library may be used under the terms of either the GNU General Public License or +// the GNU Lesser General Public License as follows: +// +// GNU General Public License Usage +// This library 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 3 of the License, or +// (at your option) any later version. +// +// This library 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 at <> +// for more details. +// +// GNU Lesser General Public License Usage +// This library 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.1 of the License, or +// (at your option) any later version. +// +// This library 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 at <> +// for more details. +// +//################################################################################################## + +#pragma once + +#include "cafPdmObjectHandle.h" + +namespace caf +{ + +//================================================================================================== +/// Interface for Pick Events +//================================================================================================== +class PickEvent +{ +public: + virtual ~PickEvent() {} +}; + +//================================================================================================== +/// Interface for Pick handlers +//================================================================================================== +class PickEventHandler +{ +public: + virtual void registerAsPickEventHandler() = 0; + virtual void unregisterAsPickEventHandler() = 0; + // TODO: Rename to just handlePickEvent when the RicPickEventHandler::handlePickEvent has been renamed + virtual bool handlePickEvent(const PickEvent& eventObject) = 0; + virtual void notifyUnregistered() = 0; + +}; +} + diff --git a/Fwk/AppFwk/cafUserInterface/cafProgressInfo.cpp b/Fwk/AppFwk/cafUserInterface/cafProgressInfo.cpp index 8cd8a121dd..c232719a52 100644 --- a/Fwk/AppFwk/cafUserInterface/cafProgressInfo.cpp +++ b/Fwk/AppFwk/cafUserInterface/cafProgressInfo.cpp @@ -50,6 +50,18 @@ namespace caf { + //-------------------------------------------------------------------------------------------------- + /// + //-------------------------------------------------------------------------------------------------- + ProgressTask::ProgressTask(ProgressInfo& parentTask) + : m_parentTask(parentTask) + { + } + ProgressTask::~ProgressTask() + { + m_parentTask.incrementProgress(); + } + //================================================================================================== /// /// \class caf::ProgressInfo @@ -99,9 +111,9 @@ namespace caf { /// If you do not need a title for a particular level, simply pass "" and it will be ignored. /// \sa setProgressDescription //-------------------------------------------------------------------------------------------------- - ProgressInfo::ProgressInfo(size_t maxProgressValue, const QString& title) + ProgressInfo::ProgressInfo(size_t maxProgressValue, const QString& title, bool delayShowingProgress) { - ProgressInfoStatic::start(maxProgressValue, title); + ProgressInfoStatic::start(maxProgressValue, title, delayShowingProgress); if (qApp) { @@ -152,16 +164,6 @@ namespace caf { ProgressInfoStatic::incrementProgress(); } - //-------------------------------------------------------------------------------------------------- - /// Convenience method for incrementing progress and setting step size and description for next step - //-------------------------------------------------------------------------------------------------- - void ProgressInfo::incrementProgressAndUpdateNextStep(size_t nextStepSize, const QString& nextDescription) - { - incrementProgress(); - setNextProgressIncrement(nextStepSize); - setProgressDescription(nextDescription); - } - //-------------------------------------------------------------------------------------------------- /// To make a certain operation span more of the progress bar than one tick, /// set the number of progress ticks that you want it to use before calling it. @@ -176,15 +178,18 @@ namespace caf { //-------------------------------------------------------------------------------------------------- void ProgressInfo::setNextProgressIncrement(size_t nextStepSize) { - ProgressInfoStatic::setNextProgressIncrement(nextStepSize); + ProgressInfoStatic::setNextProgressIncrement(nextStepSize); } - - - - - - + //-------------------------------------------------------------------------------------------------- + /// + //-------------------------------------------------------------------------------------------------- + caf::ProgressTask ProgressInfo::task(const QString& description, int stepSize) + { + setProgressDescription(description); + setNextProgressIncrement(stepSize); + return caf::ProgressTask(*this); + } //================================================================================================== /// @@ -343,18 +348,6 @@ namespace caf { } - //-------------------------------------------------------------------------------------------------- - /// - //-------------------------------------------------------------------------------------------------- - static bool isUpdatePossible() - { - if (!qApp) return false; - - if (!progressDialog()) return false; - - return progressDialog()->thread() == QThread::currentThread(); - } - //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -369,6 +362,10 @@ namespace caf { #ifdef _MSC_VER #pragma warning (push) #pragma warning (disable: 4668) + // Define this one to tell windows.h to not define min() and max() as macros + #if defined WIN32 && !defined NOMINMAX + #define NOMINMAX + #endif #include #pragma warning (pop) #endif @@ -431,6 +428,23 @@ namespace caf { } } + //================================================================================================== + /// + /// \class caf::ProgressInfoBlocker + /// + /// Used to disable progress info on a temporary basis + /// + //================================================================================================== + + ProgressInfoBlocker::ProgressInfoBlocker() + { + ProgressInfoStatic::s_disabled = true; + } + + ProgressInfoBlocker::~ProgressInfoBlocker() + { + ProgressInfoStatic::s_disabled = false; + } //================================================================================================== /// @@ -440,11 +454,12 @@ namespace caf { /// //================================================================================================== + bool ProgressInfoStatic::s_disabled = false; //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- - void ProgressInfoStatic::start(size_t maxProgressValue, const QString& title) + void ProgressInfoStatic::start(size_t maxProgressValue, const QString& title, bool delayShowingProgress) { if (!isUpdatePossible()) return; @@ -458,7 +473,14 @@ namespace caf { progressDialog()->setMinimum(0); progressDialog()->setWindowTitle(title); progressDialog()->setCancelButton(nullptr); - progressDialog()->show(); + if (delayShowingProgress) + { + progressDialog()->setMinimumDuration(1000); + } + else + { + progressDialog()->show(); + } } maxProgressStack_v.push_back(maxProgressValue); @@ -475,7 +497,6 @@ namespace caf { //if (progressDialog()) progressDialog()->repaint(); } - //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -621,5 +642,18 @@ namespace caf { } } + //-------------------------------------------------------------------------------------------------- + /// + //-------------------------------------------------------------------------------------------------- + bool ProgressInfoStatic::isUpdatePossible() + { + if (s_disabled) return false; + + if (!qApp) return false; + + if (!progressDialog()) return false; + + return progressDialog()->thread() == QThread::currentThread(); + } } // namespace caf diff --git a/Fwk/AppFwk/cafUserInterface/cafProgressInfo.h b/Fwk/AppFwk/cafUserInterface/cafProgressInfo.h index fd58b0131c..135df74094 100644 --- a/Fwk/AppFwk/cafUserInterface/cafProgressInfo.h +++ b/Fwk/AppFwk/cafUserInterface/cafProgressInfo.h @@ -43,25 +43,43 @@ class QString; namespace caf { +class ProgressInfo; + +class ProgressTask +{ +public: + ProgressTask(ProgressInfo& parentTask); + ~ProgressTask(); +private: + ProgressInfo& m_parentTask; +}; + class ProgressInfo { public: - ProgressInfo(size_t maxProgressValue, const QString& title); + ProgressInfo(size_t maxProgressValue, const QString& title, bool delayShowingProgress = false); ~ProgressInfo(); void setProgressDescription(const QString& description); void setProgress(size_t progressValue); void incrementProgress(); - void incrementProgressAndUpdateNextStep(size_t nextStepSize, const QString& nextDescription); void setNextProgressIncrement(size_t nextStepSize); + ProgressTask task(const QString& description, int stepSize = 1); + }; +class ProgressInfoBlocker +{ +public: + ProgressInfoBlocker(); + ~ProgressInfoBlocker(); +}; class ProgressInfoStatic { public: - static void start(size_t maxProgressValue, const QString& title); + static void start(size_t maxProgressValue, const QString& title, bool delayShowingProgress); static void setProgressDescription(const QString& description); static void setProgress(size_t progressValue); @@ -69,6 +87,13 @@ class ProgressInfoStatic static void setNextProgressIncrement(size_t nextStepSize); static void finished(); + +private: + static bool isUpdatePossible(); +private: + friend class ProgressInfoBlocker; + + static bool s_disabled; }; } diff --git a/Fwk/AppFwk/cafUserInterface/cafQStyledProgressBar.cpp b/Fwk/AppFwk/cafUserInterface/cafQStyledProgressBar.cpp new file mode 100644 index 0000000000..03e63cd2d4 --- /dev/null +++ b/Fwk/AppFwk/cafUserInterface/cafQStyledProgressBar.cpp @@ -0,0 +1,77 @@ +//################################################################################################## +// +// Custom Visualization Core library +// Copyright (C) 2019- Ceetron Solutions AS +// +// This library may be used under the terms of either the GNU General Public License or +// the GNU Lesser General Public License as follows: +// +// GNU General Public License Usage +// This library 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 3 of the License, or +// (at your option) any later version. +// +// This library 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 at <> +// for more details. +// +// GNU Lesser General Public License Usage +// This library 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.1 of the License, or +// (at your option) any later version. +// +// This library 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 at <> +// for more details. +// +//################################################################################################## +#include "cafQStyledProgressBar.h" + +#include "cafStyleSheetTools.h" + +using namespace caf; + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QStyledProgressBar::QStyledProgressBar(QString objectName, QWidget* parent /*= nullptr*/) + : QProgressBar(parent) +{ + setObjectName(objectName); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void QStyledProgressBar::setTextBackgroundAndProgressColor(QColor textColor, QColor backgroundColor, QColor backgroundFrameColor, QColor progressColor) +{ + QString styleSheetTemplate = + "QProgressBar#%1::chunk" + "{" + "background-color: %2;" + "}"; + QString progressColString = colorStringWithAlpha(progressColor); + + QString fullStyleSheet = + StyleSheetTools::createFrameStyleSheet("QProgressBar", objectName(), textColor, backgroundColor, backgroundFrameColor); + fullStyleSheet += styleSheetTemplate.arg(objectName()).arg(progressColString); + + setStyleSheet(fullStyleSheet); + setAttribute(Qt::WA_TranslucentBackground); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString QStyledProgressBar::colorStringWithAlpha(QColor color) +{ + return QString("rgba(%1, %2, %3, %4)").arg(color.red()).arg(color.green()).arg(color.blue()).arg(color.alpha()); +} diff --git a/Fwk/AppFwk/cafUserInterface/cafQStyledProgressBar.h b/Fwk/AppFwk/cafUserInterface/cafQStyledProgressBar.h new file mode 100644 index 0000000000..a64b417d5d --- /dev/null +++ b/Fwk/AppFwk/cafUserInterface/cafQStyledProgressBar.h @@ -0,0 +1,54 @@ +//################################################################################################## +// +// Custom Visualization Core library +// Copyright (C) 2019- Ceetron Solutions AS +// +// This library may be used under the terms of either the GNU General Public License or +// the GNU Lesser General Public License as follows: +// +// GNU General Public License Usage +// This library 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 3 of the License, or +// (at your option) any later version. +// +// This library 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 at <> +// for more details. +// +// GNU Lesser General Public License Usage +// This library 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.1 of the License, or +// (at your option) any later version. +// +// This library 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 at <> +// for more details. +// +//################################################################################################## +#pragma once + +#include + +namespace caf +{ +class QStyledProgressBar : public QProgressBar +{ + Q_OBJECT + +public: + QStyledProgressBar(QString objectName, QWidget* parent = nullptr); + + void setTextBackgroundAndProgressColor(QColor textColor, QColor backgroundColor, QColor backgroundFrameColor, QColor progressColor); + +private: + static QString colorStringWithAlpha(QColor color); +}; +} \ No newline at end of file diff --git a/Fwk/AppFwk/cafUserInterface/cafStyleSheetTools.cpp b/Fwk/AppFwk/cafUserInterface/cafStyleSheetTools.cpp new file mode 100644 index 0000000000..15ef2a8ceb --- /dev/null +++ b/Fwk/AppFwk/cafUserInterface/cafStyleSheetTools.cpp @@ -0,0 +1,72 @@ +//################################################################################################## +// +// Custom Visualization Core library +// Copyright (C) 2019- Ceetron Solutions AS +// +// This library may be used under the terms of either the GNU General Public License or +// the GNU Lesser General Public License as follows: +// +// GNU General Public License Usage +// This library 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 3 of the License, or +// (at your option) any later version. +// +// This library 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 at <> +// for more details. +// +// GNU Lesser General Public License Usage +// This library 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.1 of the License, or +// (at your option) any later version. +// +// This library 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 at <> +// for more details. +// +//################################################################################################## +#include "cafStyleSheetTools.h" + +#include + +using namespace caf; + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString StyleSheetTools::createFrameStyleSheet(const QString& classType, + const QString& objectName, + const QColor& textColor, + const QColor& backgroundColor, + const QColor& backgroundFrameColor) +{ + QString styleSheetTemplate = "%1#%2" + "{" + "color: %3;" + "background-color: %4;" + "border: 1px solid %5;" + "}"; + QString textColString = colorStringWithAlpha(textColor); + QString bgColString = colorStringWithAlpha(backgroundColor); + QString bgFrameColString = colorStringWithAlpha(backgroundFrameColor); + + QString fullStyleSheet = + styleSheetTemplate.arg(classType).arg(objectName).arg(textColString).arg(bgColString).arg(bgFrameColString); + return fullStyleSheet; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString StyleSheetTools::colorStringWithAlpha(const QColor& color) +{ + return QString("rgba(%1, %2, %3, %4)").arg(color.red()).arg(color.green()).arg(color.blue()).arg(color.alpha()); +} diff --git a/Fwk/AppFwk/cafUserInterface/cafStyleSheetTools.h b/Fwk/AppFwk/cafUserInterface/cafStyleSheetTools.h new file mode 100644 index 0000000000..41eb8bbb59 --- /dev/null +++ b/Fwk/AppFwk/cafUserInterface/cafStyleSheetTools.h @@ -0,0 +1,56 @@ +//################################################################################################## +// +// Custom Visualization Core library +// Copyright (C) 2019- Ceetron Solutions AS +// +// This library may be used under the terms of either the GNU General Public License or +// the GNU Lesser General Public License as follows: +// +// GNU General Public License Usage +// This library 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 3 of the License, or +// (at your option) any later version. +// +// This library 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 at <> +// for more details. +// +// GNU Lesser General Public License Usage +// This library 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.1 of the License, or +// (at your option) any later version. +// +// This library 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 at <> +// for more details. +// +//################################################################################################## +#pragma once + +#include + +class QColor; + +namespace caf +{ +class StyleSheetTools +{ +public: + static QString createFrameStyleSheet(const QString& classType, + const QString& objectName, + const QColor& textColor, + const QColor& backgroundColor, + const QColor& backgroundFrameColor); + static QString colorStringWithAlpha(const QColor& color); +}; + +} + diff --git a/Fwk/AppFwk/cafUserInterface/cafUserInterface_UnitTests/CMakeLists.txt b/Fwk/AppFwk/cafUserInterface/cafUserInterface_UnitTests/CMakeLists.txt index 7c717e4e31..214fc545bc 100644 --- a/Fwk/AppFwk/cafUserInterface/cafUserInterface_UnitTests/CMakeLists.txt +++ b/Fwk/AppFwk/cafUserInterface/cafUserInterface_UnitTests/CMakeLists.txt @@ -1,7 +1,12 @@ cmake_minimum_required (VERSION 2.8.12) -find_package ( Qt4 COMPONENTS QtCore QtGui QtMain ) -include (${QT_USE_FILE}) +find_package(Qt5 CONFIG COMPONENTS Core) +if (Qt5Core_FOUND) + find_package(Qt5 CONFIG REQUIRED Core Gui Widgets) +else() + find_package(Qt4 COMPONENTS QtCore QtGui QtMain REQUIRED) + include(${QT_USE_FILE}) +endif(Qt5Core_FOUND) project ( cafUserInterface_UnitTests ) @@ -27,7 +32,9 @@ add_executable (${PROJECT_NAME} source_group("" FILES ${PROJECT_FILES}) -message(STATUS ${PROJECT_NAME}" - Qt includes : " ${QT_LIBRARIES}) +if (Qt5Core_FOUND) + set(QT_LIBRARIES Qt5::Core Qt5::Gui Qt5::Widgets) +endif() target_link_libraries ( ${PROJECT_NAME} cafUserInterface @@ -36,15 +43,24 @@ target_link_libraries ( ${PROJECT_NAME} ) # Copy Qt Dlls -if (MSVC) - set (QTLIBLIST QtCore QtGui) - foreach (qtlib ${QTLIBLIST}) - - # Debug - execute_process(COMMAND cmake -E copy_if_different ${QT_BINARY_DIR}/${qtlib}d4.dll ${CMAKE_CURRENT_BINARY_DIR}/Debug/${qtlib}d4.dll) - - # Release - execute_process(COMMAND cmake -E copy_if_different ${QT_BINARY_DIR}/${qtlib}4.dll ${CMAKE_CURRENT_BINARY_DIR}/Release/${qtlib}4.dll) - endforeach( qtlib ) -endif(MSVC) - +if (Qt5Core_FOUND) + foreach (qtlib ${QT_LIBRARIES}) + add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_if_different $ $ + ) + endforeach(qtlib) + # Copy Qt Dlls +else() + # Copy Qt Dlls + if (MSVC) + set (QTLIBLIST QtCore QtGui QtOpenGl ) + foreach (qtlib ${QTLIBLIST}) + + # Debug + execute_process(COMMAND cmake -E copy_if_different ${QT_BINARY_DIR}/${qtlib}d4.dll ${CMAKE_BINARY_DIR}/Debug/${qtlib}d4.dll) + + # Release + execute_process(COMMAND cmake -E copy_if_different ${QT_BINARY_DIR}/${qtlib}4.dll ${CMAKE_BINARY_DIR}/Release/${qtlib}4.dll) + endforeach( qtlib ) + endif(MSVC) +endif(Qt5Core_FOUND) diff --git a/Fwk/AppFwk/cafUserInterface/cafUserInterface_UnitTests/cafPdmUiTreeSelectionQModelTest.cpp b/Fwk/AppFwk/cafUserInterface/cafUserInterface_UnitTests/cafPdmUiTreeSelectionQModelTest.cpp index 6dbf4f02b3..79a548508d 100644 --- a/Fwk/AppFwk/cafUserInterface/cafUserInterface_UnitTests/cafPdmUiTreeSelectionQModelTest.cpp +++ b/Fwk/AppFwk/cafUserInterface/cafUserInterface_UnitTests/cafPdmUiTreeSelectionQModelTest.cpp @@ -85,13 +85,13 @@ TEST(PdmUiTreeSelectionQModelTest, ParentBehaviour) { QModelIndex firstChildIndex = myModel.index(0, 0, parentIndex); - EXPECT_STREQ("Second_a", myModel.data(firstChildIndex).toString().toAscii()); + EXPECT_STREQ("Second_a", myModel.data(firstChildIndex).toString().toLatin1()); EXPECT_TRUE(parentIndex == myModel.parent(firstChildIndex)); } { QModelIndex secondChildIndex = myModel.index(1, 0, parentIndex); - EXPECT_STREQ("Second_b", myModel.data(secondChildIndex).toString().toAscii()); + EXPECT_STREQ("Second_b", myModel.data(secondChildIndex).toString().toLatin1()); EXPECT_TRUE(parentIndex == myModel.parent(secondChildIndex)); } } diff --git a/Fwk/AppFwk/cafViewer/CMakeLists.txt b/Fwk/AppFwk/cafViewer/CMakeLists.txt index 2d0661008c..d08144d34e 100644 --- a/Fwk/AppFwk/cafViewer/CMakeLists.txt +++ b/Fwk/AppFwk/cafViewer/CMakeLists.txt @@ -3,16 +3,24 @@ cmake_minimum_required (VERSION 2.8.12) project (cafViewer) # Qt -find_package ( Qt4 COMPONENTS QtCore QtGui QtMain ) -include (${QT_USE_FILE}) +if (CAF_USE_QT5) + find_package(Qt5 COMPONENTS Core Gui OpenGL Widgets REQUIRED) +else() + find_package(Qt4 COMPONENTS QtCore QtGui QtMain QtOpenGl REQUIRED) + include(${QT_USE_FILE}) +endif(CAF_USE_QT5) # These headers need to go through Qt's MOC compiler -set( QOBJECT_HEADERS +set( MOC_HEADER_FILES cafViewer.h ) if ( NOT CMAKE_AUTOMOC ) - qt4_wrap_cpp( MOC_FILES_CPP ${QOBJECT_HEADERS} ) + if (CAF_USE_QT5) + qt5_wrap_cpp(MOC_SOURCE_FILES ${MOC_HEADER_FILES} ) + else() + qt4_wrap_cpp(MOC_SOURCE_FILES ${MOC_HEADER_FILES} ) + endif(CAF_USE_QT5) endif() @@ -32,7 +40,7 @@ add_library( ${PROJECT_NAME} cafViewer.cpp cafViewer.h - ${MOC_FILES_CPP} + ${MOC_SOURCE_FILES} ) target_include_directories(${PROJECT_NAME} @@ -40,6 +48,10 @@ target_include_directories(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR} ) +if (CAF_USE_QT5) + set(QT_LIBRARIES Qt5::Core Qt5::Gui Qt5::OpenGL Qt5::Widgets) +endif(CAF_USE_QT5) + target_link_libraries ( ${PROJECT_NAME} LibCore LibGeometry @@ -57,3 +69,11 @@ if (MSVC) endif() source_group("" FILES ${PROJECT_FILES}) + +# cotire +if (COMMAND caf_apply_cotire) + list(APPEND CAF_COTIRE_EXCLUDE_FILES + cafOpenGLWidget.cpp + ) + caf_apply_cotire("${PROJECT_NAME}") +endif() diff --git a/Fwk/AppFwk/cafViewer/cafCadNavigation.cpp b/Fwk/AppFwk/cafViewer/cafCadNavigation.cpp index a8340535bc..13b4c39e02 100644 --- a/Fwk/AppFwk/cafViewer/cafCadNavigation.cpp +++ b/Fwk/AppFwk/cafViewer/cafCadNavigation.cpp @@ -104,6 +104,7 @@ bool caf::CadNavigation::handleInputEvent(QInputEvent* inputEvent) m_hasMovedMouseDuringNavigation = false; isEventHandled = true; } + forcePointOfInterestUpdateDuringNextWheelZoom(); } break; case QEvent::MouseButtonRelease: @@ -121,6 +122,7 @@ bool caf::CadNavigation::handleInputEvent(QInputEvent* inputEvent) } } + forcePointOfInterestUpdateDuringNextWheelZoom(); } break; case QEvent::MouseMove: @@ -151,11 +153,12 @@ bool caf::CadNavigation::handleInputEvent(QInputEvent* inputEvent) { if (inputEvent->modifiers() == Qt::NoModifier) { - initializeRotationCenter(); + QWheelEvent* we = static_cast(inputEvent); + + updatePointOfInterestDuringZoomIfNecessary(we->x(), we->y()); + if (m_isRotCenterInitialized) { - QWheelEvent* we = static_cast ( inputEvent); - int translatedMousePosX, translatedMousePosY; cvfEventPos(we->x(), we->y(), &translatedMousePosX, &translatedMousePosY); diff --git a/Fwk/AppFwk/cafViewer/cafCadNavigation.h b/Fwk/AppFwk/cafViewer/cafCadNavigation.h index 6855190f18..b4a4330967 100644 --- a/Fwk/AppFwk/cafViewer/cafCadNavigation.h +++ b/Fwk/AppFwk/cafViewer/cafCadNavigation.h @@ -46,9 +46,9 @@ class CadNavigation : public TrackBallBasedNavigation { public: CadNavigation(); - virtual ~CadNavigation(); + ~CadNavigation() override; protected: - virtual bool handleInputEvent(QInputEvent* inputEvent); + bool handleInputEvent(QInputEvent* inputEvent) override; }; } // End namespace caf diff --git a/Fwk/AppFwk/cafViewer/cafCeetronNavigation.h b/Fwk/AppFwk/cafViewer/cafCeetronNavigation.h index 2eca8e0e20..bc3add0da2 100644 --- a/Fwk/AppFwk/cafViewer/cafCeetronNavigation.h +++ b/Fwk/AppFwk/cafViewer/cafCeetronNavigation.h @@ -50,14 +50,14 @@ class CeetronNavigation : public NavigationPolicy { public: CeetronNavigation(); - virtual ~CeetronNavigation(); + ~CeetronNavigation() override; protected: // General navigation policy reimplememtation - virtual void init(); - virtual bool handleInputEvent(QInputEvent* inputEvent); - virtual void setView( const cvf::Vec3d& alongDirection, const cvf::Vec3d& upDirection ); - virtual cvf::Vec3d pointOfInterest(); - virtual void setPointOfInterest(cvf::Vec3d poi); + void init() override; + bool handleInputEvent(QInputEvent* inputEvent) override; + void setView( const cvf::Vec3d& alongDirection, const cvf::Vec3d& upDirection ) override; + cvf::Vec3d pointOfInterest() override; + void setPointOfInterest(cvf::Vec3d poi) override; // Ceetron navigation stuff void mouseMoveEvent(QMouseEvent* event); diff --git a/Fwk/AppFwk/cafViewer/cafCeetronPlusNavigation.cpp b/Fwk/AppFwk/cafViewer/cafCeetronPlusNavigation.cpp index 0a7f233ae6..a5b205f421 100644 --- a/Fwk/AppFwk/cafViewer/cafCeetronPlusNavigation.cpp +++ b/Fwk/AppFwk/cafViewer/cafCeetronPlusNavigation.cpp @@ -42,6 +42,7 @@ #include "cvfRay.h" #include "cvfManipulatorTrackball.h" +#include #include #include "cvfTrace.h" @@ -68,6 +69,7 @@ bool caf::CeetronPlusNavigation::handleInputEvent(QInputEvent* inputEvent) { if (! inputEvent) return false; bool isEventHandled = false; + switch (inputEvent->type()) { case QEvent::MouseButtonPress: @@ -123,6 +125,7 @@ bool caf::CeetronPlusNavigation::handleInputEvent(QInputEvent* inputEvent) m_isZooming = true; } } + forcePointOfInterestUpdateDuringNextWheelZoom(); } break; case QEvent::MouseButtonRelease: @@ -147,6 +150,7 @@ bool caf::CeetronPlusNavigation::handleInputEvent(QInputEvent* inputEvent) m_hasMovedMouseDuringNavigation = false; } } + forcePointOfInterestUpdateDuringNextWheelZoom(); } break; case QEvent::MouseMove: @@ -186,11 +190,12 @@ bool caf::CeetronPlusNavigation::handleInputEvent(QInputEvent* inputEvent) { if (inputEvent->modifiers() == Qt::NoModifier) { - initializeRotationCenter(); + QWheelEvent* we = static_cast(inputEvent); + + updatePointOfInterestDuringZoomIfNecessary(we->x(), we->y()); + if (m_isRotCenterInitialized) { - QWheelEvent* we = static_cast ( inputEvent); - int translatedMousePosX, translatedMousePosY; cvfEventPos(we->x(), we->y(), &translatedMousePosX, &translatedMousePosY); diff --git a/Fwk/AppFwk/cafViewer/cafCeetronPlusNavigation.h b/Fwk/AppFwk/cafViewer/cafCeetronPlusNavigation.h index 9e44dd6fd7..d3a6070c89 100644 --- a/Fwk/AppFwk/cafViewer/cafCeetronPlusNavigation.h +++ b/Fwk/AppFwk/cafViewer/cafCeetronPlusNavigation.h @@ -44,9 +44,9 @@ class CeetronPlusNavigation : public TrackBallBasedNavigation { public: CeetronPlusNavigation(); - virtual ~CeetronPlusNavigation(); + ~CeetronPlusNavigation() override; protected: - virtual bool handleInputEvent(QInputEvent* inputEvent); + bool handleInputEvent(QInputEvent* inputEvent) override; }; } // End namespace caf diff --git a/Fwk/AppFwk/cafViewer/cafNavigationPolicy.h b/Fwk/AppFwk/cafViewer/cafNavigationPolicy.h index 1b58c32119..b183e64158 100644 --- a/Fwk/AppFwk/cafViewer/cafNavigationPolicy.h +++ b/Fwk/AppFwk/cafViewer/cafNavigationPolicy.h @@ -57,7 +57,7 @@ class NavigationPolicy : public cvf::Object { public: NavigationPolicy(); - virtual ~NavigationPolicy(); + ~NavigationPolicy() override; friend class Viewer; public: // protected: // Should be protected but this friending does not work on gcc 4.1.2 diff --git a/Fwk/AppFwk/cafViewer/cafTrackBallBasedNavigation.cpp b/Fwk/AppFwk/cafViewer/cafTrackBallBasedNavigation.cpp index e71b46b904..b1fc7a0db0 100644 --- a/Fwk/AppFwk/cafViewer/cafTrackBallBasedNavigation.cpp +++ b/Fwk/AppFwk/cafViewer/cafTrackBallBasedNavigation.cpp @@ -45,6 +45,7 @@ #include "cvfRay.h" #include "cvfManipulatorTrackball.h" +#include #include #include @@ -59,6 +60,8 @@ caf::TrackBallBasedNavigation::TrackBallBasedNavigation() : m_isZooming(false), m_lastPosX(0), m_lastPosY(0), + m_lastWheelZoomPosX(-1), + m_lastWheelZoomPosY(-1), m_consumeEvents(false) { @@ -86,6 +89,8 @@ void caf::TrackBallBasedNavigation::init() m_isZooming = false; m_lastPosX = 0; m_lastPosY = 0; + m_lastWheelZoomPosX = -1; + m_lastWheelZoomPosY = -1; } //-------------------------------------------------------------------------------------------------- @@ -149,7 +154,39 @@ void caf::TrackBallBasedNavigation::setPointOfInterest(cvf::Vec3d poi) m_trackball->setRotationPoint(poi); m_isRotCenterInitialized = true; m_viewer->updateParallelProjectionCameraPosFromPointOfInterestMove(m_pointOfInterest); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void caf::TrackBallBasedNavigation::updatePointOfInterestDuringZoomIfNecessary(int zoomX, int zoomY) +{ + bool hitSomething = false; + cvf::HitItemCollection hic; + if (shouldRaytraceForNewPoiDuringWheelZoom(zoomX, zoomY)) + { + hitSomething = m_viewer->rayPick(zoomX, zoomY, &hic); + updateWheelZoomPosition(zoomX, zoomY); + } + + if (hitSomething) + { + cvf::Vec3d pointOfInterest = hic.firstItem()->intersectionPoint(); + this->setPointOfInterest(pointOfInterest); + } + else + { + initializeRotationCenter(); + } +} +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void caf::TrackBallBasedNavigation::forcePointOfInterestUpdateDuringNextWheelZoom() +{ + m_lastWheelZoomPosX = -1; + m_lastWheelZoomPosY = -1; } //-------------------------------------------------------------------------------------------------- @@ -230,3 +267,33 @@ cvf::ref caf::TrackBallBasedNavigation::createZoomRay(int cvfXPos, int return ray; } + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void caf::TrackBallBasedNavigation::updateWheelZoomPosition(int zoomX, int zoomY) +{ + m_lastWheelZoomPosX = zoomX; + m_lastWheelZoomPosY = zoomY; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool caf::TrackBallBasedNavigation::shouldRaytraceForNewPoiDuringWheelZoom(int zoomX, int zoomY) const +{ + // Raytrace if the last zoom position isn't set + if (m_lastWheelZoomPosX == -1 || m_lastWheelZoomPosY == -1) + { + return true; + } + int diffX = zoomX - m_lastWheelZoomPosX; + int diffY = zoomY - m_lastWheelZoomPosY; + + const int pixelThreshold = 5; + if (diffX * diffX + diffY * diffY > pixelThreshold * pixelThreshold) + { + return true; + } + return false; +} diff --git a/Fwk/AppFwk/cafViewer/cafTrackBallBasedNavigation.h b/Fwk/AppFwk/cafViewer/cafTrackBallBasedNavigation.h index a27596fb12..eb2af4a81e 100644 --- a/Fwk/AppFwk/cafViewer/cafTrackBallBasedNavigation.h +++ b/Fwk/AppFwk/cafViewer/cafTrackBallBasedNavigation.h @@ -37,6 +37,8 @@ #include "cafNavigationPolicy.h" +#include + namespace cvf { class ManipulatorTrackball; class Ray; @@ -57,17 +59,19 @@ class TrackBallBasedNavigation: public NavigationPolicy { public: TrackBallBasedNavigation(); - virtual ~TrackBallBasedNavigation(); + ~TrackBallBasedNavigation() override; void enableEventEating(bool enable) { m_consumeEvents = enable; } void enableRotation(bool enable) { m_isRotationEnabled = enable; } protected: // General navigation policy overrides - virtual void init(); + void init() override; - virtual void setView( const cvf::Vec3d& alongDirection, const cvf::Vec3d& upDirection ); - virtual cvf::Vec3d pointOfInterest(); - virtual void setPointOfInterest(cvf::Vec3d poi); + void setView( const cvf::Vec3d& alongDirection, const cvf::Vec3d& upDirection ) override; + cvf::Vec3d pointOfInterest() override; + void setPointOfInterest(cvf::Vec3d poi) override; + void updatePointOfInterestDuringZoomIfNecessary(int zoomX, int zoomY); + void forcePointOfInterestUpdateDuringNextWheelZoom(); // Track ball navigation specific void initializeRotationCenter(); @@ -91,9 +95,15 @@ class TrackBallBasedNavigation: public NavigationPolicy bool isSupposedToConsumeEvents() { return m_consumeEvents; } bool isRotationEnabled() { return m_isRotationEnabled; } +private: + void updateWheelZoomPosition(int zoomX, int zoomY); + bool shouldRaytraceForNewPoiDuringWheelZoom(int zoomX, int zoomY) const; + private: bool m_consumeEvents; bool m_isRotationEnabled; + int m_lastWheelZoomPosX; + int m_lastWheelZoomPosY; }; } // End namespace caf diff --git a/Fwk/AppFwk/cafViewer/cafViewer.cpp b/Fwk/AppFwk/cafViewer/cafViewer.cpp index f38c310505..431d5f8641 100644 --- a/Fwk/AppFwk/cafViewer/cafViewer.cpp +++ b/Fwk/AppFwk/cafViewer/cafViewer.cpp @@ -90,13 +90,13 @@ class GlobalViewerDynUniformSet: public cvf::DynamicUniformSet m_uniformSet->setUniform(m_headlightPosition.p()); } - virtual ~GlobalViewerDynUniformSet() {} + ~GlobalViewerDynUniformSet() override {} void setHeadLightPosition(const cvf::Vec3f posRelativeToCamera) { m_headlightPosition->set(posRelativeToCamera);} - virtual cvf::UniformSet* uniformSet() { return m_uniformSet.p(); } - virtual void update(cvf::Rendering* rendering){}; + cvf::UniformSet* uniformSet() override { return m_uniformSet.p(); } + void update(cvf::Rendering* rendering) override{}; private: cvf::ref m_uniformSet; @@ -474,7 +474,7 @@ const caf::NavigationPolicy* caf::Viewer::getNavigationPolicy() const //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -bool caf::Viewer::rayPick(int winPosX, int winPosY, cvf::HitItemCollection* pickedPoints) +bool caf::Viewer::rayPick(int winPosX, int winPosY, cvf::HitItemCollection* pickedPoints, cvf::Vec3d* globalRayOrigin/*=nullptr*/) { CVF_ASSERT(m_mainRendering.notNull()); @@ -485,7 +485,11 @@ bool caf::Viewer::rayPick(int winPosX, int winPosY, cvf::HitItemCollection* pick if (ris.notNull()) { bool retVal = m_mainRendering->rayIntersect(*ris, pickedPoints); - + if (retVal && globalRayOrigin) + { + CVF_ASSERT(ris->ray() != nullptr); + *globalRayOrigin = ris->ray()->origin(); + } return retVal; } else @@ -568,13 +572,13 @@ void caf::Viewer::paintEvent(QPaintEvent* event) } m_overlayPaintingQImage.fill(Qt::transparent); - QPainter overlyPainter(&m_overlayPaintingQImage); + QPainter overlayPainter(&m_overlayPaintingQImage); // Call virtual method to allow subclasses to paint on the OpenGlCanvas if (m_isOverlayPaintingEnabled) { - this->paintOverlayItems(&overlyPainter); + this->paintOverlayItems(&overlayPainter); } // Draw performance overlay @@ -585,7 +589,7 @@ void caf::Viewer::paintEvent(QPaintEvent* event) hud.addStrings(m_renderingSequence->performanceInfo()); hud.addStrings(*m_mainCamera); hud.addString(QString("PaintCount: %1").arg(m_paintCounter++)); - hud.draw(&overlyPainter, width(), height()); + hud.draw(&overlayPainter, width(), height()); } // Convert the QImage into the cvf::TextureImage, @@ -973,7 +977,7 @@ int caf::Viewer::currentFrameIndex() const //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -bool caf::Viewer::isOverlyPaintingEnabled() const +bool caf::Viewer::isOverlayPaintingEnabled() const { return m_isOverlayPaintingEnabled; } @@ -981,7 +985,7 @@ bool caf::Viewer::isOverlyPaintingEnabled() const //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void caf::Viewer::enableOverlyPainting(bool val) +void caf::Viewer::enableOverlayPainting(bool val) { m_isOverlayPaintingEnabled = val; updateOverlayImagePresence(); diff --git a/Fwk/AppFwk/cafViewer/cafViewer.h b/Fwk/AppFwk/cafViewer/cafViewer.h index 9a58b4ee64..2f8401bf84 100644 --- a/Fwk/AppFwk/cafViewer/cafViewer.h +++ b/Fwk/AppFwk/cafViewer/cafViewer.h @@ -81,7 +81,7 @@ class Viewer : public caf::OpenGLWidget Q_OBJECT public: Viewer(const QGLFormat& format, QWidget* parent); - ~Viewer(); + ~Viewer() override; QWidget* layoutWidget() { return m_layoutWidget; } // Use this when putting it into something cvf::Camera* mainCamera(); @@ -135,13 +135,13 @@ class Viewer : public caf::OpenGLWidget // Test whether it is any point in doing navigation etc. bool canRender() const; - bool rayPick(int winPosX, int winPosY, cvf::HitItemCollection* pickedPoints) ; + bool rayPick(int winPosX, int winPosY, cvf::HitItemCollection* pickedPoints, cvf::Vec3d* rayGlobalOrigin = nullptr) ; cvf::OverlayItem* overlayItem(int winPosX, int winPosY); // QPainter based drawing on top of the OpenGL graphics - bool isOverlyPaintingEnabled() const; - void enableOverlyPainting(bool val); + bool isOverlayPaintingEnabled() const; + void enableOverlayPainting(bool val); // Performance information for debugging etc. void enablePerfInfoHud(bool enable); @@ -159,7 +159,7 @@ public slots: virtual void slotEndAnimation(); public: - virtual QSize sizeHint() const; + QSize sizeHint() const override; protected: // Method to override if painting directly on the OpenGl Canvas is needed. @@ -169,11 +169,12 @@ public slots: virtual void optimizeClippingPlanes(); // Standard overrides. Not for overriding - virtual void resizeGL(int width, int height); - virtual void paintEvent(QPaintEvent* event); + void resizeGL(int width, int height) override; + void paintEvent(QPaintEvent* event) override; // Support the navigation policy concept - virtual bool event( QEvent* e ); + bool event( QEvent* e ) override; + cvf::ref m_navigationPolicy; bool m_navigationPolicyEnabled; @@ -196,7 +197,6 @@ public slots: void removeModelFromAllFrames(cvf::Model* model); void updateCamera(int width, int height); - void releaseOGlResourcesForCurrentFrame(); void debugShowRenderingSequencePartNames(); diff --git a/Fwk/AppFwk/cafVizExtensions/CMakeLists.txt b/Fwk/AppFwk/cafVizExtensions/CMakeLists.txt index 2d0f236581..de2c6a8bf7 100644 --- a/Fwk/AppFwk/cafVizExtensions/CMakeLists.txt +++ b/Fwk/AppFwk/cafVizExtensions/CMakeLists.txt @@ -5,6 +5,14 @@ project (cafVizExtensions) # Open GL find_package( OpenGL ) +# Qt +if (CAF_USE_QT5) + find_package(Qt5 COMPONENTS Core Gui OpenGL Widgets REQUIRED) +else() + find_package(Qt4 COMPONENTS QtCore QtGui QtMain QtOpenGl REQUIRED) + include(${QT_USE_FILE}) +endif(CAF_USE_QT5) + add_library( ${PROJECT_NAME} cafDisplayCoordTransform.cpp cafDisplayCoordTransform.h @@ -18,6 +26,8 @@ add_library( ${PROJECT_NAME} cafCategoryLegend.h cafOverlayScalarMapperLegend.h cafOverlayScalarMapperLegend.cpp + cafOverlayScaleLegend.h + cafOverlayScaleLegend.cpp cafInternalLegendRenderTools.h cafInternalLegendRenderTools.cpp cafCategoryMapper.cpp @@ -41,6 +51,11 @@ target_include_directories(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR} ) + +if (CAF_USE_QT5) + set(QT_LIBRARIES Qt5::Core Qt5::Gui Qt5::OpenGL Qt5::Widgets) +endif(CAF_USE_QT5) + target_link_libraries ( ${PROJECT_NAME} LibCore LibGeometry diff --git a/Fwk/AppFwk/cafVizExtensions/cafBoxManipulatorGeometryGenerator.h b/Fwk/AppFwk/cafVizExtensions/cafBoxManipulatorGeometryGenerator.h index 9d12a4bab6..c4717df9b5 100644 --- a/Fwk/AppFwk/cafVizExtensions/cafBoxManipulatorGeometryGenerator.h +++ b/Fwk/AppFwk/cafVizExtensions/cafBoxManipulatorGeometryGenerator.h @@ -23,7 +23,7 @@ class BoxManipulatorGeometryGenerator : public cvf::Object { public: BoxManipulatorGeometryGenerator(); - ~BoxManipulatorGeometryGenerator(); + ~BoxManipulatorGeometryGenerator() override; void setOrigin(const cvf::Vec3d& origin); void setSize(const cvf::Vec3d& size); diff --git a/Fwk/AppFwk/cafVizExtensions/cafBoxManipulatorPartManager.h b/Fwk/AppFwk/cafVizExtensions/cafBoxManipulatorPartManager.h index dd9612c50e..a42681cdb3 100644 --- a/Fwk/AppFwk/cafVizExtensions/cafBoxManipulatorPartManager.h +++ b/Fwk/AppFwk/cafVizExtensions/cafBoxManipulatorPartManager.h @@ -49,7 +49,7 @@ class BoxManipulatorPartManager : public cvf::Object public: BoxManipulatorPartManager(); - ~BoxManipulatorPartManager(); + ~BoxManipulatorPartManager() override; void setOrigin(const cvf::Vec3d& origin); void setSize(const cvf::Vec3d& size); diff --git a/Fwk/AppFwk/cafVizExtensions/cafCategoryLegend.h b/Fwk/AppFwk/cafVizExtensions/cafCategoryLegend.h index 33090e6a39..e1e57bc5fb 100644 --- a/Fwk/AppFwk/cafVizExtensions/cafCategoryLegend.h +++ b/Fwk/AppFwk/cafVizExtensions/cafCategoryLegend.h @@ -28,7 +28,7 @@ class CategoryLegend : public caf::TitledOverlayFrame { public: CategoryLegend(cvf::Font* font, const CategoryMapper* categoryMapper); - virtual ~CategoryLegend(); + ~CategoryLegend() override; size_t categoryCount() const; diff --git a/Fwk/AppFwk/cafVizExtensions/cafCategoryMapper.h b/Fwk/AppFwk/cafVizExtensions/cafCategoryMapper.h index a4ec3fc1d4..3a8f67d156 100644 --- a/Fwk/AppFwk/cafVizExtensions/cafCategoryMapper.h +++ b/Fwk/AppFwk/cafVizExtensions/cafCategoryMapper.h @@ -30,14 +30,14 @@ class CategoryMapper : public cvf::ScalarMapper // Overrides used from legend - virtual cvf::Vec2f mapToTextureCoord(double scalarValue) const; - virtual bool updateTexture(cvf::TextureImage* image) const; + cvf::Vec2f mapToTextureCoord(double scalarValue) const override; + bool updateTexture(cvf::TextureImage* image) const override; - virtual cvf::Color3ub mapToColor(double normalizedValue) const; + cvf::Color3ub mapToColor(double normalizedValue) const override; - virtual void majorTickValues(std::vector* domainValues) const; - virtual double normalizedValue(double domainValue) const; - virtual double domainValue(double normalizedValue) const; + void majorTickValues(std::vector* domainValues) const override; + double normalizedValue(double domainValue) const override; + double domainValue(double normalizedValue) const override; private: friend class CategoryLegend; diff --git a/Fwk/AppFwk/cafVizExtensions/cafDisplayCoordTransform.cpp b/Fwk/AppFwk/cafVizExtensions/cafDisplayCoordTransform.cpp index fa85ed6994..5b44a424e5 100644 --- a/Fwk/AppFwk/cafVizExtensions/cafDisplayCoordTransform.cpp +++ b/Fwk/AppFwk/cafVizExtensions/cafDisplayCoordTransform.cpp @@ -45,10 +45,25 @@ cvf::Vec3d caf::DisplayCoordTransform::transformToDisplayCoord(const cvf::Vec3d& coord.x() *= m_scale.x(); coord.y() *= m_scale.y(); coord.z() *= m_scale.z(); - + return coord; } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector caf::DisplayCoordTransform::transformToDisplayCoords(const std::vector& domainCoords) const +{ + std::vector displayCoords; + + for (const auto& coord : domainCoords) + { + displayCoords.emplace_back(transformToDisplayCoord(coord)); + } + + return displayCoords; +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- diff --git a/Fwk/AppFwk/cafVizExtensions/cafDisplayCoordTransform.h b/Fwk/AppFwk/cafVizExtensions/cafDisplayCoordTransform.h index 3e31256cd8..8de3febcf1 100644 --- a/Fwk/AppFwk/cafVizExtensions/cafDisplayCoordTransform.h +++ b/Fwk/AppFwk/cafVizExtensions/cafDisplayCoordTransform.h @@ -5,8 +5,10 @@ #include "cvfObject.h" #include "cvfVector3.h" -namespace caf { +#include +namespace caf +{ //================================================================================================== // // @@ -19,7 +21,9 @@ class DisplayCoordTransform : public cvf::Object void setScale(const cvf::Vec3d& scale); void setTranslation(const cvf::Vec3d& translation); - cvf::Vec3d transformToDisplayCoord(const cvf::Vec3d& domainCoord) const; + cvf::Vec3d transformToDisplayCoord(const cvf::Vec3d& domainCoord) const; + std::vector transformToDisplayCoords(const std::vector& domainCoords) const; + cvf::Vec3d translateToDisplayCoord(const cvf::Vec3d& domainCoord) const; cvf::Vec3d scaleToDisplaySize(const cvf::Vec3d& domainSize) const; @@ -33,4 +37,4 @@ class DisplayCoordTransform : public cvf::Object cvf::Vec3d m_translation; }; -} +} // namespace caf diff --git a/Fwk/AppFwk/cafVizExtensions/cafFixedAtlasFont.cpp b/Fwk/AppFwk/cafVizExtensions/cafFixedAtlasFont.cpp index 374ef3f607..9eac677803 100644 --- a/Fwk/AppFwk/cafVizExtensions/cafFixedAtlasFont.cpp +++ b/Fwk/AppFwk/cafVizExtensions/cafFixedAtlasFont.cpp @@ -55,89 +55,88 @@ namespace caf { - -// Fixed Atlas Font: Droid Sans Regular (12pt) +// Fixed Atlas Font: Droid Sans Regular (10pt) // Exported by FreeType Font Extractor 1.0.0 // Copyright (c) 2011 Ceetron AS // -------------------------------------------------------------------------------- // Font name -const char CAF_FIXED_ATLAS_FONT_12_PT_NAME[] = "Droid Sans Regular (12pt)"; +const char CAF_FIXED_ATLAS_FONT_10_PT_NAME[] = "Droid Sans Regular (10pt)"; // Number of glyphs -const size_t CAF_FIXED_ATLAS_FONT_12_PT_NUM_GLYPHS = 256; +const size_t CAF_FIXED_ATLAS_FONT_10_PT_NUM_GLYPHS = 256; // Horizontal bearings X -const short CAF_FIXED_ATLAS_FONT_12_PT_HORIZONTAL_BEARINGS_X[] = +const short CAF_FIXED_ATLAS_FONT_10_PT_HORIZONTAL_BEARINGS_X[] = { 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, 0, 0, 0, - 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, -1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, - 1, -1, 1, 0, 1, 1, 1, 0, 1, 0, -2, 1, 1, 1, 1, 0, 1, 0, 1, -1, 0, 1, -1, -1, -1, -2, 0, 1, -1, 0, 0, 0, - 3, 1, 1, 1, 1, 1, 0, 0, 1, 0, -1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, -1, -1, 0, -1, 1, 0, 4, 0, 1, 0, + 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, -1, 1, 2, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, + 1, -1, 1, 1, 1, 1, 1, 1, 1, 0, -1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, -1, -1, -1, -1, 1, 1, -1, 0, 0, 0, + 3, 1, 1, 1, 1, 1, 0, 1, 1, 0, -1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, -1, -1, 0, -1, 1, 0, 3, 0, 1, 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, 0, 0, 0, 0, - 0, 1, 1, 1, 0, 1, 4, 0, 2, 1, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 3, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, - -1, -1, -1, -1, -1, -1, -1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, -2, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, 1, -1 + 0, 1, 1, 1, 0, 0, 3, 0, 2, 1, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 3, 1, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, + -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, -1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, -1, 1, -1 }; // Horizontal bearings Y -const short CAF_FIXED_ATLAS_FONT_12_PT_HORIZONTAL_BEARINGS_Y[] = +const short CAF_FIXED_ATLAS_FONT_10_PT_HORIZONTAL_BEARINGS_Y[] = { 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, 0, 0, 0, - 0, 12, 12, 12, 13, 12, 12, 12, 12, 12, 13, 10, 2, 5, 2, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 9, 9, 10, 8, 10, 12, - 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, -1, - 13, 9, 13, 9, 13, 9, 13, 9, 13, 12, 12, 13, 13, 9, 9, 9, 9, 9, 9, 9, 11, 9, 9, 9, 9, 9, 9, 12, 13, 12, 8, 0, + 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 10, 8, 2, 4, 2, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 7, 7, 7, 6, 7, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, -1, + 10, 7, 10, 7, 10, 7, 10, 7, 10, 9, 9, 10, 10, 7, 7, 7, 7, 7, 7, 7, 9, 7, 7, 7, 7, 7, 7, 9, 10, 9, 7, 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, 0, 0, 0, 0, - 0, 9, 12, 12, 9, 12, 13, 13, 12, 12, 12, 8, 6, 5, 12, 13, 12, 10, 12, 12, 13, 9, 13, 7, 0, 12, 12, 8, 12, 12, 12, 9, - 16, 16, 16, 17, 15, 15, 12, 12, 16, 16, 16, 15, 16, 16, 16, 15, 12, 17, 16, 16, 16, 17, 15, 9, 13, 16, 16, 16, 15, 16, 12, 13, - 13, 13, 13, 14, 12, 14, 9, 9, 13, 13, 13, 12, 13, 13, 13, 12, 13, 14, 13, 13, 13, 14, 12, 9, 9, 13, 13, 13, 12, 13, 13, 12 + 0, 7, 9, 9, 7, 9, 10, 10, 9, 9, 9, 6, 5, 4, 9, 11, 9, 8, 9, 9, 10, 7, 10, 6, 0, 9, 9, 6, 9, 9, 9, 7, + 12, 12, 12, 13, 11, 11, 9, 9, 12, 12, 12, 11, 12, 12, 12, 11, 9, 13, 12, 12, 12, 13, 11, 8, 10, 12, 12, 12, 11, 12, 9, 10, + 10, 10, 10, 11, 9, 11, 7, 7, 10, 10, 10, 9, 10, 10, 10, 9, 10, 11, 10, 10, 10, 11, 9, 8, 7, 10, 10, 10, 9, 10, 10, 9 }; // Horizontal advances -const cvf::uint CAF_FIXED_ATLAS_FONT_12_PT_HORIZONTAL_ADVANCES[] = +const cvf::uint CAF_FIXED_ATLAS_FONT_10_PT_HORIZONTAL_ADVANCES[] = { - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 4, 4, 7, 10, 9, 13, 11, 4, 5, 5, 9, 9, 4, 5, 4, 6, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 4, 4, 9, 9, 9, 7, - 14, 11, 11, 10, 11, 8, 8, 11, 11, 6, 4, 9, 8, 14, 12, 11, 9, 11, 10, 8, 8, 11, 10, 14, 9, 8, 9, 5, 6, 5, 9, 7, - 9, 9, 9, 8, 9, 9, 4, 8, 9, 4, 4, 8, 4, 14, 9, 9, 9, 9, 6, 7, 5, 9, 8, 12, 8, 8, 8, 6, 9, 6, 9, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 4, 4, 9, 9, 9, 9, 9, 8, 9, 13, 6, 8, 9, 5, 13, 8, 7, 9, 6, 6, 9, 9, 10, 4, 3, 6, 6, 8, 12, 12, 12, 7, - 11, 11, 11, 11, 11, 11, 14, 10, 8, 8, 8, 8, 6, 6, 6, 6, 11, 12, 11, 11, 11, 11, 11, 9, 11, 11, 11, 11, 11, 8, 9, 10, - 9, 9, 9, 9, 9, 9, 14, 8, 9, 9, 9, 9, 4, 4, 4, 4, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 8, 9, 8 + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 3, 4, 5, 8, 7, 11, 9, 3, 4, 4, 7, 7, 3, 4, 3, 5, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 3, 3, 7, 7, 7, 6, + 11, 8, 8, 8, 9, 7, 6, 9, 9, 5, 3, 8, 6, 11, 9, 10, 7, 10, 8, 7, 7, 9, 7, 11, 7, 7, 7, 4, 5, 4, 7, 5, + 8, 7, 8, 6, 8, 7, 4, 7, 8, 3, 3, 6, 3, 11, 8, 8, 8, 8, 5, 6, 4, 8, 6, 10, 7, 6, 6, 5, 7, 5, 7, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 3, 4, 7, 7, 7, 7, 7, 6, 8, 11, 5, 6, 7, 4, 11, 7, 6, 7, 5, 5, 8, 8, 9, 3, 3, 5, 5, 6, 10, 10, 10, 6, + 8, 8, 8, 8, 8, 8, 11, 8, 7, 7, 7, 7, 5, 5, 5, 5, 9, 9, 10, 10, 10, 10, 10, 7, 10, 9, 9, 9, 9, 7, 7, 8, + 7, 7, 7, 7, 7, 7, 11, 6, 7, 7, 7, 7, 3, 3, 3, 3, 8, 8, 8, 8, 8, 8, 8, 7, 8, 8, 8, 8, 8, 6, 8, 6 }; // Character widths -const cvf::uint CAF_FIXED_ATLAS_FONT_12_PT_CHARACTER_WIDTHS[] = +const cvf::uint CAF_FIXED_ATLAS_FONT_10_PT_CHARACTER_WIDTHS[] = { - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 4, 2, 5, 8, 7, 11, 10, 2, 5, 4, 8, 9, 3, 3, 3, 8, 7, 5, 8, 7, 9, 7, 7, 7, 7, 7, 3, 3, 7, 7, 7, 6, - 12, 12, 8, 9, 9, 6, 6, 10, 8, 5, 5, 9, 7, 11, 9, 10, 7, 10, 9, 8, 8, 8, 11, 15, 10, 11, 8, 3, 8, 3, 9, 7, - 3, 7, 7, 6, 7, 7, 5, 9, 7, 3, 4, 8, 2, 12, 7, 7, 7, 7, 5, 6, 5, 7, 10, 14, 8, 10, 7, 5, 2, 5, 7, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 4, 2, 7, 7, 8, 8, 2, 7, 5, 11, 4, 7, 7, 3, 11, 8, 5, 9, 6, 5, 3, 7, 7, 3, 3, 4, 4, 7, 11, 12, 12, 6, - 12, 12, 12, 12, 12, 12, 14, 9, 6, 6, 6, 6, 5, 5, 5, 5, 10, 9, 10, 10, 10, 10, 10, 7, 10, 8, 8, 8, 8, 11, 7, 8, - 7, 7, 7, 7, 7, 7, 12, 6, 7, 7, 7, 7, 3, 3, 5, 5, 7, 7, 7, 7, 7, 7, 7, 8, 7, 7, 7, 7, 7, 10, 7, 10 + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 3, 2, 4, 8, 5, 9, 8, 2, 3, 3, 7, 7, 2, 3, 3, 7, 5, 3, 6, 5, 6, 5, 5, 5, 5, 5, 3, 3, 5, 5, 5, 5, + 9, 10, 6, 7, 7, 5, 5, 7, 7, 5, 4, 8, 5, 9, 7, 8, 5, 8, 7, 6, 7, 7, 9, 13, 9, 9, 5, 3, 7, 3, 7, 5, + 3, 5, 6, 4, 6, 5, 5, 7, 6, 3, 4, 6, 2, 9, 6, 6, 6, 6, 4, 5, 4, 6, 8, 12, 7, 8, 5, 5, 1, 5, 5, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 3, 2, 5, 5, 7, 7, 1, 5, 4, 9, 4, 4, 5, 3, 9, 7, 4, 7, 5, 4, 3, 6, 7, 3, 3, 2, 4, 4, 10, 10, 10, 5, + 10, 10, 10, 10, 10, 10, 11, 7, 5, 5, 5, 5, 5, 5, 5, 5, 8, 7, 8, 8, 8, 8, 8, 7, 8, 7, 7, 7, 7, 9, 5, 6, + 5, 5, 5, 5, 5, 5, 9, 4, 5, 5, 5, 5, 3, 3, 4, 4, 6, 6, 6, 6, 6, 6, 6, 7, 6, 6, 6, 6, 6, 8, 6, 8 }; // Character heights -const cvf::uint CAF_FIXED_ATLAS_FONT_12_PT_CHARACTER_HEIGHTS[] = +const cvf::uint CAF_FIXED_ATLAS_FONT_10_PT_CHARACTER_HEIGHTS[] = { - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 4, 12, 4, 12, 14, 12, 12, 4, 15, 15, 7, 9, 4, 2, 2, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 9, 11, 8, 5, 8, 12, - 13, 12, 12, 12, 12, 12, 12, 12, 12, 12, 15, 12, 12, 12, 12, 12, 12, 15, 12, 12, 12, 12, 12, 12, 12, 12, 12, 15, 12, 15, 7, 2, - 3, 9, 13, 9, 13, 9, 13, 13, 13, 12, 16, 13, 13, 9, 9, 9, 13, 13, 9, 9, 11, 9, 9, 9, 9, 13, 9, 15, 17, 15, 5, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 4, 12, 12, 12, 7, 12, 17, 13, 2, 12, 5, 7, 5, 2, 12, 2, 5, 10, 7, 7, 3, 13, 15, 2, 4, 7, 5, 7, 12, 12, 12, 12, - 16, 16, 16, 17, 15, 15, 12, 16, 16, 16, 16, 15, 16, 16, 16, 15, 12, 17, 16, 16, 16, 17, 15, 7, 14, 16, 16, 16, 15, 16, 12, 13, - 13, 13, 13, 14, 12, 14, 9, 13, 13, 13, 13, 12, 13, 13, 13, 12, 13, 14, 13, 13, 13, 14, 12, 7, 9, 13, 13, 13, 12, 17, 17, 16 + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 3, 9, 3, 9, 10, 9, 9, 3, 11, 11, 6, 7, 3, 2, 2, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 7, 8, 5, 3, 5, 9, + 10, 9, 9, 9, 9, 9, 9, 9, 9, 9, 11, 9, 9, 9, 9, 9, 9, 12, 9, 9, 9, 9, 9, 9, 9, 9, 9, 11, 9, 11, 6, 1, + 2, 7, 10, 7, 10, 7, 10, 10, 10, 9, 12, 10, 10, 7, 7, 7, 10, 10, 7, 7, 9, 7, 7, 7, 7, 10, 7, 11, 13, 11, 4, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 3, 9, 9, 9, 6, 9, 13, 10, 1, 9, 4, 5, 4, 2, 9, 1, 4, 8, 6, 6, 2, 10, 12, 2, 3, 6, 4, 5, 9, 9, 9, 10, + 12, 12, 12, 13, 11, 11, 9, 12, 12, 12, 12, 11, 12, 12, 12, 11, 9, 13, 12, 12, 12, 13, 11, 7, 11, 12, 12, 12, 11, 12, 9, 10, + 10, 10, 10, 11, 9, 11, 7, 10, 10, 10, 10, 9, 10, 10, 10, 9, 10, 11, 10, 10, 10, 11, 9, 7, 7, 10, 10, 10, 9, 13, 13, 12 }; // Texture image dimensions -const size_t CAF_FIXED_ATLAS_FONT_12_PT_TEXTURE_IMAGE_WIDTH = 4096; -const size_t CAF_FIXED_ATLAS_FONT_12_PT_TEXTURE_IMAGE_HEIGHT = 17; +const size_t CAF_FIXED_ATLAS_FONT_10_PT_TEXTURE_IMAGE_WIDTH = 3328; +const size_t CAF_FIXED_ATLAS_FONT_10_PT_TEXTURE_IMAGE_HEIGHT = 13; // Texture image data -const char* CAF_FIXED_ATLAS_FONT_12_PT_TEXTURE_IMAGE[] = +const char* CAF_FIXED_ATLAS_FONT_10_PT_TEXTURE_IMAGE[] = { "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", @@ -147,87 +146,518 @@ const char* CAF_FIXED_ATLAS_FONT_12_PT_TEXTURE_IMAGE[] = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////2////0////8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///8f///8H////x////wf///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////4v///wb///8A////0////xj///8A////AP///wD///8A////AP///wD///8A////AP///wD////g////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8P////zv///wX///8A////TP///93////f////Tv///wD///8A////AP///wD///8v////w/////X////u////ov///y/////W////iv///wD///8A////AP///wD///8A////x////wf///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9x////rv///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///+t////cv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///zv///+0////AP///67///8/////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///2P///8A////AP///wD///8A////AP///wD///8A////AP///wD////b////Hv///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////EP///xD///8Q////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///1L////3////Uf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8R////7////yP///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////B////6v////v////rv///wn///8A////AP///wD///8A////AP///wD///8A////AP///wD///8g/////////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD//////////////////////////////2D///8A////AP///wD///8A////AP///wD///8A////s/////H////w////t////yL///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD/////////IP///wD///8A////AP///wD///8A////AP///wD///+5////9f///+r///+f////D////wD///8A////AP///wD///8A////AP///wD///8A////C////6b////x////vv///xv///8A////AP///wD///8A////AP///wD///8A////AP///xT////5////K////wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///88////0P////b////L////MP///wD///8A////AP///wD///8A////AP///wD///8A////Rf///+r////Z////Xv///wD///8A////AP///wD///8A////AP///wD///8A////AP///1L////3////Uf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////b", + "////Hv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8G////Xf///8r///8A////AP///wD///8A////AP///wD///8A////AP///3r////0////9P////T////0////AP///wD///8A////AP///wD///8A////AP///wD////K////Xf///wb///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD////b////T////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8T////mP///9X////f////3P///6b///8A////AP///wD///8A////AP///wD///8T////9v///yD///8A////AP///wD///8A////JP////b///8T////AP///wD///8A//////////b////0////7v///7H///8f", + "////AP///wD///8A////AP///wD///8A////AP///wD///8a////of///9n////2////8v///8T///8A////AP///wD///8A////AP///wD/////////9v////X////X////l////xX///8A////AP///wD///8A////AP///wD///8A//////////b////0////9P////T///8A////AP///wD///8A////AP///wD///8A////AP////////8w", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Kv///7X////o////8////+L///+s////AP///wD///8A////AP///wD///8A/////////zD///8A////AP///wD///8w/////////wD///8A////AP///wD///8A////AP///yX////S/////////83///8a////AP///wD///8A////AP///wD///8A", + "////AP///wD////w////5f///17///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////zD///8A////AP///wD///+C////yP///wn///8A////AP///wD///8A////AP/////////2////9P////T///+n////AP///wD///8A////AP///wD///8A////AP///wD/////////MP///wD///8g////7v///wj///8A", + "////MP////////8A////AP///wD///8A/////////zD///8A////AP///wD///++/////////wD///8A////AP///wD///8A////AP///wD///8w////uf///+j////n////tf///yn///8A////AP///wD///8A////AP///wD/////////MP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8S////sf///wz///8A////AP///wD///8A////AP////////8w////AP///wD///9D////7f///w////8A////AP///wD///8A////AP///wD///8S////xv////D////w////tv///yH///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////zD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wX///97////2v////P////W////c////wP///8A////AP///wD///8A////AP///wD///8A////AP///wD///9F/////f///0T///8A////AP///wD///8A////AP///wD///8A////AP///wD///9C/////v///zP///8A////AP///wD///8//////v///zb///8A////AP///wz////e////RP///wD///8A////AP///2f////h", + "////DP///wD///8A////AP///wD///8A////AP///wD///8A/////////zD///8A////AP///wD///8A////AP///wD///8A/////v////j////0////9P////T///8A////AP///wD///8A////AP///wD///8A////AP/////////1////9P///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////PP///+L///8F////AP///wD///8A////AP///wD///8A////9P////X/////////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///7z///9h////AP///wD///8A////X////73///8A////AP///wD///8A////AP///wD////k////5P///+T////k////5P///wD///8A////AP///wD///8A////AP///wD///8A", + "////A////5D///+2////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///2j////w////5v///1r////x////AP///wD///8A////AP///wD///8A////AP///wD////y////XP///+H////v////o////wz///8A////AP///wD///8A////AP///wD///8A////F////7v////2////tv///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///w////+m////8P///9////9Z/////P///wD///8A////AP///wD///8A////AP///wD///8L////oP////D////w////ff///wD///8A////AP///wD///8A////AP///wD///8A////AP////////8o////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///1L////S////1f///+L///+v", + "////Jv///wD///8A////AP///wD///8A////AP///wD/////////KP///wD///8A////KP////////8A////AP///wD///8A////AP///wD///8A////AP////////8o////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///+3////r////dP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////", + "////KP///wD///9l////3f///wv///8A////AP///wD///8A////AP///wD///8A/////////yj///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////8o////AP///wD/////////KP///wD///8o/////////wD///8A////AP///wD/////////KP///wD///8A////KP////////8A////AP///wD///8A", + "////AP///wD///8A////Bv///43////n////5////5D///8I////AP///wD///8A////AP///wD///8A////AP////////8o////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////KP////////8A////AP///wD///8A////AP///wD///8A/////////yj///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///w7////N////8v///9////9R////AP///wD///8A////AP///wD///8A////AP///wD///8A////bP////P////o////AP///wD///8A////AP///wD///8A////AP///wD///8A////Of///9H////1////2////1L////7////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///8v////A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///zj////9////Nf///wD///8A////Ov////7///80////AP///wD///8A////Mf////T///8k////AP///yX////z////MP///wD///8A////AP///wD///8A////AP///yD////x////4////03///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD////7////2////9T////U////Gv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9H////zP////H///8A////AP///wD///8A////AP///wD///8A////AP////T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////x////y////0X///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////Uf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////Gv///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP//////////////////////////////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////zD///8A////AP///wD///8A////AP///wD///8A////AP////T///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8Q////z/////P////e////VP///wD///8A////AP///wD///8A////AP///wD///8A////yv///xj///8Z////zv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8H////fv///77///+0////vv///37///8H////AP///wD///8A", + "////AP///wD///+v////sf///5v////T////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///5X///8A////lf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9j////AP///wD///8A////AP///wD///8A////AP///wD///8Q////EP///xD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wf///9+////vv///7T///++////fv///wf///8A////AP///wD///8A////AP///+T////k////5P///+T////k////5P///+T///8A////AP///wD///8A////AP///wD///9L////2////9f///9J////AP///wD///8A////AP///wD///8A////AP///wD///8A////cv////T////0", + "////9P////T////0////Y////wD///8A////AP///wD///8A////AP////b////K////yP///8j///8r////AP///wD///8A////AP///wD///8A////AP///wD////I////zf///9X///9L////AP///wD///8A////AP///wD///8A////AP///wD///8A////t////4////8C////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP////////8o////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////xP///wD////E////AP///wD///8A////AP///wD///8A////Uv////f///9R////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///7D///+o////WP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////6P///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Wf///8f////I////W////wD///8A////AP///wD///8A////AP///wD///8A////AP///5X///8A////lf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8N////1////xv///8A", + "////AP///wD///8A////AP///+j///8A////AP///wD///8A////Df///9f///8b////AP///wD////2////yv///8j////I////K////wD///8A////AP///wD///8N////1////xv///8A////AP///wD///8A////6P///wD///8A////AP///wD///8v////yP////b////d////h////wD///8A////AP///wD///8A////AP///wD///8A", + "////E/////b///8g////AP///wD///8A////AP///yT////2////E////wD///8A////AP///xP////2////IP///wD///8A////AP///wD///8k////9v///xP///8A////AP///wD///8T////9v///yD///8A////AP///wD///8A////JP////b///8T////AP///wD///8A////E/////b///8g////AP///wD///8A////AP///yT////2", + "////E////wD///8A////AP///xP////2////IP///wD///8A////AP///wD///8k////9v///xP///8A////AP///wD///8T////9v///yD///8A////AP///wD///8A////JP////b///8T////AP///wD///8A////Ef////P///8p////AP///wD///8A//////////b////0////9P////T///8A////AP///wD///8A////AP///7D///+o", + "////WP///wD///8A////AP///wD///8A////AP///wD/////////9v////T////0////9P///wD///8A////AP///wD///8A////AP///wD///8A//////////b////0////9P////T///8A////AP///wD///8A////AP///wD///8A////AP/////////2////9P////T////0////AP///wD///8A////AP///wD///8A////AP///wD/////", + "////9v////T////0////9P///wD///8A////AP///wD///8A////AP///wD///8A////Jf///9L/////////zf///xr///8A////AP///wD///8A////AP///wD///8A////AP///yX////S/////////83///8a////AP///wD///8A////AP///wD///8A////AP///wD///8l////0v/////////N////Gv///wD///8A////AP///wD///8A", + "////AP///wD///8A////Jf///9L/////////zf///xr///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////9v////X////X////l////xX///8A////AP///wD///8A////AP///wD/////////MP///wD///8A////AP///77/////////AP///wD///8A////AP///wD///8A////AP///zD///+5////6P///+f///+1", + "////Kf///wD///8A////AP///wD///8A////AP///wD///8w////uf///+j////n////tf///yn///8A////AP///wD///8A////AP///wD///8A////MP///7n////o////5////7X///8p////AP///wD///8A////AP///wD///8A////AP///zD///+5////6P///+f///+1////Kf///wD///8A////AP///wD///8A////AP///wD///8w", + "////uf///+j////n////tf///yn///8A////AP///wD///8A////AP///wD///8A////B////wD///8A////AP///wn///8A////AP///wD///8A////AP///wD///8A////Av///yb///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wX///97////2v////P////W////c////wP///8A////AP///wD///8A", + "////AP///wD///8F////e////9r////z////1v///3P///8D////AP///wD///8A////AP///wD///8A////Bf///3v////a////8////9b///9z////A////wD///8A////AP///wD///8A////AP///wX///97////2v////P////W////c////wP///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////zD///8A", + "////AP///wD///8A////AP///wD///8A/////////zD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////8o////AP///8/////x////a////wD///8A////AP///wD///8A////AP///wD///9o////8P///+b///9a////8f///wD///8A////AP///wD///8A////AP///wD///8A////aP////D////m", + "////Wv////H///8A////AP///wD///8A////AP///wD///8A////AP///2j////w////5v///1r////x////AP///wD///8A////AP///wD///8A////AP///wD///9o////8P///+b///9a////8f///wD///8A////AP///wD///8A////AP///wD///8A////aP////D////m////Wv////H///8A////AP///wD///8A////AP///wD///8A", + "////AP///2j////w////5v///1r////x////AP///wD///8A////AP///wD///8A////AP///wD///9d////6f///+////+X////B////5H////p////8P///3f///8A////AP///wD///8A////AP///7D///+o////WP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wv///+g////8P////D///99////AP///wD///8A", + "////AP///wD///8A////AP///wD///8L////oP////D////w////ff///wD///8A////AP///wD///8A////AP///wD///8A////C////6D////w////8P///33///8A////AP///wD///8A////AP///wD///8A////AP///wv///+g////8P////D///99////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////yj///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////yj///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////KP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////yj///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////D////53////p////5f///4n///8F////AP///wD///8A////AP///wD///8A////AP////////8o////AP///wD///8o/////////wD///8A////AP///wD///8A////AP///wD///8G////jf///+f////n////kP///wj///8A////AP///wD///8A////AP///wD///8A////Bv///43////n////5////5D///8I////AP///wD///8A", + "////AP///wD///8A////AP///wb///+N////5////+f///+Q////CP///wD///8A////AP///wD///8A////AP///wD///8G////jf///+f////n////kP///wj///8A////AP///wD///8A////AP///wD///8A////Bv///43////n////5////5D///8I////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///7v///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///9b////z////+D////n////kP///wj///8A////AP///wD///8A////AP///wD///8A////Of///9H////1////2////1L////7////AP///wD///8A////AP///wD///8A////AP///zn////R////9f///9v///9S////+////wD///8A////AP///wD///8A////AP///wD///85", + "////0f////X////b////Uv////v///8A////AP///wD///8A////AP///wD///8A////Of///9H////1////2////1L////7////AP///wD///8A////AP///wD///8A////AP///yD////x////4////03///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////KP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////IP////H////j////Tf///wD///8A////AP///wD///8A////AP///wD///8A////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAA////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///9r///9P////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////e////Hf///97///8d////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///7j///8z////AP///6D///9J////AP///wD///8A", + "////AP///wD///8A////AP///8L////2/////f///8D///8v////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///3v///9o////AP///9j///8r////NP///9j///8A////AP///wD///8A////zv///5r///8Q////Gf///4r/////////qf///wD///8A////AP///wD///8A////AP///97///8d////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8a////9P///x////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////IP////X///8Z////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8M////2v///1r////c////Dv///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD////0////AP///wD///8A////AP///wD///8A////AP///wD///8A////o////4X///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///////////////////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9S////9P///1H///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///4v///+Y////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///3v///+r////Ev///7L///+B////AP///wD///8A////AP///wD///8A////AP///wD///8A////IP////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////jP///8X///8T////DP///wz///8E", + "////AP///wD///8A////AP///wD///8A////AP///1v///8P////Df///5X///++////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////yD///8A////AP///wD///8A////AP///wD///8A////Uv///wn///8S////r////5f///8A////AP///wD///8A////AP///wD///8A////AP///4L///+y", + "////D////5f///+o////AP///wD///8A////AP///wD///8A////AP///wD///8A////q////4v///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////2f///2////8F////eP///8////8A////AP///wD///8A////AP///wD///8A////AP///wL///8A////JP///9j///9A////AP///wD///8A////AP///wD///8A", + "////AP///wD///9S////9P///1H///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////o////4X///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///xv///+D////1f///5L///8z////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////M////5L////V////g////xv///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////2v///0////8A////AP///wD///8A////AP///wD///8A////AP///wD///8T////3P///2v///8K////AP///wL///87////AP///wD///8A////AP///wD///8A////AP///6L///9/", + "////AP///wD///8A////AP///4L///+h////AP///wD///8A////AP////////8w////AP///w3///+o////v////wD///8A////AP///wD///8A////AP///wD///8c////7////53///8j////Av///w3///9E////AP///wD///8A////AP///wD///8A/////////zD///8Q////Yv///7/////o////FP///wD///8A////AP///wD///8A", + "////AP////////8w////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////MP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Jf////X///9+////Fv///wD///89/////////wD///8A////AP///wD///8A////AP////////8w////AP///wD///8A////MP////////8A", + "////AP///wD///8A////AP///wD///8A////IP////////8Q////AP///wD///8A////AP///wD///8A////AP///wD///8A////A////z/////3////C////wD///8A////AP///wD///8A////AP///wD///8A////AP////////8w////AP///wD///9Y////3////xf///8A////AP///wD///8A////AP///wD/////////MP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////zD///8A////fP///97///9Z////AP///zD/////////AP///wD///8A////AP////////8w////AP///wD///9T////3/////////8A////AP///wD///8A////AP///wD///8t////9P///2v///8N////Df///2v////x////JP///wD///8A////AP///wD///8A", + "/////////zD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////uP///8z///8Q////AP///wD///8A////AP///wD/////////MP///wD///8A////wf///3X///8A////AP///wD///8A////AP///wD///8A////Ef///0j///8F////Fv///6L////C////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP////////8w////AP///wD///8A////AP///wD///8A////AP///wD///+B////1////0r///8G////J////9L///97////AP///wD///8A////AP///wD///8A////AP///wD///8A////n////6n///+e////AP///wD///8A////AP///wD///8A////AP///wD///8A////fv///8j///+D", + "////AP///wD///8A////jf///8H///9z////AP///wD///8A////Q////97///8L////AP///xb////u////SP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////8w////AP///wD///8A////AP///wD///8A////AP///6n///+b////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////", + "////KP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///7X///9u////AP///wD///8A////AP///wD///8A////AP///wD///8o/////////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///80////3f///wT///8A////Av///9n///84////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///6f////p////FP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////t////Yv///wX///+P/////////wD///8A////AP///wD///8A////AP///wD///8A/////////7f///8O////Lv///83///+M", + "////AP///wD///8A////AP///wD///8A////AP///57///+9////IP///zL///8A////AP///wD///8A////AP///wD///8A////AP///wD///+S////x////yv///8N////sP////////8A////AP///wD///8A////AP///wD///8A////jP///7////8p////FP///zz///8A////AP///wD///8A////AP///wD///8A////AP///wD/////", + "////KP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////t////Of///wD///8F////ff///8////8A////AP///wD///8A////AP///wD///8A/////////yj///8A////AP///yj/////////AP///wD///8A////AP///wD///8A////AP///wD/////////KP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8D////Kv////3///8R////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////yj///8X////7P///z3///8A////AP///wD///8A////AP///wD///8A////AP////////8o////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////KP///wD///8A/////////yj///8A", + "////KP////////8A////AP///wD///8A/////////yj///8A////AP///yj/////////AP///wD///8A////AP///wD///8A////AP///37////J////Lv///y/////J////gP///wD///8A////AP///wD///8A////AP///wD/////////KP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///yj/////////AP///wD///8A////AP///wD///8A////AP////////8o////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8L////Nv///wD///9U////5////wD///8A////AP///wD///8A////AP///wD///8A////AP///+j///9d////BP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///9P///+b////D////xf///+//////////wD///8A////AP///wD///8A////AP///wD///8A////AP///zP///+5////xv///yb///8A////AP///wD///8A////AP///wD///8A////AP///wD///+I////rv///4////8A////AP///4////+z////hP///wD///8A////AP///wD///+G////uP///wD///+5////g////wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///z7////v////Ef///wD///8A////AP///wD///8A////AP///wD///8A////mP///3z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////6v///2H///8B////AP///wD///8A////AP///wD///8A////AP///wD////0////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////Af///2L////o////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///2r///8N////kf///+z///99////AP///wD///8A////AP///wD///8A////AP///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////P///0P///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///yL////O//////////z///+1////AP///wD///8A////AP///wD///8A////AP///wD///9f////vf///wz///8M////DP///wD///8A////AP///wD///8A////AP///wD///8A////AP///7T////B////4////8L///+4////AP///wD///8A////AP///wD///8A", + "////AP///wf////0////9P/////////2////9P///xP///8A////AP///wD///8A////AP///wD////0////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////DP///zL///8A////RP///+n///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8I////tf///1P///8A////AP///wD///9W////s////wb///8A////AP///wD///8A////fv///53///+u////9P///wD///8A////AP///wD///8A////AP///wD///8A////AP///1L///98////Uv///3z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////9P///wD///8A////AP///wD///8A////AP///wD///8A////////////////////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wj///+1////U////wD///8A////AP///1b///+z////Bv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////4v///yL///8X////2P///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///2P///8A////AP///wD///8A////AP///wD///8A////AP///wD///8+////pv///w3///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////D////wD///8g////4f///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///xT////p////pf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////KP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///8T///8A////xP///wD///8A////AP///wD///8A////AP///1L////0////Uf///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////Dv///+D///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///+j///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///9v///8E////Bf///9z///8A////AP///wD///8A////AP///wD///8A////AP///wD///99", + "////Uf///33///9R////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///1b///+q////AP///wD////H////yP///8j////6////jP///wD///8A////AP///wD///9W////qv///wD///8A////Pv///6b///8N////AP///wD///8A////AP///wD///8A////AP///1b///+q////AP///8f////I////yP////r///+M", + "////AP///wD///8A////zf///3////8N////K////1P///8A////AP///wD///8A////AP///wD///8A////AP///wD///+i////f////wD///8A////AP///wD///+C////of///wD///8A////AP///wD///8A////ov///3////8A////AP///wD///8A////gv///6H///8A////AP///wD///8A////AP///6L///9/////AP///wD///8A", + "////AP///4L///+h////AP///wD///8A////AP///wD///+i////f////wD///8A////AP///wD///+C////of///wD///8A////AP///wD///8A////ov///3////8A////AP///wD///8A////gv///6H///8A////AP///wD///8A////AP///6L///9/////AP///wD///8A////AP///4L///+h////AP///wD///8A////AP///wD///+R", + "////mP///wD///8A////AP////////8w////AP///wD///8A////AP///wD///8A////AP///wD///8A////Dv///+D///8A////AP///wD///8A////AP///wD///8A/////////zD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////8w////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD/////////MP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////zD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8g/////////xD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////IP////////8Q////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///yD/////////EP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8g/////////xD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////zD///8Q////Yv///7/////o////FP///wD///8A////AP///wD///8A/////////zD///8A", + "////AP///1P////f/////////wD///8A////AP///wD///8A////AP///y3////0////a////w3///8N////a/////H///8k////AP///wD///8A////AP///wD///8t////9P///2v///8N////Df///2v////x////JP///wD///8A////AP///wD///8A////Lf////T///9r////Df///w3///9r////8f///yT///8A////AP///wD///8A", + "////AP///y3////0////a////w3///8N////a/////H///8k////AP///wD///8A////AP///wD///8t////9P///2v///8N////Df///2v////x////JP///wD///8A////AP///wD///8A////B////9X///84////AP///zf////W////Cf///wD///8A////AP///wD///8A////AP///yT////n////sP///+L////n////tf///yn///8A", + "////AP///wD///8A////AP///wD///+B////1////0r///8G////J////9L///97////AP///wD///8A////AP///wD///8A////gf///9f///9K////Bv///yf////S////e////wD///8A////AP///wD///8A////AP///4H////X////Sv///wb///8n////0v///3v///8A////AP///wD///8A////AP///wD///+B////1////0r///8G", + "////J////9L///97////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////8w////AP///wD///8A////AP///wD///8A////AP////////8w////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////KP///wD///8l////Sv///+r///8A////AP///wD///8A////AP///wD///8A", + "////7f///2L///8F////j/////////8A////AP///wD///8A////AP///wD///8A////AP///+3///9i////Bf///4//////////AP///wD///8A////AP///wD///8A////AP///wD////t////Yv///wX///+P/////////wD///8A////AP///wD///8A////AP///wD///8A////7f///2L///8F////j/////////8A////AP///wD///8A", + "////AP///wD///8A////AP///+3///9i////Bf///4//////////AP///wD///8A////AP///wD///8A////AP///wD////t////Yv///wX///+P/////////wD///8A////AP///wD///8A////AP///wD///8A////6////2j///8D////eP///9b///+/////Kf///xX///87////AP///wD///8A////AP///wD///8A////Dv///+D///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///+M////v////yn///8U////PP///wD///8A////AP///wD///8A////AP///wD///8A////jP///7////8p////FP///zz///8A////AP///wD///8A////AP///wD///8A////AP///4z///+/////Kf///xT///88////AP///wD///8A////AP///wD///8A////AP///wD///+M", + "////v////yn///8U////PP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////8o////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////8o////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////yj///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP////////8o////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///5////+w////Df///yv////E////dP///wD///8A////AP///wD///8A////AP///wD/////////KP///wD///8A////KP////////8A////AP///wD///8A////AP///wD///8A////fv///8n///8u////L////8n///+A", + "////AP///wD///8A////AP///wD///8A////AP///37////J////Lv///y/////J////gP///wD///8A////AP///wD///8A////AP///wD///9+////yf///y7///8v////yf///4D///8A////AP///wD///8A////AP///wD///8A////fv///8n///8u////L////8n///+A////AP///wD///8A////AP///wD///8A////AP///37////J", + "////Lv///y/////J////gP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////f/////7///9V////L////8n///+A////AP///wD///8A////AP///wD///8A////AP///9P///+b////D////xf///+//////////wD///8A////AP///wD///8A", + "////AP///wD////T////m////w////8X////v/////////8A////AP///wD///8A////AP///wD///8A////0////5v///8P////F////7//////////AP///wD///8A////AP///wD///8A////AP///9P///+b////D////xf///+//////////wD///8A////AP///wD///8A////AP///wD///8A////AP///z7////v////Ef///wD///8A", + "////AP///wD///8A////AP///wD///8A/////////yj///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Pv///+////8R////AP///wD///8A////AP///wD///8A////AP///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////9f///zT////1////NP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///+I////Zv///wD///9t////e////wD///8A////AP///wD///8A////AP///wD///9U////C////+L///98////1f///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8M////z////wf////z////Af///wL////z////AP///wD///8A////AP////T///87", + "////AP///wr////F////xP///+b///8u////AP///wD///8A////AP///wD////1////NP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////gP///7D///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+0////f////wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8J////Jv///2z////1////b////yf///8J////AP///wD///8A////AP///wD///8A////AP///wD///8A////9P///wD///8A////AP///wD///8A////AP///wD///8A////AP///2/////f////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8Z////8P///xj///8A////AP///wD///8A////AP///wD///8A////AP///wD////L////SP///wD///9O////z////wD///8A////AP///wD///8A////AP///wD///8A////AP///yD/////", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wH///+n////p////wH///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8s////7////wD///8A////AP///wD///8A////AP///wD///8A////////////////////////////////////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///zX////k////AP///wD///8A////AP///wD///8A////AP///wD////W////QP///wD///8x////6f///wD///8A////AP///wD///8A////AP///wD///8A////AP///0j////n////A////wD///8A////AP///wD///8A////AP///wD///8A////AP////b///8z////AP///yz////z////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///9f////q////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///2/////f////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////r////ov///wv///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////ev////T////0////9P////T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////DP///6P////r////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////lP///3j///9B////5f///8T///9P////3v///8f///8i////AP///wD///8A////AP///wD///84////3f///wH///8A////AP///wH////f////OP///wD///8A////AP///wD/////////MP///wD///8A////S/////T///8A////AP///wD///8A////AP///wD///8A////nv///7v///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP////////8w////AP///wD///8D////6v///5b///8A////AP///wD///8A////AP///wD/////////MP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////zD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///6P///+r////AP///wD///8A", + "////MP////////8A////AP///wD///8A////AP///wD/////////MP///wD///8A////AP///zD/////////AP///wD///8A////AP///wD///8A////AP///yD/////////EP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8B/////////yz///8A////AP///wD///8A////AP///wD///8A////AP///wD/////", + "////MP///wD///80////6P///yz///8A////AP///wD///8A////AP///wD///8A/////////zD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////8w////AP///9b///81////t////wD///8w/////////wD///8A////AP///wD/////////MP///wD///8I////3f///13/////////AP///wD///8A", + "////AP///wD///8A////qf///6L///8A////AP///wD///8A////o////6D///8A////AP///wD///8A////AP////////8w////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////QP////T///8Z////AP///wD///8A////AP///wD///8A/////////zD///8A////P////+X///8J", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9A////9P///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////MP///wD///8A////AP///wD///8A////AP///wD///8A////4P///23///8A////AP///wD///9Q////3////wD///8A////AP///wD///8A////AP///wD///8A", + "////CP///+3///8j////7P///wf///8A////AP///wD///8A////AP///wD///8A////AP///7r///9q////0v///wD///8A////AP///9n///9c////sf///wD///8A////AP///wD///+Z////k////wD///+j////o////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////MP///wD///8A////AP///wD///8A", + "////AP///wD///8p////+P///yL///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////yj///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///y/////q////Cv///wD///8A////AP///wD///8A////AP///wD///8A////KP////////8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///6z///9l////AP///1n///+0////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////u////4X///8N", + "////Lv////////8A////AP///wD///8A////AP///wD///8A////AP////////9E////AP///wD///9s////3f///wD///8A////AP///wD///8A////AP///wD////j////Xf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////4f///2b///8A////AP///0H/////////AP///wD///8A////AP///wD///8A", + "////AP///9////9X////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////yj///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////vf///2v///8O////Df///03////y////AP///wD///8A////AP///wD///8A////AP////////8o////AP///wD///8o/////////wD///8A", + "////AP///wD///8A////AP///wD///8A/////////yj///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////J////wD///8A////AP///wD///8A////AP///wD///8A////AP////////8u////qP///47///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////KP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////yj///8A////AP////////8o////AP///yj/////////AP///wD///8A////AP////////8o////AP///wD///8o/////////wD///8A////AP///wD///8A////AP///wD////a////aP///wD///8A////af///9n///8A////AP///wD///8A////AP///wD///8A", + "/////////yf///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8o/////////wD///8A////AP///wD///8A////AP///wD/////////KP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////d////+X///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD/////////KP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////7////Nf///wD///8A////Rv////////8A////AP///wD///8A////AP///wD///8A////AP///wD///+T////cP///3v///+I////AP///wD///8A////AP///wD///8A////AP///wD///8A////2P///zr////g", + "////Av///wH////c////O////9X///8A////AP///wD///8A////B////9f///+h////1P///wb///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////tP///3L///8A////AP///wD///8A////AP///wD///8A////AP///xj////m////Ff///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP////////8o////AP///wD///8A////AP///wD///8A////AP///wD///8A////9P///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8o/////////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///99////6v///4////8L////af///wD///8A////AP///wD///8A", + "////AP///wD///8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAA////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////n///82////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+t////zv///zz///8I////Mf///wD///8A////AP///wD///8A////AP///wD///8A////B/////////8W////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///+8////W////wD///9I////sv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////MP///wD///8A////AP///wD///8A////AP///wD///8A////9P///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////A////3v////U", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////gP///1P///8v////yP///9z////T////AP///1X///97////AP///wD///8A////AP///wD///8A////Av///+L///8A////AP///wD///8A////AP///wD///8A////AP///wD///+4", + "////H////7j///8f////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+A////U////wD/////////BP///8D///89////Vf///3v///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///+H///8l////Gf///9f///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////0////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///zH///+5////FP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////F////9////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////yT///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD////E////AP///8T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///6f///+m////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////o////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD////b////BP///wX////a////AP///wD///8A////AP///wD///8A////AP///wD///8A////H////7f///8f////t////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////uf///0b///8A////m////0T///8A////6P///wD///8A////AP///wD///8A////AP///7n///9G////AP///wD///8x", + "////uf///xT///8A////AP///wD///8A////AP///wD///8A////uf///0b///+b////RP///wD////o////AP///wD///8A////AP////j///8f////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////OP///93///8B////AP///wD///8B////3////zj///8A////AP///wD///8A////AP///zj////d", + "////Af///wD///8A////Af///9////84////AP///wD///8A////AP///wD///84////3f///wH///8A////AP///wH////f////OP///wD///8A////AP///wD///8A////OP///93///8B////AP///wD///8B////3////zj///8A////AP///wD///8A////AP///zj////d////Af///wD///8A////Af///9////84////AP///wD///8A", + "////AP///wD///84////3f///wH///8A////AP///wH////f////OP///wD///8A////AP///wD///8A////IP////L///8T////AP///wD/////////MP///wD///8A////AP///wD///8A////AP///wD///8A////AP///6f///+m////AP///wD///8A////AP///wD///8A////AP////////8w////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD/////////MP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////zD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////8w////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////IP////////8Q", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///yD/////////EP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8g/////////xD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////IP////////8Q////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP////////8w////AP///wD///8D////6v///5b///8A////AP///wD///8A////AP////////8w////AP///wj////d////Xf////////8A////AP///wD///8A////AP///wD///+p////ov///wD///8A////AP///wD///+j////oP///wD///8A////AP///wD///8A////qf///6L///8A////AP///wD///8A////o////6D///8A", + "////AP///wD///8A////AP///6n///+i////AP///wD///8A////AP///6P///+g////AP///wD///8A////AP///wD///+p////ov///wD///8A////AP///wD///+j////oP///wD///8A////AP///wD///8A////qf///6L///8A////AP///wD///8A////o////6D///8A////AP///wD///8A////AP///wD///84////4////2v////h", + "////Nf///wD///8A////AP///wD///8A////AP///wD///8l////+P///8////8F////Df///2v////x////JP///wD///8A////AP///wD///8A////4P///23///8A////AP///wD///9Q////3////wD///8A////AP///wD///8A////AP///+D///9t////AP///wD///8A////UP///9////8A////AP///wD///8A////AP///wD////g", + "////bf///wD///8A////AP///1D////f////AP///wD///8A////AP///wD///8A////4P///23///8A////AP///wD///9Q////3////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////MP///wD///8A////AP///wD///8A////AP///wD/////////9v///+v///+w////Hv///wD///8A////AP///wD///8A", + "////AP///wD///8A/////////yj///8A////AP///0H////y////AP///wD///8A////AP///wD///8A////AP///7v///+F////Df///y7/////////AP///wD///8A////AP///wD///8A////AP///wD///+7////hf///w3///8u/////////wD///8A////AP///wD///8A////AP///wD///8A////u////4X///8N////Lv////////8A", + "////AP///wD///8A////AP///wD///8A////AP///7v///+F////Df///y7/////////AP///wD///8A////AP///wD///8A////AP///wD///+7////hf///w3///8u/////////wD///8A////AP///wD///8A////AP///wD///8A////u////4X///8N////Lv////////8A////AP///wD///8A////AP///wD///8A////AP///7n///9x", + "////AP///wn/////////V////wD///8A////AP///wD///8A////AP///wD///8A////AP///6f///+m////AP///wD///8A////AP///wD///8A////AP///wD///8A////3////1f///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///9////9X////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD////f////V////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////3////1f///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////KP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////KP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP////////8o////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////KP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////q////Pv///wD///8A////Yv///9P///8A////AP///wD///8A////AP///wD///8A/////////yj///8A", + "////AP///yj/////////AP///wD///8A////AP///wD///8A////AP///9r///9o////AP///wD///9p////2f///wD///8A////AP///wD///8A////AP///wD////a////aP///wD///8A////af///9n///8A////AP///wD///8A////AP///wD///8A////2v///2j///8A////AP///2n////Z////AP///wD///8A////AP///wD///8A", + "////AP///9r///9o////AP///wD///9p////2f///wD///8A////AP///wD///8A////AP///wD////a////aP///wD///8A////af///9n///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///9r///95////3f///wv///9p////2f///wD///8A", + "////AP///wD///8A////AP///wD////7////Nf///wD///8A////Rv////////8A////AP///wD///8A////AP///wD///8A////+////zX///8A////AP///0b/////////AP///wD///8A////AP///wD///8A////AP////v///81////AP///wD///9G/////////wD///8A////AP///wD///8A////AP///wD////7////Nf///wD///8A", + "////Rv////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////tP///3L///8A////AP///wD///8A////AP///wD///8A////AP////////8n////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+0////cv///wD///8A////AP///wD///8A////AP///wD///8A", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////8f///xL///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD//////////////////////////////////////////////wD///8A////AP///wD///8A////AP///wD////g////PP///+////8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///3X///9u////3f///y3///80////1f///wD///8A////AP///wD///+q////qf///w3///+5////uv///wb///9k////x////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///8f///9q////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////b////8T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Tv////D///+p////0P///6j////v////Vf///wD///8A////AP///wD///8A////AP///3L////0////9P/////////0////9P///2P///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///5n///+J////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////6////yr///8A////Lf///+z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8g/////////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Bv///8H///+C////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8V////lv///67///8A////AP///wD///8A", + "////AP///wD///8A////AP///6z///95////DP///wz/////////Kv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9I////8f///wD///8A////AP///wD///8A////AP///wD///8A////9P///yn///8A////Kf////P///8A////AP///wD///8A////AP///wD///8A////AP///wD///8C////4v///0r///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///+u////ov///w7///+u////nv///wD///8A////AP///wD///8A////AP///wD///8A////MP///9b////m////jf///+D///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////DP///2/////K////k////zT///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///80////k////8r///9v////DP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD////5////J////wD///8A////AP///wD///8A////AP///wD///8A////AP///9X///8b////zf///2P///8A////af////////8u////qv///wD///8A////AP///wD///8A////AP///83////0////9P////T////0////zv///wD///8A////AP///wD///8A/////////zD///8A////D////6b///+9", + "////AP///wD///8A////AP///wD///8A////AP///9v///9i////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////MP///wD///8A////AP///5n////U////AP///wD///8A////AP///wD///8A/////////zD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////8w", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////c////W////wD///8A////AP///zD/////////AP///wD///8A////AP///wD///8A/////////zD///8A////AP///wD///8w/////////wD///8A////AP///wD///8A////AP///wD///8g/////////xD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP////////8w////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////zb///8a////4f///0f///8A////AP///wD///8A////AP///wD///8A////AP////////8w////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////MP///zf///+5////AP///7X///8d", + "////MP////////8A////AP///wD///8A/////////zD///8A////fP///6H///8u/////////wD///8A////AP///wD///8A////AP///+D///9a////AP///wD///8A////AP///1v////a////AP///wD///8A////AP///wD/////////9v///+n///+j////D////wD///8A////AP///wD///8A////AP///wD///8A////AP///zD///+5", + "////6P////7////d////MP///wD///8A////AP///wD///8A////AP////////8w////AP///73///9n////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8b////vf///77///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////zD///8A////AP///wD///8A////AP///wD///8A", + "////AP////7///8x////AP///wD///8A////MP////7///8A////AP///wD///8A////AP///wD///8A////AP///1P///+/////AP///7////9S////AP///wD///8A////AP///wD///8A////AP///wP////y////GP///9v///8i////AP///yn////J////G////+3///8B////AP///wD///8A////Dv///+D///99////6f///xP///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8X/////////0H///8A////AP///wD///8A////AP///wD///8A////AP///6T///+f////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////8o////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+n", + "////fP///wD///8A////AP///wD///8A////AP///wD///8A////AP///yj/////////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8n////3f///wf////T////MP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///yv///+b////3/////X/////////AP///wD///8A////AP///wD///8A////AP///wD/////////Lf///wD///8A////Pv////f///8A////AP///wD///8A////AP///wD///8A////+P///zv///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP////j///8+////AP///wD///8s/////////wD///8A////AP///wD///8A////AP///wD////3////9v////T////0////8////wD///8A////AP///wD///8A////AP///wD///8A////AP////////8o////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wb////H///////////////r", + "////av///wD///8A////AP///wD///8A////AP///wD/////////Kv///wD///8A////KP////////8A////AP///wD///8A////AP///wD///8A////AP////////8o////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////yj///8A////AP///wD///8A////AP///wD///8A////AP///wD/////", + "////yP///9f///8I////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////yj///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////8p////AP///wD/////////KP///wD///8o/////////wD///8A////AP///wD/////////Kv///wD///8A////KP////////8A////AP///wD///8A", + "////AP///wD///8A////9v///z3///8A////AP///z7////2////AP///wD///8A////AP///wD///8A////AP////////94////4f///+////+j////DP///wD///8A////AP///wD///8A////AP///wD///8P////pv////D////f////cf////////8A////AP///wD///8A////AP///wD///8A/////////yn///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8m////wP///+b///9F////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////yj///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////yj///8A////AP///yr/////////AP///wD///8A////AP///wD///8A////AP///wD///8G", + "////6////x////8l////5f///wP///8A////AP///wD///8A////AP///wD///8A////KP///+n///8B////s////0P///84////uP///wH////p////Jf///wD///8A////AP///wD///9U/////////1D///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///7/////S////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////gf///5L///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wH/////////J////wD///8A////AP///wD///8A////AP///wD///8A////AP////T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////J/////////8B////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////3////Kf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////6f///23///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD/////////IP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////8v///wP///8A////AP///9z///8A////AP///wD///8A////AP///wD///8A////B/////T////0//////////b////0////E////wD///8A////AP///wD///8A////AP////T///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Mv///9T////m////g////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///77///8A////yv///1L///8A////B////wD///8A////u////wD///8A", + "////AP///wD///+X////tf///7P///95////AP///wD///8A////AP///wD///8A////AP///wD///8A////UP///3z///9Q////fP///wD///8A////AP///wD///8A////AP///wD///8A////AP///3r////0////9P////T/////////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////vv///wD///8A/////////3D///+b////AP///wD///+7////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9J////2////9j///9H////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////9P///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Nv///7j///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////s////+n///9Z////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP////////+/////8v///97///9f////+////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////xP///wD////E////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////6P///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Xf///8X////F////V////wD///8A////AP///wD///8A////AP///wD///8A////AP///33///9P////ff///0////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////6P///yT////T", + "////B////wn///+5////E////+j///8A////AP///wD///8A////AP///+j///8k////0////wf///8A////AP///zb///+4////AP///wD///8A////AP///8j////N////1f///3D////T////Ef///7n///8T////6P///wD///8A////AP///wD////X////Vv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD////N////9P////T////0////9P///87///8A////AP///wD///8A////AP///wD///8A////zf////T////0////9P////T////O////AP///wD///8A////AP///wD///8A////AP///83////0////9P////T////0////zv///wD///8A////AP///wD///8A////AP///wD////N////9P////T////0////9P///87///8A", + "////AP///wD///8A////AP///wD///8A////zf////T////0////9P////T////O////AP///wD///8A////AP///wD///8A////AP///83////0////9P////T////0////zv///wD///8A////AP///wD///8A////AP///wD///+n////9/////T////0/////////zD///8A////AP///wD///8A////AP///wD///8a////of///9n////2", + "////8v///8T///8A////AP///wD///8A////AP///wD/////////MP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////zD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////8w////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////", + "////MP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///yD/////////EP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8g/////////xD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////IP////////8Q////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///yD/////////EP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////MP///wD///8A////AP///5n////U////AP///wD///8A////AP///wD/////////MP///wD///98////of///y7/////////AP///wD///8A////AP///wD///8A////4P///1r///8A////AP///wD///8A", + "////W////9r///8A////AP///wD///8A////AP///+D///9a////AP///wD///8A////AP///1v////a////AP///wD///8A////AP///wD////g////Wv///wD///8A////AP///wD///9b////2v///wD///8A////AP///wD///8A////4P///1r///8A////AP///wD///8A////W////9r///8A////AP///wD///8A////AP///+D///9a", + "////AP///wD///8A////AP///1v////a////AP///wD///8A////AP///wD///8A////AP///2z/////////Z////wD///8A////AP///wD///8A////AP///wD///8A////qv///6X////P////Vf///wD///8A////o////6D///8A////AP///wD///8A////AP////7///8x////AP///wD///8A////MP////7///8A////AP///wD///8A", + "////AP///wD////+////Mf///wD///8A////AP///zD////+////AP///wD///8A////AP///wD///8A/////v///zH///8A////AP///wD///8w/////v///wD///8A////AP///wD///8A////AP////7///8x////AP///wD///8A////MP////7///8A////AP///wD///8A////AP///wD///8A////AP///wD///8X/////////0H///8A", + "////AP///wD///8A////AP///wD///8A/////////zD///8J////of///7z///8A////AP///wD///8A////AP///wD///8A////AP////////8o////AP///xj////Y////k////wD///8A////AP///wD///8A////AP///wD///8r////m////9/////1/////////wD///8A////AP///wD///8A////AP///wD///8A////K////5v////f", + "////9f////////8A////AP///wD///8A////AP///wD///8A////AP///yv///+b////3/////X/////////AP///wD///8A////AP///wD///8A////AP///wD///8r////m////9/////1/////////wD///8A////AP///wD///8A////AP///wD///8A////K////5v////f////9f////////8A////AP///wD///8A////AP///wD///8A", + "////AP///yv///+b////3/////X/////////AP///wD///8A////AP///wD///8A////AP///wD///8p////mP///8j////O//////////b////0////9P////P///8A////AP///wD///8A////F////7v////2////tv///wD///8A////AP///wD///8A////AP///wD///8A////AP////f////2////9P////T////z////AP///wD///8A", + "////AP///wD///8A////AP///wD////3////9v////T////0////8////wD///8A////AP///wD///8A////AP///wD///8A////9/////b////0////9P////P///8A////AP///wD///8A////AP///wD///8A////AP////f////2////9P////T////z////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////yj///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////yj///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////KP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////yj///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////7f///z7///8A////AP///z3////1////AP///wD///8A////AP///wD///8A////AP////////8q////AP///wD///8o/////////wD///8A////AP///wD///8A////AP///wD////2////Pf///wD///8A////Pv////b///8A////AP///wD///8A////AP///wD///8A////9v///z3///8A////AP///z7////2////AP///wD///8A", + "////AP///wD///8A////AP////b///89////AP///wD///8+////9v///wD///8A////AP///wD///8A////AP///wD////2////Pf///wD///8A////Pv////b///8A////AP///wD///8A////AP///wD///8A////9v///z3///8A////AP///z7////2////AP///wD///8A////AP///wD///8A////AP///27////0////9P////T////0", + "////9P///2b///8A////AP///wD///8A////AP///wD////2////OP///4z///+P////PP////b///8A////AP///wD///8A////AP///wD///8A/////////yj///8A////AP///yr/////////AP///wD///8A////AP///wD///8A////AP////////8o////AP///wD///8q/////////wD///8A////AP///wD///8A////AP///wD/////", + "////KP///wD///8A////Kv////////8A////AP///wD///8A////AP///wD///8A/////////yj///8A////AP///yr/////////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///7/////S////AP///wD///8A////AP///wD///8A////AP///wD/////////eP///+H////v////o////wz///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////v////9L///8A////AP///wD///8A////AP///wD///8A////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////T///8f////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///yD////M////AP///wz////c////AP///wD///8A", + "////AP///wD///8A////AP///wD///8f////9v///+n///9r////AP///wD///8A////AP///wD///8A////AP///wD///9M////3v///9////9Y////z////1v////f////3v///0n///8A////AP///wD///8A////Cf///5r////0////2P///wv///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD////v////Qv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///0X////r////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wf///8F////AP///8P///8A////BP///wn///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD////0////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8j////7v///w////8A////AP///wD///8A////AP///wD///8A////AP////v///8i////AP///yP////6////AP///wD///8A////AP///wD///8A////AP///wD///8A////IP////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8T////4v///0L///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD////8/////////5j///8G////AP///wD///8A////AP///wD///8A////AP///wD///8X////4f///x////8A/////////yD///8A////AP///wD///8A////AP///wD///8A////Ef///wT///8z////v////7H///8A////AP///wD///8A////AP///wD///8A////AP////r///+M", + "////Af///3z////A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///4L///+p////AP///wD///8A////AP///wD///8A////AP///wD///8A////Fv///+z////2////2P///wn///8A////AP///wD///8A////AP///wD///8A////AP///8D///94////AP///4b////3////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////A////1T////G////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////xv///1P///8D////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////ov///7f///8F////AP///wD///8A////AP///wD///8A////AP///wD////x////Af////f///8U////AP///w7/////////A////+L///8A////AP///wD///8A////AP///wD///9k", + "////rv///wD///8A////q////2X///8A////AP///wD///8A////AP/////////2////9f////////++////EP///wD///8A////AP///wD///8A////AP///wD////2////SP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////zD///8A////AP///wD///9Q////9f///wD///8A////AP///wD///8A", + "////AP/////////2////9P////T////0////AP///wD///8A////AP///wD///8A////AP///wD/////////9v////T////0////9P///wD///8A////AP///wD///8A////AP///wD///8A////9////0f///8A////AP////T////2/////////wD///8A////AP///wD///8A////AP/////////2////9P////T////0////9v////////8A", + "////AP///wD///8A////AP///wD///8A////IP////////8Q////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////MP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////+f////zv///2n///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////MP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////zD///+V////XP///wD///9X////fP///zD/////////AP///wD///8A////AP////////8w////G////+j///8Z////MP////////8A////AP///wD///8A////AP///wD////4////Rv///wD///8A////AP///wD///9H////9v///wD///8A////AP///wD///8A", + "/////////zD///8Q////u////53///8A////AP///wD///8A////AP///wD///8A////AP///y3////0////a////w3///8N////a////+////8q////AP///wD///8A////AP///wD/////////9v////j/////////gf///wj///8A////AP///wD///8A////AP///wD///8A////AP///w3///+Y////+P///63///8X////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP////////8w////AP///wD///8A////AP///wD///8A////AP///wD/////////MP///wD///8A////AP///zD/////////AP///wD///8A////AP///wD///8A////AP///wD///+s////bf///wD///9u////q////wD///8A////AP///wD///8A////AP///wD///8y////5f///wD///+L", + "////cv///wD///93////fP///wD////o////K////wD///8A////AP///wD///9W/////////2b///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////n////9b///++////AP///wD///8A////AP///wD///8A////AP///wD///8l////+P///yT///8A////AP///wD///8A////AP///wD///8A////AP///wD/////", + "////KP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8j////7////xD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8o/////////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///5z///+1////qv///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8o/////v///wD///8A////AP///wD///8A////AP///wD///8A/////////0L///8A////AP///2r////d", + "////AP///wD///8A////AP///wD///8A////AP///+L///9f////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////g////av///wD///8A////Rf////////8A////AP///wD///8A////AP///wD///8A////3v///1r///8A////Pf///+f///8A////AP///wD///8A////AP///wD///8A////AP///wD/////", + "////KP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////9f///xL///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////0f///8A////AP///zX////0////AP///wD///8A////AP///wD///8A////AP///wD/////////KP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP////////8o////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////0v////d////Gv///wD///8A////AP///wD///8A////AP///wD///8A////AP////////8o////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////Pv///wD///8K/////////zj///8A", + "////Mv////b///8A////AP///wD///8A/////////0f///8A////AP///zX////0////AP///wD///8A////AP///wD///8A////AP///93///9n////AP///wD///9q////1////wD///8A////AP///wD///8A////AP///wD/////////t////w7///8u////zf///4z///8A////AP///wD///8A////AP///wD///8A////kv///8f///8r", + "////Df///6//////////AP///wD///8A////AP///wD///8A////AP////////9N////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////1v///5j///8K////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////8o////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP////////8o////AP///wD///8o/////////wD///8A////AP///wD///8A////AP///wD///8A////Uv///8f///8A////AP///83///9L////AP///wD///8A////AP///wD///8A////AP///3j///+l////AP///1j///+Y////if///2P///8A////ov///3b///8A////AP///wD///8C////xf///8L////C////Av///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///yP////Z////2////zH///8A////AP///wD///8A////AP///wD///8A////AP///wz////j////I////wD///8A////AP///wD///8A////AP///wD///8A////AP///wz///9t////7v///wf///8A////AP///wD///8A////AP///wD///8A////AP///wD////0////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wf////u////bf///wz///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////9P///xv///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////r///8/////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////o/////////+v////o////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///7r///9e////AP///0r////B////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////rv///6/////R////Af///wD///8A////AP///wD///8A////AP///wD////0////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///9r///97////JP///+v///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///+0////AP////b///8M////AP///wD///8A////AP///7P///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+V////AP///5X///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///7T///8A////AP/////////O////o////wD///8A////s////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///3L////0////9P/////////0////9P///2P///8A////AP///wD///8A////AP///wD///8k////A////wr////o////AP///wD///8A////AP///wD///8A////AP///wD///8A////GP///wH///8q////1P///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////m////w////8W////v/////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///8T///8A////xP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////ff///+X///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+U", + "////AP///5T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///+j///8A////gP///3////8A////KP///5b////l////AP///wD///8A////AP///wD////o////AP///4D///9/////JP///wP///8K////6P///wD///8A////AP///wD///8P////AP///yD////h////gP///3////8o////lv///+X///8A", + "////AP///wD///8A////U////+3///8o////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////ZP///67///8A////AP///6v///9l////AP///wD///8A////AP///wD///8A////AP///2T///+u////AP///wD///+r////Zf///wD///8A////AP///wD///8A////AP///wD///9k////rv///wD///8A", + "////q////2X///8A////AP///wD///8A////AP///wD///8A////ZP///67///8A////AP///6v///9l////AP///wD///8A////AP///wD///8A////AP///2T///+u////AP///wD///+r////Zf///wD///8A////AP///wD///8A////AP///wD///9k////rv///wD///8A////q////2X///8A////AP///wD///8A////AP///wD///8A", + "////Mv///+b///8G////AP/////////2////9P////T////0////AP///wD///8c////7////53///8j////Av///w3///9E////AP///wD///8A////AP///wD///8A//////////b////0////9P////T///8A////AP///wD///8A////AP///wD///8A////AP/////////2////9P////T////0////AP///wD///8A////AP///wD///8A", + "////AP///wD/////////9v////T////0////9P///wD///8A////AP///wD///8A////AP///wD///8A//////////b////0////9P////T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8g/////////xD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////IP////////8Q////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///yD/////////EP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8g/////////xD///8A////AP///wD///8A////AP///wD///8A////AP///wD////0//////////b////0////AP///wD///9Q////9f///wD///8A////AP///wD///8A/////////zD///8b", + "////6P///xn///8w/////////wD///8A////AP///wD///8A////AP////j///9G////AP///wD///8A////AP///0f////2////AP///wD///8A////AP///wD////4////Rv///wD///8A////AP///wD///9H////9v///wD///8A////AP///wD///8A////+P///0b///8A////AP///wD///8A////R/////b///8A////AP///wD///8A", + "////AP////j///9G////AP///wD///8A////AP///0f////2////AP///wD///8A////AP///wD////4////Rv///wD///8A////AP///wD///9H////9v///wD///8A////AP///wD///8A////AP///zn////k////a////+L///84////AP///wD///8A////AP///wD///8A////AP///9z///9Z////M////+T///8R////AP///1v////a", + "////AP///wD///8A////AP///wD/////////MP///wD///8A////AP///zD/////////AP///wD///8A////AP///wD///8A/////////zD///8A////AP///wD///8w/////////wD///8A////AP///wD///8A////AP////////8w////AP///wD///8A////MP////////8A////AP///wD///8A////AP///wD/////////MP///wD///8A", + "////AP///zD/////////AP///wD///8A////AP///wD///8A////AP///wD///8A////n////9b///++////AP///wD///8A////AP///wD///8A////AP////////8w////AP///1D////1////AP///wD///8A////AP///wD///8A////AP///wD/////////KP///wD////D////rf///wX///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////KP////7///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///yj////+////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8o/////v///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////KP////7///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///yj////+////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8o/////v///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////A/////3///9W////AP///z3////n////AP///wD///8A////AP///57///+9////IP///zL///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD////e////Wv///wD///89////5////wD///8A////AP///wD///8A////AP///wD///8A////3v///1r///8A////Pf///+f///8A////AP///wD///8A////AP///wD///8A////AP///97///9a////AP///z3////n////AP///wD///8A////AP///wD///8A////AP///wD////e", + "////Wv///wD///89////5////wD///8A////AP///wD///8A////AP///wD///8A////AP////////8o////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////8o////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////yj///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP////////8o////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///6r///+t////Df///xD///+x////6P///wD///8A////AP///wD///8A////AP///wD/////////R////wD///8A////Nf////T///8A////AP///wD///8A////AP///wD///8A////3f///2f///8A////AP///2r////X", + "////AP///wD///8A////AP///wD///8A////AP///93///9n////AP///wD///9q////1////wD///8A////AP///wD///8A////AP///wD////d////Z////wD///8A////av///9f///8A////AP///wD///8A////AP///wD///8A////3f///2f///8A////AP///2r////X////AP///wD///8A////AP///wD///8A////AP///93///9n", + "////AP///wD///9q////1////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////3f///2f///8L////3P///43////a////AP///wD///8A////AP///wD///8A////AP////////8o////AP///wD///8o/////////wD///8A////AP///wD///8A", + "////AP///wD/////////KP///wD///8A////KP////////8A////AP///wD///8A////AP///wD///8A/////////yj///8A////AP///yj/////////AP///wD///8A////AP///wD///8A////AP////////8o////AP///wD///8o/////////wD///8A////AP///wD///8A////AP///wD///8A////AP///yP////Z////2////zH///8A", + "////AP///wD///8A////AP///wD///8A/////////7f///8O////Lv///83///+M////AP///wD///8A////AP///wD///8A////AP///wD///8A////I////9n////b////Mf///wD///8A////AP///wD///8A////AP///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////3////Lf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////4v///wn///8A////1f///xX///8A////AP///wD///8A////AP///wD///9o////6v///+z///8l////AP///wD///8A////AP///wD///8A////AP///wD///8A////2P///y3///80////2P///2////90////AP///wD///8A////AP///wD///8A////AP///wD///98", + "////2P///9z///9b////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////+////zf///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///84////+v///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD////r////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////9P///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///6f///96////AP///wD///8A////AP///wD///8A////AP///wD////v////Kv///wD///8t////6v///wD///8A////AP///wD///8A////AP///wD///8A////AP///x//////", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///2H////B////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///x3///+u////i////wD///8A////AP///wD///8A////AP///wD///8A////AP///17///+5////AP////////8g////AP///wD///8A////AP///wD///8A", + "////AP////H////x////9P///7L///8a////AP///wD///8A////AP///wD///8A////AP///wD////i////i////+X////V////L////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8h////9v///xD///8A////AP///wD///8A////AP///wD///8A////AP///5n///+z////I////7X///+N////AP///wD///8A", + "////AP///wD///8A////AP///wD////z////Kf///wD///8i////9P///wD///8A////AP///wD///8A////AP///wD///8A////Uv////f///9R////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wb///+0////kv///wD///8A////AP///wD///8A////AP///wD///8A", + "////2////xL////i////I////wD///8A////8P///w/////q////AP///wD///8A////AP///wD///8A////Cv///+n///8S////Ef///+n///8L////AP///wD///8A////AP///wD/////////MP///wD///8U////nf///6D///8A////AP///wD///8A////AP///wD///8A////2f///2X///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP////////8w////AP///wD///8A////Y////9n///8A////AP///wD///8A////AP///wD/////////MP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////zD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///9r///9i////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD/////////MP///wD///8A////AP///zD/////////AP///wD///8A////AP///wD///8A////AP///yD/////////EP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////zD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////", + "////Mv///6H///9m////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////zD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////81////4P///wr///8A////B////8v///8x/////////wD///8A////AP///wD/////////Lf///6T///94////AP///zD/////////AP///wD///8A", + "////AP///wD///8A////4P///1r///8A////AP///wD///8A////W////9v///8A////AP///wD///8A////AP////////8w////AP///1P////q////AP///wD///8A////AP///wD///8A////AP///wD///+p////ov///wD///8A////AP///wD///+j////o////wD///8A////AP///wD///8A/////////zD///8A////Gf///7L///+r", + "////AP///wD///8A////AP///wD///8A////AP///wD///+v////yP///yn///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////MP///wD///8A////AP///wD///8A////AP///wD///8A/////////zD///8A////AP///wD///8w/////////wD///8A////AP///wD///8A////AP///wD///8O", + "////9v///x3///8A////Hf////b///8N////AP///wD///8A////AP///wD///8A////bv///7L///8A////Ov///8H///8A////xf///zD///8A////tv///2n///8A////AP///wD///8B////tv///9z///+9////Av///wD///8A////AP///wD///8A////AP///wD///8A////Nv///+z///8V////1////0z///8A////AP///wD///8A", + "////AP///wD///8A////AP///6D///+j////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////yj///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////mf///4r///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////KP////////8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8c////9P///yj///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////MP///yX///8B", + "////c////93///8A////AP///wD///8A////AP///wD///8A////AP////////+z////Dv///y3////K////jP///wD///8A////AP///wD///8A////AP///wD///+c////wP///yP///8o////AP///wD///8A////AP///wD///8A////AP///wD///8A////kP///8z///8v////Ef///7j/////////AP///wD///8A////AP///wD///8A", + "////AP///4z///+7////E////5P///+j////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////yj///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////NP///+/////5////zv///zH///8A////AP///wD///8A////AP///wD///8A////AP/////////A////Gf///xD///+c////pv///wD///8A", + "////AP///wD///8A////AP///wD///8A/////////yj///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////KP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////8n////aP///8v///8J////AP///wD///8A////AP///wD///8A////AP///wD/////////KP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////6b///8J////ZP////r///+a////Cf///4X///+3////AP///wD///8A////AP////////+/////Gf///xD///+c////pv///wD///8A////AP///wD///8A////AP///wD///+D////yf///y////8w////y////3j///8A////AP///wD///8A////AP///wD///8A", + "/////////0T///8A////AP///2z////d////AP///wD///8A////AP///wD///8A////AP///+H///9m////AP///wD///9B/////////wD///8A////AP///wD///8A////AP///wD/////////vf///y7///8R////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////D///9R////CP///zD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD/////////KP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////KP///wD///8A////KP////////8A////AP///wD///8A////AP///wD///8A////AP///7H///9x////AP///wD///91////rf///wD///8A////AP///wD///8A////AP///wD////I////YP///wD///8K", + "////1f///9H///8S////AP///1n////G////AP///wD///8A////eP///8X///8E////xv///3X///8A////AP///wD///8A////AP///wD///8A////AP///wD///+F////kf///47///+R////AP///wD///8A////AP///wD///8A////AP///wD///8A////av///6j///8A////AP///wD///8A////AP///wD///8A////AP///wD////+", + "////7f///zj///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////9P///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Of///+7////+////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////H///8O////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////n////cP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////8g////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///+3////vv///+L///+9////sP///wD///8A////AP///wD///8A////AP///wD///8A////Mv///+f///8J////z////07///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////0////IP///1X////p", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////vv///wD////L////U////wD///8P////AP///wD///+7////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///++////AP///wD/////////GP////H///8A////AP///7v///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////0////AP///wD///8A////AP///wD///8A////AP///wD///8A////gv///8/////V////bv///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///5L////U////zP///4////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////zX///8A////AP///0b/////////AP///wD///8A////AP///wD///8A////AP///wL///9i", + "////pP///6b////E////AP///8T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///1b////l////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////o////AP///wj////T////JP///wD///9b////5v///wD///8A////AP///wD///8A////6P///wD///8I////0////6b////P", + "////1f///27///8A////AP///wD///8A////AP///wD///8X////3////wj////T////JP///1v////m////AP///wD///8A////AP///wD///+P////wf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wr////p////Ev///xH////p////C////wD///8A////AP///wD///8A////AP///wD///8K", + "////6f///xL///8R////6f///wv///8A////AP///wD///8A////AP///wD///8A////Cv///+n///8S////Ef///+n///8L////AP///wD///8A////AP///wD///8A////AP///wr////p////Ev///xH////p////C////wD///8A////AP///wD///8A////AP///wD///8K////6f///xL///8R////6f///wv///8A////AP///wD///8A", + "////AP///wD///8A////Cv///+n///8S////Ef///+n///8L////AP///wD///8A////AP///wD///8A////AP///wD///+9////Xv///wD/////////MP///wD///8A////AP///wD///8A////nv///7v///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////8w////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD/////////MP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////zD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////8w////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////IP////////8Q", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///yD/////////EP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8g/////////xD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////IP////////8Q////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP////////8w////AP///wD///8A////Y////9n///8A////AP///wD///8A////AP////////8t////pP///3j///8A////MP////////8A////AP///wD///8A////AP///wD////g////Wv///wD///8A////AP///wD///9b////2////wD///8A////AP///wD///8A////4P///1r///8A////AP///wD///8A////W////9v///8A", + "////AP///wD///8A////AP///+D///9a////AP///wD///8A////AP///1v////b////AP///wD///8A////AP///wD////g////Wv///wD///8A////AP///wD///9b////2////wD///8A////AP///wD///8A////4P///1r///8A////AP///wD///8A////W////9v///8A////AP///wD///8A////AP///wn////Z////Of///wD///82", + "////2P///wr///8A////AP///wD///8A////AP///wD////3////Rv///wD///+M////nv///wD///9K////9v///wD///8A////AP///wD///8A/////////zD///8A////AP///wD///8w/////////wD///8A////AP///wD///8A////AP////////8w////AP///wD///8A////MP////////8A////AP///wD///8A////AP///wD/////", + "////MP///wD///8A////AP///zD/////////AP///wD///8A////AP///wD///8A/////////zD///8A////AP///wD///8w/////////wD///8A////AP///wD///8A////AP///wD///8A////Nv///+z///8V////1////0z///8A////AP///wD///8A////AP///wD/////////MP///xj///+u////0P///wD///8A////AP///wD///8A", + "////AP///wD///8A/////////yj///8A////+f///yX///8A////AP///wD///8A////AP///wD///8A////AP///zD///8l////Af///3P////d////AP///wD///8A////AP///wD///8A////AP///wD///8w////Jf///wH///9z////3f///wD///8A////AP///wD///8A////AP///wD///8A////MP///yX///8B////c////93///8A", + "////AP///wD///8A////AP///wD///8A////AP///zD///8l////Af///3P////d////AP///wD///8A////AP///wD///8A////AP///wD///8w////Jf///wH///9z////3f///wD///8A////AP///wD///8A////AP///wD///8A////MP///yX///8B////c////93///8A////AP///wD///8A////AP///wD///8A////AP///0L///8d", + "////AP///1X////8////uP///xP///+U////o////wD///8A////AP///wD////j////Xf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////jP///7v///8T////k////6P///8A////AP///wD///8A////AP///wD///8A////AP///4z///+7////E////5P///+j////AP///wD///8A////AP///wD///8A", + "////AP///wD///+M////u////xP///+T////o////wD///8A////AP///wD///8A////AP///wD///8A////jP///7v///8T////k////6P///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////KP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////KP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP////////8o////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////KP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8W////q////+7////h////wP///7j///8A////AP///wD///8A////AP///wD///8A/////////7////8Z", + "////EP///5z///+m////AP///wD///8A////AP///wD///8A////AP///4P////J////L////zD////L////eP///wD///8A////AP///wD///8A////AP///wD///+D////yf///y////8w////y////3j///8A////AP///wD///8A////AP///wD///8A////g////8n///8v////MP///8v///94////AP///wD///8A////AP///wD///8A", + "////AP///4P////J////L////zD////L////eP///wD///8A////AP///wD///8A////AP///wD///+D////yf///y////8w////y////3j///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///4P////J////Lv///1X/////////fv///wD///8A", + "////AP///wD///8A////AP///wD/////////KP///wD///8A////KP////////8A////AP///wD///8A////AP///wD///8A/////////yj///8A////AP///yj/////////AP///wD///8A////AP///wD///8A////AP////////8o////AP///wD///8o/////////wD///8A////AP///wD///8A////AP///wD/////////KP///wD///8A", + "////KP////////8A////AP///wD///8A////AP///wD///8A////AP///wD///+F////kf///47///+R////AP///wD///8A////AP///wD///8A////AP////////9E////AP///wD///9s////3f///wD///8A////AP///wD///8A////AP///wD///8A////AP///4X///+R////jv///5H///8A////AP///wD///8A////AP///wD///8A", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////+f///zr///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////g////4P////n////k////4P////b////m////4P///wD///8A////AP///wD///8A////7////zz////g////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP////P///8B////Av////P///8H////z////wz///8A////AP///wD///8A////AP///wD///8A////6v///0b///9J////4f///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///+z///9Y////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////Wv///+n///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///3L///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8v////6P///wn///8A////AP///wD///8A////AP///wD///8A", + "////0v///0j///8A////Tv///8n///8A////AP///wD///8A////AP///wD///8A////AP///6b///89/////////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8q////9P///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Lv////H///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////tv///17////5////IP///wD///8A////AP///wD///8A////AP///wD////i////Lf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////q////1z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///7z///9o", + "////AP///wD///8A////AP///wD///8A////AP///wD////0////Lv///wD///8w////8v///wD///8A////AP///wD///8A////AP///wD///8A////6v///zH///8A////Of///9X///8A////AP///wD///8A////AP///wD///8A////AP///1T////3////U////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9S", + "////9////1H///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////Kv////H///8A////AP///wD///8A////AP///wD///8A////AP///67///9F////h////6D///8B////AP///+P///84////zv///wD///8A////AP///wD///8A////AP///wD///+R////aP///2j///+T////AP///wD///8A////AP///wD///8A/////////zD///8A////AP///0H////0", + "////AP///wD///8A////AP///wD///8A////AP///5f////D////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////MP///wD///8A////AP///7P///+f////AP///wD///8A////AP///wD///8A/////////zD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////8w", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+a////uP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////zD///8A////AP///wD///8w/////////wD///8A////AP///wD///8A////AP///wD///8g/////////xD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP////////8w////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////zD///8C////nv///37///8A////AP///wD///8A////AP///wD///8A////AP////////8w////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////eP///6H///8A////AP///wD///+W", + "////a/////////8A////AP///wD///8A/////////1z////b////B////wD///8w/////////wD///8A////AP///wD///8A////AP///6r///+h////AP///wD///8A////AP///6L///+i////AP///wD///8A////AP///wD/////////MP///wD///9f////8f///wD///8A////AP///wD///8A////AP///wD///8A////4P///1r///8A", + "////AP///wD///8A////W////+P///8A////AP///wD///8A////AP////////8w////AP///wD///9O////7P///wD///8A////AP///wD///8A////AP///wD///8A////9f///z7///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////zD///8A////AP///wD///8A////AP///wD///8A", + "////AP////////8w////AP///wD///8A////MP////////8A////AP///wD///8A////AP///wD///8A////YP///8v///8A////AP///wD////L////X////wD///8A////AP///wD///8A////AP///6r///9/////AP///wH////j////Jv///+D///8A////AP///4P///+m////AP///wD///8A////cf///9H///8L////wv///3b///8A", + "////AP///wD///8A////AP///wD///8A////Af///8n///9w////AP///1X////X////BP///wD///8A////AP///wD///8A////AP///wD///8i////+P///yj///8A////AP///wD///8A////AP///wD///8A////AP////////8o////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Gf////H///8Z", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///yj/////////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///1/////V////8////9v///9K////AP///wD///8A////AP///wD///8A////AP///wD/////////dv///+H////v////ov///wz///8A////AP///wD///8A////AP///wD///8A////F////7j////0////wv///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///w3///+i////7v///93///91/////////wD///8A////AP///wD///8A////AP///wD///8N////p////+7///+8////GP///wD///8A////AP///wD///8A////AP///wD///8A////qf/////////a////1P///wD///8A////AP///wD///8A////AP///wD///8A////AP///9L///+N////Df///43////N", + "////AP///wD///8A////AP///wD///8A////AP///wD/////////bf///9n////s////p////y3///8A////AP///wD///8A////AP///wD///8A////AP////////8o////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////yj///8A////AP///wD///8A////AP///wD///8A////AP///wD/////", + "////KP///wD///+l////qP///wD///8A////AP///wD///8A////AP///wD///8A/////////yj///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////z///9h////6P///+L///9f////cP///+r////G////P////wD///8A////AP///wD////8////Uv///9n////s////p////y3///8A////AP///wD///8A", + "////AP///wD///8A////B////47////m////5v///4n///8F////AP///wD///8A////AP///wD///8A////AP////////8r////AP///wD///8+////9////wD///8A////AP///wD///8A////AP///wD////4////Pv///wD///8A////LP////////8A////AP///wD///8A////AP///wD///8A////+v///zX////W////6f///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///9h////5v///+3///+W////AP///wD///8A////AP///wD///8A////AP///wD///+2/////////9r////K////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////yj///8A////AP///yj/////////AP///wD///8A////AP///wD///8A////AP///xX////5", + "////HP///wD///8A////Hf////j///8V////AP///wD///8A////AP///wD///8Z/////f///xr///8A////AP///6L///+3////AP///wD///8T////+////xn///8A////Lv////L///8p////AP///yn////y////Lv///wD///8A////AP///wD///8A////AP///wD///8D////5P///zn///80////6////wX///8A////AP///wD///8A", + "////AP///wD///+l////1P///9j////+////AP///wD///8A////AP///wD///8A////AP///wD///8A////Fv///3f////r////Bv///wD///8A////AP///wD///8A////AP///wD///8A////AP////T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Bv///+v///9f////Cf///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////zv///8n///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///7b///9C////AP///7b///9C////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////7v///zP///8V/////////xL///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A/////////xT///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8P////7f///zv///8A////AP///yP////E////9P///8X///8l////AP///wD///8A////AP///wD///8H////g////97////5////4f///47///8S////Q/////j///+M////AP///wD///8A////AP///wD///8A", - "////tv///0L///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8E////x////6z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+p////yf///wT///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///27///+4////AP///wD///+x////dv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8w////CP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////O////Xv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////UP///1D///9Q////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///1L////3////Uf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8T////9////1z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///zP///++////7////7////84////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////9g////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////////////////////////////////////dP///wD///8A////AP///wD///8A////AP///wD///8A", - "////j////93////3////6////8H///9K////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////9g////AP///wD///8A////AP///wD///8A////AP///wD///+Z////4P////z////o////vf///0H///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///yv///++////8v///9j///9q////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///xH////0////e////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8G////f////9v////2////2P///2////8B////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////HP////f////y////zP///2T///8B////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///1L////3////Uf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////O////Xv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///8+////v////wD///8A////AP///wD///8A////AP///wD///8A////AP///yH///8s////LP///yz///8s////LP///yz///8A////AP///wD///8A////AP///wD///8A////AP///wD///+/////Pv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD////O////yf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Hv///5r////L////8////+7////O////hf///wD///8A////AP///wD///8A////AP///wD///8U////+v///2f///8A////AP///wD///8A////AP///wD///9r////+v///xT///8A////AP///wD///8A", - "/////////////////////////+/////G////T////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Jv///5/////L////8/////n////i////rf///wD///8A////AP///wD///8A////AP///wD////////////////////v////yf///5f///8a////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////////////////////////////////////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////90////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///x////+a////y/////T////7////6f///8T///+O////AP///wD///8A////AP///wD///8A", - "/////////3T///8A////AP///wD///8A////dP////////8A////AP///wD///8A////AP///wD///8A////AP///2b////7//////////////+W////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////t////9f///8b///84////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "/////////3T///8A////AP///wD///8A////t////93///8L////AP///wD///8A////AP///wD///8A////AP///////////////////////////////////6D///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////dP///wD///8A////Wf////////8q////AP///wD///90/////////wD///8A////AP///wD///8A", - "/////////3T///8A////AP///wD///8A////Gf////P/////////AP///wD///8A////AP///wD///8A////AP///wD///8A////WP///7f////n////5////7X///9O////AP///wD///8A////AP///wD///8A////AP///wD/////////dP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///8A////AP///2b///+b////AP///wD///8A////AP///wD///8A////AP////////90////AP///wD///8A////Af///8T////f////DP///wD///8A////AP///wD///8A////AP///wD///8T////qP///+L////3////7P///8T///9U////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8g/////////1T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8v////t////+r////m////sv///yn///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Y/////////9m////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////a/////////9I////AP///wD///8A////WP////////9c////AP///wD///8A////AP///w7////q////fP///wD///8A////AP///wD///+k////6////w7///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////IP////////9U////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "//////////////////////////////////////////////8A////AP///wD///8A////AP///wD///8A////AP///////////////////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///33////j////A////wD///8A////AP///wD///8A////AP///wD///8A", - "////////////////////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///7X///+3////AP///wD///8A////AP///wD///+1////t////wD///8A////AP///wD///8A////AP///wD///8Y////GP///xj///8Y////GP///xj///8Y////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///2D////W////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///y3////D////9v///+z///+Z////L/////////8A////AP///wD///8A////AP///wD///8A////AP///wD/////////PP///6z////1////2v///2L///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///z/////E////8v///+7///+X////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9m////2v////X///+t////Sv////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////LP///7j////s////+f///9L///9W////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP////////9s////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///yH///+o////5v////n////p////x////2n///8C////AP///wD///8A////AP///wD///8A////AP///wD/////////bP///wD///8A////AP///2z/////////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP////////9s////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///+7////s////gv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////bP///wD///8A////Av///73////V////Cv///wD///8A////AP///wD///8A////AP///wD///8A", - "/////////2z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////9s////AP///wD///8A////wP///6z///8A////AP///wD///9s/////////wD///8A////AP///wD/////////bP///wD///8A////AP///2z/////////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///0H////K////8////8v///9F////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////9s////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///2z/////////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "/////////2z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///w////+4////7/////L///+6////Jf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////NP///9P////7////4f///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////F////6z////u////8P///5////9H/////////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///x3////9////+v///xX///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wT////x////7v///wX///8A////AP///wn////0////8f///wT///8A////AP///wD///8A", - "////p////+T///8P////AP///wD///8Q////5f///6f///8A////AP///wD///8A////AP///wD///8A////AP///xj////y////8f///6z///8W////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///////////////////////////////////8k////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8l////t/////H///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////8s////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////x////tf///yP///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////qv///9L///9D////CP///yj///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD/////////If///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///7b///9z////AP///1v////J////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////iv///8b////v////U////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///37///9W////L////8j////c////s////wD///9Z////ef///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////fv///1b///8A/////////9j///97////AP///1n///95////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////9P///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP////////8o////AP///wD///8q/////////wD///8A////AP///wD///8A////AP///wD///96////////////////////xP///wD////E////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////6P///wD///8A", + "////R////7j///8A////AP///wD///8A////AP///wD///8A////AP///+j///8A////AP///0f///+4////AP///wD///8A////AP///wD///8A////AP///wD///+z////6f///1n///8A////R////7j///8A////AP///wD///8A////AP///wD///8A////Iv////r///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////kf///2j///9o////k////wD///8A////AP///wD///8A////AP///wD///8A////AP///5H///9o////aP///5P///8A////AP///wD///8A////AP///wD///8A////AP///wD///+R////aP///2j///+T////AP///wD///8A////AP///wD///8A////AP///wD///8A////kf///2j///9o////k////wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///5H///9o////aP///5P///8A////AP///wD///8A////AP///wD///8A////AP///wD///+R////aP///2j///+T////AP///wD///8A////AP///wD///8A////AP///wD///8A////SP///8////8A/////////zD///8A////AP///wD///8A////AP///9v///9i////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD/////////MP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////zD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////8w////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////", + "////MP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///yD/////////EP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8g/////////xD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////IP////////8Q////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///yD/////////EP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////MP///wD///8A////AP///7P///+f////AP///wD///8A////AP///wD/////////XP///9v///8H////AP///zD/////////AP///wD///8A////AP///wD///8A////qv///6H///8A////AP///wD///8A", + "////ov///6L///8A////AP///wD///8A////AP///6r///+h////AP///wD///8A////AP///6L///+i////AP///wD///8A////AP///wD///+q////of///wD///8A////AP///wD///+i////ov///wD///8A////AP///wD///8A////qv///6H///8A////AP///wD///8A////ov///6L///8A////AP///wD///8A////AP///6r///+h", + "////AP///wD///8A////AP///6L///+i////AP///wD///8A////AP///wD///8A////Cf///wD///8A////AP///wn///8A////AP///wD///8A////AP///wD///8A////4P///1r///8A////Cv///9z///9D////eP///9j///8A////AP///wD///8A////AP////////8w////AP///wD///8A////MP////////8A////AP///wD///8A", + "////AP///wD/////////MP///wD///8A////AP///zD/////////AP///wD///8A////AP///wD///8A/////////zD///8A////AP///wD///8w/////////wD///8A////AP///wD///8A////AP////////8w////AP///wD///8A////MP////////8A////AP///wD///8A////AP///wD///8A////Af///8n///9w////AP///1X////X", + "////BP///wD///8A////AP///wD///8A//////////b////z////xP///zD///8A////AP///wD///8A////AP///wD///8A////AP////////8o////AP///7b///+J////AP///wD///8A////AP///wD///8A////AP///wD///9f////1f////P////b////Sv///wD///8A////AP///wD///8A////AP///wD///8A////X////9X////z", + "////2////0r///8A////AP///wD///8A////AP///wD///8A////AP///1/////V////8////9v///9K////AP///wD///8A////AP///wD///8A////AP///wD///9f////1f////P////b////Sv///wD///8A////AP///wD///8A////AP///wD///8A////X////9X////z////2////0r///8A////AP///wD///8A////AP///wD///8A", + "////AP///1/////V////8////9v///9K////AP///wD///8A////AP///wD///8A////AP///wD///+I////3P////D////N////N////5H////s////vf///xn///8A////AP///wD///8A////+P///zv///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///w3///+n////7v///7z///8Y////AP///wD///8A", + "////AP///wD///8A////AP///wD///8N////p////+7///+8////GP///wD///8A////AP///wD///8A////AP///wD///8A////Df///6f////u////vP///xj///8A////AP///wD///8A////AP///wD///8A////AP///w3///+n////7v///7z///8Y////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////yj///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////yj///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////KP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////yj///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////Bv///9f///9V////AP///wD///8A////AP///wD///8A////AP////z///9S////2f///+z///+n////Lf///wD///8A////AP///wD///8A////AP///wD///8H////jv///+b////m////if///wX///8A////AP///wD///8A////AP///wD///8A////B////47////m////5v///4n///8F////AP///wD///8A", + "////AP///wD///8A////AP///wf///+O////5v///+b///+J////Bf///wD///8A////AP///wD///8A////AP///wD///8H////jv///+b////m////if///wX///8A////AP///wD///8A////AP///wD///8A////B////47////m////5v///4n///8F////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///7v///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8H////jv///+b////s////zv///1z///8A////AP///wD///8A////AP///wD///8A/////////yj///8A////AP///yj/////////AP///wD///8A////AP///wD///8A////AP////////8o////AP///wD///8o/////////wD///8A////AP///wD///8A////AP///wD/////", + "////KP///wD///8A////KP////////8A////AP///wD///8A////AP///wD///8A/////////yj///8A////AP///yj/////////AP///wD///8A////AP///wD///8A////AP///wD///8D////5P///zn///80////6////wX///8A////AP///wD///8A////AP///wD/////////K////wD///8A////Pv////f///8A////AP///wD///8A", + "////AP///wD///8A////AP///wP////k////Of///zT////r////Bf///wD///8A////AP///wD///8A////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////+////1v///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A/////////1j///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////////////////////////////////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A/////////3T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////8s////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8P////rv///+j////6////5f///53///8U////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////yv///1L///8A////VP///8f///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////F////43////c////4f///9z///+N////F////wD///8A////AP///wD///8A////AP///wD///+X////5f///6j////j////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8y////qv///wD///8y////qv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////CP///zD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9Q////UP///1D///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8X////jf///9z////h////3P///43///8X////AP///wD///8A////AP///wD///8A////AP///xj///8Y////GP///xj///8Y////GP///xj///8Y////AP///wD///8A////AP///wD///8A////AP///wD///8h////v/////T///+9////H////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////CP////////////////////////////////////////8w////AP///wD///8A////AP///wD///8A////AP////3////5////+P////j////4////Rf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+8////8v////P////J////Ov///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////1v///2D///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////9s////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////8P///wD////w////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////Uv////f///9R////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///93////I////WP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////8g////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////Qf///97////d////Q////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///6r///8x////AP///6r///8x////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8N////5P///0X///8A////AP///wD///8A////AP////////8g////AP///wD///8A////AP///wD///8A", - "////Df///+T///9F////AP///wD///8A/////f////n////4////+P////j///9F////AP///wD///8A////AP///wD///8N////5P///0X///8A////AP///wD///8A////AP////////8g////AP///wD///8A////AP///wD///8L////lf///+f////x////yP///2n///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////FP////r///9n////AP///wD///8A////AP///wD///8A////a/////r///8U////AP///wD///8A////AP///xT////6////Z////wD///8A////AP///wD///8A////AP///2v////6////FP///wD///8A////AP///wD///8U////+v///2f///8A////AP///wD///8A////AP///wD///9r////+v///xT///8A////AP///wD///8A", - "////FP////r///9n////AP///wD///8A////AP///wD///8A////a/////r///8U////AP///wD///8A////AP///xT////6////Z////wD///8A////AP///wD///8A////AP///2v////6////FP///wD///8A////AP///wD///8U////+v///2f///8A////AP///wD///8A////AP///wD///9r////+v///xT///8A////AP///wD///8A", - "////Ef////T///9s////AP///wD///8A////AP///wD///////////////////////////////////8A////AP///wD///8A////AP///wD////d////yP///1j///8A////AP///wD///8A////AP///wD///8A////AP///wD///////////////////////////////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////////////////////////////////////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///////////////////////////////////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///////////////////////////////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////Zv////v//////////////5b///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///2b////7//////////////+W////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9m////+///////////////lv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////Zv////v//////////////5b///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////////////////////v////yf///5f///8a////AP///wD///8A////AP///wD///8A////AP///wD/////////dP///wD///8A////AP///wD///8Z////8/////////8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///9Y////t////+f////n////tf///07///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////WP///7f////n////5////7X///9O////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///1j///+3////5////+f///+1////Tv///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///9Y////t////+f////n////tf///07///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////WP///7f////n////5////7X///9O////AP///wD///8A////AP///wD///8A////AP///wD///9I////R////wD///8A////AP///0L///9U////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///zb///8D////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8v////t////+r////m////sv///yn///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////L////7f////q////5v///7L///8p////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///y////+3////6v///+b///+y////Kf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8v////t////+r////m////sv///yn///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////IP////////9U////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "/////////3T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////9s////AP///63////t////8////7f///8g////AP///wD///8A////AP///wD///8A////AP///wD///8t////w/////b////s////mf///y//////////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////Lf///8P////2////7P///5n///8v/////////wD///8A////AP///wD///8A////AP///wD///8A////AP///y3////D////9v///+z///+Z////L/////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8t////w/////b////s////mf///y//////////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////Lf///8P////2////7P///5n///8v/////////wD///8A////AP///wD///8A////AP///wD///8A////AP///y3////D////9v///+z///+Z////L/////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8w////yf////f////d////bP///wD///8s////rv///+f////4////0v///1X///8A////AP///wD///8A", - "////AP///wD////d////yP///1j///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8s////uP///+z////5////0v///1b///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////LP///7j////s////+f///9L///9W////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///yz///+4////7P////n////S////Vv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8s////uP///+z////5////0v///1b///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////2z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "/////////2z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////2z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////9s////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///1L////Q////8////8f///89////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////9s////AP///wD///8A////bP////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Qf///8r////z////y////0X///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///0H////K////8////8v///9F////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9B////yv////P////L////Rf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Qf///8r////z////y////0X///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///0H////K////8////8v///9F////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///+T///8Z////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9O////zv///8D////x////y////0X///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////F////6z////u////8P///5////9H/////////wD///8A////AP///wD///8A////AP///wD///8A////AP///xf///+s////7v////D///+f////R/////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8X////rP///+7////w////n////0f/////////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////F////6z////u////8P///5////9H/////////wD///8A////AP///wD///8A////AP///wD///8A////AP///xj////y////8f///6z///8W////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////bP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////GP////L////x////rP///xb///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////z///9H////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9y////fv///wD///9a////jv///wD///8A", + "////AP///wD///8A////AP///+H///9l////4P///xz///8w////AP///wD///8A////AP///wD///8A////AP///wD////d////Lf///zT////V////AP///2n///96////AP///wD///8A////AP///wD///8A////AP///+r///9Z////Tf///+v///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD////D////gP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///4P///+/////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///7X///9r////AP///wD///8A////AP///wD///8A////AP///4b///+r////Ev///7L///93////AP///wD///8A////AP///wD///8A////AP///wD///9n////5f////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////jv///0f///8J////fv///83///8A", + "////AP///wD///8A////AP///wD///8A////AP///3b///82////CP///3v////U////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///x3////U////8v///yD///8A////AP///wD///8A////AP///wD///8A////y////1L///8M////DP///wP///8A////AP///wD///8A////AP///wD///8A////AP///0H////b", + "////MP///wT///8H////AP///wD///8A////AP///wD///8A////AP///wD///8M////DP///wz///9j////yP///wD///8A////AP///wD///8A////AP///wD///8A////1////4P///8R////hv///9b///8A////AP///wD///8A////AP///wD///8A////AP///6j///+U////D////7D///9/////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////VP////f///9T////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///1L///8u////Df///27////b////AP///wD///8A////AP///wD///8A////AP///wD///85////wv///wn///+N////0////9P////S////mv///4f///8A////AP///wD///8A////AP///wD///8A", + "////J////8D///+/////Kv///wD///8A////AP///wD///8A////AP////////8w////AP///yH///+r////zf///wD///8A////AP///wD///8A////AP///wD///8U////5v///6L///8h////Av///yb///9G////AP///wD///8A////AP///wD///8A/////////zD///8A////Hf///5D////v////Gv///wD///8A////AP///wD///8A", + "////AP////////8w////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////MP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////F////+r///+R////HP///wD///8n////N////wD///8A////AP///wD///8A////AP////////8w////AP///wD///8A////MP////////8A", + "////AP///wD///8A////AP///wD///8A////IP////////8Q////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////MP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////8w////AP///wH///+a////lf///wL///8A////AP///wD///8A////AP///wD/////////MP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////8b///9D////AP///wD///8A////Nf///8D/////////AP///wD///8A////AP/////////b////Tv///wD///8A////MP////////8A////AP///wD///8A////AP///wD///8t////8////27///8P////D////23////x////JP///wD///8A////AP///wD///8A", + "/////////zD///8j////wP///7X///8A////AP///wD///8A////AP///wD///8A////AP////j///9G////AP///wD///8A////AP///0f////3////AP///wD///8A////AP///wD/////////MP///wD///8a////r////43///8A////AP///wD///8A////AP///wD///8A////AP///9X///+Q////Cv///xz///85////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP////////8w////AP///wD///8A////AP///wD///8A////AP///wD/////////MP///wD///8A////AP///zD/////////AP///wD///8A////AP///wD///8A////AP///7r///95////AP///wD///8A////ev///7n///8A////AP///wD///8A////AP///wD////l////TP///wD///8A", + "////l////6z///+W////AP///wD///9Q////4////wD///8A////Mf///+3///8n////AP///x3////o////M////wD///8A////AP///wD///8A////AP///2D////a////Bf///wD///8B////zf///2n///8A////AP///wD///8A////AP///wD///8A////AP///5z///+o////AP///wD///8A////AP///wD///8A////AP///wD/////", + "////KP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///4v///+Y////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8o/////////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////yf///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////J/////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////9", + "////Kf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////2////Ov///wD///86////9f///wD///8A////AP///wD///8A////AP///wD///8A/////////yj///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP////////8o////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////yj///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////8o////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////Pv///wD///8A////av///93///8A////AP///wD///8A////AP///wD///8A////4P///2r///8A", + "////AP///0X/////////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Bf///9////8o////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////Sv///9v///8A////AP///9f///9Q////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8B/////////yf///8A////AP///wD///8A////AP///wD///8A////AP///wD////0////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///yf/////////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", @@ -235,39 +665,34 @@ const char* CAF_FIXED_ATLAS_FONT_12_PT_TEXTURE_IMAGE[] = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", - "AAAAAAAAAAAAAAAAAAAAAP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///83////I////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////L////V////wD////L////V////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///8r///9Z////AP///+7///83////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////8U////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///3f////B////AP///wD///+2////o////yL///+q////t////wD///8A////AP///wD///8A", - "////i/////v///9+////R////2r////b////4f////P///+j////Af///wD///8A////AP///wD///8A////AP///8v///9X////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////fv////D///8X////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////Fv////D///96////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9P/////////1H///9W/////////1P///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////yz///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////cP///+T///8J////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///////////////////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9S////9P///1H///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///6L////F////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///xr////q////p////0v///+s////7v///yD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////YP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////t////+3///9d////TP///0z///9M////TP///yL///8A////AP///wD///8A////AP///wD///8A////AP///8L///9q////RP///0z///+g/////////1T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////YP///wD///8A////AP///wD///8A////AP///wD///8A", - "////uv///2b///8+////TP///57/////////Rv///wD///8A////AP///wD///8A////AP///wD///8A////AP///xn////x////pv///0f///91////+v///2L///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////lP///+X///8F////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////h/////H///9s////Qf///3P////2////dP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wn///8v////Ov///4T////8////kf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9S////9P///1H///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////cP///+T///8J////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///zz///+9////8P///4L///8A////AP///wD///8A////AP///wD///8A////AP///wD////A////////////////////////////////////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////gv////D///+9////PP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////zf///8j///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////WP////L///+Y////SP///x////8f////Sv///5P///8A////AP///wD///8A////AP///wD///8A", - "////AP///63////G////AP///wD///8A////AP///wD///8A////yP///63///8A////AP///wD///8A////AP////////+O////MP///zH///9J////pP////////9T////AP///wD///8A////AP///wD///8A////AP///wD///8A////Yf////b////S////a////0L///89////XP///5r///8A////AP///wD///8A////AP///wD///8A", - "/////////47///8w////SP///3D////c////8f///1T///8A////AP///wD///8A////AP///wD///8A////AP////////+O////MP///zD///8w////MP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////dP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///1j////z////2v///3T///9K////Mv///0H///+m/////////wD///8A////AP///wD///8A////AP////////90////AP///wD///8A////AP///3T/////////AP///wD///8A////AP///wD///8A////AP///wD///8A////KP////////9c////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////Qv///zr///+u////7P///xL///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////90////AP///wD///8A////X/////3///89////AP///wD///8A////AP///wD///8A////AP///wD/////////jv///zD///8w////MP///zD///8e////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "/////////3T///8A////AP///6v////8////f////wD///8A////dP////////8A////AP///wD///8A////AP////////90////AP///wD///8A////AP///6D////4/////////wD///8A////AP///wD///8A////AP///wD///8A////jf////7///+S////S////0r///+Q/////f///37///8A////AP///wD///8A////AP///wD///8A", - "/////////3T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///2j/////////mv///wT///8A////AP///wD///8A////AP///wD/////////dP///wD///8A////AP///2v/////////Q////wD///8A////AP///wD///8A////AP///wD///8A", - "////JP///6r///9f////OP///1X///+X/////////2T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////IP////////9U////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8r////+P///87///9m////R////6/////2////KP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///7n////N////vP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///6r////k////gP///wD///8A////AP///4/////j////nP///wD///8A////AP///wD///8A////bP////H///8T////AP///wD///8n/////P///3D///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///yD/////////VP///wD///8A////AP///wD///8A////AP///wD///8A////AP///7L////m////Nf///zD///8w////MP///zD///8w////AP///wD///8A////AP///wD///8A////AP///wD/////////hf///yz///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wP////j////ff///wD///8A////AP///wD///8A////AP///wD///8A////AP///yz///+F/////////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8m////+f///0b///8A////AP///wD///9A////+////yn///8A////AP///wD///8A////AP///wD///8A", - "/////////////////////////////////////////wD///8A////AP///wD///8A////AP///wD///8A////AP///zH////4////Vv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////M////3f///0////8+////hv///+b/////////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "//////////D///+E////R////7v/////////R////wD///8A////AP///wD///8A////AP///wD///8A////AP///zP////9////zv///2H///9X////fP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9L/////////7T///9F////e////+z/////////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////JP////f////B////Zv///0f///9x////b////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////bP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////L////uf///yf///8Q////NP///2P////1////kP///wD///8A////AP///wD///8A////AP///wD///8A", - "/////////2z///8A////AP///wD///9s/////////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////bP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///88////b/////////8z////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "/////////2z///8A////AP///3/////2////K////wD///8A////AP///wD///8A////AP///wD///8A////AP////////9s////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////bP///wD///8A////AP///8D///+s////AP///wD///8A////bP////////8A////AP///wD///8A", - "/////////2z///8A////AP///wD///9s/////////wD///8A////AP///wD///8A////AP///wD///8A////AP///zD////7////t////1H///+4/////f///zX///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////bP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///9s/////////wD///8A////AP///wD///8A////AP///wD///8A////AP////////9s////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8a////jf///0H///9B////zf///8P///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///8j////V////Rv///0L///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///6b////x////df///0D///+S////7f////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///96////zP///9z///9w////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///87////5v///9H///9D////AP///wD///9J////1f///+n///86////AP///wD///8A////AP///xH////k////nv///wD///8A////n////+P///8R////AP///wD///8A////AP///wD///8A////AP///wD///8H////Nf///0n////T////uP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////o////9f///8O////CP///wj///8I////Af///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////x////8r///88////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////LP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////PP///8r////E////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///0v///8A////AP///0L////e////4////1f///8A////AP///wD///8A////AP///wD///8A////AP///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////3P///1D///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///yD////N//////////v///+8////AP///wD///8A////AP///wD///8A////AP///wD///8A////4////2D///8R////Kv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///zr////p////Cv///wD///8E////4v///0b///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///7z///+q////Gv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8H////s////1X///8A////AP///wD///9Z////sf///wb///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wf///+z////Vf///wD///8A////AP///1n///+x////Bv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///3L///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////KP///wD///8A////KP////////8A////AP///wD///8A////AP///wD///8A////2////////////////////8T///8A////xP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////ff///+X///8A////AP///wD///+r////Vf///wD///8A////AP///wD///8A////AP///33////l////AP///wD///8A////q////1X///8A////AP///wD///8A////AP///wD///8Y////Af///yr////U////AP///wD///+r////Vf///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///yf////A////v////yr///8A////AP///wD///8A////AP///wD///8A////AP///wD///8n////wP///7////8q////AP///wD///8A////AP///wD///8A////AP///wD///8A////J////8D///+/", + "////Kv///wD///8A////AP///wD///8A////AP///wD///8A////AP///yf////A////v////yr///8A////AP///wD///8A////AP///wD///8A////AP///wD///8n////wP///7////8q////AP///wD///8A////AP///wD///8A////AP///wD///8A////J////8D///+/////Kv///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD////S////Qf////////8w////AP///wD///8A////AP///wD////2////SP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////zD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////8w////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD/////////MP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////zD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8g/////////xD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////IP////////8Q////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///yD/////////EP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8g/////////xD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////zD///8A////Hf///5D////v////Gv///wD///8A////AP///wD///8A/////////9v///9O", + "////AP///wD///8w/////////wD///8A////AP///wD///8A////AP///y3////z////bv///w////8P////bf////H///8k////AP///wD///8A////AP///wD///8t////8////27///8P////D////23////x////JP///wD///8A////AP///wD///8A////Lf////P///9u////D////w////9t////8f///yT///8A////AP///wD///8A", + "////AP///y3////z////bv///w////8P////bf////H///8k////AP///wD///8A////AP///wD///8t////8////27///8P////D////23////x////JP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///6r///+i////AP///wD///9E////3P///7v///+g", + "////AP///wD///8A////AP///wD/////////MP///wD///8A////AP///zD/////////AP///wD///8A////AP///wD///8A/////////zD///8A////AP///wD///8w/////////wD///8A////AP///wD///8A////AP////////8w////AP///wD///8A////MP////////8A////AP///wD///8A////AP///wD/////////MP///wD///8A", + "////AP///zD/////////AP///wD///8A////AP///wD///8A////AP///2D////a////Bf///wD///8B////zf///2n///8A////AP///wD///8A////AP////////8w////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////9////Kv///wD///9C////6v///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Av///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///+L///9f////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+u////SP///6////+s////AP///wD///8A////AP///wD///8A////AP///wD///8A////Av///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wL///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Sv///9v///8A////AP///9f///9Q", + "////AP///wD///8A////AP///wD///8A/////////z7///8A////AP///2r////d////AP///wD///8A////AP///wD///8A////AP///wD///9K////2////wD///8A////1////1D///8A////AP///wD///8A////AP///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", @@ -276,40 +701,34 @@ const char* CAF_FIXED_ATLAS_FONT_12_PT_TEXTURE_IMAGE[] = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////Vf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////Jv///8r///8A////Ef///9b///8A////AP///wD///8A////AP///wD///9A////0v/////////l////f////wD///8A////AP///wD///8A////AP///wD///8A////Uf///9/////e////Sf///wD///8G////zv///w////8A////AP///wD///8A////AP///wD///9d", + "////5////+n///9g////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////ev///7n///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+9////ev///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///88////3////wT///8A////AP///wD///8A////AP///wD///8K////rv///+3///+k////Bv///wD///8A////AP///wD///8A////AP///wD///8A////AP///2//////", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///0z////O////9v///8n///8v////AP///wD///8A////AP///wD///8A////AP///wD///9l////1/////b////M////Nf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////aP////////8g////AP///wD///8A////AP///wD///8A", + "////AP///7T///////////////////9Q////AP///wD///8A////AP///wD///8A////AP///wD///8A////XP///9j////5////Rf///wD///8A////AP///wD///8A////AP///wD///8A//////////////////////////////8A////AP///wD///8A////AP///wD///8A////AP///zb////M////9v///8z///81////AP///wD///8A", + "////AP///wD///8A////AP///wD///8b////wP////D///+l////Cv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+G////3f////b////M////Ov///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///4j///+1////Jf///wD///8F////Zf///9j///8N////AP///wD///8A////AP///wD///8A////AP///wD///+5////vP///wD///8A////AP///wD///8A////AP///wD/////////9v////T////s////tv///yr///8A////AP///wD///8A////AP///wD///8A////AP///xP///+Y////1v////T////i////kf///wD///8A", + "////AP///wD///8A////AP/////////2////9f///93///+i////HP///wD///8A////AP///wD///8A////AP///wD/////////9v////T////0////9P///wD///8A////AP///wD///8A////AP///wD///8A//////////b////0////9P////T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8X////nv///9n////y", + "////4f///33///8A////AP///wD///8A////AP///wD/////////MP///wD///8A////AP///zD/////////AP///wD///8A////AP///wD///8A////Jf///9P/////////zv///xr///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////zD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////", + "////MP///wD///8A////Af///5X///+r////B////wD///8A////AP///wD///8A/////////zD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP/////////i////Av///wD///8A////AP///wD////T/////////wD///8A////AP///wD/////////uf///wD///8A////AP///zD/////////AP///wD///8A", + "////AP///wD///8A////AP///y7///+1////5v///+b///+y////KP///wD///8A////AP///wD///8A////AP/////////2////7f///7D///8e////AP///wD///8A////AP///wD///8A////AP///wD////g////Wv///wD///8A////AP///wD///9b////2////wD///8A////AP///wD///8A//////////b////v////wv///4j///8W", + "////AP///wD///8A////AP///wD///8A////AP///wD///8z////yP////T////k////gP///wD///8A////AP///wD///8A////AP///wD////0////9P////T/////////9v////T////0////AP///wD///8A////AP///wD///8A/////P///y////8A////AP///wD///8w/////////wD///8A////AP///wD///8A////AP///xf////8", + "////KP///wD///8A////AP///yn////8////Fv///wD///8A////AP///wD///8i/////////xn///8A////AP///0X////+////Sv///wD///8A////Hf////////8h////C////9j///9e////AP///wD///8A////Uf///9n///8L////AP///wD///8A////AP///w3////n////UP///wD///8A////AP///0f////q////Dv///wD///8A", + "////AP///wD////0////9P////T////4/////v///wD///8A////AP///wD///8A////AP///wD///8A/////////yj///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///xH////v////I////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////KP////////8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////8o////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///yj/////////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////3P///2H///8A////DP///wD///8A////AP///wD///8A////AP///wD///8A////w////37///8A////fP///8f///8A////AP///wD///8A////AP///wD///8A////AP////////8o////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8E////3P///yL///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////KP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////8o////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////KP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "/////////7D///8N////Lf///8r///+M////AP///wD///8A////AP///wD///8A////AP///5D////M////L////xH///+3/////////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///9b////F////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///6z///9/////AP///wD///97////sP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP////////8o////AP///wD///8A////AP///wD///8A////AP///wD///8A////9P///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8o/////////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////+f///8r///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////9b////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////I////zf///0z///9M////TP///0z///9M////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///7X///+d////7P///+v///+f////uP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////90////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////LP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////Gf///5P///9O////NP///0z////M////tf///wD///8A////AP///wD///8A////AP///wD///8A////AP///8n///9R////AP///1T////T////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////L////9z///9t////Ff///wD///8V////b////93///8v////AP///wD///8A////AP///wD///8A", - "////6P///yf///8s/////////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8G////0v///2X///8G////0v///2X///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///yz/////////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////////////////////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8v////3P///23///8V////AP///xX///9v////3f///y////8A////AP///wD///8A////AP///wD//////////////////////////////////////////////wD///8A////AP///wD///8A////AP///wD///8A", - "////v////6L///8h////i////7v///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wH///8s////LP///yz///9c////NP///yz///8s////CP///wD///8A////AP///wD///8A////AP///wD///9Q////sP///xT///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////Tf///w3///8M////ff///97///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///1b////4////Lv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////bP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP////D///8A////8P///wD///8A////AP///wD///8A////AP///wD///8A////AP///1L////0////Uf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Q////+X///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD/////////IP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///9T///9E////R////9T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9m////0f///wX///9m////0f///wX///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///1f////Z////Bv///wD///8A////AP///wD/////////IP///wD///8A////AP///wD///8A////AP///wD///9X////2f///wb///8A////AP///1D///+w////FP///wD///8A////AP///wD///8A////AP///wD///8A////AP///1f////Z////Bv///wD///8A////AP///wD/////////IP///wD///8A////AP///wD///8A", - "////k////+3///9l////UP///4b///+Y////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+t////xv///wD///8A////AP///wD///8A////AP///8j///+t////AP///wD///8A////AP///wD///8A////rf///8b///8A////AP///wD///8A////AP///wD////I////rf///wD///8A////AP///wD///8A", - "////AP///63////G////AP///wD///8A////AP///wD///8A////yP///63///8A////AP///wD///8A////AP///wD///+t////xv///wD///8A////AP///wD///8A////AP///8j///+t////AP///wD///8A////AP///wD///8A////rf///8b///8A////AP///wD///8A////AP///wD////I////rf///wD///8A////AP///wD///8A", - "////AP///63////G////AP///wD///8A////AP///wD///8A////yP///63///8A////AP///wD///8A////AP///wD///+R////2////wL///8A////AP///wD///8A/////////47///8w////MP///zD///8w////AP///wD///8A////AP///wD///8A////AP///0P////l////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "/////////47///8w////MP///zD///8w////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////+O////MP///zD///8w////MP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////jv///zD///8w////MP///zD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "/////////47///8w////MP///zD///8w////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8o/////////1z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////KP////////9c////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///yj/////////XP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8o/////////1z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////47///8w////SP///3D////c////8f///1T///8A////AP///wD///8A////AP///wD///8A", - "/////////3T///8A////AP///wD///8A////oP////j/////////AP///wD///8A////AP///wD///8A////AP///wD///+N/////v///5L///9L////Sv///5D////9////fv///wD///8A////AP///wD///8A////AP///wD///8A////jf////7///+S////S////0r///+Q/////f///37///8A////AP///wD///8A////AP///wD///8A", - "////AP///43////+////kv///0v///9K////kP////3///9+////AP///wD///8A////AP///wD///8A////AP///wD///+N/////v///5L///9L////Sv///5D////9////fv///wD///8A////AP///wD///8A////AP///wD///8A////jf////7///+S////S////0r///+Q/////f///37///8A////AP///wD///8A////AP///wD///8A", - "////Rv///+H///8p////AP///yf////e////Rf///wD///8A////AP///wD///8A////AP///wD///8A////AP///w3////u////ov///6v////j////5////7X///9O////AP///wD///8A////AP///wD///8A////AP///wD///8r////+P///87///9m////R////6/////2////KP///wD///8A////AP///wD///8A////AP///wD///8A", - "////K/////j////O////Zv///0f///+v////9v///yj///8A////AP///wD///8A////AP///wD///8A////AP///yv////4////zv///2b///9H////r/////b///8o////AP///wD///8A////AP///wD///8A////AP///wD///8r////+P///87///9m////R////6/////2////KP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///yD/////////VP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////90////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////bP///wD///+U////QP///0X////Y////t////wD///8A////AP///wD///8A////AP///wD///8A", - "////zP///93///9P////Pv///4b////m/////////wD///8A////AP///wD///8A////AP///wD///8A////AP///8z////d////T////z7///+G////5v////////8A////AP///wD///8A////AP///wD///8A////AP///wD////M////3f///0////8+////hv///+b/////////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////zP///93///9P////Pv///4b////m/////////wD///8A////AP///wD///8A////AP///wD///8A////AP///8z////d////T////z7///+G////5v////////8A////AP///wD///8A////AP///wD///8A////AP///wD////M////3f///0////8+////hv///+b/////////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////zf///9z///9K////Tv///9H///+L////6f///8T///9t////T////3n///90////AP///wD///8A////AP///wD///8A////AP///0P////l////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8k////9////8H///9m////R////3H///9v////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////JP////f////B////Zv///0f///9x////b////wD///8A////AP///wD///8A////AP///wD///8A////AP///yT////3////wf///2b///9H////cf///2////8A////AP///wD///8A////AP///wD///8A////AP///wD///8k////9////8H///9m////R////3H///9v////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP////////9s////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////9s////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////9s////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD/////////bP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///0j////+////hf///0f///+2////+f///yr///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////bP///wD///8A////AP///2z/////////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////MP////v///+3////Uf///7j////9////Nf///wD///8A////AP///wD///8A////AP///wD///8A////AP///zD////7////t////1H///+4/////f///zX///8A////AP///wD///8A////AP///wD///8A////AP///wD///8w////+////7f///9R////uP////3///81////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////MP////v///+3////Uf///7j////9////Nf///wD///8A////AP///wD///8A////AP///wD///8A////AP///zD////7////t////1H///+4/////f///zX///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8a////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////OP////////+6////RP///7j////9////Nf///wD///8A////AP///wD///8A////AP///wD///8A////AP///6b////x////df///0D///+S////7f////////8A////AP///wD///8A////AP///wD///8A////AP///wD///+m////8f///3X///9A////kv///+3/////////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////pv////H///91////QP///5L////t/////////wD///8A////AP///wD///8A////AP///wD///8A////AP///6b////x////df///0D///+S////7f////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8H////Nf///0n////T////uP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "/////////2z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wf///81////Sf///9P///+4////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", @@ -317,75 +736,646 @@ const char* CAF_FIXED_ATLAS_FONT_12_PT_TEXTURE_IMAGE[] = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///9n///9P////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////8a////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///1P////o////6f///2v///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///++////d////wD///8A////AP///3L////C////AP///wD///8A////AP///wD///8A////9P///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////x////QP///wf///8s", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wb///96////u////7P///+7////ef///wb///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Bv///3r///+7////s////7v///95////Bv///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////yj///8A////AP///yj/////////AP///wD///8A////AP///wD///8A////AP////f/////", + "///////////////E////AP///8T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///1b////l////AP///wD///8A////G////9f///8N////AP///wD///8A////AP///wD///9W////5f///wD///8A////AP///xv////X", + "////Df///wD///8A////AP///wD///8A////kv///9T////M////j////wD///8A////G////9f///8N////AP///wD///8A////AP///wD///9T////2f///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////uf///7z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///7n///+8////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+5////vP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////uf///7z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///7n///+8////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD//////////////4r///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Xv////n/////////9v////T////0////9P///wD///8A////2f///2X///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP/////////2////9P////T////0////AP///wD///8A", + "////AP///wD///8A////AP///wD/////////9v////T////0////9P///wD///8A////AP///wD///8A////AP///wD///8A//////////b////0////9P////T///8A////AP///wD///8A////AP///wD///8A////AP/////////2////9P////T////0////AP///wD///8A////AP///wD///8A////AP///wD///8l////0//////////O", + "////Gv///wD///8A////AP///wD///8A////AP///wD///8A////Jf///9P/////////zv///xr///8A////AP///wD///8A////AP///wD///8A////AP///yX////T/////////87///8a////AP///wD///8A////AP///wD///8A////AP///wD///8l////0//////////O////Gv///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP/////////2////9f///93///+i////HP///wD///8A////AP///wD///8A////AP////////+5////AP///wD///8A////MP////////8A////AP///wD///8A////AP///wD///8A////Lv///7X////m////5v///7L///8o////AP///wD///8A////AP///wD///8A////AP///y7///+1////5v///+b///+y////KP///wD///8A", + "////AP///wD///8A////AP///wD///8u////tf///+b////m////sv///yj///8A////AP///wD///8A////AP///wD///8A////Lv///7X////m////5v///7L///8o////AP///wD///8A////AP///wD///8A////AP///y7///+1////5v///+b///+y////KP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8r////8v///27///8P////CP///8X////2////Hv///wD///8A////AP///wD///8A/////P///y////8A////AP///wD///8w/////////wD///8A////AP///wD///8A////AP////z///8v////AP///wD///8A////MP////////8A////AP///wD///8A////AP///wD////8", + "////L////wD///8A////AP///zD/////////AP///wD///8A////AP///wD///8A/////P///y////8A////AP///wD///8w/////////wD///8A////AP///wD///8A////AP///w3////n////UP///wD///8A////AP///0f////q////Dv///wD///8A////AP///wD/////////MP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////1////3D///8A////X////+b///8A////AP///wD///8A////AP///wD///8A////AP///wD///8D////kP///7b///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///7f///+P////Av///wD///8A////AP///wD///8A////AP///wD///8A////AP///67///9c////X////67///8A", + "////AP///wD///8A////AP///wD///8A////AP///8r///8R////hv///+3///9t////AP///wD///8A////AP///wD///8A////AP///wD///8A////yv///xj///8Z////zv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+Q////sv///4r///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+c////wP///yP///8o////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wP///+Q////tv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////t////4////8C////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////rv///1z///9f////rv///wD///8A////AP///wD///8A////AP///wD///8A////AP///8r///8Y////Gf///87///8A////AP///wD///8A////AP///wD///8A////AP///wP///+Q////tv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+3////j////wL///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////rv///1z///9f////rv///wD///8A////AP///wD///8A////AP///wD///8A////AP///8r///8Y////Gf///87///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Q/////3////x////I////wD///8A////AP///wD///8A////AP///wD///8A////AP///8r///8R", + "////hv///+3///9t////AP///wD///8A////AP///wD///8A////AP///wD///8D////kP///7b///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///7f///+P////Av///wD///8A////AP///wD///8A////AP///wD///8A////AP///67///9c////X////67///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD////K////Ef///4b////t////bf///wD///8A////AP///wD///8A////AP///wD///8A////yv///xj///8Z////zv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////A////5D///+2////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+3////j////wL///8A////AP///wD///8A////AP///wD///8A////AP///wD///+u////XP///1////+u////AP///wD///8A////AP///wD///8A////AP///wD///8A////yv///xj///8Z", + "////zv///wD///8A////AP///wD///8A////AP///wD///8A////AP///6z///9/////AP///wD///97////sP///wD///8A////AP///wD///8A////AP////////+w////Df///y3////K////jP///wD///8A////AP///wD///8A////AP///wD///8A////rP///3////8A////AP///3v///+w////AP///wD///8A////AP///wD///8A", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////4P///2z///8A////4P///2z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+m////f////wD////J////XP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+i////4P////r/////////0f///3n///8H////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8K////5v///0f///8A////8P///0L///8A////Rf///+////8A////AP///wD///8A////AP///+P///+e////AP///wD///8A////Mv////7////6////If///wD///8A////AP///wD///8A////AP///wD////g////bP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////C////+////+M////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+N////7f///wr///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///4v////W////4v///4z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP////////8s////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///xz////+////bv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///84/////////y////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///92////5f///wb///8A////CP///+j///99////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A/////////2D///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wr////D////yv///w7///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///7n////O////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///8A/////////2D///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////tv///8X///8A////AP///wD///8A////AP///wD///8A////AP///wD///+L////z////wH///8A////AP///5j////Q////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///yP////9////Wv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///+L///+C////AP///wD///8A////if///9r///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////bv////////83////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///xz////+////bv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Ov///7v////u////fv///w////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8P////ff///+3///+6////Of///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////G/////P///9T////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9L/////////yb///8A////AP///wD///8A////Jv////////9L////AP///wD///8A////AP///wD/////////dP///wD///8A////AP///wD////I////zP///wD///8A////AP///wD///8A////AP///wD///8A", - "////Hv////f///+q////Bv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////90////AP///wD///8A////Cf///7L////v////Ff///wD///8A////AP///wD///8A////AP///wD/////////dP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "/////////3T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///xn////z////sf///wv///8A////AP///wD///8A////dP////////8A////AP///wD///8A////AP///wD/////////dP///wD///8A////AP///wD///90/////////wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///yD/////////VP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////GP////////9S////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////dP///wD///8A////GP///+7///+O////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "/////////3T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////90////AP///wj////0////iv///9T///8A////AP///3T/////////AP///wD///8A////AP///wD/////////dP///wD///8A////AP///zP////8////j/////////8A////AP///wD///8A////AP///wD///8A", - "////M/////////9w////AP///wD///8A////AP///23////9////KP///wD///8A////AP///wD///8A////AP////////90////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///xz////y////nP///wD///8A////AP///wD///8A////AP///wD///8A", - "/////////3T///8A////AP///x3////y////mf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///7z////U////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///yD/////////VP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////rf///+z///8C////AP///wD///8B////1f///6j///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///xP////7////Uv////z///8V////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////o////n////7n///8A////AP///wD////G////k////9z///8A////AP///wD///8A", - "////AP///wX////a////jP///wD///8A////pP///9////8G////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8g/////////1T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8a////8P///37///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "/////////2z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9R////+v///xj///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////bP////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///4r////S////Av///wD///8B////yv///5P///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////P////3v///wL///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////4////43///8A////AP///wD///+b/////////wD///8A////AP///wD///8A////AP///wD///8A////AP////////+4////AP///wD///8A////3v///7T///8A////AP///wD///8A////AP///wD///8A////AP///wD///+x////6v///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////uv///9r///8A////AP///wD///+0/////////wD///8A////AP///wD///8A////AP///wD///8A////AP///6f////m////Av///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////2z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////8v///2n///8A////AP///wD///8A////fv///+z///8A////AP///wD///8A////AP///wD///8A////AP////////9s////AP///wD///8A////bP////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////2z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wT/////////Y////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////9s////AP///0H////9////ZP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////bP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "/////////2z///8A////AP///wD////A////rP///wD///8A////AP///2z/////////AP///wD///8A////AP////////9s////AP///wD///8A////bP////////8A////AP///wD///8A////AP///wD///8A////AP///wD///+r////2P///wD///8A////AP///9z///+s////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "/////////2z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////bP////////8A////AP///wD///8A////AP///wD///8A////AP///wD/////////bP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///3f////0////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////1////ff///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////o////ov///wD///8A////AP///7//////////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////2P///4H///+Q////0P///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////gP///7r///+Y////kf///wD///8A////kf///5v///+8////f////wD///8A////AP///wD///8A////Rv////7///9I////Sf////7///9E////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////Nv////////82////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///xP////q////gP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////v///9x////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "/////////yz///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9x////+v///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////j////Sv///3j////2////c////0f////j////AP///wD///8A////AP///wD///8A////AP///wD///8A", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////g////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///xb////1////N////wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///87////9f///xX///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Uf///7b////a////1////53///8S////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP////////8w////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////qv///6H///8A", + "////AP///wD///8A////ov///6L///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////8o////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///yj/////////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////KP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8o/////////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///0n////a////9P///7////8A////AP///wD///8A////AP///wD///8A////AP///yj////C////5P//////////", + "////3////w7///8A////AP///wD///8A////AP///wD/////////KP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////yj///8A////AP///wD///8A////AP///wD///8A////AP///wD/////", + "////KP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////yj///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////z///9Z////3f///+////+i////DP///wD///8A////AP///wD///8A////AP///wD///8N////ov///+7////d////V/////z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///xX////5////I////wD///8A////H/////n///8V////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////q////Yf///wH///8A////AP///wD///8A////AP///wD///8A////AP////T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8B////Yv///+j///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", - "AAAAAAAAAAAAAAAAAAAAAP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////T///++////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////bv///9v//////////////+////+c////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////M/////////84////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+e////0P///zP///8t////w////5r///8A////AP///wD///8A////AP///wD///8A////AP///wD///8B////MP///zD/////////jv///zD///8o////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "/////////yz///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////av///+7///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////Dv///9j///80////AP///wD///8A////AP///wD///80////2P///w7///8A////AP///wD///8A////AP///1n////E////3P////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////g////7L///8A////g////7L///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///8s/////////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8O////2P///zT///8A////AP///wD///8A////AP///zT////Y////Dv///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////P///84////AP///x3////y////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////yz///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///zX////L////M////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Af///2n////W////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8C////3v///8z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "/////////2z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////w////AP////D///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///9L///+6////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////yD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////3////E////xT////2////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///7L///+C////AP///7L///+C////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////u////3z///8A////9f////j////4//////////n///8b////AP///wD///8A////AP///wD///8A////AP///7v///98////AP///wD///8A////Nf///8v///8z////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////u////3z///8A////9f////j////4//////////n///8b////AP///wD///8A////AP///+X///93////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////S/////////8m////AP///wD///8A////AP///yb/////////S////wD///8A////AP///wD///8A", - "////AP///0v/////////Jv///wD///8A////AP///wD///8m/////////0v///8A////AP///wD///8A////AP///wD///9L/////////yb///8A////AP///wD///8A////Jv////////9L////AP///wD///8A////AP///wD///8A////S/////////8m////AP///wD///8A////AP///yb/////////S////wD///8A////AP///wD///8A", - "////AP///0v/////////Jv///wD///8A////AP///wD///8m/////////0v///8A////AP///wD///8A////AP///wD///9L/////////yb///8A////AP///wD///8A////Jv////////9L////AP///wD///8A////AP///wD///8A////IP////z///9O////AP///wD///8A////AP////////90////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD////S////uv///wD///8A////AP///wD///8A////AP///wD///8A////AP////////90////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////dP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "/////////3T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////90////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////IP////////9U////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///yD/////////VP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8g/////////1T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////IP////////9U////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP////////90////AP///wD///8A////Cf///7L////v////Ff///wD///8A////AP///wD///8A////AP////////90////AP///wD///8A////M/////z///+P/////////wD///8A////AP///wD///8A////AP///wD///8z/////////3D///8A////AP///wD///8A////bf////3///8o////AP///wD///8A////AP///wD///8A", - "////M/////////9w////AP///wD///8A////AP///23////9////KP///wD///8A////AP///wD///8A////AP///zP/////////cP///wD///8A////AP///wD///9t/////f///yj///8A////AP///wD///8A////AP///wD///8z/////////3D///8A////AP///wD///8A////bf////3///8o////AP///wD///8A////AP///wD///8A", - "////M/////////9w////AP///wD///8A////AP///23////9////KP///wD///8A////AP///wD///8A////AP///wD///8o////uP///yb///+2////J////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////rf////////+d////QP///0r///+Q/////f///37///8A////AP///wD///8A////AP///wD///8A", - "////rf///+z///8C////AP///wD///8B////1f///6j///8A////AP///wD///8A////AP///wD///8A////AP///63////s////Av///wD///8A////Af///9X///+o////AP///wD///8A////AP///wD///8A////AP///wD///+t////7P///wL///8A////AP///wH////V////qP///wD///8A////AP///wD///8A////AP///wD///8A", - "////rf///+z///8C////AP///wD///8B////1f///6j///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8g/////////1T///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////dP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "/////////2z///8A////AP///wD///8A////dv////L///8A////AP///wD///8A////AP///wD///8A////AP///+P///+N////AP///wD///8A////m/////////8A////AP///wD///8A////AP///wD///8A////AP///wD////j////jf///wD///8A////AP///5v/////////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////4////43///8A////AP///wD///+b/////////wD///8A////AP///wD///8A////AP///wD///8A////AP///+P///+N////AP///wD///8A////m/////////8A////AP///wD///8A////AP///wD///8A////AP///wD////j////jf///wD///8A////AP///5v/////////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////T///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Zf///+f////t////lf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP////////8o////AP///wD///8o/////////wD///8A////AP///wD///8A////AP///wD////h////////////////////xP///wD////E////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Uf///9b///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Av///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////vv///wD///++////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///5f////D////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Av///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8C////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///yz///+0////5v///+////+4////5P///yz///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///z/////T////8////9j///9K////AP///wD///8A////AP///wD///8A////AP///wD///8A////p////+n///8U////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8U", + "////6f///6X///8A////AP///wD///8A////AP///wD///8A////AP///wD///8N////3f///93///8N////AP///wD///8A////AP///wD///8A////AP///wD///9u////7P///4T///8Q////yv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////vv///wD///++////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////F////7j////0////wv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+n////6f///xT///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///xT////p////pf///wD///8A////AP///wD///8A////AP///wD///8A////AP///w3////d////3f///w3///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+n////6f///xT///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////FP///+n///+l////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///w3////d////3f///w3///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///7P///9o////Vf///6T///8A////AP///wD///8A////AP///wD///8A////AP///wD///9u////7P///4T///8Q////yv///wD///8A////AP///wD///8A////AP///wD///8A////p////+n///8U////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8U////6f///6X///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8N////3f///93///8N////AP///wD///8A////AP///wD///8A////AP///wD///8A////bv///+z///+E////EP///8r///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///6f////p////FP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////FP///+n///+l////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////Df///93////d////Df///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///xX////5////I////wD///8A////H/////n///8V////AP///wD///8A////AP///wD/////////dP///93////v////ov///wz///8A////AP///wD///8A", + "////AP///wD///8A////Ff////n///8j////AP///wD///8f////+f///xX///8A////AP///wD///8A////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////b////73///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////vv///2////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////MP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///y3////z////bv///w////8P////bf////H///8k////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////", + "////9f////T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////T////1/////////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////R////8n////v////AP///wD///8A////AP///wD///8A////AP///wD////0////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////7////8j///9F////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////0////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////mf///////////////////8T///8E////xP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wP///+Q////tv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////t////4////8C////AP///wD///8A////AP///wD///8A////AP///wD///8A////rv///1z///9f", + "////rv///wD///8A////AP///wD///8A////AP///wD///8A////AP///8r///8R////hv///+3///9t////AP///wD///8A////AP///wD///8A////AP///wD////K////GP///xn////O////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///47///+y////iP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8U////5v///6L///8h////Av///yb///9G////AP///wD///8A////AP///wD///8A////AP///wP///+Q////tv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////t////4////8C////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////rv///1z///9f////rv///wD///8A////AP///wD///8A////AP///wD///8A////AP///8r///8Y////Gf///87///8A////AP///wD///8A////AP///wD///8A////AP///wD///8D////kP///7b///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///7f///+P////Av///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///67///9c////X////67///8A////AP///wD///8A////AP///wD///8A////AP///wD////K////GP///xn////O////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///8r///8R", + "////hv///+3///9t////AP///wD///8A////AP///wD///8A////AP///wD///8A////A////5D///+2////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+3////j////wL///8A////AP///wD///8A////AP///wD///8A////AP///wD///+u////XP///1////+u////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////yv///xH///+G////7f///23///8A////AP///wD///8A////AP///wD///8A////AP///8r///8Y////Gf///87///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///xv///8A", + "////AP///wD///8A////AP///wD///8A////AP///wP///+Q////tv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////t////4////8C////AP///wD///8A////AP///wD///8A////AP///wD///8A////rv///1z///9f////rv///wD///8A////AP///wD///8A////AP///wD///8A////AP///8r///8Y", + "////Gf///87///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///7f///+P////Av///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wL///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///47///+y////iP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wL///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8C////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A/////////yj///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Lv///7X////m////5v///7L///8o////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wT////c////Iv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////9P///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////9P///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///xD///+g", + "////6v////////////////////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+n////6f///xT///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///xT////p////pf///wD///8A////AP///wD///8A////AP///wD///8A////AP///w3////d////3f///w3///8A////AP///wD///8A////AP///wD///8A////AP///wD///9u////7P///4T///8Q////yv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///xP///+Y////1v////T////i////kf///wD///8A////AP///wD///8A////AP///wD///+n////6f///xT///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///xT////p////pf///wD///8A////AP///wD///8A////AP///wD///8A////AP///w3////d////3f///w3///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////p////+n///8U", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8U////6f///6X///8A////AP///wD///8A////AP///wD///8A////AP///wD///8N////3f///93///8N////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9u////7P///4T///8Q////yv///wD///8A////AP///wD///8A////AP///wD///8A////AP///6f////p////FP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////FP///+n///+l////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////Df///93////d////Df///wD///8A////AP///wD///8A////AP///wD///8A////AP///27////s////hP///xD////K////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+n////6f///xT///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///xT////p////pf///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///w3////d////3f///w3///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8U////6f///6X///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////t////4////8C////AP///wD///8A////AP///wD///8A////AP////////8o////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///8r///8Y////Gf///87///8A////AP///wD///8A////AP///wD///8A", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////T///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wL///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wL///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Av///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///xT////p////pf///wD///8A////AP///wD///8A////AP///wD/////////KP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AA==" +}; + +// Texture image block count +const size_t CAF_FIXED_ATLAS_FONT_10_PT_TEXTURE_IMAGE_BLOCK_COUNT = 902; + + +// Fixed Atlas Font: Droid Sans Regular (12pt) +// Exported by FreeType Font Extractor 1.0.0 +// Copyright (c) 2011 Ceetron AS +// -------------------------------------------------------------------------------- + +// Font name +const char CAF_FIXED_ATLAS_FONT_12_PT_NAME[] = "Droid Sans Regular (12pt)"; + +// Number of glyphs +const size_t CAF_FIXED_ATLAS_FONT_12_PT_NUM_GLYPHS = 256; + +// Horizontal bearings X +const short CAF_FIXED_ATLAS_FONT_12_PT_HORIZONTAL_BEARINGS_X[] = +{ + 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, 0, 0, 0, + 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, -1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, + 1, -1, 1, 0, 1, 1, 1, 0, 1, 0, -2, 1, 1, 1, 1, 0, 1, 0, 1, -1, 0, 1, -1, -1, -1, -2, 0, 1, -1, 0, 0, 0, + 3, 1, 1, 1, 1, 1, 0, 0, 1, 0, -1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, -1, -1, 0, -1, 1, 0, 4, 0, 1, 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, 0, 0, 0, 0, + 0, 1, 1, 1, 0, 1, 4, 0, 2, 1, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 3, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, + -1, -1, -1, -1, -1, -1, -1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, -2, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, 1, -1 +}; + +// Horizontal bearings Y +const short CAF_FIXED_ATLAS_FONT_12_PT_HORIZONTAL_BEARINGS_Y[] = +{ + 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, 0, 0, 0, + 0, 12, 12, 12, 13, 12, 12, 12, 12, 12, 13, 10, 2, 5, 2, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 9, 9, 10, 8, 10, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, -1, + 13, 9, 13, 9, 13, 9, 13, 9, 13, 12, 12, 13, 13, 9, 9, 9, 9, 9, 9, 9, 11, 9, 9, 9, 9, 9, 9, 12, 13, 12, 8, 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, 0, 0, 0, 0, + 0, 9, 12, 12, 9, 12, 13, 13, 12, 12, 12, 8, 6, 5, 12, 13, 12, 10, 12, 12, 13, 9, 13, 7, 0, 12, 12, 8, 12, 12, 12, 9, + 16, 16, 16, 17, 15, 15, 12, 12, 16, 16, 16, 15, 16, 16, 16, 15, 12, 17, 16, 16, 16, 17, 15, 9, 13, 16, 16, 16, 15, 16, 12, 13, + 13, 13, 13, 14, 12, 14, 9, 9, 13, 13, 13, 12, 13, 13, 13, 12, 13, 14, 13, 13, 13, 14, 12, 9, 9, 13, 13, 13, 12, 13, 13, 12 +}; + +// Horizontal advances +const cvf::uint CAF_FIXED_ATLAS_FONT_12_PT_HORIZONTAL_ADVANCES[] = +{ + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 4, 4, 7, 10, 9, 13, 11, 4, 5, 5, 9, 9, 4, 5, 4, 6, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 4, 4, 9, 9, 9, 7, + 14, 11, 11, 10, 11, 8, 8, 11, 11, 6, 4, 9, 8, 14, 12, 11, 9, 11, 10, 8, 8, 11, 10, 14, 9, 8, 9, 5, 6, 5, 9, 7, + 9, 9, 9, 8, 9, 9, 4, 8, 9, 4, 4, 8, 4, 14, 9, 9, 9, 9, 6, 7, 5, 9, 8, 12, 8, 8, 8, 6, 9, 6, 9, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 4, 4, 9, 9, 9, 9, 9, 8, 9, 13, 6, 8, 9, 5, 13, 8, 7, 9, 6, 6, 9, 9, 10, 4, 3, 6, 6, 8, 12, 12, 12, 7, + 11, 11, 11, 11, 11, 11, 14, 10, 8, 8, 8, 8, 6, 6, 6, 6, 11, 12, 11, 11, 11, 11, 11, 9, 11, 11, 11, 11, 11, 8, 9, 10, + 9, 9, 9, 9, 9, 9, 14, 8, 9, 9, 9, 9, 4, 4, 4, 4, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 8, 9, 8 +}; + +// Character widths +const cvf::uint CAF_FIXED_ATLAS_FONT_12_PT_CHARACTER_WIDTHS[] = +{ + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 4, 2, 5, 8, 7, 11, 10, 2, 5, 4, 8, 9, 3, 3, 3, 8, 7, 5, 8, 7, 9, 7, 7, 7, 7, 7, 3, 3, 7, 7, 7, 6, + 12, 12, 8, 9, 9, 6, 6, 10, 8, 5, 5, 9, 7, 11, 9, 10, 7, 10, 9, 8, 8, 8, 11, 15, 10, 11, 8, 3, 8, 3, 9, 7, + 3, 7, 7, 6, 7, 7, 5, 9, 7, 3, 4, 8, 2, 12, 7, 7, 7, 7, 5, 6, 5, 7, 10, 14, 8, 10, 7, 5, 2, 5, 7, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 4, 2, 7, 7, 8, 8, 2, 7, 5, 11, 4, 7, 7, 3, 11, 8, 5, 9, 6, 5, 3, 7, 7, 3, 3, 4, 4, 7, 11, 12, 12, 6, + 12, 12, 12, 12, 12, 12, 14, 9, 6, 6, 6, 6, 5, 5, 5, 5, 10, 9, 10, 10, 10, 10, 10, 7, 10, 8, 8, 8, 8, 11, 7, 8, + 7, 7, 7, 7, 7, 7, 12, 6, 7, 7, 7, 7, 3, 3, 5, 5, 7, 7, 7, 7, 7, 7, 7, 8, 7, 7, 7, 7, 7, 10, 7, 10 +}; + +// Character heights +const cvf::uint CAF_FIXED_ATLAS_FONT_12_PT_CHARACTER_HEIGHTS[] = +{ + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 4, 12, 4, 12, 14, 12, 12, 4, 15, 15, 7, 9, 4, 2, 2, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 9, 11, 8, 5, 8, 12, + 13, 12, 12, 12, 12, 12, 12, 12, 12, 12, 15, 12, 12, 12, 12, 12, 12, 15, 12, 12, 12, 12, 12, 12, 12, 12, 12, 15, 12, 15, 7, 2, + 3, 9, 13, 9, 13, 9, 13, 13, 13, 12, 16, 13, 13, 9, 9, 9, 13, 13, 9, 9, 11, 9, 9, 9, 9, 13, 9, 15, 17, 15, 5, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 4, 12, 12, 12, 7, 12, 17, 13, 2, 12, 5, 7, 5, 2, 12, 2, 5, 10, 7, 7, 3, 13, 15, 2, 4, 7, 5, 7, 12, 12, 12, 12, + 16, 16, 16, 17, 15, 15, 12, 16, 16, 16, 16, 15, 16, 16, 16, 15, 12, 17, 16, 16, 16, 17, 15, 7, 14, 16, 16, 16, 15, 16, 12, 13, + 13, 13, 13, 14, 12, 14, 9, 13, 13, 13, 13, 12, 13, 13, 13, 12, 13, 14, 13, 13, 13, 14, 12, 7, 9, 13, 13, 13, 12, 17, 17, 16 +}; + +// Texture image dimensions +const size_t CAF_FIXED_ATLAS_FONT_12_PT_TEXTURE_IMAGE_WIDTH = 4096; +const size_t CAF_FIXED_ATLAS_FONT_12_PT_TEXTURE_IMAGE_HEIGHT = 17; + +// Texture image data +const char* CAF_FIXED_ATLAS_FONT_12_PT_TEXTURE_IMAGE[] = +{ + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////zv///8n///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///7b///9C////AP///7b///9C////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////7v///zP///8V/////////xL///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A/////////xT///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8P////7f///zv///8A////AP///yP////E////9P///8X///8l////AP///wD///8A////AP///wD///8H////g////97////5////4f///47///8S////Q/////j///+M////AP///wD///8A////AP///wD///8A", + "////tv///0L///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8E////x////6z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+p////yf///wT///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///27///+4////AP///wD///+x////dv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8w////CP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////O////Xv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////UP///1D///9Q////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///1L////3////Uf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8T////9////1z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///zP///++////7////7////84////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////9g////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////////////////////////////////////dP///wD///8A////AP///wD///8A////AP///wD///8A", + "////j////93////3////6////8H///9K////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////9g////AP///wD///8A////AP///wD///8A////AP///wD///+Z////4P////z////o////vf///0H///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///yv///++////8v///9j///9q////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///xH////0////e////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8G////f////9v////2////2P///2////8B////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////HP////f////y////zP///2T///8B////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///1L////3////Uf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////O////Xv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8+////v////wD///8A////AP///wD///8A////AP///wD///8A////AP///yH///8s////LP///yz///8s////LP///yz///8A////AP///wD///8A////AP///wD///8A////AP///wD///+/////Pv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD////O////yf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Hv///5r////L////8////+7////O////hf///wD///8A////AP///wD///8A////AP///wD///8U////+v///2f///8A////AP///wD///8A////AP///wD///9r////+v///xT///8A////AP///wD///8A", + "/////////////////////////+/////G////T////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Jv///5/////L////8/////n////i////rf///wD///8A////AP///wD///8A////AP///wD////////////////////v////yf///5f///8a////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////////////////////////////////////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////90////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///x////+a////y/////T////7////6f///8T///+O////AP///wD///8A////AP///wD///8A", + "/////////3T///8A////AP///wD///8A////dP////////8A////AP///wD///8A////AP///wD///8A////AP///2b////7//////////////+W////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////t////9f///8b///84////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "/////////3T///8A////AP///wD///8A////t////93///8L////AP///wD///8A////AP///wD///8A////AP///////////////////////////////////6D///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////dP///wD///8A////Wf////////8q////AP///wD///90/////////wD///8A////AP///wD///8A", + "/////////3T///8A////AP///wD///8A////Gf////P/////////AP///wD///8A////AP///wD///8A////AP///wD///8A////WP///7f////n////5////7X///9O////AP///wD///8A////AP///wD///8A////AP///wD/////////dP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///2b///+b////AP///wD///8A////AP///wD///8A////AP////////90////AP///wD///8A////Af///8T////f////DP///wD///8A////AP///wD///8A////AP///wD///8T////qP///+L////3////7P///8T///9U////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8g/////////1T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8v////t////+r////m////sv///yn///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Y/////////9m////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////a/////////9I////AP///wD///8A////WP////////9c////AP///wD///8A////AP///w7////q////fP///wD///8A////AP///wD///+k////6////w7///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////IP////////9U////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "//////////////////////////////////////////////8A////AP///wD///8A////AP///wD///8A////AP///////////////////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///33////j////A////wD///8A////AP///wD///8A////AP///wD///8A", + "////////////////////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///7X///+3////AP///wD///8A////AP///wD///+1////t////wD///8A////AP///wD///8A////AP///wD///8Y////GP///xj///8Y////GP///xj///8Y////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///2D////W////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///y3////D////9v///+z///+Z////L/////////8A////AP///wD///8A////AP///wD///8A////AP///wD/////////PP///6z////1////2v///2L///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///z/////E////8v///+7///+X////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9m////2v////X///+t////Sv////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////LP///7j////s////+f///9L///9W////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP////////9s////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///yH///+o////5v////n////p////x////2n///8C////AP///wD///8A////AP///wD///8A////AP///wD/////////bP///wD///8A////AP///2z/////////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP////////9s////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///+7////s////gv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////bP///wD///8A////Av///73////V////Cv///wD///8A////AP///wD///8A////AP///wD///8A", + "/////////2z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////9s////AP///wD///8A////wP///6z///8A////AP///wD///9s/////////wD///8A////AP///wD/////////bP///wD///8A////AP///2z/////////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///0H////K////8////8v///9F////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////9s////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///2z/////////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "/////////2z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///w////+4////7/////L///+6////Jf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////NP///9P////7////4f///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////F////6z////u////8P///5////9H/////////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///x3////9////+v///xX///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wT////x////7v///wX///8A////AP///wn////0////8f///wT///8A////AP///wD///8A", + "////p////+T///8P////AP///wD///8Q////5f///6f///8A////AP///wD///8A////AP///wD///8A////AP///xj////y////8f///6z///8W////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///////////////////////////////////8k////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8l////t/////H///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////8s////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////x////tf///yP///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////+////1v///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A/////////1j///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////////////////////////////////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A/////////3T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////8s////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8P////rv///+j////6////5f///53///8U////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////yv///1L///8A////VP///8f///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////F////43////c////4f///9z///+N////F////wD///8A////AP///wD///8A////AP///wD///+X////5f///6j////j////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8y////qv///wD///8y////qv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////CP///zD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9Q////UP///1D///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8X////jf///9z////h////3P///43///8X////AP///wD///8A////AP///wD///8A////AP///xj///8Y////GP///xj///8Y////GP///xj///8Y////AP///wD///8A////AP///wD///8A////AP///wD///8h////v/////T///+9////H////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////CP////////////////////////////////////////8w////AP///wD///8A////AP///wD///8A////AP////3////5////+P////j////4////Rf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+8////8v////P////J////Ov///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////1v///2D///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////9s////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////8P///wD////w////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////Uv////f///9R////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///93////I////WP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////8g////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////Qf///97////d////Q////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///6r///8x////AP///6r///8x////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8N////5P///0X///8A////AP///wD///8A////AP////////8g////AP///wD///8A////AP///wD///8A", + "////Df///+T///9F////AP///wD///8A/////f////n////4////+P////j///9F////AP///wD///8A////AP///wD///8N////5P///0X///8A////AP///wD///8A////AP////////8g////AP///wD///8A////AP///wD///8L////lf///+f////x////yP///2n///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////FP////r///9n////AP///wD///8A////AP///wD///8A////a/////r///8U////AP///wD///8A////AP///xT////6////Z////wD///8A////AP///wD///8A////AP///2v////6////FP///wD///8A////AP///wD///8U////+v///2f///8A////AP///wD///8A////AP///wD///9r////+v///xT///8A////AP///wD///8A", + "////FP////r///9n////AP///wD///8A////AP///wD///8A////a/////r///8U////AP///wD///8A////AP///xT////6////Z////wD///8A////AP///wD///8A////AP///2v////6////FP///wD///8A////AP///wD///8U////+v///2f///8A////AP///wD///8A////AP///wD///9r////+v///xT///8A////AP///wD///8A", + "////Ef////T///9s////AP///wD///8A////AP///wD///////////////////////////////////8A////AP///wD///8A////AP///wD////d////yP///1j///8A////AP///wD///8A////AP///wD///8A////AP///wD///////////////////////////////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////////////////////////////////////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///////////////////////////////////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///////////////////////////////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////Zv////v//////////////5b///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///2b////7//////////////+W////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9m////+///////////////lv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////Zv////v//////////////5b///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////////////////////v////yf///5f///8a////AP///wD///8A////AP///wD///8A////AP///wD/////////dP///wD///8A////AP///wD///8Z////8/////////8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///9Y////t////+f////n////tf///07///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////WP///7f////n////5////7X///9O////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///1j///+3////5////+f///+1////Tv///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///9Y////t////+f////n////tf///07///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////WP///7f////n////5////7X///9O////AP///wD///8A////AP///wD///8A////AP///wD///9I////R////wD///8A////AP///0L///9U////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///zb///8D////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8v////t////+r////m////sv///yn///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////L////7f////q////5v///7L///8p////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///y////+3////6v///+b///+y////Kf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8v////t////+r////m////sv///yn///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////IP////////9U////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "/////////3T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////9s////AP///63////t////8////7f///8g////AP///wD///8A////AP///wD///8A////AP///wD///8t////w/////b////s////mf///y//////////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////Lf///8P////2////7P///5n///8v/////////wD///8A////AP///wD///8A////AP///wD///8A////AP///y3////D////9v///+z///+Z////L/////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8t////w/////b////s////mf///y//////////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////Lf///8P////2////7P///5n///8v/////////wD///8A////AP///wD///8A////AP///wD///8A////AP///y3////D////9v///+z///+Z////L/////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8w////yf////f////d////bP///wD///8s////rv///+f////4////0v///1X///8A////AP///wD///8A", + "////AP///wD////d////yP///1j///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8s////uP///+z////5////0v///1b///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////LP///7j////s////+f///9L///9W////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///yz///+4////7P////n////S////Vv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8s////uP///+z////5////0v///1b///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////2z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "/////////2z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////2z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////9s////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///1L////Q////8////8f///89////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////9s////AP///wD///8A////bP////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Qf///8r////z////y////0X///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///0H////K////8////8v///9F////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9B////yv////P////L////Rf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Qf///8r////z////y////0X///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///0H////K////8////8v///9F////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///+T///8Z////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9O////zv///8D////x////y////0X///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////F////6z////u////8P///5////9H/////////wD///8A////AP///wD///8A////AP///wD///8A////AP///xf///+s////7v////D///+f////R/////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8X////rP///+7////w////n////0f/////////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////F////6z////u////8P///5////9H/////////wD///8A////AP///wD///8A////AP///wD///8A////AP///xj////y////8f///6z///8W////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////bP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////GP////L////x////rP///xb///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///83////I////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////L////V////wD////L////V////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///8r///9Z////AP///+7///83////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////8U////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///3f////B////AP///wD///+2////o////yL///+q////t////wD///8A////AP///wD///8A", + "////i/////v///9+////R////2r////b////4f////P///+j////Af///wD///8A////AP///wD///8A////AP///8v///9X////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////fv////D///8X////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////Fv////D///96////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9P/////////1H///9W/////////1P///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////yz///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////cP///+T///8J////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///////////////////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9S////9P///1H///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///6L////F////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///xr////q////p////0v///+s////7v///yD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////YP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////t////+3///9d////TP///0z///9M////TP///yL///8A////AP///wD///8A////AP///wD///8A////AP///8L///9q////RP///0z///+g/////////1T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////YP///wD///8A////AP///wD///8A////AP///wD///8A", + "////uv///2b///8+////TP///57/////////Rv///wD///8A////AP///wD///8A////AP///wD///8A////AP///xn////x////pv///0f///91////+v///2L///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////lP///+X///8F////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////h/////H///9s////Qf///3P////2////dP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wn///8v////Ov///4T////8////kf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9S////9P///1H///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////cP///+T///8J////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///zz///+9////8P///4L///8A////AP///wD///8A////AP///wD///8A////AP///wD////A////////////////////////////////////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////gv////D///+9////PP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////zf///8j///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////WP////L///+Y////SP///x////8f////Sv///5P///8A////AP///wD///8A////AP///wD///8A", + "////AP///63////G////AP///wD///8A////AP///wD///8A////yP///63///8A////AP///wD///8A////AP////////+O////MP///zH///9J////pP////////9T////AP///wD///8A////AP///wD///8A////AP///wD///8A////Yf////b////S////a////0L///89////XP///5r///8A////AP///wD///8A////AP///wD///8A", + "/////////47///8w////SP///3D////c////8f///1T///8A////AP///wD///8A////AP///wD///8A////AP////////+O////MP///zD///8w////MP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////dP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///1j////z////2v///3T///9K////Mv///0H///+m/////////wD///8A////AP///wD///8A////AP////////90////AP///wD///8A////AP///3T/////////AP///wD///8A////AP///wD///8A////AP///wD///8A////KP////////9c////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////Qv///zr///+u////7P///xL///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////90////AP///wD///8A////X/////3///89////AP///wD///8A////AP///wD///8A////AP///wD/////////jv///zD///8w////MP///zD///8e////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "/////////3T///8A////AP///6v////8////f////wD///8A////dP////////8A////AP///wD///8A////AP////////90////AP///wD///8A////AP///6D////4/////////wD///8A////AP///wD///8A////AP///wD///8A////jf////7///+S////S////0r///+Q/////f///37///8A////AP///wD///8A////AP///wD///8A", + "/////////3T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///2j/////////mv///wT///8A////AP///wD///8A////AP///wD/////////dP///wD///8A////AP///2v/////////Q////wD///8A////AP///wD///8A////AP///wD///8A", + "////JP///6r///9f////OP///1X///+X/////////2T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////IP////////9U////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8r////+P///87///9m////R////6/////2////KP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///7n////N////vP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///6r////k////gP///wD///8A////AP///4/////j////nP///wD///8A////AP///wD///8A////bP////H///8T////AP///wD///8n/////P///3D///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///yD/////////VP///wD///8A////AP///wD///8A////AP///wD///8A////AP///7L////m////Nf///zD///8w////MP///zD///8w////AP///wD///8A////AP///wD///8A////AP///wD/////////hf///yz///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wP////j////ff///wD///8A////AP///wD///8A////AP///wD///8A////AP///yz///+F/////////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8m////+f///0b///8A////AP///wD///9A////+////yn///8A////AP///wD///8A////AP///wD///8A", + "/////////////////////////////////////////wD///8A////AP///wD///8A////AP///wD///8A////AP///zH////4////Vv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////M////3f///0////8+////hv///+b/////////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "//////////D///+E////R////7v/////////R////wD///8A////AP///wD///8A////AP///wD///8A////AP///zP////9////zv///2H///9X////fP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9L/////////7T///9F////e////+z/////////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////JP////f////B////Zv///0f///9x////b////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////bP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////L////uf///yf///8Q////NP///2P////1////kP///wD///8A////AP///wD///8A////AP///wD///8A", + "/////////2z///8A////AP///wD///9s/////////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////bP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///88////b/////////8z////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "/////////2z///8A////AP///3/////2////K////wD///8A////AP///wD///8A////AP///wD///8A////AP////////9s////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////bP///wD///8A////AP///8D///+s////AP///wD///8A////bP////////8A////AP///wD///8A", + "/////////2z///8A////AP///wD///9s/////////wD///8A////AP///wD///8A////AP///wD///8A////AP///zD////7////t////1H///+4/////f///zX///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////bP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///9s/////////wD///8A////AP///wD///8A////AP///wD///8A////AP////////9s////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8a////jf///0H///9B////zf///8P///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///8j////V////Rv///0L///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///6b////x////df///0D///+S////7f////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///96////zP///9z///9w////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///87////5v///9H///9D////AP///wD///9J////1f///+n///86////AP///wD///8A////AP///xH////k////nv///wD///8A////n////+P///8R////AP///wD///8A////AP///wD///8A////AP///wD///8H////Nf///0n////T////uP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////o////9f///8O////CP///wj///8I////Af///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////x////8r///88////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////LP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////PP///8r////E////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///0v///8A////AP///0L////e////4////1f///8A////AP///wD///8A////AP///wD///8A////AP///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////+f///8r///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////9b////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////I////zf///0z///9M////TP///0z///9M////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///7X///+d////7P///+v///+f////uP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////90////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////LP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////Gf///5P///9O////NP///0z////M////tf///wD///8A////AP///wD///8A////AP///wD///8A////AP///8n///9R////AP///1T////T////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////L////9z///9t////Ff///wD///8V////b////93///8v////AP///wD///8A////AP///wD///8A", + "////6P///yf///8s/////////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8G////0v///2X///8G////0v///2X///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///yz/////////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////////////////////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8v////3P///23///8V////AP///xX///9v////3f///y////8A////AP///wD///8A////AP///wD//////////////////////////////////////////////wD///8A////AP///wD///8A////AP///wD///8A", + "////v////6L///8h////i////7v///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wH///8s////LP///yz///9c////NP///yz///8s////CP///wD///8A////AP///wD///8A////AP///wD///9Q////sP///xT///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////Tf///w3///8M////ff///97///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///1b////4////Lv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////bP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP////D///8A////8P///wD///8A////AP///wD///8A////AP///wD///8A////AP///1L////0////Uf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Q////+X///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD/////////IP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///9T///9E////R////9T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9m////0f///wX///9m////0f///wX///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///1f////Z////Bv///wD///8A////AP///wD/////////IP///wD///8A////AP///wD///8A////AP///wD///9X////2f///wb///8A////AP///1D///+w////FP///wD///8A////AP///wD///8A////AP///wD///8A////AP///1f////Z////Bv///wD///8A////AP///wD/////////IP///wD///8A////AP///wD///8A", + "////k////+3///9l////UP///4b///+Y////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+t////xv///wD///8A////AP///wD///8A////AP///8j///+t////AP///wD///8A////AP///wD///8A////rf///8b///8A////AP///wD///8A////AP///wD////I////rf///wD///8A////AP///wD///8A", + "////AP///63////G////AP///wD///8A////AP///wD///8A////yP///63///8A////AP///wD///8A////AP///wD///+t////xv///wD///8A////AP///wD///8A////AP///8j///+t////AP///wD///8A////AP///wD///8A////rf///8b///8A////AP///wD///8A////AP///wD////I////rf///wD///8A////AP///wD///8A", + "////AP///63////G////AP///wD///8A////AP///wD///8A////yP///63///8A////AP///wD///8A////AP///wD///+R////2////wL///8A////AP///wD///8A/////////47///8w////MP///zD///8w////AP///wD///8A////AP///wD///8A////AP///0P////l////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "/////////47///8w////MP///zD///8w////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////+O////MP///zD///8w////MP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////jv///zD///8w////MP///zD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "/////////47///8w////MP///zD///8w////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8o/////////1z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////KP////////9c////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///yj/////////XP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8o/////////1z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////47///8w////SP///3D////c////8f///1T///8A////AP///wD///8A////AP///wD///8A", + "/////////3T///8A////AP///wD///8A////oP////j/////////AP///wD///8A////AP///wD///8A////AP///wD///+N/////v///5L///9L////Sv///5D////9////fv///wD///8A////AP///wD///8A////AP///wD///8A////jf////7///+S////S////0r///+Q/////f///37///8A////AP///wD///8A////AP///wD///8A", + "////AP///43////+////kv///0v///9K////kP////3///9+////AP///wD///8A////AP///wD///8A////AP///wD///+N/////v///5L///9L////Sv///5D////9////fv///wD///8A////AP///wD///8A////AP///wD///8A////jf////7///+S////S////0r///+Q/////f///37///8A////AP///wD///8A////AP///wD///8A", + "////Rv///+H///8p////AP///yf////e////Rf///wD///8A////AP///wD///8A////AP///wD///8A////AP///w3////u////ov///6v////j////5////7X///9O////AP///wD///8A////AP///wD///8A////AP///wD///8r////+P///87///9m////R////6/////2////KP///wD///8A////AP///wD///8A////AP///wD///8A", + "////K/////j////O////Zv///0f///+v////9v///yj///8A////AP///wD///8A////AP///wD///8A////AP///yv////4////zv///2b///9H////r/////b///8o////AP///wD///8A////AP///wD///8A////AP///wD///8r////+P///87///9m////R////6/////2////KP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///yD/////////VP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////90////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////bP///wD///+U////QP///0X////Y////t////wD///8A////AP///wD///8A////AP///wD///8A", + "////zP///93///9P////Pv///4b////m/////////wD///8A////AP///wD///8A////AP///wD///8A////AP///8z////d////T////z7///+G////5v////////8A////AP///wD///8A////AP///wD///8A////AP///wD////M////3f///0////8+////hv///+b/////////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////zP///93///9P////Pv///4b////m/////////wD///8A////AP///wD///8A////AP///wD///8A////AP///8z////d////T////z7///+G////5v////////8A////AP///wD///8A////AP///wD///8A////AP///wD////M////3f///0////8+////hv///+b/////////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////zf///9z///9K////Tv///9H///+L////6f///8T///9t////T////3n///90////AP///wD///8A////AP///wD///8A////AP///0P////l////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8k////9////8H///9m////R////3H///9v////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////JP////f////B////Zv///0f///9x////b////wD///8A////AP///wD///8A////AP///wD///8A////AP///yT////3////wf///2b///9H////cf///2////8A////AP///wD///8A////AP///wD///8A////AP///wD///8k////9////8H///9m////R////3H///9v////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP////////9s////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////9s////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////9s////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD/////////bP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///0j////+////hf///0f///+2////+f///yr///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////bP///wD///8A////AP///2z/////////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////MP////v///+3////Uf///7j////9////Nf///wD///8A////AP///wD///8A////AP///wD///8A////AP///zD////7////t////1H///+4/////f///zX///8A////AP///wD///8A////AP///wD///8A////AP///wD///8w////+////7f///9R////uP////3///81////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////MP////v///+3////Uf///7j////9////Nf///wD///8A////AP///wD///8A////AP///wD///8A////AP///zD////7////t////1H///+4/////f///zX///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8a////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////OP////////+6////RP///7j////9////Nf///wD///8A////AP///wD///8A////AP///wD///8A////AP///6b////x////df///0D///+S////7f////////8A////AP///wD///8A////AP///wD///8A////AP///wD///+m////8f///3X///9A////kv///+3/////////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////pv////H///91////QP///5L////t/////////wD///8A////AP///wD///8A////AP///wD///8A////AP///6b////x////df///0D///+S////7f////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8H////Nf///0n////T////uP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "/////////2z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wf///81////Sf///9P///+4////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////4P///2z///8A////4P///2z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+m////f////wD////J////XP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+i////4P////r/////////0f///3n///8H////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8K////5v///0f///8A////8P///0L///8A////Rf///+////8A////AP///wD///8A////AP///+P///+e////AP///wD///8A////Mv////7////6////If///wD///8A////AP///wD///8A////AP///wD////g////bP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////C////+////+M////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+N////7f///wr///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///4v////W////4v///4z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP////////8s////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///xz////+////bv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///84/////////y////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///92////5f///wb///8A////CP///+j///99////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A/////////2D///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wr////D////yv///w7///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///7n////O////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A/////////2D///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////tv///8X///8A////AP///wD///8A////AP///wD///8A////AP///wD///+L////z////wH///8A////AP///5j////Q////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///yP////9////Wv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///+L///+C////AP///wD///8A////if///9r///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////bv////////83////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///xz////+////bv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Ov///7v////u////fv///w////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8P////ff///+3///+6////Of///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////G/////P///9T////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9L/////////yb///8A////AP///wD///8A////Jv////////9L////AP///wD///8A////AP///wD/////////dP///wD///8A////AP///wD////I////zP///wD///8A////AP///wD///8A////AP///wD///8A", + "////Hv////f///+q////Bv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////90////AP///wD///8A////Cf///7L////v////Ff///wD///8A////AP///wD///8A////AP///wD/////////dP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "/////////3T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///xn////z////sf///wv///8A////AP///wD///8A////dP////////8A////AP///wD///8A////AP///wD/////////dP///wD///8A////AP///wD///90/////////wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///yD/////////VP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////GP////////9S////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////dP///wD///8A////GP///+7///+O////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "/////////3T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////90////AP///wj////0////iv///9T///8A////AP///3T/////////AP///wD///8A////AP///wD/////////dP///wD///8A////AP///zP////8////j/////////8A////AP///wD///8A////AP///wD///8A", + "////M/////////9w////AP///wD///8A////AP///23////9////KP///wD///8A////AP///wD///8A////AP////////90////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///xz////y////nP///wD///8A////AP///wD///8A////AP///wD///8A", + "/////////3T///8A////AP///x3////y////mf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///7z////U////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///yD/////////VP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////rf///+z///8C////AP///wD///8B////1f///6j///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///xP////7////Uv////z///8V////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////o////n////7n///8A////AP///wD////G////k////9z///8A////AP///wD///8A", + "////AP///wX////a////jP///wD///8A////pP///9////8G////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8g/////////1T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8a////8P///37///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "/////////2z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9R////+v///xj///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////bP////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///4r////S////Av///wD///8B////yv///5P///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////P////3v///wL///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////4////43///8A////AP///wD///+b/////////wD///8A////AP///wD///8A////AP///wD///8A////AP////////+4////AP///wD///8A////3v///7T///8A////AP///wD///8A////AP///wD///8A////AP///wD///+x////6v///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////uv///9r///8A////AP///wD///+0/////////wD///8A////AP///wD///8A////AP///wD///8A////AP///6f////m////Av///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////2z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////8v///2n///8A////AP///wD///8A////fv///+z///8A////AP///wD///8A////AP///wD///8A////AP////////9s////AP///wD///8A////bP////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////2z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wT/////////Y////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////9s////AP///0H////9////ZP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////bP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "/////////2z///8A////AP///wD////A////rP///wD///8A////AP///2z/////////AP///wD///8A////AP////////9s////AP///wD///8A////bP////////8A////AP///wD///8A////AP///wD///8A////AP///wD///+r////2P///wD///8A////AP///9z///+s////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "/////////2z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////bP////////8A////AP///wD///8A////AP///wD///8A////AP///wD/////////bP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///3f////0////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////1////ff///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////o////ov///wD///8A////AP///7//////////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////2P///4H///+Q////0P///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////gP///7r///+Y////kf///wD///8A////kf///5v///+8////f////wD///8A////AP///wD///8A////Rv////7///9I////Sf////7///9E////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////Nv////////82////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///xP////q////gP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////v///9x////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "/////////yz///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9x////+v///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////j////Sv///3j////2////c////0f////j////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////T///++////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////bv///9v//////////////+////+c////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////M/////////84////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+e////0P///zP///8t////w////5r///8A////AP///wD///8A////AP///wD///8A////AP///wD///8B////MP///zD/////////jv///zD///8o////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "/////////yz///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////av///+7///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////Dv///9j///80////AP///wD///8A////AP///wD///80////2P///w7///8A////AP///wD///8A////AP///1n////E////3P////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////g////7L///8A////g////7L///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8s/////////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8O////2P///zT///8A////AP///wD///8A////AP///zT////Y////Dv///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////P///84////AP///x3////y////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////yz///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///zX////L////M////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Af///2n////W////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8C////3v///8z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "/////////2z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////w////AP////D///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///9L///+6////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////yD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////3////E////xT////2////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///7L///+C////AP///7L///+C////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////u////3z///8A////9f////j////4//////////n///8b////AP///wD///8A////AP///wD///8A////AP///7v///98////AP///wD///8A////Nf///8v///8z////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////u////3z///8A////9f////j////4//////////n///8b////AP///wD///8A////AP///+X///93////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////S/////////8m////AP///wD///8A////AP///yb/////////S////wD///8A////AP///wD///8A", + "////AP///0v/////////Jv///wD///8A////AP///wD///8m/////////0v///8A////AP///wD///8A////AP///wD///9L/////////yb///8A////AP///wD///8A////Jv////////9L////AP///wD///8A////AP///wD///8A////S/////////8m////AP///wD///8A////AP///yb/////////S////wD///8A////AP///wD///8A", + "////AP///0v/////////Jv///wD///8A////AP///wD///8m/////////0v///8A////AP///wD///8A////AP///wD///9L/////////yb///8A////AP///wD///8A////Jv////////9L////AP///wD///8A////AP///wD///8A////IP////z///9O////AP///wD///8A////AP////////90////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD////S////uv///wD///8A////AP///wD///8A////AP///wD///8A////AP////////90////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////dP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "/////////3T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////90////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////IP////////9U////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///yD/////////VP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8g/////////1T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////IP////////9U////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP////////90////AP///wD///8A////Cf///7L////v////Ff///wD///8A////AP///wD///8A////AP////////90////AP///wD///8A////M/////z///+P/////////wD///8A////AP///wD///8A////AP///wD///8z/////////3D///8A////AP///wD///8A////bf////3///8o////AP///wD///8A////AP///wD///8A", + "////M/////////9w////AP///wD///8A////AP///23////9////KP///wD///8A////AP///wD///8A////AP///zP/////////cP///wD///8A////AP///wD///9t/////f///yj///8A////AP///wD///8A////AP///wD///8z/////////3D///8A////AP///wD///8A////bf////3///8o////AP///wD///8A////AP///wD///8A", + "////M/////////9w////AP///wD///8A////AP///23////9////KP///wD///8A////AP///wD///8A////AP///wD///8o////uP///yb///+2////J////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////rf////////+d////QP///0r///+Q/////f///37///8A////AP///wD///8A////AP///wD///8A", + "////rf///+z///8C////AP///wD///8B////1f///6j///8A////AP///wD///8A////AP///wD///8A////AP///63////s////Av///wD///8A////Af///9X///+o////AP///wD///8A////AP///wD///8A////AP///wD///+t////7P///wL///8A////AP///wH////V////qP///wD///8A////AP///wD///8A////AP///wD///8A", + "////rf///+z///8C////AP///wD///8B////1f///6j///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8g/////////1T///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////dP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "/////////2z///8A////AP///wD///8A////dv////L///8A////AP///wD///8A////AP///wD///8A////AP///+P///+N////AP///wD///8A////m/////////8A////AP///wD///8A////AP///wD///8A////AP///wD////j////jf///wD///8A////AP///5v/////////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////4////43///8A////AP///wD///+b/////////wD///8A////AP///wD///8A////AP///wD///8A////AP///+P///+N////AP///wD///8A////m/////////8A////AP///wD///8A////AP///wD///8A////AP///wD////j////jf///wD///8A////AP///5v/////////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////4////43///8A////AP///wD///+b/////////wD///8A////AP///wD///8A////AP///wD///8A////AP///+X///+J////AP///wD///8v/////////+X///8B////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////S////uv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////p////+b///8C////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///6f////m////Av///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+n////5v///wL///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////p////+b///8C////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////bP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////bP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", @@ -405,39 +1395,1330 @@ const char* CAF_FIXED_ATLAS_FONT_12_PT_TEXTURE_IMAGE[] = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////1v///3r///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////X///+B////AP////X///+B////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////gv///6X///8A////o////4H///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////tf///2v///9C/////////4f////t////nv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///2v////M////AP////L///9C////AP///0X////u////AP///wD///8A////AP///wD////0////hP///wD///8A////Gf///9/////L////yf///9D///8H////AP///wD///8A////AP///wD///8A", - "////9f///4H///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///2D/////////I////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////I/////////9f////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////kv///7T////L///////////////L////tP///5X///8A////AP///wD///8A////AP///wD///8A////AP///wH///8s////LP///yz/////////UP///yz///8s////CP///wD///8A////AP///wD///8A////AP///wD///8A////zv///9n///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///87///+Y////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////xf///6f///8A////AP///wD///+o////yf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////9g////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////D////87////D////Cv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///9/////8f///wD///8A////AP///wD///8A////AP///wD///8A////AP///////////////////////////////////////////////////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///4b////x////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////zP///4T///8A////AP///wD///9p////9P///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////r////8n///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////0////fP///wD///8A////AP///3D////x////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wX////v////l////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////zv///9n///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////uf///+v///96////Df///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///yH///8s////LP///yz///8s////LP///yz///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8N////eP///+r///+4////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD////8////X////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///5b///+0////AP///xr///+6////9P///7////8g////uP////L///+Y////Av///wD///8A////AP///wD///8A////A////+X///+V////MP///zD///8w////MP///5P////m////A////wD///8A////AP///wD///8A", - "/////////3T///8A////AP///wD///8A////lf////T///8A////AP///wD///8A////AP///wD///8A////AP///5f////0////GP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////dP///wD///8A////AP///wD///8e////9////43///8A////AP///wD///8A////AP///wD///8A", - "/////////3T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////90////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+S////+P///xz///8A////AP///wD///8A////AP///3T/////////AP///wD///8A////AP///wD///8A", - "/////////3T///8A////AP///wD///8A////dP////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8g/////////1T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////cf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "/////////3T///8A////AP///63////Y////CP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////90////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////dP///wD///9O////7f///wn////t////Kf///wD///90/////////wD///8A////AP///wD///8A", - "/////////3T///8A////AP///wD////D////nv///2f/////////AP///wD///8A////AP///wD///8A////AP///6T////r////B////wD///8A////AP///wD///8G////6////5z///8A////AP///wD///8A////AP///wD/////////dP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///9Y////t////+f////+/////////2D///8A////AP///wD///8A////AP///wD///8A////AP////////90////AP///wD///+1////4v///w7///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+F////8v///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8g/////////1T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///+L///+m////AP///wD///8A////AP///4v////g////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9l////4////wD////i////Z////wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8o/////////0v////w////Af///wD///8F////9////zj/////////Hf///wD///8A////AP///wD///8A////Uv////f///8d////J/////z///9c////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////IP////////9U////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///2T////5////K////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////9s////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////u////6n///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///2z/////////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8N////5////2T///8A////Vv///+7///8S////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///2n////1////hf///1H///87////iv////////8A////AP///wD///8A////AP///wD///8A////AP///wD/////////ff///wD///8A////AP///6z////g////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////3v///7D///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///+T///+o////AP///wD///8A////f/////////8A////AP///wD///8A////AP///wD///8A////AP///wD////d////rf///zD///8w////MP///zD///8w////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP////////9s////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///4D////h////Y////0j///9I////V////8X////W////AP///wD///8A////AP///wD///8A////AP///wD/////////bP///wD///8A////AP///2z/////////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP////////9s////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////2z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////o////x/////m////pf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "/////////2z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////9s////AP///wD///8A////wP///6z///8A////AP///wD///9s/////////wD///8A////AP///wD/////////bP///wD///8A////AP///2z/////////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////3v///6j///8A////AP///wD///+r////3f///wD///8A////AP///wD///8A////AP///wD///8A////AP////////9r////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///2z/////////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "/////////2z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///zP////i////yP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////2z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "/////////27///8A////AP///wD///+B/////////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////N/////////8x////O/////////8w////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///8X///+G////WP///97///8A////AP///9n///9a////if///8T///8A////AP///wD///8A", - "////AP///wD///+U////4////+P///+R////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////R////nf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////WP////n///8s////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD/////////bP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////8s////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////bP////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////V////+L////a////QP///wD///8A////TP///wD///8A////AP///wD///8A////AP///wD///8A////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////1v///3r///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////X///+B////AP////X///+B////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////gv///6X///8A////o////4H///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////tf///2v///9C/////////4f////t////nv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///2v////M////AP////L///9C////AP///0X////u////AP///wD///8A////AP///wD////0////hP///wD///8A////Gf///9/////L////yf///9D///8H////AP///wD///8A////AP///wD///8A", + "////9f///4H///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///2D/////////I////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////I/////////9f////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////kv///7T////L///////////////L////tP///5X///8A////AP///wD///8A////AP///wD///8A////AP///wH///8s////LP///yz/////////UP///yz///8s////CP///wD///8A////AP///wD///8A////AP///wD///8A////zv///9n///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///87///+Y////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////xf///6f///8A////AP///wD///+o////yf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////9g////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////D////87////D////Cv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///9/////8f///wD///8A////AP///wD///8A////AP///wD///8A////AP///////////////////////////////////////////////////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///4b////x////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////zP///4T///8A////AP///wD///9p////9P///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////r////8n///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////0////fP///wD///8A////AP///3D////x////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wX////v////l////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////zv///9n///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////uf///+v///96////Df///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///yH///8s////LP///yz///8s////LP///yz///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8N////eP///+r///+4////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD////8////X////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///5b///+0////AP///xr///+6////9P///7////8g////uP////L///+Y////Av///wD///8A////AP///wD///8A////A////+X///+V////MP///zD///8w////MP///5P////m////A////wD///8A////AP///wD///8A", + "/////////3T///8A////AP///wD///8A////lf////T///8A////AP///wD///8A////AP///wD///8A////AP///5f////0////GP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////dP///wD///8A////AP///wD///8e////9////43///8A////AP///wD///8A////AP///wD///8A", + "/////////3T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////90////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+S////+P///xz///8A////AP///wD///8A////AP///3T/////////AP///wD///8A////AP///wD///8A", + "/////////3T///8A////AP///wD///8A////dP////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8g/////////1T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////cf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "/////////3T///8A////AP///63////Y////CP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////90////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////dP///wD///9O////7f///wn////t////Kf///wD///90/////////wD///8A////AP///wD///8A", + "/////////3T///8A////AP///wD////D////nv///2f/////////AP///wD///8A////AP///wD///8A////AP///6T////r////B////wD///8A////AP///wD///8G////6////5z///8A////AP///wD///8A////AP///wD/////////dP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///9Y////t////+f////+/////////2D///8A////AP///wD///8A////AP///wD///8A////AP////////90////AP///wD///+1////4v///w7///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+F////8v///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8g/////////1T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///+L///+m////AP///wD///8A////AP///4v////g////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9l////4////wD////i////Z////wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8o/////////0v////w////Af///wD///8F////9////zj/////////Hf///wD///8A////AP///wD///8A////Uv////f///8d////J/////z///9c////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////IP////////9U////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///2T////5////K////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////9s////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////u////6n///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///2z/////////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8N////5////2T///8A////Vv///+7///8S////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///2n////1////hf///1H///87////iv////////8A////AP///wD///8A////AP///wD///8A////AP///wD/////////ff///wD///8A////AP///6z////g////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////3v///7D///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///+T///+o////AP///wD///8A////f/////////8A////AP///wD///8A////AP///wD///8A////AP///wD////d////rf///zD///8w////MP///zD///8w////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP////////9s////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///4D////h////Y////0j///9I////V////8X////W////AP///wD///8A////AP///wD///8A////AP///wD/////////bP///wD///8A////AP///2z/////////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP////////9s////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////2z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////o////x/////m////pf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "/////////2z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////9s////AP///wD///8A////wP///6z///8A////AP///wD///9s/////////wD///8A////AP///wD/////////bP///wD///8A////AP///2z/////////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////3v///6j///8A////AP///wD///+r////3f///wD///8A////AP///wD///8A////AP///wD///8A////AP////////9r////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///2z/////////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "/////////2z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///zP////i////yP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////2z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "/////////27///8A////AP///wD///+B/////////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////N/////////8x////O/////////8w////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///8X///+G////WP///97///8A////AP///9n///9a////if///8T///8A////AP///wD///8A", + "////AP///wD///+U////4////+P///+R////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////R////nf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////WP////n///8s////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD/////////bP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////8s////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////bP////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////V////+L////a////QP///wD///8A////TP///wD///8A////AP///wD///8A////AP///wD///8A////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////v////sv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////ZP/////////I////dv///0H///9Y////fv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wn/////////av///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////5////0b///8A////AP///y3////e////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////CP//////////////////////////////2P///wD///8A////AP///wD///8A////AP///wD///8A////AP////////8s////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8L////a////+3///+h////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///3f///+G////AP///w3///+V////4/////n////K////AP///4n///90////AP///wD///8A////AP///wD///8Z////AP///yb////o////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////CP////X///8s////CP////X///8s////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///yH///8s////LP///yz///8s////UP////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////d////4b///8A////AP////////9A////AP///8f///8y////if///3T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+8////p////yP///+R////uP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP////////8s////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////I////9f///89////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////3P////P////o////KP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////9q////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////8P///wD////w////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9+////bv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////8g////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////1f///0T///9H////0f///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8t////9f///wj///8t////9f///wj///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///yb////w////IP///4T///91////AP////////8g////AP///wD///8A////AP///wD///8A", + "////AP///wD///8m////8P///yD///8A////AP///wD///8j////1////z3///8A////AP///wD///8A////AP///wD///8A////AP///yb////w////IP///4T///91////AP////////8g////AP///wD///8A////AP///wD////3////Yf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wP////l////lf///zD///8w////MP///zD///+T////5v///wP///8A////AP///wD///8A////AP///wD///8D////5f///5X///8w////MP///zD///8w////k////+b///8D////AP///wD///8A////AP///wD///8A////A////+X///+V////MP///zD///8w////MP///5P////m////A////wD///8A////AP///wD///8A", + "////AP///wP////l////lf///zD///8w////MP///zD///+T////5v///wP///8A////AP///wD///8A////AP///wD///8D////5f///5X///8w////MP///zD///8w////k////+b///8D////AP///wD///8A////AP///wD///8A////A////+X///+V////MP///zD///8w////MP///5P////m////A////wD///8A////AP///wD///8A", + "////AP///wD///+o////w////zD///8w////MP///zD/////////dP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////fv///27///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////dP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "/////////3T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////90////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////dP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///yD/////////VP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8g/////////1T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////IP////////9U////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///yD/////////VP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////dP///wD///8A////AP///wD///8e////9////43///8A////AP///wD///8A////AP///wD/////////dP///wD///8A////AP///8P///+e////Z/////////8A////AP///wD///8A////AP///wD///8A", + "////pP///+v///8H////AP///wD///8A////AP///wb////r////nP///wD///8A////AP///wD///8A////AP///6T////r////B////wD///8A////AP///wD///8G////6////5z///8A////AP///wD///8A////AP///wD///+k////6////wf///8A////AP///wD///8A////Bv///+v///+c////AP///wD///8A////AP///wD///8A", + "////pP///+v///8H////AP///wD///8A////AP///wb////r////nP///wD///8A////AP///wD///8A////AP///6T////r////B////wD///8A////AP///wD///8G////6////5z///8A////AP///wD///8A////AP///wD///8A////AP///yT////k////I////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////Mf////3////r////sP///wD///8A////AP///23////9////KP///wD///8A////AP///wD///8A////AP///+L///+m////AP///wD///8A////AP///4v////g////AP///wD///8A////AP///wD///8A////AP///wD////i////pv///wD///8A////AP///wD///+L////4P///wD///8A////AP///wD///8A////AP///wD///8A", + "////4v///6b///8A////AP///wD///8A////i////+D///8A////AP///wD///8A////AP///wD///8A////AP///+L///+m////AP///wD///8A////AP///4v////g////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////IP////////9U////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "///////////////9////4f///7b///85////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////9s////AP///wD///8A////Av///7X////Z////AP///wD///8A////AP///wD///8A////AP///wD///9p////9f///4X///9R////O////4r/////////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////af////X///+F////Uf///zv///+K/////////wD///8A////AP///wD///8A////AP///wD///8A////AP///2n////1////hf///1H///87////iv////////8A////AP///wD///8A////AP///wD///8A////AP///wD///9p////9f///4X///9R////O////4r/////////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////af////X///+F////Uf///zv///+K/////////wD///8A////AP///wD///8A////AP///wD///8A////AP///2n////1////hf///1H///87////iv////////8A////AP///wD///8A////AP///wD///8A////AP///wD///93////5P///03///8Z////CP////////+t////MP///zD///8w////MP///zD///8A////AP///wD///8A", + "////AP///wD///8A////fv///27///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///93///+t////MP///zD///8w////MP///zD///8A////AP///wD///8A////AP///wD///8A////AP///wD////d////rf///zD///8w////MP///zD///8w////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////3f///63///8w////MP///zD///8w////MP///wD///8A////AP///wD///8A////AP///wD///8A////AP///93///+t////MP///zD///8w////MP///zD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////2z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "/////////2z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////2z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////9s////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////7f///4L///8A////AP///wD///+n////1v///wD///8A////AP///wD///8A////AP///wD///8A////AP////////9s////AP///wD///8A////bP////////8A////AP///wD///8A////AP///wD///8A////AP///wD////e////qP///wD///8A////AP///6v////d////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////3v///6j///8A////AP///wD///+r////3f///wD///8A////AP///wD///8A////AP///wD///8A////AP///97///+o////AP///wD///8A////q////93///8A////AP///wD///8A////AP///wD///8A////AP///wD////e////qP///wD///8A////AP///6v////d////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////3v///6j///8A////AP///wD///+r////3f///wD///8A////AP///wD///8A////AP///wD///8A////AP///7j///////////////////////////////////+A////AP///wD///8A////AP///wD///8A////AP///wD////e////h////6j///+W////AP///6v////d////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "/////////27///8A////AP///wD///+B/////////wD///8A////AP///wD///8A////AP///wD///8A////AP////////9u////AP///wD///8A////gf////////8A////AP///wD///8A////AP///wD///8A////AP///wD/////////bv///wD///8A////AP///4H/////////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "/////////27///8A////AP///wD///+B/////////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////R////nf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////a////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///9H///+d////AP///wD///8A////AP///wD///8A////AP///wD///8A////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///9v///+G////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "/////////////////////////////////////////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////8U////ff////D///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8F////3v///1P///+8////pv///yP///+q////sv///wD///8A////AP///wD///8A", + "////uf///9f///8J////D////9D////a////Ff///xr////z////cP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+i////3f///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD////d////of///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///5v///+J////Rf///67///+u////Rf///4f///+h////AP///wD///8A////AP///wD///8A////AP///wD///8I/////////////////////////////////////////zD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///9l////8////w3///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///+H///+H////AP///wD///8A////iP///+P///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////YP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8W////2f///7f///8F////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////q////73///8A////AP///wD///8A////AP///wD///8A////AP///wD////J////r////0z///9M////TP///0z/////////j////0z///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wL////c////1v///wD///8A////AP///wD///8A////AP///wD///8A////AP///+z///+d////AP///wD///8A////hf///97///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///zz/////////Of///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////vf///9H///8G////AP///xD////W////rv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////q////83///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///5f////m////ef///w3///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////A////////////////////////////////////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////Df///3n////l////l////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////2////6////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////I////Y////wD///+o////uP///x7///+8////5////03///8m////3f///2r///8A////AP///wD///8A", + "////AP///wD///+H////////////////////////////////////iP///wD///8A////AP///wD///8A////AP////////90////AP///wD///8A////AP///8H////a////AP///wD///8A////AP///wD///8A////AP///wD////K////vP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "/////////3T///8A////AP///wD///8A////AP///8L////A////AP///wD///8A////AP///wD///8A////AP////////90////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////dP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////x////7z///8A////AP///wD///8A////MP///zD///+O/////////wD///8A////AP///wD///8A////AP////////90////AP///wD///8A////AP///3T/////////AP///wD///8A////AP///wD///8A////AP///wD///8A////IP////////9U////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A/////////3T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////90////AP///1T////8////N////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////dP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "/////////3T///8A////oP///6L///8A////n////37///8A////dP////////8A////AP///wD///8A////AP////////90////AP///wD///9X////8////xj///9y/////////wD///8A////AP///wD///8A////AP///wD////R////sv///wD///8A////AP///wD///8A////AP///7P////M////AP///wD///8A////AP///wD///8A", + "/////////3T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+N/////v///5L///9L////Sv///5D////+////hP///wD///8A////AP///wD///8A////AP///wD/////////dP///wD///9a/////////0f///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///85////7P///7j///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////IP////////9U////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////9////df///wD///8A////AP///wD///90/////f///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////u////5n///8A////lv///73///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Z////+7///8D////8f///yv///8A////NP///9z///8C////8f///13///8A////AP///wD///8A////AP///wD////E////nf///6T////P////Af///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///yv/////////W////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////vP///8j///8C////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////bP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////Jv////7///8/////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9s/////////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///1/////n////Ef///9v///9w////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8E////cP///8P////k////9/////7/////////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "/////////3D///8A////AP///wD///+E////+P///wD///8A////AP///wD///8A////AP///wD///8A////AP////f///+G////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////5////hP///wD///8A////AP///2//////////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////9////////////////////////////////////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////bP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////nP////////////////////L////B////Mf///wD///8A////AP///wD///8A////AP///wD///8A", + "/////////23///8A////AP///wD///9s/////////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////bP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////9s////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "/////////+7////7////2v///w3///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////9s////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////bf///wD///8A////AP///8D///+s////AP///wD///8A////bP////////8A////AP///wD///8A", + "/////////23///8A////AP///wD///9s/////////wD///8A////AP///wD///8A////AP///wD///8A////AP////f///+D////AP///wD///8A////hP////f///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////d////6z////1////2v///2L///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///2b////a////9f///63///91/////////wD///8A////AP///wD///8A////AP///wD///8A////AP////////9s////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////DP///5r////9////0v///yf///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP////////9s////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////9s////AP///wD///8A////bf////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///5b////X////AP///wH////e////kP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///w7////7////S////xH////7////LP///yH////+////Fv///07////7////Dv///wD///8A////AP///wD///8A////C/////P////w////Cf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8C////4P////P///8L////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///+y////yf///wL///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////2z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////LP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///2z/////////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////6v///6b///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///8/////t////BP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////3T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///+X///9I////AP///wD///8v////7f///wD///8A////AP///wD///8A////AP///wD///8A////AP///wH///8w////MP////////+O////MP///yj///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////LP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wX///97////7f////D////4////Kv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////O////If///wD///+b////y////zH///8X////Rv///wD///8k////yv///wD///8A////AP///wD///8A", + "////of///9z////T////Zf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9/////sv///wD///9/////sv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////A////////////////////////////////////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///87///8h////AP///wD/////////QP///1T///+i////AP///yT////K////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////H////7v////y////uf///x3///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wH///8s////LP///yz/////////UP///yz///8s////CP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9F////2f///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8Z////if///67///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////uf///+T////v////sf///07/////////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP////D///8A////8P///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD/////////IP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///0X////e////3f///0D///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////s////37///8A////s////37///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////hf///7L///8E////v////yn/////////IP///wD///8A////AP///wD///8A////AP///wD///8A////AP///4X///+y////AP///wD///8A////AP///0X////Z////AP///wD///8A////AP///wD///8A////AP///wD///8A////hf///7L///8E////v////yn/////////IP///wD///8A////AP///wD///8A", + "////yv///6z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////h////////////////////////////////////4j///8A////AP///wD///8A////AP///wD///8A////AP///4f///////////////////////////////////+I////AP///wD///8A////AP///wD///8A", + "////AP///wD///+H////////////////////////////////////iP///wD///8A////AP///wD///8A////AP///wD///8A////h////////////////////////////////////4j///8A////AP///wD///8A////AP///wD///8A////AP///4f///////////////////////////////////+I////AP///wD///8A////AP///wD///8A", + "////AP///wD///+H////////////////////////////////////iP///wD///8A////AP///wD///8A////AP///wD///8A////M////////////////////////////////////3T///8A////AP///wD///8A////AP///wD///8A////AP///yb///+f////y/////P////5////4v///63///8A////AP///wD///8A////AP///wD///8A", + "/////////3T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////90////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////dP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "/////////3T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8g/////////1T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////IP////////9U////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///yD/////////VP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8g/////////1T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////3T///8A////AP///wD///8A////AP///8L////A////AP///wD///8A////AP///wD///8A", + "/////////3T///8A////AP///1f////z////GP///3L/////////AP///wD///8A////AP///wD///8A////AP///9H///+y////AP///wD///8A////AP///wD///8A////s////8z///8A////AP///wD///8A////AP///wD////R////sv///wD///8A////AP///wD///8A////AP///7P////M////AP///wD///8A////AP///wD///8A", + "////0f///7L///8A////AP///wD///8A////AP///wD///+z////zP///wD///8A////AP///wD///8A////AP///9H///+y////AP///wD///8A////AP///wD///8A////s////8z///8A////AP///wD///8A////AP///wD////R////sv///wD///8A////AP///wD///8A////AP///7P////M////AP///wD///8A////AP///wD///8A", + "////AP///yf///+4////Jv///7f///8n////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///6X////q////NP////z///9I////AP///wD///8G////6////5z///8A////AP///wD///8A////AP///wD////9////df///wD///8A////AP///wD///90/////f///wD///8A////AP///wD///8A////AP///wD///8A", + "/////f///3X///8A////AP///wD///8A////dP////3///8A////AP///wD///8A////AP///wD///8A////AP////3///91////AP///wD///8A////AP///3T////9////AP///wD///8A////AP///wD///8A////AP///wD////9////df///wD///8A////AP///wD///90/////f///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///yv/////////W////wD///8A////AP///wD///8A////AP///wD///8A////AP////////+O////M////0r///+n/////v///0v///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////bP///wD///8A////H////7v////5////R////wD///8A////AP///wD///8A////AP///wD///8A", + "////BP///3D////D////5P////f////+/////////wD///8A////AP///wD///8A////AP///wD///8A////AP///wT///9w////w////+T////3/////v////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8E////cP///8P////k////9/////7/////////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////BP///3D////D////5P////f////+/////////wD///8A////AP///wD///8A////AP///wD///8A////AP///wT///9w////w////+T////3/////v////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8E////cP///8P////k////9/////7/////////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////Cv///2X///+p////6P////v/////////////////////////////////////////AP///wD///8A////AP///wD///8/////xP////L////u////l////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////3////////////////////////////////////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////9////////////////////////////////////wD///8A////AP///wD///8A////AP///wD///8A////AP////f///////////////////////////////////8A////AP///wD///8A////AP///wD///8A////AP///wD////3////////////////////////////////////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP////////9s////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////9s////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////9s////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD/////////bP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////D///+E////AP///wD///8A////gv////T///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////bf///wD///8A////AP///2z/////////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////9////4P///8A////AP///wD///+E////9////wD///8A////AP///wD///8A////AP///wD///8A////AP////f///+D////AP///wD///8A////hP////f///8A////AP///wD///8A////AP///wD///8A////AP///wD////3////g////wD///8A////AP///4T////3////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////9////4P///8A////AP///wD///+E////9////wD///8A////AP///wD///8A////AP///wD///8A////AP////f///+D////AP///wD///8A////hP////f///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////9////3////8j////9f///yf///+C////9////wD///8A////AP///wD///8A////AP///wD///8A////AP////////9s////AP///wD///8A////bf////////8A////AP///wD///8A////AP///wD///8A////AP///wD/////////bP///wD///8A////AP///23/////////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "/////////2z///8A////AP///wD///9t/////////wD///8A////AP///wD///8A////AP///wD///8A////AP////////9s////AP///wD///8A////bf////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8C////4P////P///8L////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "/////////3f///+s////9f///9r///9i////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wL////g////8////wv///8A////AP///wD///8A////AP///wD///8A////AP///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////g////kv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///xT///8v////+////x3///9R////4////xT///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////H////7f////R////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///1/////W////Kv///8j////z////wv///yH///8A////AP///wD///8A////AP///yX////m////x////8L////m////IP///wD///8A////lv///9X///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////1////6P///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////o////9f///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////K////yf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP////////8s////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Cv////D///9r////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////2////ev///wD///8A////AP///3v////2////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A/////////2D///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///x/////o////lf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///zj///9J////lf///+3///9S////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////Hv///+n///9C////AP///wD///8A/////////2D///8A////AP///wD///8A////AP///wD///8A////AP///z7///9R////P////3H///+8/////////2f///8A////AP///wD///8A////AP///wD///8A////AP///wD////7////7P///3n///8t////V/////D///+H////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////yf///6j///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///y7////w////yf///1r////c////4P///x7///8A////AP///wD///8A////AP///wD///8A////AP///wD///8J////jv///+T////0////n////5P////v////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////I////6T////r////fP///w7///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8O////fP///+r///+j////Iv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///1r/////////d////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////7f///z////8A////6////2H///8A////Vv////////8D////AP///2T////H////AP///wD///8A////AP///wD///8A////Jf////////9W////AP///wD///9T/////////yb///8A////AP///wD///8A////AP///wD/////////jv///zD///8y////TP///6T////8////W////wD///8A////AP///wD///8A////AP///wD///8A", + "////7v///5z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////90////AP///wD///8A////AP///wD///+g////5////wD///8A////AP///wD///8A////AP///wD/////////jv///zD///8w////MP///zD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "/////////47///8w////MP///zD///8w////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///+3///+c////AP///wD///8A////AP////////////////////////8A////AP///wD///8A////AP///wD/////////jv///zD///8w////MP///zD///+O/////////wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///yD/////////VP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////90////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////2////0f////o////hv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "/////////3T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////90////BP///+3///9R////AP///0v////T////AP///3T/////////AP///wD///8A////AP///wD/////////dP///wD///8I////4P///3r///8A////dP////////8A////AP///wD///8A////AP///wD///8A", + "////8P///5n///8A////AP///wD///8A////AP///wD///+Z////7v///wD///8A////AP///wD///8A////AP///////////////f///+H///+2////Of///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8z/////////3D///8A////AP///wD///8A////bf////7///85////AP///wD///8A////AP///wD///8A", + "/////////////////////////+X///8t////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///0X///+3/////v///9P///8h////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///yD/////////VP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "/////////3T///8A////AP///wD///8A////dP////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////FP////z///9L////AP///0j////8////Fv///wD///8A////AP///wD///8A////AP///wD///8A////AP///6b///+4////AP///7r///9k////AP///2v///+m////AP///7z///+d////AP///wD///8A", + "////AP///wD///8A////Of////z////8////SP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+e/////////8T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///yH////0////cf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "/////////2z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///4/////U////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////bP////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8B////x////9P////Y////Bf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///9q/////////wD///8A////AP///wD///8A////AP///wD///8A////AP////////98////AP///wD///8A////qf///+H///8A////AP///wD///8A////AP///wD///8A////AP///wD////a////s////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////4////6v///8A////AP///wD///+A/////////wD///8A////AP///wD///8A////AP///wD///8A////AP///9v///+n////AP///wD///8A////hP///+b///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////2z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///+3///9q////Av///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////9+////AP///wD///8A////bv////3///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////2z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD/////////bP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////9n////0////8j///8K////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////bP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "/////////37///8A////AP///wD////C////u////wD///8A////AP///27////9////AP///wD///8A////AP////////9+////AP///wD///8A////bv////3///8A////AP///wD///8A////AP///wD///8A////AP///wD////h////p////wD///8A////AP///6r////c////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "//////////P///+E////R////7v/////////R////wD///8A////AP///wD///8A////AP///wD///8A////AP///0v/////////tP///0X///97////7f////////8A////AP///wD///8A////AP///wD///8A////AP///wD/////////hf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///6/////z////Z////wP///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////bP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////bP///wD///8A////AP///2z/////////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wb////u////e////wD///8A////gv///+r///8F////AP///wD///8A////AP///wD///8A////AP///wD///9P/////v///xH///8A////wf///3b///9n////zf///wD///8S/////v///07///8A////AP///wD///8A////AP///3b////0////9P///3H///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////SP///+X////q////Yf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////G/////H///9y////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Hv////////9U////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "/////////yz///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9V/////////x7///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///+X///+a////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////y////n////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////H/////////+F////IP///yD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+f////0v///zb///8w////xv///53///8A////AP///wD///8A////AP///wD///8A////AP///wD///8I///////////////////////////////Y////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "/////////yz///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+e////9v///23///8H////nf///8L///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////4////wH///8A////6////1L///8A////AP///wD///8A////Af///+L///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Bf///9D///9l////Bf///9D///9l////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////j////Af///wD///8A/////////93////w////Vf///wD///8B////4v///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8I/////////////////////////////////////////zD///8A////AP///wD///8A////AP///wD///8A", + "////XP///0r///8J////ZP///+f///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///0v///8y////A////1X////s////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "//////////H///91////QP///5H////4/////////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////w////AP////D///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///6n///9s////+P///yD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////Zv///9D///8F////Zv///9D///8F////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////yn////f////Tv///yH///+y/////P///yD///8A////AP///wD///8A////AP///wD///8A////AP////////8p////3////07///9c////Sv///wn///9k////5////wD///8A////AP///wD///8A", + "////vP////L////z////yf///0T////f////Tv///yH///+y/////P///yD///8A////AP///wD///8A////AP///0r////+////cf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///yX/////////Vv///wD///8A////U/////////8m////AP///wD///8A////AP///wD///8A", + "////AP///wD///8l/////////1b///8A////AP///1P/////////Jv///wD///8A////AP///wD///8A////AP///wD///8A////Jf////////9W////AP///wD///9T/////////yb///8A////AP///wD///8A////AP///wD///8A////AP///yX/////////Vv///wD///8A////U/////////8m////AP///wD///8A////AP///wD///8A", + "////AP///wD///8l/////////1b///8A////AP///1P/////////Jv///wD///8A////AP///wD///8A////AP///wD///8A////Jf////////9W////AP///wD///9T/////////yb///8A////AP///wD///8A////AP///wD///8A////AP///wD///++////pP///wD///8A////AP////////+O////MP///zD///8w////MP///wD///8A", + "////AP///2H////2////0v///2v///9C////Pf///1z///+a////AP///wD///8A////AP///wD///8A////AP////////+O////MP///zD///8w////MP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////jv///zD///8w////MP///zD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "/////////47///8w////MP///zD///8w////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////+O////MP///zD///8w////MP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////IP////////9U////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///yD/////////VP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8g/////////1T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////IP////////9U////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////MP////////+O////MP///zD///8A////AP///wD///+g////5////wD///8A////AP///wD///8A////AP////////90////AP///wj////g////ev///wD///90/////////wD///8A////AP///wD///8A////AP///wD////w////mf///wD///8A////AP///wD///8A////AP///5n////u////AP///wD///8A////AP///wD///8A", + "////8P///5n///8A////AP///wD///8A////AP///wD///+Z////7v///wD///8A////AP///wD///8A////AP////D///+Z////AP///wD///8A////AP///wD///8A////mf///+7///8A////AP///wD///8A////AP///wD////w////mf///wD///8A////AP///wD///8A////AP///5n////u////AP///wD///8A////AP///wD///8A", + "////8P///5n///8A////AP///wD///8A////AP///wD///+Z////7v///wD///8A////AP///wD///8A////AP///0T////h////Kv///wD///8o////3////0X///8A////AP///wD///8A////AP///wD///8A////AP///wD////N////rv///wD///+U////2f///wb///8A////AP///7P////M////AP///wD///8A////AP///wD///8A", + "/////////3T///8A////AP///wD///8A////dP////////8A////AP///wD///8A////AP///wD///8A////AP////////90////AP///wD///8A////AP///3T/////////AP///wD///8A////AP///wD///8A////AP///wD/////////dP///wD///8A////AP///wD///90/////////wD///8A////AP///wD///8A////AP///wD///8A", + "/////////3T///8A////AP///wD///8A////dP////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+e/////////8T///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////dP///wD///8A////Af///8n////M////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "/////////2z///8A////SP////L////U////M////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////av////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///2r/////////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///9q/////////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////av////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///2r/////////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///9q/////////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////f///6f///8A////AP///wD///+E////5v///wD///8A////AP///wD///8z/////f///87///9h////V////3z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////2////6f///8A////AP///wD///+E////5v///wD///8A////AP///wD///8A////AP///wD///8A////AP///9v///+n////AP///wD///8A////hP///+b///8A////AP///wD///8A////AP///wD///8A////AP///wD////b////p////wD///8A////AP///4T////m////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////2////6f///8A////AP///wD///+E////5v///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////bP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////bP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD/////////bP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////2z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////K////tf///wD///8A////AP///7T////w////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "/////////37///8A////AP///wD///9u/////f///wD///8A////AP///wD///8A////AP///wD///8A////AP///+H///+n////AP///wD///8A////qv///9z///8A////AP///wD///8A////AP///wD///8A////AP///wD////h////p////wD///8A////AP///6r////c////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////4f///6f///8A////AP///wD///+q////3P///wD///8A////AP///wD///8A////AP///wD///8A////AP///+H///+n////AP///wD///8A////qv///9z///8A////AP///wD///8A////AP///wD///8A////AP///wD////h////p////wD///8A////AP///6r////c////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////Gv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///+H///+n////AP///5L///+v////mf///97///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////bP///wD///8A////AP///2z/////////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "/////////2z///8A////AP///wD///9s/////////wD///8A////AP///wD///8A////AP///wD///8A////AP////////9s////AP///wD///8A////bP////////8A////AP///wD///8A////AP///wD///8A////AP///wD/////////bP///wD///8A////AP///2z/////////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////SP///+X////q////Yf///wD///8A////AP///wD///8A////AP///wD///8A////AP/////////z////hP///0f///+7/////////0f///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9I////5f///+r///9h////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////5f///57///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////FP///+T///9Q////H/////z///8s////FP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///85//////////P////f////M////wD///8A////AP///wD///8A////AP///wD///8A////AP///yP////E////9P///8X///8o////1f///1////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////GP///+7/////////qP///wz///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///+7///+L////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///4z////t////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////7v///+3///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////LP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+R////1P///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////9////3r///8A////AP///wD///96////9P///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////9g////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////P/////////9G////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD//////////////+P///84////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9K////6v///yD///8A////AP////////9g////AP///wD///8A////AP///wD///8A////AP///wD////3////7f////b////w////xf///1b///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////7////5L///+Y////8f///+T///+N////CP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///1b////7////HP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////eP///////////////f///0v///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////if///+7///9W////LP///3b////s////+v///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////LP///7D////u////f////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9/////7v///7D///8s////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////c/////7///9H////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///+v///88////AP////T///9I////AP///zX/////////Cf///wD///8z////8////wD///8A////AP///wD///8A////AP///wD////D////sv///wD///8A////sf///8X///8A////AP///wD///8A////AP///wD///8A", + "///////////////////////////////2////aP///wD///8A////AP///wD///8A////AP///wD///8A////AP///+z///+d////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////dP///wD///8A////AP///wD///8A////nP///+////8A////AP///wD///8A////AP///wD///8A", + "////////////////////////////////////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///////////////////////////////////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////r////nv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "//////////////////////////////////////////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8g/////////1T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////dP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "/////////4n////k////3f///wb///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////90////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////dP///0P////2////Cv///wD///8G////8P///yj///90/////////wD///8A////AP///wD///8A", + "/////////3P///8A////e////9////8I////AP///3T/////////AP///wD///8A////AP///wD///8A////AP////H///+Y////AP///wD///8A////AP///wD///8A////mP///+7///8A////AP///wD///8A////AP///wD/////////jv///zP///9K////p/////7///9L////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////pP///+v///8H////AP///wD///8A////AP///wb////r////mv///wD///8A////AP///wD///8A////AP////////+O////MP///0X///+d////+P///0P///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////E////73/////////z////1////8G////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8g/////////1T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////90////AP///wD///8A////AP///3T/////////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///2f////0////CP///wD///8G////8v///2j///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD////l////gP///wD///+B////nf///wD///+i////b////wD///+D////3v///wD///8A////AP///wD///8A////AP///wz////u////9P///w3///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8r/////P///3D////7////Tf///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////cP////X///8i////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////9s////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wr////v////a////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///2z/////////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///zT////+////TP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////jf///+z///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////tP///wD///8A////AP///9v///+1////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////qv///+z///8B////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///7j////e////AP///wD///8A////uv////////8A////AP///wD///8A////AP///wD///8A////AP///wD///+j////7////wX///8A////AP///7j///+4////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP////////9s////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+J////pf///wn///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////v////wD///8A////AP///6T////G////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP////////9s////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////2z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////Zf///xn////d////t////wX///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "/////////2z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////+4////AP///wD///8D////8P///+v///8H////AP///wD///+i////yf///wD///8A////AP///wD/////////v////wD///8A////AP///6T////G////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////sf///9j///8A////AP///wD////b////qf///wD///8A////AP///wD///8A////AP///wD///8A////AP////////+4////AP///wD///8A////3v///7T///8A////AP///wD///8A////AP///wD///8A////AP///wD///+6////2v///wD///8A////AP///7T/////////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "/////////9n///8E////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////0////gP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////2z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "/////////2z///8A////AP///wD///9s/////////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9T/////v///yD///8A////AP///yT/////////UP///wD///8A////AP///wD///8A////AP///wD///8A////lP///9T///8A////AP///3T///+5////qf///4b///8A////AP///9H///+T////AP///wD///8A", + "////AP///zX////6////Y////2T////5////Mv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///63///+i////n////8P///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9n////9f///yL///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////S////7L////f////C////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////8s////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////DP///9////+y////S////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////g////jv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////8P///6P///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////z/////////////////////////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////t////5v////q////6f///5r///+1////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///+C////yf////T///8y////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////8v///3b///8A////AP///2X////0////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///+L///8B////AP///+v///9V////AP///wD///8A////AP///wH////i////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8x////qv///wD///8x////qv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////4v///wH///8A////AP////////9x////gf////n///8Z////Af///+L///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP////////8s////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///1z////M////9P///9T///9I////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///94////3f////f////X////Uv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////+i////AP///wD///8A////v/////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////E////1D///9P////8P///wD////w////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8T////of////////8g////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///6r///8x////AP///6r///8x////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////8g////Tv///9////8J////WP////////8g////AP///wD///8A////AP///wD///8A", + "////AP///wD/////////IP///07////f////Zv///8z////0////1P///0j///8A////AP///wD///8A////AP///03///8N////DP///33////e////Tv///9////8J////WP////////8g////AP///wD///8A////AP///wD///8A////ef////////9Y////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////w////7L///8A////AP///7H////F////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///8P///+y////AP///wD///+x////xf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////D////sv///wD///8A////sf///8X///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////w////7L///8A////AP///7H////F////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///8P///+y////AP///wD///+x////xf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////D////sv///wD///8A////sf///8X///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////Sv////r///8b////AP///wD///////////////////////////////////8A////AP///x7////3////qv///wb///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///////////////////////////////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////////////////////////////////////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///////////////////////////////////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///////////////////////////////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///yD/////////VP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8g/////////1T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////IP////////9U////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///yD/////////VP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//////////////////////////////AP///wD///8A////nP///+////8A////AP///wD///8A////AP///wD/////////c////wD///97////3////wj///8A////dP////////8A////AP///wD///8A////AP///wD///8A", + "////8f///5j///8A////AP///wD///8A////AP///wD///+Y////7v///wD///8A////AP///wD///8A////AP////H///+Y////AP///wD///8A////AP///wD///8A////mP///+7///8A////AP///wD///8A////AP///wD////x////mP///wD///8A////AP///wD///8A////AP///5j////u////AP///wD///8A////AP///wD///8A", + "////8f///5j///8A////AP///wD///8A////AP///wD///+Y////7v///wD///8A////AP///wD///8A////AP////H///+Y////AP///wD///8A////AP///wD///8A////mP///+7///8A////AP///wD///8A////AP///wD///9P////TP///wD///8A////AP///0T///9Z////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////7////5f///8A////Ef///+v///93////AP///wD///+Z////7v///wD///8A////AP///wD///8A////AP////////90////AP///wD///8A////AP///3T/////////AP///wD///8A////AP///wD///8A////AP///wD/////////dP///wD///8A////AP///wD///90/////////wD///8A////AP///wD///8A////AP///wD///8A", + "/////////3T///8A////AP///wD///8A////dP////////8A////AP///wD///8A////AP///wD///8A////AP////////90////AP///wD///8A////AP///3T/////////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8r/////P///3D////7////Tf///wD///8A////AP///wD///8A////AP///wD///8A", + "/////////3T///8A////AP///wD///+c////9P///wD///8A////AP///wD///8A////AP///wD///8A////AP////////9s////AP///+b///+n////Bf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///43////s////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///+N////7P///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////jf///+z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///43////s////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///+N////7P///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////jf///+z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Hv/////////v////Bf///wD///8A////uP///7f///8A////AP///wD///8A", + "////sf///+r///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///6P////v////Bf///wD///8A////uP///7j///8A////AP///wD///8A////AP///wD///8A////AP///wD///+j////7////wX///8A////AP///7j///+4////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////o////+////8F////AP///wD///+4////uP///wD///8A////AP///wD///8A////AP///wD///8A////AP///6P////v////Bf///wD///8A////uP///7j///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////2z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "/////////2z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////2z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////9s////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////Xf////3///9+////Pf///4X////+////2P///wD///8A////AP///wD///8A////AP///wD///8A////AP////////+/////AP///wD///8A////pP///8b///8A////AP///wD///8A////AP///wD///8A////AP///wD///+x////2P///wD///8A////AP///9v///+p////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////sf///9j///8A////AP///wD////b////qf///wD///8A////AP///wD///8A////AP///wD///8A////AP///7H////Y////AP///wD///8A////2////6n///8A////AP///wD///8A////AP///wD///8A////AP///wD///+x////2P///wD///8A////AP///9v///+p////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////sf///9j///8A////AP///wD////b////qf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///+T///8Z////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+x////2P///wD///8V////8f///+X///+s////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "/////////2z///8A////AP///wD///9s/////////wD///8A////AP///wD///8A////AP///wD///8A////AP////////9s////AP///wD///8A////bP////////8A////AP///wD///8A////AP///wD///8A////AP///wD/////////bP///wD///8A////AP///2z/////////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "/////////2z///8A////AP///wD///9s/////////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///63///+i////n////8P///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////uP///wD///8A////AP///97///+0////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////rf///6L///+f////w////wD///8A////AP///wD///8A////AP///wD///8A////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///+r///+q////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP////////////////////////////////////////8A////AP///wD///8A////AP///wD///8A////AP///yb////M/////P////////9k////B////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+1////pf///yP///+q////tv///1P////f////Bv///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///2v////9////df///9P////X////Hv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////7////gP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///+A////+v///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////yz///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////KP////////89////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///+T///+H////AP///wD///8A////iP///97///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////YP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///+4////vf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///xD///9e////9f///1z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///4b////R////C////wD////+////YP///wD///8A////AP///wD///8A////AP///wD///8A", + "////5f///2n///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///83///+x////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8D////4P///4f///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////Y/////v///98////HP///4D////5////U////wD///8A////AP///wD///8A////AP///wD///8A////AP///+D///+E////AP///wD///8A////l////+v///8A////AP///wD///8A////AP///wD///8A////AP///wD///9S////9////1H///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////N////7z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////vP///zb///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+u////yP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////B////Yf///wD////P////cf///wD///8l/////////xb///8A////NP///+7///8A////AP///wD///8A", + "////AP///wD///8A////Yf////r///8U////FP////r///9j////AP///wD///8A////AP///wD///8A////AP////////90////AP///wD///8S////T////+////90////AP///wD///8A////AP///wD///8A////AP///wD////F////wf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "/////////3T///8A////AP///wD///8A////AP///8D////G////AP///wD///8A////AP///wD///8A////AP////////90////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////dP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////wv///8T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////90////AP///wD///8A////AP///3T/////////AP///wD///8A////AP///wD///8A////AP///wD///8A////IP////////9U////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A/////////3T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////90////OP////X///9S////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////dP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "/////////3L///+V////r////wD///8A////AP///6P///99////c/////////8A////AP///wD///8A////AP////////9u////Gf////P///9V////AP///wD///90/////////wD///8A////AP///wD///8A////AP///wD////S////sv///wD///8A////AP///wD///8A////AP///7P////M////AP///wD///8A////AP///wD///8A", + "/////////3T///8A////AP///wH////J////zP///wD///8A////AP///wD///8A////AP///wD///8A////AP///9H///+y////AP///wD///8A////AP///wD///8A////s////9f///8A////AP///wD///8A////AP///wD/////////dP///wD///8A////AP///8X////J////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///6P////y////TP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////IP////////9U////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////dP///wD///8A////AP///wD///90/////////wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///+9////rf///wD///8A////AP///6z///++////AP///wD///8A////AP///wD///8A////AP///wD///8k/////////0j///8A////R////9X///8A////2f///zn///8A////S/////////8e////AP///wD///8A////AP///wD///+L////6////97///+N////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////sv///8j///8A////nP///9P///8C////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wL////G////vf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////bP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///9j////8////w3///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9s/////////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9Q////mf///1T///84////Yf////L///+p////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "//////////L///9/////Rv///7X/////////SP///wD///8A////AP///wD///8A////AP///wD///8A////AP///yz////8////1v///2f///9X////Zf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9H/////////77///9H////hf////P/////////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////Kf////n///+9////TP///37////9////Qf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wj/////////cP///wj///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Ev///9f////+////7f///6b///8S////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "/////////+////+W////Qv///3j////y////ef///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////bP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////9s////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "/////////2z///8A////If///+T///+n////Av///wD///8A////AP///wD///8A////AP///wD///8A////AP////////9s////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////7P///4j///9C////mf/////////Q////rv///0P///9y////8P///37///8A////AP///wD///8A", + "/////////+3///+W////Qv///3j////y////ef///wD///8A////AP///wD///8A////AP///wD///8A////AP///zn////9////uP///1L///+5////+////zD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////ff///wD///8A////AP///6z////g////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////5P///6j///8A////AP///wD///9//////////wD///8A////AP///wD///8A////AP///wD///8A////AP////////++////wf///17///9J////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////0f///8j///9D////W////2j///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////CP////////9w////CP///wf///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////9s////AP///wD///8A////bP////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////sv///8L///8A////AP///wD///8A////xv///7D///8A////AP///wD///8A////AP///wD///8A", + "////AP///9n///+Z////AP///wD///8n////8v///+r///8+////AP///wD///+S////2P///wD///8A////AP///w3////c////rv///wD///8A////r////9r///8M////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///xj////7////S////0f/////////Jf///wD///8A////AP///wD///8A////AP///wD///8A", + "////Bf///wj///8I////Cf///8T///+9////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP/////////g////Iv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////LP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8i////4P////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////2////4L///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///8z////w////Bv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////3T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8J////7P///1T///+S////s////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///9r///9/////AP///yv////b////vP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////N////If///wD///+d////z////zH///8h////Qf///wD///8k////yf///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///83///8h////AP///wD/////////Tf///0z////7////Gv///yT////J////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////LP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////bv///wD///8A////AP///4H/////////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////KP///+j///////////////D///8A////8P///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD/////////IP///wD///+z////hP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////yD///8A////s////4T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wH///9p////1v///wD///+z////hP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///+y////1v///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///2H////6////FP///xT////6////Y////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9h////+v///xT///8U////+v///2P///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////Yf////r///8U////FP////r///9j////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///2H////6////FP///xT////6////Y////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9h////+v///xT///8U////+v///2P///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////Yf////r///8U////FP////r///9j////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wH////U////h////wD///8A/////////3T///8A////AP///wD///8A////AP///wD///+X////9P///xj///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "/////////3T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////90////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////dP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "/////////3T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8g/////////1T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////IP////////9U////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///yD/////////VP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8g/////////1T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////3T///8A////AP///wD///8A////AP///8D////G////AP///wD///8A////AP///wD///8A", + "/////////27///8Z////8////1X///8A////AP///3T/////////AP///wD///8A////AP///wD///8A////AP///9L///+y////AP///wD///8A////AP///wD///8A////s////8z///8A////AP///wD///8A////AP///wD////S////sv///wD///8A////AP///wD///8A////AP///7P////M////AP///wD///8A////AP///wD///8A", + "////0v///7L///8A////AP///wD///8A////AP///wD///+z////zP///wD///8A////AP///wD///8A////AP///9L///+y////AP///wD///8A////AP///wD///8A////s////8z///8A////AP///wD///8A////AP///wD////S////sv///wD///8A////AP///wD///8A////AP///7P////M////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////H///+Y////AP///wD///9l////8////xv///8A////pv///+3///8A////AP///wD///8A////AP///wD/////////dP///wD///8A////AP///wD///90/////////wD///8A////AP///wD///8A////AP///wD///8A", + "/////////3T///8A////AP///wD///8A////dP////////8A////AP///wD///8A////AP///wD///8A////AP////////90////AP///wD///8A////AP///3T/////////AP///wD///8A////AP///wD///8A////AP///wD/////////dP///wD///8A////AP///wD///90/////////wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////sv///8j///8A////nP///9P///8C////AP///wD///8A////AP///wD///8A////AP////////90////AP///wD///8D////5P///9j///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////bP///wD////b////mf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////UP///5n///9U////OP///2H////y////qf///wD///8A////AP///wD///8A////AP///wD///8A////AP///1D///+Z////VP///zj///9h////8v///6n///8A////AP///wD///8A////AP///wD///8A////AP///wD///9Q////mf///1T///84////Yf////L///+p////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////UP///5n///9U////OP///2H////y////qf///wD///8A////AP///wD///8A////AP///wD///8A////AP///1D///+Z////VP///zj///9h////8v///6n///8A////AP///wD///8A////AP///wD///8A////AP///wD///9Q////mf///1T///84////Yf////L///+p////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////gf///3v///9G////Pv///7f////o////7v///73///9M////fv////z///8+////AP///wD///8A////AP///97///+w////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8p////+f///73///9M////fv////3///9B////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////Kf////n///+9////TP///37////9////Qf///wD///8A////AP///wD///8A////AP///wD///8A////AP///yn////5////vf///0z///9+/////f///0H///8A////AP///wD///8A////AP///wD///8A////AP///wD///8p////+f///73///9M////fv////3///9B////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP////////9s////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////9s////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////9s////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD/////////bP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9u////2v////D///+z////yP///6D///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////7f///5b///9C////eP////L///95////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////Of////3///+4////Uv///7n////7////MP///wD///8A////AP///wD///8A////AP///wD///8A////AP///zn////9////uP///1L///+5////+////zD///8A////AP///wD///8A////AP///wD///8A////AP///wD///85/////f///7j///9S////uf////v///8w////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////Of////3///+4////Uv///7n////7////MP///wD///8A////AP///wD///8A////AP///wD///8A////AP///zn////9////uP///1L///+5////+////zD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////Of////3///+3////RP///7v/////////Of///wD///8A////AP///wD///8A////AP///wD///8A////AP////////9s////AP///wD///8A////bP////////8A////AP///wD///8A////AP///wD///8A////AP///wD/////////bP///wD///8A////AP///2z/////////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "/////////2z///8A////AP///wD///9s/////////wD///8A////AP///wD///8A////AP///wD///8A////AP////////9s////AP///wD///8A////bP////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///xj////7////S////0f/////////Jf///wD///8A////AP///wD///8A////AP///wD///8A", + "/////////33///8A////AP///wD///+s////4P///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////GP////v///9L////R/////////8l////AP///wD///8A////AP///wD///8A////AP///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////v////tv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////hf///6P///8A////pf///3v///8A////AP///wD///8A////AP///wD///8A////AP///wD////J////wv///xj/////////FP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////8P///0L///8A////Rf///+////8A////y////2v///8A////AP///wD///8A////AP///wD///8A////AP///wD////Z////o////wD///8J////yP///7r///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////7P///6L///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////o////+v///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wj///8B////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///++////p////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////J////p////wD///8A////AP///6n////B////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A/////////2D///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////gf////D///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///5f////d////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8D////v////6v///8B////+P///2D///8A////AP///wD///8A////AP///wD///8A////AP///9L///99////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+W////7v///wf///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///3H////t////Cf///wD///8A////AP///wD///8A////AP///wD///8A////AP///9////+N////AP///wD///8A////k////9n///8A////AP///wD///8A////AP///wD///8A////AP///wD////1////af///wD///8A////AP///3z////L////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////VP////f///9T////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Yf////b///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////k////5n///8A////Zv///+H///8r////Lf////////8k////AP///13////E////AP///wD///8A////AP///wD///8A////AP///wv////z////a////2v////0////DP///wD///8A////AP///wD///8A////AP///wD/////////dP///wD///8A////AP///wD///+J////6P///wD///8A////AP///wD///8A////AP///wD///8A", + "////jP////j///8f////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////90////AP///wD///8A////AP///xT////y////l////wD///8A////AP///wD///8A////AP///wD/////////dP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "/////////3T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///4j////5////JP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////dP///wD///8A////AP///wD///90/////////wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///yD/////////VP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////90////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////dP///wD///9Z////9v///zn///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "/////////3T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////9s////5f///17///8A////AP///wD///9P////0v///2//////////AP///wD///8A////AP///wD/////////ZP///6D////C////AP///wD///8A////dP////////8A////AP///wD///8A////AP///wD///8A", + "////pf///+r///8H////AP///wD///8A////AP///wb////q////nf///wD///8A////AP///wD///8A////AP////////90////AP///wD///8A////nP////T///8A////AP///wD///8A////AP///wD///8A////AP///wD////w////mf///wD///8A////AP///wD///8A////AP///5n////y////AP///wD///8A////AP///wD///8A", + "/////////3T///8A////AP///wD///+W////9P///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////s////jP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///yD/////////VP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "/////////3T///8A////AP///wD///8A////dP////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8W/////P///1////8A////AP///wD///9e/////P///xf///8A////AP///wD///8A////AP///wD///8A////Y/////7///8R////AP///w/////8////IP////n///8I////AP///xP/////////Xv///wD///8A", + "////AP///wD///8q////+v///2T///9P////+////yv///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////PP////////9F////AP///x/////5////X////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Kf////j///9k////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "/////////2z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////zf///5f///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////bP////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////Rf///7D////g////+P///+L///+b////E////wD///8A////AP///wD///8A////AP///wD///8A////AP////////93////sP////X////Z////Yv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Ov///8D////w////6////6b///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///2D////Y////8////6n///90/////////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///82////wf////H////N////UP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////J////////////////////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///6b////p////Yv///17////o////pf///wD///8A////AP///wD///8A////AP///wD///8A////AP////////9z////nf////D////V////ff///xP///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////2z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD/////////bP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////9s////AP///wD///8p////6////5X///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////bP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "/////////0r///+l////9P///93///+B////Bf///4r////o////3v///4P///8W////AP///wD///8A////AP////////9I////nf////D////V////ff///xP///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////SP///8v////y////yf///0D///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "/////////27///8A////AP///wD///+E////+P///wD///8A////AP///wD///8A////AP///wD///8A////AP////n///+E////AP///wD///8A////b/////////8A////AP///wD///8A////AP///wD///8A////AP///wD/////////Nf///3/////t////5////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///zL////H////9f///97///99////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///9n////////////////////w////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////bP///wD///8A////AP///2z/////////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////Ff////v///9m////AP///wD///8A////AP///2f////6////Ff///wD///8A////AP///wD///8A////AP///x7/////////Xf///wD///8A////AP///9r////y////Bf///wD///8A////U/////////8d////AP///wD///+j////5v///xP///8A////AP///xP////m////ov///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///94////6P///wT///8D////5f///4f///8A////AP///wD///8A////AP///wD///8A////AP///7z//////////////////////////////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8e////k/////f///8U////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "/////////yz///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8U////9////3v///8M////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///9b///92////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9h/////////8////99////Qv///2H///9b////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP////////90////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////av///+b///8E////H/////v///83////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9B////6////8D////9////v////xv///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////dP///4b///8A////Dv///5n////m////8P///6P///8A////iv///3L///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///90////hv///wD///8A//////////7////S////dv///wD///+K////cv///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////yz///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "/////////2z///8A////AP///wD///9t/////////wD///8A////AP///wD///8A////AP///wD///8A////AP///6X////////////////////w////AP////D///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////yD///8A////If///+////8m////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////8g////AP///yH////v////Jv///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///9z////z////6P///yj///8A////If///+////8m////AP///wD///8A////AP///wD///8A////AP///wD///8A////X/////v///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8L////8////2v///9r////9P///wz///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////C/////P///9r////a/////T///8M////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wv////z////a////2v////0////DP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8L////8////2v///9r////9P///wz///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////C/////P///9r////a/////T///8M////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wv////z////a////2v////0////DP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////YP///+7///8L////AP////////90////AP///wD///8A////AP///wD///8A", + "////yv///7z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////90////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////dP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "/////////3T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////90////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////IP////////9U////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///yD/////////VP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8g/////////1T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////IP////////9U////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP////////90////AP///wD///8A////AP///xT////y////l////wD///8A////AP///wD///8A////AP////////9k////oP///8L///8A////AP///wD///90/////////wD///8A////AP///wD///8A////AP///wD///+l////6v///wf///8A////AP///wD///8A////Bv///+r///+d////AP///wD///8A////AP///wD///8A", + "////pf///+r///8H////AP///wD///8A////AP///wb////q////nf///wD///8A////AP///wD///8A////AP///6X////q////B////wD///8A////AP///wD///8G////6v///53///8A////AP///wD///8A////AP///wD///+l////6v///wf///8A////AP///wD///8A////Bv///+r///+d////AP///wD///8A////AP///wD///8A", + "////pf///+r///8H////AP///wD///8A////AP///wb////q////nf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////S////sv///wD///8A////Av///8v///+n////AP///93////I////AP///wD///8A////AP///wD///8A", + "/////////3T///8A////AP///wD///8A////dP////////8A////AP///wD///8A////AP///wD///8A////AP////////90////AP///wD///8A////AP///3T/////////AP///wD///8A////AP///wD///8A////AP///wD/////////dP///wD///8A////AP///wD///90/////////wD///8A////AP///wD///8A////AP///wD///8A", + "/////////3T///8A////AP///wD///8A////dP////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////PP////////9F////AP///x/////5////X////wD///8A////AP///wD///8A////AP///wD/////////jv///zL///9k////sP////////9w////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "/////////2z///8A////M////+T///+t////DP///wD///8A////AP///wD///8A////AP///wD///8A////AP///0X///+w////4P////j////i////m////xP///8A////AP///wD///8A////AP///wD///8A////AP///wD///9F////sP///+D////4////4v///5v///8T////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////Rf///7D////g////+P///+L///+b////E////wD///8A////AP///wD///8A////AP///wD///8A////AP///0X///+w////4P////j////i////m////xP///8A////AP///wD///8A////AP///wD///8A////AP///wD///9F////sP///+D////4////4v///5v///8T////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////Rf///7D////g////+P///+L///+b////E////wD///8A////AP///wD///8A////AP///wD///8A////AP///2v////E////7P///+r///+7////J////y3///+9////8P///8z///9N////AP///wD///8A////AP///wD////3////hv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///zb////B////8f///83///9Q////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///82////wf////H////N////UP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Nv///8H////x////zf///1D///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///zb////B////8f///83///9Q////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////bP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////bP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD/////////bP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////2z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////E/////r///9P////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "/////////0j///+d////8P///9X///99////E////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9I////y/////L////J////QP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////SP///8v////y////yf///0D///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///0j////L////8v///8n///9A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9I////y/////L////J////QP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////SP///8v////y////yf///0D///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9I////yv////T////O////yv///1L///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////bP///wD///8A////AP///2z/////////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "/////////2z///8A////AP///wD///9s/////////wD///8A////AP///wD///8A////AP///wD///8A////AP////////9s////AP///wD///8A////bP////////8A////AP///wD///8A////AP///wD///8A////AP///wD/////////bP///wD///8A////AP///2z/////////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///94////6P///wT///8D////5f///4f///8A////AP///wD///8A////AP///wD///8A////AP////////9u////AP///wD///8A////hP////j///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///3j////o////BP///wP////l////h////wD///8A////AP///wD///8A////AP///wD///8A", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////9P///8L///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///1/////J////AP///3////+h////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////8////3b///8A/////////xT///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////L///9C////AP///0X////u////AP///0f////n////Cv///wD///8A////AP///wD///8A////AP///wD///8A////9f///3////8A////AP///3n////y////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///9P////L////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///8z////S////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////VP////n///8W////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////f////+X///8G////AP///wj////o////cf///wD///8A////AP///wD///8A////AP///wD///8A////AP///57///94////Af////z///9g////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8R////B////wD///8A////AP///5z////e////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////CP///wD///8A////AP///wD///+N////7f///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///xj////n////cf///+////9g////AP///wD///8A////AP///wD///8A////AP///wD///+/////kv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////N/////////90////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8N////8P///2b///8A////AP///wD///8A////AP///wD///8A////AP///wD////u////iv///wD///8A////AP///4z////t////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////0f///5n///8A////AP///wD////J////if///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9S////9////1H///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///3v////k////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///yP////z////Iv///wH///98////4/////f////M////Hv///wD///+v////j////wD///8A////AP///wD///8A////AP///wD///8A////nf///8H////C////oP///wD///8A////AP///wD///8A////AP///wD///8A", + "/////////3T///8A////AP///wD///8A////u////+b///8A////AP///wD///8A////AP///wD///8A////AP///xT////u////sv///wj///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////dP///wD///8A////AP///wL///+e////9f///x7///8A////AP///wD///8A////AP///wD///8A", + "/////////3T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////90////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8O////4////7v///8O////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "/////////3T///8A////AP///wD///8A////dP////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8g/////////1T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////dP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "/////////3T///8A////AP///4H////r////JP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////90////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////mP////v///8R////AP///wD///8A////CP////L///+M/////////wD///8A////AP///wD///8A", + "/////////4v////8////Mv///wD///8A////AP///3T/////////AP///wD///8A////AP///wD///8A////AP///zP/////////cP///wD///8A////AP///wD///9t/////f///yn///8A////AP///wD///8A////AP///wD/////////dP///wD///8A////A////+T////Y////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////8f///5j///8A////AP///wD///8A////AP///wD///+Y////7v///wD///8A////AP///wD///8A////AP////////90////AP///wD///8A////wf///9n///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////5v///6f///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8g/////////1T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////90////AP///wD///8A////AP///3T/////////AP///wD///8A////AP///wD///8A////AP///wD///8A////af////z///8T////AP///wD///8A////E/////z///9p////AP///wD///8A////AP///wD///8A", + "////AP///6L////Y////AP///wD///8A////1P///4T////M////AP///wD///8A////2v///5////8A////AP///wD///8A////vv///8j///8B////AP///7f////A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///8b////A////AP///wD///8A////l////+H///8H////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///97////8P///xr///8A////AP///wD///8A////AP///wD///8A////AP////////9s////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////N/////////8t////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///2z/////////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////av///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////a/////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP////////9s////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////y////kv///wD///8A////lP///+7///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////bP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////2z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////bP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "/////////2z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////97////AP///wD///8A////qf///+H///8A////AP///wD///8A////AP///wD///8A////AP///wD////j////q////wD///8A////AP///4D/////////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8G////4v///2z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8B////3P///43///8A////AP///4j////l////A////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///xT/////////Xf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////8s////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Xf////////8I////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///2z////b///////////////u////pv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////1////h////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////Av///9v///+E////AP///wD///+l////uf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////bf////3///+v////Pf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wz////W////Nv///wD///8A////AP///wD///8A////N////9b///8M////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////DP///9b///82////AP///wD///8A////AP///wD///83////1v///wz///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wj///8B////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////9s////AP///wD///8A////bP////////8A////AP///wD///8A////AP///wD///8A////AP///wD////f////////////////////8P///wD////w////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////8g////AP///wD///98////u////wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD/////////IP///wD///8A////fP///7v///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Gf///4n///+u////AP///wD///98////u////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///53////B////wv///6D///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+d////wf///8L///+g////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////nf///8H////C////oP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///53////B////wv///6D///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+d////wf///8L///+g////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////nf///8H////C////oP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wb////l////av///wD/////////dP///wD///8A////AP///wD///8A////AP///+7///+c////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////dP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "/////////3T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////90////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////dP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///yD/////////VP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8g/////////1T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////IP////////9U////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///yD/////////VP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////dP///wD///8A////AP///wL///+e////9f///x7///8A////AP///wD///8A////AP///wD/////////i/////z///8y////AP///wD///8A////dP////////8A////AP///wD///8A////AP///wD///8A", + "////M/////////9w////AP///wD///8A////AP///23////9////Kf///wD///8A////AP///wD///8A////AP///zP/////////cP///wD///8A////AP///wD///9t/////f///yn///8A////AP///wD///8A////AP///wD///8z/////////3D///8A////AP///wD///8A////bf////3///8p////AP///wD///8A////AP///wD///8A", + "////M/////////9w////AP///wD///8A////AP///23////9////Kf///wD///8A////AP///wD///8A////AP///zP/////////cP///wD///8A////AP///wD///9t/////f///yn///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////pf///+r///8H////AP///wD///83/////f///1P/////////m////wD///8A////AP///wD///8A////AP////////90////AP///wD///8A////AP///3T/////////AP///wD///8A////AP///wD///8A////AP///wD/////////dP///wD///8A////AP///wD///90/////////wD///8A////AP///wD///8A////AP///wD///8A", + "/////////3T///8A////AP///wD///8A////dP////////8A////AP///wD///8A////AP///wD///8A////AP////////90////AP///wD///8A////AP///3T/////////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///8b////A////AP///wD///8A////l////+H///8H////AP///wD///8A////AP///wD///8A", + "////////////////////6////8f///9g////Af///wD///8A////AP///wD///8A////AP///wD///8A////AP////////9s////AP///wD///8U////0////6f///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////A////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////2v///7P///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///6f///+A////Cf///5/////O////Af///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8D////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////A////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8B////3P///43///8A////AP///4j////l////A////wD///8A////AP///wD///8A////AP///wD/////////e////wD///8A////AP///6n////h////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wH////c////jf///wD///8A////iP///+X///8D////AP///wD///8A////AP///wD///8A////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////n////O////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///85////7v///wD///9Z////x////wD///8A////AP///wD///8A////AP///wD///8A////AP///6z////n////cf////////9a////gP///1L///8A////AP///wD///8A////AP///wD///8A////AP///wD///+8////pv///yP///+q////sf///wD///8A////wP///3f///8A////AP///wD///8A////AP///wD///8A", + "////AP///7v////h////Wf///0r////c////uv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+c////8////wH///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wH////0////m////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wT////m////ef///wD///8A////AP///wD///8A////AP///wD///8A////AP///yH////w////p////0z///+s////6P///xf///8A////AP///wD///8A////AP///wD///8A////AP///wD///83////1v///63////3////YP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////uP///9r///9v////RP///3r////7////ff///wD///8A////AP///wD///8A////AP///wD///8A////AP///7f////A////Zv///0L///9y////9v///5n///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////QP///+/////z////YP///wD///8A////AP///wD///8A////AP///wD///8A", + "////rP///7////9M////TP///0z///9M////Df///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+U/////P///5P///9K////R////w7///8A////AP///wD///8A////AP///wD///8A////AP///wD///9M////TP///0z///9M////TP///7r////V////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////nP////L///99////Sf///37////z////mv///wD///8A////AP///wD///8A////AP///wD///8A////AP///2X////6////eP///0j///+m////8f///xj///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////VP////f///9T////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///5j///+G////UP///2b////u////kf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////iP///8b///8Z////AP///wD///8A////AP///wD///9V////7f///xX///8A////AP///wD///8A", + "////AP///wD///8A////AP///zv////7////+////z7///8A////AP///wD///8A////AP///wD///8A////AP////////+O////MP///zX///9f////l/////////+Q////AP///wD///8A////AP///wD///8A////AP///wD///8A////Tf///+7////R////af///z3///9R////kP///3v///8A////AP///wD///8A////AP///wD///8A", + "/////////47///8w////Pf///2T////I////9////2H///8A////AP///wD///8A////AP///wD///8A////AP////////+O////MP///zD///8w////MP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////jv///zD///8w////MP///zD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///zr////e////4f///3X///9J////OP///1z///+f////Vv///wD///8A////AP///wD///8A////AP////////90////AP///wD///8A////AP///3T/////////AP///wD///8A////AP///wD///8A////AP///wD///8A////KP////////9c////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A/////////3T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////90////AP///wD///8A////p////9v///8U////AP///wD///8A////AP///wD///8A////AP///wD/////////dP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "/////////9z///+8////AP///wD///8A////AP///wD///+n////2f////////8A////AP///wD///8A////AP/////////2////n////wD///8A////AP///wD///90/////////wD///8A////AP///wD///8A////AP///wD///8A////jP////7///+V////Tf///0r///+R/////f///33///8A////AP///wD///8A////AP///wD///8A", + "/////////47///8y////ZP///7D/////////cv///wD///8A////AP///wD///8A////AP///wD///8A////AP///9L///+y////AP///wD///8A////AP///wD///8A////s////8z///8A////AP///wD///8A////AP///wD/////////jv///zH///9F////m/////////90////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///4r////6////hf///0H///9R////kv///1n///8A////AP///wD///8A////AP///wD///8A////AP///zD///8w////Sv////////90////MP///zD///8Y////AP///wD///8A////AP///wD///8A////AP///wD/////////dP///wD///8A////AP///wD///90/////////wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///7/////B////AP///wD///8A////AP///wD////C////v////wD///8A////AP///wD///8A////AP///wD////h////oP///wD///8A////AP///5v////f////lf///wD///8A////AP///6H////f////AP///wD///8A////Wf////3///8z////AP///wD///8m////+f///1n///8A////AP///wD///8A////AP///wD///8A", + "////AP///1H/////////Pf///wD///8A////AP///xz////4////cf///wD///8A////AP///wD///8A////AP///zD///8w////MP///zD///8w////NP///+T///+x////AP///wD///8A////AP///wD///8A////AP///wD/////////bP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///6H////D////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9s/////////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "/////////2z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///2z/////////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////t////dv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////6f///43///8A////AP///4z////o////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "/////////2z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wX////b////Wf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////9s////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "/////////2z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////9s////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////r////wD///8A////AP///9v///+1////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////uP///97///8A////AP///wD///+6/////////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///4r///9o////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Q/////////8s////AP///wD///8o/////////0v///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////2z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////LP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///2z/////////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////zv///8v///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////9c////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////sf///+v///9Y////SP///4b///87////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///1L////9////Hv///wD///8A////L/////////87////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///+b///+B////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////LP///9v///9v////Fv///wD///8W////cP///9v///8s////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8s////2////2////8W////AP///xb///9w////2////yz///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////bP///wD///8A////AP///2z/////////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////+P////////////////////D///8A////8P///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////qf///2z////4////IP///wD///8A////B////9r///9W////AP///wD///8A////AP///wD///8A////AP///6n///9s////+P///yD///8A////AP///wf////a////Vv///wD///8A////AP///wD///8A////AP///wD///9L////Mv///wP///9V////7P///wD///8A////B////9r///9W////AP///wD///8A////AP///wD///8A", + "////AP///wD////K////z////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///87////+/////v///8+////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////O/////v////7////Pv///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///zv////7////+////z7///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///87////+/////v///8+////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////O/////v////7////Pv///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///zv////7////+////z7///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////d////9r///8w/////////47///8w////MP///zD///8w////AP///wD////s////nf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "/////////47///8w////MP///zD///8w////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////+O////MP///zD///8w////MP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////jv///zD///8w////MP///zD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "/////////47///8w////MP///zD///8w////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8o/////////1z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////KP////////9c////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///yj/////////XP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8o/////////1z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////47///8w////Pf///2T////I////9////2H///8A////AP///wD///8A////AP///wD///8A", + "//////////b///+f////AP///wD///8A////AP///3T/////////AP///wD///8A////AP///wD///8A////AP///wD///+M/////v///5X///9N////Sv///5H////9////ff///wD///8A////AP///wD///8A////AP///wD///8A////jP////7///+V////Tf///0r///+R/////f///33///8A////AP///wD///8A////AP///wD///8A", + "////AP///4z////+////lf///03///9K////kf////3///99////AP///wD///8A////AP///wD///8A////AP///wD///+M/////v///5X///9N////Sv///5H////9////ff///wD///8A////AP///wD///8A////AP///wD///8A////jP////7///+V////Tf///0r///+R/////f///33///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///zP/////////cP///wD///8A////AP///5/////z////+////yb///8A////AP///wD///8A////AP///wD/////////dP///wD///8A////AP///wD///90/////////wD///8A////AP///wD///8A////AP///wD///8A", + "/////////3T///8A////AP///wD///8A////dP////////8A////AP///wD///8A////AP///wD///8A////AP////////90////AP///wD///8A////AP///3T/////////AP///wD///8A////AP///wD///8A////AP///wD/////////dP///wD///8A////AP///wD///90/////////wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///1H/////////Pf///wD///8A////AP///xz////4////cf///wD///8A////AP///wD///8A////AP////////90////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////m////hP///wD///8A////AP///33////w////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////YP///9b///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///9b///9g////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///8v///9h////AP///2P////J////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///+X///8F////A////5n////k////M////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////yv///1L///8A////VP///8f///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///1n////c////2v///1P///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///6r////s////Af///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9g////1v///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////1v///2D///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////L////Yf///wD///9j////yf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////yv///1L///8A////VP///8f///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///2D////W////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///9b///9g////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////L////Yf///wD///9j////yf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////yv///1L///8A////VP///8f///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///84////vv///+f////z////Kf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////5f///wX///8D////mf///+T///8z////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////YP///9b///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///9b///9g////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////y////2H///8A////Y////8n///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///+X///8F////A////5n////k////M////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////K////Uv///wD///9U////x////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////YP///9b///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////W////YP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///8v///9h////AP///2P////J////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////K////Uv///wD///9U////x////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Q/////////8s////AP///wD///8o/////////0v///8A////AP///wD///8A////AP///wD///8A", + "/////////6////8A////AP///wD////b////tf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9D/////////yz///8A////AP///yj/////////S////wD///8A////AP///wD///8A////AP///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////+////2v///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////E/////////8V////M////+3///8A////AP///wD///8A////AP///wD///8A////AP///wD///8M////iP///9v/////////8f///8r///9j////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////KP///8j////z////wP///x////8A////AP///zv////t////D////wD///8A////AP///wD///8A////AP///wD///8c////rP///+z////w////sf///x3///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////Wf////////8t////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8t/////////1j///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////gf///+D///8C////AP///wD///8A////AP///wD///8A////AP///wD///8A////PP///8D////v////u////y7///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wf///+I/////P///2D///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///xf///+O////3v////f////Z////df///wP///8A////AP///wD///8A////AP///wD///8A////AP///wD///8q////n////+T////4////2v///4b///8K////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///96/////////2D///8A////AP///wD///8A////AP///wD///8A////AP///5n//////////////////////////////yz///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Av///2L////I////8f////L///8e////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "/////////////////////////////////////////wD///8A////AP///wD///8A////AP///wD///8A////AP///wf///+E////3f////f////d////hf///wf///8A////AP///wD///8A////AP///wD///8A////AP///wD///8B////av///9X////x////vf///yn///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9n////xP////D////k////kf///wv///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wT///+F////5////3P///9A////HP///0H///+Y////7v///03///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////2P///9v///8A////AP///wD///8A////AP///wD///8A////AP///wD////////////////////9////6v///8r///9x////A////wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8b////l////8j////z////7P///8v///92////AP///wD///8A////AP///wD///8A////AP////////////////////j////S////ov///yX///8A////AP///wD///8A////AP///wD///8A////AP///wD///////////////////////////////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////////////////////////////////////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Cf///3n///+3////4P////j////l////vv///17///8A////AP///wD///8A////AP///wD/////////dP///wD///8A////AP///wD///90/////////wD///8A////AP///wD///8A////AP///wD///8A", + "////Zv////z//////////////5f///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////90////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////dP///wD///8A////AP///wj////H////x////wn///8A////AP///wD///8A////AP///wD///8A", + "/////////3T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//////////////bP///wD///8A////AP///wD///8A////Uv//////////////AP///wD///8A////AP///wD/////////8////xn///8A////AP///wD///8A////dP////////8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///9V////s////+X////n////sv///03///8A////AP///wD///8A////AP///wD///8A////AP///////////////////+v////H////Yv///wH///8A////AP///wD///8A////AP///wD///8A////AP///wD///+l////6v///wf///8A////AP///wD///8A////Bv///+r///+d////AP///wD///8A////AP///wD///8A", + "////////////////////7P///8r///9k////Af///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8E////eP///9b////2////6f///8b///9d////AP///wD///8A////AP///wD///8A////AP///wD/////////////////////////////////////////gP///wD///8A////AP///wD///8A////AP///wD///8A", + "/////P///3L///8A////AP///wD///8A////dP////////8A////AP///wD///8A////AP///wD///8A////AP///xf////9////c////wD///8A////AP///wD///8A////c/////3///8X////AP///wD///8A////AP///wD///8g/////////2j///8A////AP///wD///9h/////////1////8A////AP///wD///9o/////////x////8A", + "////Df///+X///+Y////AP///wD///8A////AP///4j////l////Df///wD///8A////AP///wD///8A////AP///wP////X////uf///wD///8A////AP///wD///8A////kf///+z///8O////AP///wD///8A////AP///wD//////////////////////////////////////////////wD///8A////AP///wD///8A////AP///wD///8A", + "/////////2z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///xP////3////Wf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////bP////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////9s////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///9s/////////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////vf///87///87////PP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///53////g////Pf///zv////f////uf///xH///8A////AP///wD///8A////AP///wD///8A////AP////////9s////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8E////3v///2T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD/////////bP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////9s////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////bP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "/////////+z///97////Rv///7X/////////SP///wD///8A////AP///wD///8A////AP///wD///8A////AP///0f/////////vv///0f///+F////7v////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///6j////M////AP///wD///8A////AP///8j///+t////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////9s////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "/////////yz///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9s/////////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///8v////I////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////WP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///xb///+l////6////+/////F////Rf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////G////tP///wD///8A////AP///wD///+3////vv///wD///8A////AP///wD///8A////AP///wD///8A", + "/////////yz///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////O////xP///0z///8/////b////1z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8V////iP///9j////g////2P///4j///8V////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///xX///+I////2P///+D////Y////iP///xX///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "/////////2z///8A////AP///wD///9s/////////wD///8A////AP///wD///8A////AP///wD///8A////AP///+z////////////////////w////AP////D///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///xP///+h/////////yD///8A////AP///wD///9F////5P///w3///8A////AP///wD///8A////AP///wD///8T////of////////8g////AP///wD///8A////Rf///+T///8N////AP///wD///8A////AP///wD///8A", + "////eP///93////3////1////1L///8A////AP///wD///9F////5P///w3///8A////AP///wD///8A////AP///wD///8A////x////8z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///9j////b////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD////Y////2////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////2P///9v///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///9j////b////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD////Y////2////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9a//////////////9U////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///w/////y/////////////////////////////////////////wD///8A", + "////xf///8H///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///////////////////////////////////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///////////////////////////////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////////////////////////////////////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///////////////////////////////////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9m/////P//////////////l////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////Zv////z//////////////5f///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///2b////8//////////////+X////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9m/////P//////////////l////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP////////////////////j////S////ov///yX///8A////AP///wD///8A////AP///wD///8A////AP/////////z////Gf///wD///8A////AP///wD///90/////////wD///8A////AP///wD///8A////AP///wD///8A////AP///1X///+z////5f///+f///+y////Tf///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///9V////s////+X////n////sv///03///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Vf///7P////l////5////7L///9N////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///1X///+z////5f///+f///+y////Tf///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///9V////s////+X////n////sv///03///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////jP////7///+V////TP///0H///+Z/////////7H///8A////AP///wD///8A////AP///wD///8A", + "/////P///3L///8A////AP///wD///8A////dP////////8A////AP///wD///8A////AP///wD///8A////AP////z///9y////AP///wD///8A////AP///3T/////////AP///wD///8A////AP///wD///8A////AP///wD////8////cv///wD///8A////AP///wD///90/////////wD///8A////AP///wD///8A////AP///wD///8A", + "/////P///3L///8A////AP///wD///8A////dP////////8A////AP///wD///8A////AP///wD///8A////AP///wP////X////uf///wD///8A////AP///wD///8A////kf///+z///8O////AP///wD///8A////AP///wD/////////dP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////mv////D///9g////Nv///1f////k////tf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Mf////j///9W////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9W////+P///y7///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8n////8f///3D////x////JP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+5////cf///6n///+q////dP///7P///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///8n///9R////AP///1T////T////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD////h////EP///xX////e////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8s/////P///9b///9n////V////2X///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8x////+P///1b///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///1b////4////Lv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////J/////H///9w////8f///yT///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///8n///9R////AP///1T////T////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///zH////4////Vv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9W////+P///y7///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////J/////H///9w////8f///yT///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///8n///9R////AP///1T////T////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///2/////4////7v///2v///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///7n///9x////qf///6r///90////s////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Mf////j///9W////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9W////+P///y7///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///yf////x////cP////H///8k////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+5////cf///6n///+q////dP///7P///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////yf///1H///8A////VP///9P///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Mf////j///9W////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////Vv////j///8u////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8n////8f///3D////x////JP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////yf///1H///8A////VP///9P///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///6j////M////AP///wD///8A////AP///8j///+t////AP///wD///8A////AP///wD///8A////AP/////////u////e////0b///+1/////////0j///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////qP///8z///8A////AP///wD///8A////yP///63///8A////AP///wD///8A////AP///wD///8A", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A/////////xT///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wf////q////rf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////rf///+j///8G////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///z3///+Y////zP////P////P////mv///xv///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////dP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////M/////////9w////AP///wD///8A////AP///23////9////Kf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////9s////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///2z/////////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////bP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////bP////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///y/////M////9////8T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8O////mv///+f////////////////////9////Gf///wD///8A////AP///wD///8A////AP///wD/////////bP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////2z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////bP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "/////////2z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////9M////qf////P////Z////Yv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////YP///9j////z////pf///0n/////////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///xT////5////bP///wD///8A////AP///wD///9o////+v///xX///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD////5////cf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////8s////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////cv////j///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////8s////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////I////67////r////9P///9L///9w////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////9s////AP///wD///8A////bP////////8A////AP///wD///8A////AP///wD///8A////AP///wD////N////////////////////8P///wD////w////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////A////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////4f///xD///8V////3v///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///4z////4////H////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wP///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8D////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///9V////s////+X////w////xP///5P////1////E////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wr///+O////4f////j////k////m////xT///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///8/////e////Av///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////Av///97////M////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///4H/////////gf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////N////+X///+X////A////wb////j////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////4f///xX///8X////4P///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///zr////A////8P///+v///+m////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////z////97///8C////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8C////3v///8z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///+B/////////4H///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////P////3v///wL///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////Av///97////M////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+B/////////4H///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///+p////Pv///yv///+V////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///83////5f///5f///8D////Bv///+P///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///8/////e////Av///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////Av///97////M////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////gf////////+B////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////N////+X///+X////A////wb////j////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///8/////e////Av///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wL////e////zP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///4H/////////gf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///xT////5////bP///wD///8A////AP///wD///9o////+v///xX///8A////AP///wD///8A////AP///wD/////////dv///6n////z////2f///2L///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////FP////n///9s////AP///wD///8A////AP///2j////6////Ff///wD///8A////AP///wD///8A////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////8U////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////dv////////83////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////Nf////////9y////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A/////////3T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+M/////v///5X///9N////Sv///5H////9////ff///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////hf///yz///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///yz///+F/////////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////w////8z///8/////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////LP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////P////83///+/////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////LP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////bv////////////////////T///9A////9P///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////YP///9b///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////W////YP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///8v///9h////AP///2P////J////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///+X///8F////A////5n////k////M////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////yv///1L///8A////VP///8f///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///+H///8V////F////+D///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8U////7v///7L///8I////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///9g////1v///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////1v///2D///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////y////2H///8A////Y////8n///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///8r///9S////AP///1T////H////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////YP///9b///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///9b///9g////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////y////2H///8A////Y////8n///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///8r///9S////AP///1T////H////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD////l////Bf///wP///+Z////5P///zP///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9g////1v///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////1v///2D///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////y////2H///8A////Y////8n///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////5f///wX///8D////mf///+T///8z////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////K////Uv///wD///9U////x////wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Jv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9g////1v///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////1v///2D///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////y////2H///8A////Y////8n///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///8r///9S////AP///1T////H////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD////W////YP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////A////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///1j////b////1////1H///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8D////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////A////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "/////////2z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wP////F////v////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///7z////G////Av///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////90////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///1X///+z////5f///+f///+y////Tf///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////////////////////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///////////////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wX////b////Wf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///yH///+x////7////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "/////////yz///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///+////+w////H////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "/////////yz///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wX///+L////5v////////////////////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Mf////j///9W////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////Vv////j///8u////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8n////8f///3D////x////JP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+5////cf///6n///+q////dP///7P///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///8n///9R////AP///1T////T////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9Y////2////9f///9R////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///03////u////0f///2n///89////Uf///5D///97////AP///wD///8A////AP///wD///8A////AP///wD///8x////+P///1b///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///1b////4////Lv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///yf////x////cP////H///8k////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////J////Uf///wD///9U////0////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Mf////j///9W////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///9W////+P///y7///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///yf////x////cP////H///8k////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////J////Uf///wD///9U////0////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////uf///3H///+p////qv///3T///+z////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8x////+P///1b///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///1b////4////Lv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///yf////x////cP////H///8k////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///7n///9x////qf///6r///90////s////wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////yf///1H///8A////VP///9P///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8x////+P///1b///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///1b////4////Lv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///yf////x////cP////H///8k////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD////J////Uf///wD///9U////0////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Vv////j///8u////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD////W////YP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////9s////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////K////Uv///wD///9U////x////wD///8A////AP///wD///8A////AP///wD///8A", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8E////3v///2T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////8s////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////8s////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///8/////e////Av///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wL////e////zP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///4H/////////gf///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////N////+X///+X////A////wb////j////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////G////5f////I////8////+z////L////dv///wD///8A////AP///wD///8A////AP///wD///8A////z////97///8C////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8C////3v///8z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////gf////////+B////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///8/////e////Av///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Av///97////M////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////gf////////+B////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///zf////l////l////wP///8G////4////wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////z////97///8C////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8C////3v///8z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////gf////////+B////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///83////5f///5f///8D////Bv///+P///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////z////97///8C////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8C////3v///8z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////gf////////+B////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wL////e////zP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Vv////j///8u////AP///wD///8A////AP///wD///8A////AP///wD/////////bP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////yf///1H///8A////VP///9P///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////LP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////LP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////A////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wP///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8D////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wL////e////zP///wD///8A////AP///wD///8A////AP///wD///8A", + "/////////2z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wA=" +}; + +// Texture image block count +const size_t CAF_FIXED_ATLAS_FONT_12_PT_TEXTURE_IMAGE_BLOCK_COUNT = 1451; + +// Fixed Atlas Font: Droid Sans Regular (14pt) +// Exported by FreeType Font Extractor 1.0.0 +// Copyright (c) 2011 Ceetron AS +// -------------------------------------------------------------------------------- + +// Font name +const char CAF_FIXED_ATLAS_FONT_14_PT_NAME[] = "Droid Sans Regular (14pt)"; + +// Number of glyphs +const size_t CAF_FIXED_ATLAS_FONT_14_PT_NUM_GLYPHS = 256; + +// Horizontal bearings X +const short CAF_FIXED_ATLAS_FONT_14_PT_HORIZONTAL_BEARINGS_X[] = +{ + 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, 0, 0, 0, + 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, -1, 1, 2, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, + 1, -1, 2, 1, 2, 2, 2, 1, 2, 0, -1, 2, 2, 2, 2, 1, 2, 1, 2, 0, 0, 2, -1, -1, -1, -1, 1, 2, -1, 0, 0, 0, + 4, 0, 1, 0, 0, 0, 0, 0, 1, 0, -1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 0, 1, -1, -1, 0, -1, 0, 1, 4, 1, 1, 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, 0, 0, 0, 0, + 0, 1, 1, 1, 0, 0, 4, 0, 3, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 4, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, + -1, -1, -1, -1, -1, -1, -1, 1, 2, 2, 2, 2, 0, 0, 0, 0, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, -1, 2, 1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 1, -1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, -1, 1, -1 +}; + +// Horizontal bearings Y +const short CAF_FIXED_ATLAS_FONT_14_PT_HORIZONTAL_BEARINGS_Y[] = +{ + 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, 0, 0, 0, + 0, 14, 14, 14, 15, 14, 14, 14, 14, 14, 15, 11, 2, 6, 2, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 10, 10, 11, 9, 11, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, -2, + 15, 10, 15, 10, 15, 10, 15, 10, 15, 14, 14, 15, 15, 10, 10, 10, 10, 10, 10, 10, 13, 10, 10, 10, 10, 10, 10, 14, 15, 14, 9, 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, 0, 0, 0, 0, + 0, 10, 14, 14, 10, 14, 15, 15, 14, 14, 14, 9, 7, 6, 14, 16, 14, 11, 14, 14, 15, 10, 15, 7, 0, 14, 14, 9, 14, 14, 14, 10, + 18, 18, 18, 19, 17, 17, 14, 14, 18, 18, 18, 17, 18, 18, 18, 17, 14, 19, 18, 18, 18, 19, 17, 11, 15, 18, 18, 18, 17, 18, 14, 15, + 14, 14, 14, 15, 13, 15, 10, 10, 14, 14, 14, 13, 14, 14, 14, 13, 15, 15, 14, 14, 14, 15, 13, 11, 10, 14, 14, 14, 13, 14, 15, 13 +}; + +// Horizontal advances +const cvf::uint CAF_FIXED_ATLAS_FONT_14_PT_HORIZONTAL_ADVANCES[] = +{ + 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, + 5, 4, 8, 12, 10, 16, 13, 4, 6, 6, 10, 10, 4, 6, 4, 7, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 4, 4, 10, 10, 10, 8, + 16, 12, 12, 12, 13, 10, 9, 13, 14, 6, 5, 11, 10, 17, 14, 14, 11, 14, 12, 10, 10, 14, 11, 17, 10, 10, 10, 6, 7, 6, 10, 8, + 11, 10, 11, 9, 11, 10, 7, 10, 11, 5, 5, 9, 5, 17, 11, 10, 11, 11, 8, 9, 6, 11, 10, 14, 10, 10, 8, 7, 10, 7, 10, 19, + 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, + 5, 4, 10, 10, 10, 10, 10, 10, 11, 16, 7, 10, 10, 6, 16, 10, 8, 10, 6, 6, 11, 11, 12, 4, 4, 6, 7, 10, 14, 14, 14, 8, + 12, 12, 12, 12, 12, 12, 16, 12, 10, 10, 10, 10, 6, 6, 6, 6, 13, 14, 14, 14, 14, 14, 14, 10, 14, 14, 14, 14, 14, 10, 11, 11, + 10, 10, 10, 10, 10, 10, 16, 9, 10, 10, 10, 10, 5, 5, 5, 5, 10, 11, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 10, 11, 10 +}; + +// Character widths +const cvf::uint CAF_FIXED_ATLAS_FONT_14_PT_CHARACTER_WIDTHS[] = +{ + 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, + 5, 3, 6, 12, 8, 14, 12, 2, 5, 4, 10, 9, 3, 4, 2, 9, 8, 5, 8, 8, 10, 8, 8, 8, 8, 8, 2, 3, 8, 8, 8, 7, + 14, 14, 9, 10, 10, 7, 7, 11, 10, 6, 5, 10, 8, 13, 10, 12, 8, 12, 10, 9, 10, 10, 13, 19, 12, 12, 8, 4, 9, 4, 10, 8, + 4, 8, 9, 8, 9, 9, 7, 10, 8, 3, 4, 9, 2, 14, 8, 9, 9, 9, 6, 7, 6, 8, 11, 15, 9, 11, 8, 5, 2, 5, 8, 19, + 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, + 5, 3, 7, 8, 10, 10, 2, 8, 5, 14, 5, 8, 8, 4, 14, 10, 6, 9, 6, 5, 4, 8, 9, 2, 4, 4, 5, 8, 12, 13, 14, 7, + 14, 14, 14, 14, 14, 14, 16, 10, 7, 7, 7, 7, 6, 6, 6, 6, 11, 10, 12, 12, 12, 12, 12, 9, 12, 10, 10, 10, 10, 12, 8, 9, + 8, 8, 8, 8, 8, 8, 15, 8, 9, 9, 9, 9, 4, 4, 6, 5, 9, 8, 9, 9, 9, 9, 9, 10, 9, 8, 8, 8, 8, 11, 9, 11 +}; + +// Character heights +const cvf::uint CAF_FIXED_ATLAS_FONT_14_PT_CHARACTER_HEIGHTS[] = +{ + 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, + 5, 14, 5, 14, 16, 14, 14, 5, 17, 17, 9, 9, 5, 2, 2, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 10, 13, 9, 6, 9, 14, + 16, 14, 14, 14, 14, 14, 14, 14, 14, 14, 18, 14, 14, 14, 14, 14, 14, 18, 14, 14, 14, 14, 14, 14, 14, 14, 14, 17, 14, 17, 9, 2, + 3, 10, 15, 10, 15, 10, 15, 15, 15, 14, 19, 15, 15, 10, 10, 10, 15, 15, 10, 10, 13, 10, 10, 10, 10, 15, 10, 17, 20, 17, 5, 19, + 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, + 5, 13, 14, 14, 9, 14, 20, 15, 2, 14, 6, 8, 5, 2, 14, 2, 6, 11, 8, 8, 3, 15, 17, 2, 5, 8, 6, 8, 14, 14, 14, 14, + 18, 18, 18, 19, 17, 17, 14, 19, 18, 18, 18, 17, 18, 18, 18, 17, 14, 19, 18, 18, 18, 19, 17, 9, 16, 18, 18, 18, 17, 18, 14, 15, + 14, 14, 14, 15, 13, 15, 10, 15, 14, 14, 14, 13, 14, 14, 14, 13, 15, 15, 14, 14, 14, 15, 13, 10, 11, 14, 14, 14, 13, 19, 20, 18 +}; + +// Texture image dimensions +const size_t CAF_FIXED_ATLAS_FONT_14_PT_TEXTURE_IMAGE_WIDTH = 4864; +const size_t CAF_FIXED_ATLAS_FONT_14_PT_TEXTURE_IMAGE_HEIGHT = 20; + +// Texture image data +const char* CAF_FIXED_ATLAS_FONT_14_PT_TEXTURE_IMAGE[] = +{ + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////xf////D///8v////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///6r///99////AP///wD///+q////ff///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///+7///9r////AP///wD///9N", + "/////////xL///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////0j///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8M////4////8b///8B////AP///wD///8A////A////4v////m////5v///47///8E////AP///wD///8A", + "////AP///wD///8A////Rf///7/////r////9////9n///+H////E////wD///+R/////////4b///8A////AP///wD///8A////AP///wD///8A////qv///33///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8B////wP///77///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+7////wf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wj///98////mv///wD///8A////kP///4T///8K////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD////0////X////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////i////fv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////kP///5D///+Q////kP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///87////N////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8T////+P///5v///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wn///+W////3////97///+a////Df///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////+k////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////////////////////////////////////jP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////c////8v////t////9v///9b///+e////HP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////+k////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+A", + "////0v////X////z////zP///4T///8K////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wb///+O////3P///+z///+z////JP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8W////+////7n///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////Tv///8P////t////7P///73///8+////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///+f////7////2f///6L///8f////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///87////N", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////i////fv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Q////8H///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///2T///9k////ZP///2T///9k////ZP///2T///9k////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////B////Qv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////F", + "////8P///y////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///yv///+T////v////+r////0////3f///7P///9k////AP///wD///8A////AP///wD///8A////AP///wD///8U////+f///6////8A////AP///wD///8A////AP///wD///8A////AP///7L////5", + "////FP///wD///8A////AP///wD///8A//////////////////////////z////d////pf///yP///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Av///2n///+r////2P////v////1////2P///5z///8A////AP///wD///8A////AP///wD///8A////AP///wD////////////////////4", + "////0v///6n///9W////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////////////////////////////////////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////+4////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wH///9n////rv///9z////8////9P///9z///+0////ef///wD///8A////AP///wD///8A////AP///wD///8A/////////7j///8A////AP///wD///8A////AP///wD///+4/////////wD///8A////AP///wD///8A////AP///wD///8A////AP///5b/////////////////////", + "////Tv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////q////9f///8f///88////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////7j///8A////AP///wD///8A////F////+7////h////DP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP////////////////////////////////////////+Q////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////uP///wD///8A////AP///3r/////////SP///wD///8A////AP///7j/////////AP///wD///8A////AP///wD///8A/////////7j///8A////AP///wD///8A", + "////AP///1z//////////////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Cv///4D///+4////6P///+j///+3////eP///wb///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////uP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8F////pv///z7///8A////AP///wD///8A////AP///wD///8A////AP////////+4////AP///wD///8A////AP///xz////1////5f///w3///8A////AP///wD///8A////AP///wD///8A////AP///wD///8R////k////9f////w////9////9n///+d", + "////I////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////+4////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8B////bP///8L////s////5////7r///9h////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///4n/////////jP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///5f/////////b////wD///8A////AP///wD///8A////gv////////+D////AP///wD///8A////AP///w3////n////yP///wH///8A////AP///wD///8A", + "////Dv///+v////o////Df///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////+4////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A//////////////////////////////////////////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP////////////////////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////I////2v///wH///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////////////////////wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///7/////U////Af///wD///8A////AP///wD///8B////0////8D///8A////AP///wD///8A////AP///wD///8A////AP///wD///9M////TP///0z///9M////TP///0z///9M////TP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///xL////B////yP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///xL///+h////6/////b////L////Rv///1T/////////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////Wf///0n////G////9f///+H///+k////Fv///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wX///9u////y////+7////1////2v///33///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8X////ov///+D////2////yP///0T///9x/////////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////Af///1////+/////6P////z////n////sf///zz///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////sP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wn///+B////1f////P////y////1////6L///82////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD/////////sP///wD///8A////AP///wD///+w/////////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////+w////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///+n////u", + "////lv///wX///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////sP///wD///8A////AP///yL////x////1P///wr///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////7D///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP////////+w////AP///wD///8A////AP///8D////w////AP///wD///8A////AP///7D/////////AP///wD///8A////AP///wD/////////sP///wD///8A////AP///wD///+w/////////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wj///+G", + "////0/////T////S////if///wr///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////+w////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////sP////////8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A/////////7D///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///w////+k////5v////n////i////kv///w3///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Gf///63////v", + "////+////9b///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Cf///4z////h////+P///8////9M////df////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////H/////////7v///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///+f/////////5j///8A////AP///wD///+i/////////5v///8A////AP///wD///8A////AP///wD///8A////qP////7///9A////AP///wD///8A////QP////7///+n////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///xT////v////9f///8L///8r", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////////////////////////////////////KP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8c////r////+////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP////////9k////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////v////rv///xr///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", @@ -448,41 +2729,502 @@ const char* CAF_FIXED_ATLAS_FONT_12_PT_TEXTURE_IMAGE[] = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////v////sv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////ZP/////////I////dv///0H///9Y////fv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wn/////////av///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////5////0b///8A////AP///y3////e////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////CP//////////////////////////////2P///wD///8A////AP///wD///8A////AP///wD///8A////AP////////8s////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8L////a////+3///+h////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///3f///+G////AP///w3///+V////4/////n////K////AP///4n///90////AP///wD///8A////AP///wD///8Z////AP///yb////o////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////CP////X///8s////CP////X///8s////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///yH///8s////LP///yz///8s////UP////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////d////4b///8A////AP////////9A////AP///8f///8y////if///3T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+8////p////yP///+R////uP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP////////8s////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////I////9f///89////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////3P////P////o////KP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////9q////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////8P///wD////w////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9+////bv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////8g////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////1f///0T///9H////0f///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8t////9f///wj///8t////9f///wj///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///yb////w////IP///4T///91////AP////////8g////AP///wD///8A////AP///wD///8A", - "////AP///wD///8m////8P///yD///8A////AP///wD///8j////1////z3///8A////AP///wD///8A////AP///wD///8A////AP///yb////w////IP///4T///91////AP////////8g////AP///wD///8A////AP///wD////3////Yf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wP////l////lf///zD///8w////MP///zD///+T////5v///wP///8A////AP///wD///8A////AP///wD///8D////5f///5X///8w////MP///zD///8w////k////+b///8D////AP///wD///8A////AP///wD///8A////A////+X///+V////MP///zD///8w////MP///5P////m////A////wD///8A////AP///wD///8A", - "////AP///wP////l////lf///zD///8w////MP///zD///+T////5v///wP///8A////AP///wD///8A////AP///wD///8D////5f///5X///8w////MP///zD///8w////k////+b///8D////AP///wD///8A////AP///wD///8A////A////+X///+V////MP///zD///8w////MP///5P////m////A////wD///8A////AP///wD///8A", - "////AP///wD///+o////w////zD///8w////MP///zD/////////dP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////fv///27///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////dP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "/////////3T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////90////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////dP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///yD/////////VP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8g/////////1T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////IP////////9U////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///yD/////////VP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////dP///wD///8A////AP///wD///8e////9////43///8A////AP///wD///8A////AP///wD/////////dP///wD///8A////AP///8P///+e////Z/////////8A////AP///wD///8A////AP///wD///8A", - "////pP///+v///8H////AP///wD///8A////AP///wb////r////nP///wD///8A////AP///wD///8A////AP///6T////r////B////wD///8A////AP///wD///8G////6////5z///8A////AP///wD///8A////AP///wD///+k////6////wf///8A////AP///wD///8A////Bv///+v///+c////AP///wD///8A////AP///wD///8A", - "////pP///+v///8H////AP///wD///8A////AP///wb////r////nP///wD///8A////AP///wD///8A////AP///6T////r////B////wD///8A////AP///wD///8G////6////5z///8A////AP///wD///8A////AP///wD///8A////AP///yT////k////I////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////Mf////3////r////sP///wD///8A////AP///23////9////KP///wD///8A////AP///wD///8A////AP///+L///+m////AP///wD///8A////AP///4v////g////AP///wD///8A////AP///wD///8A////AP///wD////i////pv///wD///8A////AP///wD///+L////4P///wD///8A////AP///wD///8A////AP///wD///8A", - "////4v///6b///8A////AP///wD///8A////i////+D///8A////AP///wD///8A////AP///wD///8A////AP///+L///+m////AP///wD///8A////AP///4v////g////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////IP////////9U////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "///////////////9////4f///7b///85////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////9s////AP///wD///8A////Av///7X////Z////AP///wD///8A////AP///wD///8A////AP///wD///9p////9f///4X///9R////O////4r/////////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////af////X///+F////Uf///zv///+K/////////wD///8A////AP///wD///8A////AP///wD///8A////AP///2n////1////hf///1H///87////iv////////8A////AP///wD///8A////AP///wD///8A////AP///wD///9p////9f///4X///9R////O////4r/////////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////af////X///+F////Uf///zv///+K/////////wD///8A////AP///wD///8A////AP///wD///8A////AP///2n////1////hf///1H///87////iv////////8A////AP///wD///8A////AP///wD///8A////AP///wD///93////5P///03///8Z////CP////////+t////MP///zD///8w////MP///zD///8A////AP///wD///8A", - "////AP///wD///8A////fv///27///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///93///+t////MP///zD///8w////MP///zD///8A////AP///wD///8A////AP///wD///8A////AP///wD////d////rf///zD///8w////MP///zD///8w////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////3f///63///8w////MP///zD///8w////MP///wD///8A////AP///wD///8A////AP///wD///8A////AP///93///+t////MP///zD///8w////MP///zD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////2z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "/////////2z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////2z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////9s////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////7f///4L///8A////AP///wD///+n////1v///wD///8A////AP///wD///8A////AP///wD///8A////AP////////9s////AP///wD///8A////bP////////8A////AP///wD///8A////AP///wD///8A////AP///wD////e////qP///wD///8A////AP///6v////d////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////3v///6j///8A////AP///wD///+r////3f///wD///8A////AP///wD///8A////AP///wD///8A////AP///97///+o////AP///wD///8A////q////93///8A////AP///wD///8A////AP///wD///8A////AP///wD////e////qP///wD///8A////AP///6v////d////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////3v///6j///8A////AP///wD///+r////3f///wD///8A////AP///wD///8A////AP///wD///8A////AP///7j///////////////////////////////////+A////AP///wD///8A////AP///wD///8A////AP///wD////e////h////6j///+W////AP///6v////d////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "/////////27///8A////AP///wD///+B/////////wD///8A////AP///wD///8A////AP///wD///8A////AP////////9u////AP///wD///8A////gf////////8A////AP///wD///8A////AP///wD///8A////AP///wD/////////bv///wD///8A////AP///4H/////////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "/////////27///8A////AP///wD///+B/////////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////R////nf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////a////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///9H///+d////AP///wD///8A////AP///wD///8A////AP///wD///8A////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////8/////////zD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////5j///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//////////////////////////////////////////////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////+4////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////9k////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8N////mf///97////1////8f///8////9w////Av///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////xP///43///8A////j////8D///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///xb///97", + "////y////+/////v////y////3v///8W////AP///wD///8A////AP///wD///8A////AP///wD///9k////7P///+v///92////+f///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9i////mf///wD///8A////Xv///5v///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///1/////0////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+Q////kP///5D///+Q////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Fv///3v////L", + "////7////+/////L////e////xb///8A////AP///wD///8A////AP///wD///8A////AP///0z///9M////TP///0z///9M////TP///0z///9M////TP///0z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8G////if///+b////m////h////wX///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////lP/////////////////////////////////////////8////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//////////////////////////////VP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+w////8P////L///+4////Iv///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////yv///8L///8S////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////+w////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP////////8c////HP////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////zv///83///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////j////a////nf///yf///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////9U////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////HP///7z////z////vf///x7///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///5r///9h////AP///wD///+b////Xv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8N////6P///33///8A////AP///wD///8A////AP///wD/////////VP///wD///8A////AP///wD///8A////AP///wD///8A////Df///+j///99////AP///wD///8A////AP//////////", + "////////////////////VP///wD///8A////AP///wD///8A////AP///wD///8A////dv///+z///8R////AP///wD///8A////AP///wD///8A/////////1T///8A////AP///wD///8A////AP///wD///8A////ZP///9L////1////3////6v///9I////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////FP////n///+v////AP///wD///8A////AP///wD///8A////AP///wD///+y////+f///xT///8A////AP///wD///8A////AP///xT////5////r////wD///8A////AP///wD///8A////AP///wD///8A////sv////n///8U////AP///wD///8A////AP///wD///8U////+f///6////8A////AP///wD///8A////AP///wD///8A", + "////AP///7L////5////FP///wD///8A////AP///wD///8A////FP////n///+v////AP///wD///8A////AP///wD///8A////AP///wD///+y////+f///xT///8A////AP///wD///8A////AP///xT////5////r////wD///8A////AP///wD///8A////AP///wD///8A////sv////n///8U////AP///wD///8A////AP///wD///8U", + "////+f///6////8A////AP///wD///8A////AP///wD///8A////AP///7L////5////FP///wD///8A////AP///wD///8A////Ef////T///+w////AP///wD///8A////AP///wD///8A/////////////////////////////////////////wD///8A////AP///wD///8A////AP///wD////4////2v///53///8n////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD/////////////////////////////////////////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////////////////////////////////////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//////////", + "//////////////////////////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////////////////////////////////////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////lv////////////////////////9O////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///5b/////////////////////////Tv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+W/////////////////////////07///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////lv//////////", + "//////////////9O////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////////////////////4////0v///6n///9W////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////uP///wD///8A////AP///wD///8A////XP//////////////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8K////gP///7j////o////6P///7f///94////Bv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Cv///4D///+4////6P///+j///+3////eP///wb///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wr///+A", + "////uP///+j////o////t////3j///8G////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8K////gP///7j////o////6P///7f///94////Bv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Cv///4D///+4////6P///+j///+3////eP///wb///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////J////wD///8A////AP///wD///8A////Kv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///yL///8w////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8B////bP///8L////s", + "////5////7r///9h////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Af///2z////C////7P///+f///+6////Yf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wH///9s////wv///+z////n////uv///2H///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8B////bP///8L////s////5////7r///9h////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////+4////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////7j///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////+w////AP///wD///+f////6/////D///+q////FP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8S////of///+v////2////y////0b///9U/////////wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////Ev///6H////r////9v///8v///9G////VP////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///xL///+h////6/////b////L////Rv///1T/////////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8S////of///+v////2////y////0b///9U", + "/////////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Ev///6H////r////9v///8v///9G////VP////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///xL///+h////6/////b////L////Rv///1T/////////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8H////hf///93////4////6P///6v///8u////AP///wP///99////w/////f////v////uP///zv///8A////AP///wD///8A////AP///wD///8A////+P///9r///+d////J////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8B////X////7/////o/////P///+f///+x", + "////PP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Af///1////+/////6P////z////n////sf///zz///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wH///9f////v////+j////8////5////7H///88////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8B////X////7/////o/////P///+f///+x////PP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////+w////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////7D///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////7D///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////7D///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wf///+G////0/////P////M////ev///wL///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////+w////AP///wD///8A////AP///7D/////////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////CP///4b////T////9P///9L///+J////Cv///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wj///+G////0/////T////S////if///wr///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8I////hv///9P////0////0v///4n///8K////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////CP///4b////T////9P///9L///+J////Cv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wj///+G////0/////T////S////if///wr///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////l////Sv///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8p////vf///wj///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Cf///4z////h////+P///8////9M////df////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wn///+M", + "////4f////j////P////TP///3X/////////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8J////jP///+H////4////z////0z///91/////////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Cf///4z////h////+P///8////9M////df////////8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///xT////v////9f///8L///8r////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////sP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////FP///+/////1", + "////wv///yv///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///8T////u////MP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+9////kP///wD///8A////vf///5D///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////K////kf///wD///8A////J/////////83////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////9I////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///0//////////aP///wD///8A////AP///3H////0////d////4D////3////d////wD///8A////AP///wD///8A////Sv/////////t////kP///4H///+x/////P///+j///+l/////////5L///8A////AP///wD///8A////AP///wD///8A////AP///73///+Q////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////Yf////////87////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Ov////////9f////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8J", + "////1f////v///8b////HP////n////Y////C////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////2T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////p////+T///8D////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP////////////////////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////N////zP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///6X////0", + "////Dv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wL///+z////9////5f///+b////+f///7z///8E////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////pP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////4v////////+g////jP///4z///+M////jP///0z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////z///+3////if///3r///+k////+v////L///8j////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD/////////pP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////9v///7H///+B////ev///6v////+////2P///wr///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wH///++/////f///6P///+G////6f////D///8b////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///7X////8////Fv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Vv/////////U////gf///4T////d/////v///0H///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9q////Xv///5D////h", + "////9f///zb///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////N////zP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////p////+T///8D////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///9G////xP////////+8////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD//////////////////////////////////////////////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////vP/////////D////Rf///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////xP///+7///8w////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////BP///37////5////wv///4P///9Y////S////2T///+X////4v///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///6r////5////E////wD///8A////AP///wD///8A////AP///xT////6////qv///wD///8A////AP///wD///8A////AP/////////V////aP///2j///9x////nP////n////1////Jv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////HP///7//////////1f///5n///9y", + "////f////6P////n////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////9X///9o////dP///53////b/////////7L///8W////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP/////////V////aP///2j///9o////aP///2j///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD/////////uP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///xj///+6/////////9n///+g////dP///23///+H////5v////////8A////AP///wD///8A////AP///wD///8A////AP////////+4////AP///wD///8A////AP///wD///8A", + "////uP////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8E////Nf/////////N////JP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////ff///3P////c////9f///xz///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP////////+4////AP///wD///8A////AP///6j/////////Sv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////1f///2j///9o////aP///2j///9o////Ov///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////7j///8A////AP///wD////P/////////6D///8A", + "////AP///wD///+4/////////wD///8A////AP///wD///8A////AP////////+4////AP///wD///8A////AP///wX////d//////////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////KP///9T////+////tv///4H///+A////tf////7////J////H////wD///8A////AP///wD///8A////AP///wD///8A", + "/////////7j///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8D////sv////////+1////AP///wD///8A////AP///wD///8A////AP///wD/////////uP///wD///8A////AP///wD///+k/////////1n///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////LP////T///+t////ev///3j///+2////8/////T///8r////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////uP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8C", + "////uf/////////v////mf///3z///+6/////////67///8B////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wH////h/////v///+P///8B////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////c/////////7X///8A////AP///wD///8A", + "////AP///8f/////////yf///wD///8A////AP///wD///8A////X/////////9c////AP///wD///8A////AP///4T/////////Yv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////uP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///9j/////", + "////d////2j///9o////aP///2j///9o////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////z////2T///9k////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8w/////////3T///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///2T///9k////z/////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8+/////////1L///8A////AP///wD///8A////TP////////9C////AP///wD///8A////AP///wD///8A////AP///wD///8A////////////////", + "//////////////////////////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///xH////R////9////yX///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+n/////////7T///90////j////+r////G/////////wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A/////////9H////1////mP///3n////V/////////+X///8P////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wP////F//////////D///+f////h////6j///+/////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8Q////5//////////P", + "////eP///5L////x////0f////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Af///7b/////////7P///6D///97////lP///83///+L////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////7D///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///+g////+////3z///9D////Uv///4T////L/////f///07///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////7D///8A////AP///wD///8A////sP////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////sP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///95////pv////////9e////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////7D///8A////AP///wb////M////9P///yj///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP////////+w////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////sP///wD///8A////AP///wD////A////8P///wD///8A////AP///wD///+w/////////wD///8A////AP///wD///8A/////////7D///8A////AP///wD///8A", + "////sP////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wX////M/////////9X///+D////1P/////////T////B////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////sP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///7D/////////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////+w////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8o////3P///4j///9u////m/////////+h", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///6r/////////r////23///+C////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///4X/////////2v///4D///+P////7v///9L/////////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8l/////////7z////9////HP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////5f///+H////Z////AP///wD///8A////3////+T////i////AP///wD///8A////AP///wD///8A////AP///xL////l////2////wn///8A////Cf///9z////k", + "////Ef///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8M////cP///3v////j////5v///w////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////uv////r///9R////OP///zj///84////OP///wj///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////uP////r///99////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////ZP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////fv////v///+z////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///2T///8A////AP///xb///+h////9f///9b///9J////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////9f////////8i////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////+a////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////I/////////93///+M////jP///4z///+M", + "////jP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///4////9n////AP///wD///8A////AP///27///+T////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////uP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD/////////ZP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////JP///+X///+b////cv///3L///+n/////////4z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///8T///+L////AP///4/////O////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///0/////v////n////1H///8d////Hf///1H///+f////7v///07///8A////AP///wD///8A////AP///wD///8A////7P///2z///8U////p/////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8j////8////4f///8A////Iv////L///+H////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9k/////////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////////////////////wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////T////+////+f////Uf///x3///8d////Uf///5/////u////Tv///wD///8A////AP///wD///8A////AP///wD/////////////////////////////////////////////////////////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////i/////L///9q////X////+j///+J////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///zn///9k////ZP///2T///9k////ZP///2T///9k////Yv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+F////yf///yv///8k////JP///wv///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////iv///zv///9G////z////8D///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///yb////3////z////xD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////", + "////sP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////HP///xz/////////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///83////L////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8M////H////6j///+u////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////VP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///6z///+u", + "////JP///67///+v////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+I////8////yP///8A////iP////L///8h////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///2P////0////G////wD///8A////JP///yT///8k/////////2z///8R", + "////AP///wD///8A////AP///wD///8A////AP///wD///9j////9P///xv///8A////AP///wD///+F////yf///yv///8k////JP///wv///8A////AP///wD///8A////AP///wD///8A////AP///wb////c////kP///wD///8A////AP///yT///8k////JP////////9s////Ef///wD///8A////AP///wD///8A////aP/////////J", + "////gv///5r////d////wP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+q////+f///xP///8A////AP///wD///8A////AP///wD///8U////+v///6r///8A////AP///wD///8A////AP///wD///8A////qv////n///8T////AP///wD///8A////AP///wD///8A////FP////r///+q", + "////AP///wD///8A////AP///wD///8A////AP///6r////5////E////wD///8A////AP///wD///8A////AP///xT////6////qv///wD///8A////AP///wD///8A////AP///wD///+q////+f///xP///8A////AP///wD///8A////AP///wD///8U////+v///6r///8A////AP///wD///8A////AP///wD///8A////qv////n///8T", + "////AP///wD///8A////AP///wD///8A////FP////r///+q////AP///wD///8A////AP///wD///8A////AP///6r////5////E////wD///8A////AP///wD///8A////AP///xT////6////qv///wD///8A////AP///wD///8A////AP///wD///+T/////f///yL///8A////AP///wD///8A////AP/////////V////aP///2j///9o", + "////aP///2j///8A////AP///wD///8A////AP///wD///8A////DP///x////+o////rv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////9X///9o////aP///2j///9o////aP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP/////////V////aP///2j///9o", + "////aP///2j///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////1f///2j///9o////aP///2j///9o////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////9X///9o////aP///2j///9o////aP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wT///81/////////83///8k////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8E////Nf/////////N////JP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////BP///zX/////////zf///yT///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wT///81/////////83///8k////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////9X///9o////dP///53////b/////////7L///8W////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A/////////7j///8A////AP///wD///8A////Bf///93//////////////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8o////1P////7///+2////gf///4D///+1/////v///8n///8f////AP///wD///8A////AP///wD///8A////AP///wD///8A////KP///9T////+////tv///4H///+A", + "////tf////7////J////H////wD///8A////AP///wD///8A////AP///wD///8A////AP///yj////U/////v///7b///+B////gP///7X////+////yf///x////8A////AP///wD///8A////AP///wD///8A////AP///wD///8o////1P////7///+2////gf///4D///+1/////v///8n///8f////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////KP///9T////+////tv///4H///+A////tf////7////J////H////wD///8A////AP///wD///8A////AP///wD///8A////J/////v///91////AP///wD///8A////cP////3///8x////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wH////S////2P///3X///+s////5P///+j///+3", + "////eP///wb///8A////AP///wD///8A////AP///wD///8A////AP///wD///8C////uf/////////v////mf///3z///+6/////////67///8B////AP///wD///8A////AP///wD///8A////AP///wD///8A////Av///7n/////////7////5n///98////uv////////+u////Af///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wL///+5/////////+////+Z////fP///7r/////////rv///wH///8A////AP///wD///8A////AP///wD///8A////AP///wD///8C////uf/////////v////mf///3z///+6/////////67///8B////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////uP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////+4////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////sP///wD///8A////1v///3j///+T/////////6D///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////p/////////+0////dP///4/////q////xv////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///6f/////////tP///3T///+P////6v///8b/////////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+n/////////7T///90////j////+r////G/////////wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////p/////////+0////dP///4/////q////xv////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///6f/////////tP///3T///+P////6v///8b/////////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+n", + "/////////7T///90////j////+r////G/////////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////mf/////////C////ev///37////E////9////0P///+i/////////+T///+V////mP///9D///+L////AP///wD///8A////AP///wD///8A////AP///wz///8f////qP///67///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8B////tv/////////s////oP///3v///+U////zf///4v///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Af///7b/////////7P///6D///97////lP///83///+L////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wH///+2", + "/////////+z///+g////e////5T////N////i////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8B////tv/////////s////oP///3v///+U////zf///4v///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////sP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP////////+w////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////+w////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////+w", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wT////K/////f///6D///90////of////7///+y////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////sP///wD///8A////AP///wD///+w/////////wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////Bf///8z/////////1f///4P////U/////////9P///8H////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wX////M/////////9X///+D////1P/////////T////B////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8F////zP/////////V", + "////g////9T/////////0////wf///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Bf///8z/////////1f///4P////U/////////9P///8H////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wX////M/////////9X///+D////1P/////////T////B////wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////S////xH///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////K/////3///+z////yf////P////S////if///wr///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///4X/////////2v///4D///+P", + "////7v///9L/////////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+F/////////9r///+A////j////+7////S/////////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////hf/////////a////gP///4/////u////0v////////8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///4X/////////2v///4D///+P////7v///9L/////////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8M////cP///3v////j////5v///w////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////7D///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wz///9w////e////+P////m////D////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////0P///6P///8A////AP///9D///+j////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////pv///7f///8A////AP///wX////7////XP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+T////3P////r/////", + "////4v///6L///8x////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////rv////D///8Y////AP///wD////Q////pP///wD///8A////rP///9P///8A////AP///wD///8A////AP///8j////4////Jv///wD///8A////AP///yz////v/////////6r///8B////AP///wD///8A", + "////AP///wD///8A////AP///wD////Q////o////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///9n////T////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////U////1v///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///zH////5////hv///5L////5////Mv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////9k////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///3D/////////SP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8+/////////2n///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9A/////////3T///8A////AP///3n/////////Sf///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A/////////6T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///zj////6////u////wL///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8e////AP///wD///8A////AP///zz////9", + "////rv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////6T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///xj///8A////AP///wD///8A////X/////////+C////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///9L/////////3b///8A////AP///yz////+////lv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9Y/////////23///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///83////j////Cf///wD///8A////EP///+r////D", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////GP///9f////g////Bv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///3D/////////SP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///0n////H/////v///63///80////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///80////rP////3////G////SP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///37////0////ZP///wD///8A////AP///wD///8A////AP///wH///8A////AP///wD///8A////AP///wD///8A////AP///wD///9G/////////2v///8A////AP///wD///8A////AP///wD///9r/////////0b///8A////AP///wD///8A////AP///wD/////////uP///wD///8A////AP///wD///9G/////////6////8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///8L/////////hP///wP///8A////AP///wD///8A////Af///wD///8A////AP///wD///8A////AP///wD///8A////AP////////+4////AP///wD///8A////Bv///4r/////////q////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////", + "////uP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////7j///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+3/////////4r///8E////AP///wD///8A////AP///7j/////", + "////AP///wD///8A////AP///wD///8A////AP///wD/////////uP///wD///8A////AP///wD///8A////AP///7j/////////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////uP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////N/////////+A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////uP///wD///8A////AP///0v/////////pv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////7j///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP////////+4////AP///wD///8j/////////+T////w////B////wD///8A////uP////////8A////AP///wD///8A////AP///wD/////////uP///wD///8A////AP///wD///9r/////f///8b/////////AP///wD///8A////AP///wD///8A////AP///wD///8A////Af///9P////3", + "////Uv///wD///8A////AP///wD///9S////9////8P///8A////AP///wD///8A////AP///wD///8A////AP////////+4////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Z/////////+2////C////wD///8A", + "////AP///wD///8A////AP///wD///8A/////////7j///8A////AP///wD///84/////v///7////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wv///8N////AP///wD///8A////AP///zr/////////uP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "/////////7j///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////ZP////////+S////B////wD///8A////AP///4H/////////Xf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///88/////////6z/////////Pv///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8i/////////83////0////Bv///wD///8A////AP///w/////8////yf////3///8T////AP///wD///8A////AP///wH////G////5P///wv///8A////AP///xr////1////zP///wH///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "/////////7j///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9T/////////4X///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////7D///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////mP////j///8T////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///7D/////////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///73////N////AP///wD///8A", + "////AP///8P////D////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+//////////4L///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////7v///+L///8D////AP///wD///8o////9/////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//////////////Rf///wD///8A////Af///3n/////////g////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///90/////////5H///8H////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////h/////////9r////AP///wD///8A////PP//////////////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///2v/////////j////wP///8A////AP///wD///8A////Cf///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP////////+w////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////8P///6j///8A////AP///wD///8A////Ev///+z////O////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////+w////AP///wD///8A////AP///7D/////", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////7D///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///w//////////m////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP////////+w////AP///wD///+R/////////1v///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////sP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////7D///8A////AP///wD///8A////wP////D///8A", + "////AP///wD///8A////sP////////8A////AP///wD///8A////AP////////+w////AP///wD///8A////AP///7D/////////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9y/////////3H///8A////AP///wD///9x/////////3f///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "/////////7D///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+w/////////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////sP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////Bv///wP///8A////AP///wD////A////7f///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////p////3P///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////b", + "////+v///wz///8A////AP///zv//////////////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////gv////z///8v/////////3j///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Lf////////+G/////////xv///8A////HP////////+M", + "/////////yn///8A////AP///wD///8A////AP///wD///8A////SP////////+L////AP///4z////+////Rf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////K/////7///9+////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///xz////v", + "////tf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////T///+8////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////2T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///+9////8v///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////2////jv///4D////u////7P///3////+N////9v///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8AAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///+7/////////FP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////T////9P//////////////+3///+N////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///5r/////////RP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9D////4////6H////s////6////6T////Y////NP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////Sf///2j///9o/////////9X///9o////aP///z////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////2T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wT///8D////AP///wD///8A////AP///6/////p////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///0/////n////Rf///wD///8A////AP///wD///8A////AP///0b////n////T////wD///8A////AP///wD///8A////AP///73///+T", + "////Hf///0X/////////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8E////x////9////8K////A////8b////f////Cv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////ZP////////8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////T////+f///9F////AP///wD///8A////AP///wD///8A////Rv///+f///9P////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///+f///+A////AP///wD///9j////5v///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////9P///1////8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///47///+7////Cv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///23////y////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////gv////////+9", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////7D///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////xz///8c/////////wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///xv///+v////7v///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////1T///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////t////Uf///wD///9S////7v///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Cv///+D////G////A////wr////g////xf///wP///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8C////zv///6P///8A////AP////7/////////////////////////fP///wD///8A////AP///wD///8A////AP///wD///8A////Av///87///+j////AP///wD///8A////AP///47///+7////Cv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////UP////v///8o", + "////AP///wD////+/////////////////////////3z///8A////AP///wD///8A////AP///9X////X////BP///wD///8A////Av///xj///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Rv////////9r////AP///wD///8A////AP///wD///8A////a/////////9G////AP///wD///8A", + "////AP///wD///8A////AP///0b/////////a////wD///8A////AP///wD///8A////AP///2v/////////Rv///wD///8A////AP///wD///8A////AP///wD///9G/////////2v///8A////AP///wD///8A////AP///wD///9r/////////0b///8A////AP///wD///8A////AP///wD///8A////Rv////////9r////AP///wD///8A", + "////AP///wD///8A////a/////////9G////AP///wD///8A////AP///wD///8A////AP///0b/////////a////wD///8A////AP///wD///8A////AP///2v/////////Rv///wD///8A////AP///wD///8A////AP///wD///9G/////////2v///8A////AP///wD///8A////AP///wD///9r/////////0b///8A////AP///wD///8A", + "////AP///wD///8A////Iv////3///+Q////AP///wD///8A////AP///wD/////////uP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8b////r////+7///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////+4////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////uP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////7j///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP////////+4////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////+4////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////uP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////7j///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////+4////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP////////+4////AP///wD///8A////Bv///4r/////////q////wD///8A////AP///wD///8A////AP///wD///8A////AP////////+4////AP///wD///8A////AP///2v////9////xv////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8B////0/////f///9S////AP///wD///8A////AP///1L////3", + "////w////wD///8A////AP///wD///8A////AP///wD///8A////Af///9P////3////Uv///wD///8A////AP///wD///9S////9////8P///8A////AP///wD///8A////AP///wD///8A////AP///wH////T////9////1L///8A////AP///wD///8A////Uv////f////D////AP///wD///8A////AP///wD///8A////AP///wD///8B", + "////0/////f///9S////AP///wD///8A////AP///1L////3////w////wD///8A////AP///wD///8A////AP///wD///8A////Af///9P////3////Uv///wD///8A////AP///wD///9S////9////8P///8A////AP///wD///8A////AP///wD///8A////AP///wD///90/////////3b///8A////dP////////98////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////X//////////8////rP///3f///+A////tf////7////J////H////wD///8A////AP///wD///8A////AP///wD///8A////ZP////////+S////B////wD///8A////AP///4H/////////Xf///wD///8A////AP///wD///8A////AP///wD///8A////AP///2T/////", + "////kv///wf///8A////AP///wD///+B/////////13///8A////AP///wD///8A////AP///wD///8A////AP///wD///9k/////////5L///8H////AP///wD///8A////gf////////9d////AP///wD///8A////AP///wD///8A////AP///wD///8A////ZP////////+S////B////wD///8A////AP///4H/////////Xf///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////7j///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////uP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////7D///8A", + "////AP///wb///8A////AP///8b////m////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///+7////i////A////wD///8A////KP////f/////////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////u////4v///wP///8A////AP///yj////3/////////wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////7v///+L///8D////AP///wD///8o////9/////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///+7////i////A////wD///8A////KP////f/////////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////u////4v///wP///8A", + "////AP///yj////3/////////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////7v///+L///8D////AP///wD///8o////9/////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///+v////o////CP///wD///8A////AP///4r////8/////////3z///8C////AP///wD///8A", + "////D////wD///8A////AP///wD///8A////AP///wD///8A////G////6/////u////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////a/////////+P////A////wD///8A////AP///wD///8J////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///2v/////////j////wP///8A", + "////AP///wD///8A////Cf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9r/////////4////8D////AP///wD///8A////AP///wn///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////a/////////+P////A////wD///8A////AP///wD///8J////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A/////////7D///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////sP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////sP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////sP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9x/////////2X///8A////AP///wD///92/////////0z///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A/////////7D///8A////AP///wD///8A////sP////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///3L/////////cf///wD///8A////AP///3H/////////d////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9y/////////3H///8A////AP///wD///9x", + "/////////3f///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////cv////////9x////AP///wD///8A////cf////////93////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///3L/////////cf///wD///8A////AP///3H/////////d////wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///9y/////////3H///8A////AP///wD///9x/////////3f///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wX////k/////////6D///93////1P/////////T", + "////B////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////b////+v///wz///8A////AP///zv//////////////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////2/////r///8M////AP///wD///87//////////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///9v////6////DP///wD///8A////O///////////////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////b////+v///wz///8A////AP///zv//////////////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////K/////7///9+////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////+w////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8r/////v///37///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///+P///+2////AP///wD////j////tv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///4L////d////AP///wD///8A", + "////2////4H///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////9P///6r///96/////////8L////x/////f///1L///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///xv////x////qf///wD///8A////8v///3b///8A////AP///3n////y////AP///wD///8A", + "////AP///wD////z////zP///wD///8A////AP///wD///98//////////3////Q////Av///wD///8A////AP///wD///8A////AP///wD///8A////4////7b///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///zv/////////ff///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////ff////////85////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////dv///+3////2////dP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///zn///9k////ZP///2T/////////oP///2T///9k////Yv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///89/////////5////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///9b////Q////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////lf////////8V////AP///wD///8X/////////5v///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////+k////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////bf////////+F////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////0f///+X///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////////////////////////////////////////////////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD////l////zP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////r/////L///8J////AP///wD///8A////y////9X///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Cf////H////H////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD////1////sP///wD///8A////AP///wD///+w////8f///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9U/////////1P///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///89/////////5////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////S////8n////6////n////yj///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8n////nf////r////J////S////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///x/////2////c////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Af///9/////J////AP///wD///8A////AP///wD///8A////x////+D///8B", + "////AP///wD///8A////AP///wD///8A/////////7j///8A////AP///wD///8A////AP///+r////l////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///0n/////////sv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////uP///wD///8A", + "////AP///wD///8A////uv////////8/////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////7j///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////+4////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///9E/////////7D///8A////AP///wD///8A////AP///wD///+4/////////wD///8A////AP///wD///8A////AP///wD///8A/////////7j///8A////AP///wD///8A////AP///wD///+4/////////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////7j///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wf/////////pv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////7j///8A////AP///wz////h////7P///xX///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP////////+4////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////uP///wD///8A////eP////////9I/////////1D///8A////AP///7j/////////AP///wD///8A////AP///wD///8A/////////7j///8A////AP///wD///8K", + "////5////6T///+j/////////wD///8A////AP///wD///8A////AP///wD///8A////AP///1T/////////kf///wD///8A////AP///wD///8A////AP///5L/////////R////wD///8A////AP///wD///8A////AP///wD/////////uP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////Dv///+n////p////Ef///wD///8A////AP///wD///8A////AP///wD///8A////AP////////+4////AP///wD///8B////yP////v///8r////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////0v///+3///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////+4////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///8P/////////Kv///wD///8A////AP///wD///8I////7////8H///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////lf////3///8p/////f///5f///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Z/////////91/////////0L///8A////AP///wD///9Q/////////2j/////////V////wD///8A////AP///wD///8A////NP////3///+D////AP///wD///+a", + "/////////zv///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////+4////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///8n////1////GP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP////////+w////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////DP////L///+k////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+w/////////wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///87/////////0r///8A////AP///zv/////////Rv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///93////r////FP///wD///8A////AP///8L/////////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////2////wD///8A////AP///wD///8g/////////8r///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////wP////////8u////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///8z/////////Gf///wD///8A////AP///wD////Y/////////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////C", + "/////////yX///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////sP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///97////M////Av///wD///8A////AP///wD///+r////8v///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD/////////sP///wD///8A////AP///wD///+w/////////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////+w////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "/////////6////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////tP///wD///9Q/////////5n///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////7D///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP////////+w////AP///wD///8A////AP///8D////w////AP///wD///8A////AP///7D/////////AP///wD///8A////AP///wD/////////sP///wD///8A////AP///wD///+w/////////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////xf////////8b", + "////AP///wD///8A////HP/////////H////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////+w////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////sP////////8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A/////////7D///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8e////6f///+D///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////7D///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////+v///8L///8A////AP///wD///8A////2f////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Af///97///+/////AP///9D////X////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///3T/////////I/////z///9c////AP///1n////9////Kv////////9w////AP///wD///8A////AP///wD///8A////AP///wD///+X/////P///2r////8////k////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+9", + "////3v///wH///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////W/////////9o////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////sP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP////////9k////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////sP////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Sf///9X////0////nf///xX///8A", + "////AP///2T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////n/////////wb///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////N/////v/////////0v///37///+V////t////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8l/////////53///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///6v////x", + "////aP///1/////o////tf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///7T///////////////////////////////////+c////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////9k////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///xv////d////z////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///xf////v////Rf///wD///8A", + "////Q////8P////v////9P///7j///8A////Rv///+////8W////AP///wD///8A////AP///wD///8t////n////+L////9/////////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////ff////////9O////AP///33/////////Tv///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///2T///9k////ZP///2T///9k////ZP///6D/////////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////F////+////9F////AP////////98", + "////AP///wD///+B////5////xP///9G////7////xb///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////m////g////wD///8A////Zv///+X///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP////////9k////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////nf///8H///8I////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////BP///yz////F////t////wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////+w////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP////////8c////HP////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////N////8P///2H///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////9U////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////7////1D///8A////Uf///+3///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///9O/////////33///8A////Tv////////98////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///z3////+////N////wD///+e////j////wD/////////VP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///89/////v///zf///8A////AP///wD///8A", + "////nf///8H///8I////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+9////tv///wD///8A////nv///4////8A/////////1T///8A////AP///wD///8A////AP///wD////3////oP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wH////f////yf///wD///8A////AP///wD///8A////AP///8f////g////Af///wD///8A////AP///wD///8A////AP///wD///8B////3////8n///8A////AP///wD///8A////AP///wD////H////4P///wH///8A////AP///wD///8A////AP///wD///8A////Af///9/////J////AP///wD///8A////AP///wD///8A", + "////x////+D///8B////AP///wD///8A////AP///wD///8A////AP///wH////f////yf///wD///8A////AP///wD///8A////AP///8f////g////Af///wD///8A////AP///wD///8A////AP///wD///8B////3////8n///8A////AP///wD///8A////AP///wD////H////4P///wH///8A////AP///wD///8A////AP///wD///8A", + "////Af///9/////J////AP///wD///8A////AP///wD///8A////x////+D///8B////AP///wD///8A////AP///wD///8A////AP///wD///+s////8v///w7///8A////AP///wD///8A/////////7j///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////zf////D///9h////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD/////////uP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////7j///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////+4", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////uP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////uP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////7j///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////+4////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////", + "////uP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////uP///wD///8A////AP///wD///8A////uv////////8/////AP///wD///8A////AP///wD///8A////AP///wD/////////uP///wD///8A////AP///wr////n////pP///6P/////////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////VP////////+R////AP///wD///8A////AP///wD///8A////kv////////9H////AP///wD///8A////AP///wD///8A////AP///1T/////////kf///wD///8A////AP///wD///8A////AP///5L/////////R////wD///8A////AP///wD///8A////AP///wD///9U/////////5H///8A", + "////AP///wD///8A////AP///wD///+S/////////0f///8A////AP///wD///8A////AP///wD///8A////VP////////+R////AP///wD///8A////AP///wD///8A////kv////////9H////AP///wD///8A////AP///wD///8A////AP///1T/////////kf///wD///8A////AP///wD///8A////AP///5L/////////R////wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///3T/////////t/////////98////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Af///8b/////////+v///yv///8A////AP///wD///9S////9////8P///8A////AP///wD///8A////AP///wD///8A////AP///8P/////////Kv///wD///8A", + "////AP///wD///8I////7////8H///8A////AP///wD///8A////AP///wD///8A////AP///wD////D/////////yr///8A////AP///wD///8A////CP///+/////B////AP///wD///8A////AP///wD///8A////AP///wD///8A////w/////////8q////AP///wD///8A////AP///wj////v////wf///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///8P/////////Kv///wD///8A////AP///wD///8I////7////8H///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////+4////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////////////////////7v///8P///+B", + "////B////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////+w////AP///wD///8A////AP///wD////H////7////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////d////6////xT///8A////AP///wD////C/////////wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////3f///+v///8U////AP///wD///8A////wv////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///93////r////FP///wD///8A////AP///8L/////////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////d////6////xT///8A////AP///wD////C", + "/////////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////3f///+v///8U////AP///wD///8A////wv////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///93////r////FP///wD///8A////AP///8L/////////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD////a////5v///wr///8A////AP///wD///8b//////////7///8Z////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///83////w////Yf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///8L/////////Jf///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////C/////////yX///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////wv////////8l////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///8L/////////Jf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////+w////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////7D///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////7D///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////7D///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////xf///+3///8E////AP///wD///8A////LP////////+0////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////+w////AP///wD///8A////AP///7D/////////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////F/////////xv///8A////AP///wD///8c/////////8f///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////xf////////8b////AP///wD///8A////HP/////////H////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///8X/////////G////wD///8A////AP///xz/////////x////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////F", + "/////////xv///8A////AP///wD///8c/////////8f///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////xf////////8b////AP///wD///8A////HP/////////H////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///9y//////////f///+p////AP///wD///9x/////////3f///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////+v///8L///8A////AP///wD///8A////2f////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////r////C", + "////AP///wD///8A////AP///9n/////////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////6////wv///wD///8A////AP///wD////Z/////////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////+v///8L///8A////AP///wD///8A////2f////////8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+9////3v///wH///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////sP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///73////e////Af///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///7////++////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////2////yv///wD///8A////9v///8r///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A//////////////////////////////////////////////////////////////8A////AP///wD///8A////AP///wD///8A////AP///w////8A////AP////////9I////D////+7////W////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////bP////////9K////AP////P///92////AP///wD///95////8P///wD///8A////AP///wD///8A////5P///97///8A////AP///wD///9y/////////7X///9m/////////1D///8A////AP///wD///8A////AP///wD///8A////AP////b////K////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///+C/////////zn///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///zr/////////gf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///0v///+0", + "////yP///93//////////////9z////H////tP///1H///8A////AP///wD///8A////AP///wD///8A////AP///wD///+U//////////////////////////////////////////z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Ef/////////l////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9w", + "/////////zf///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///83////f////AP///wD///8A////AP///9/////Q////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////pP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///+o/////v///0z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///8v////g////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////r////5v///4z///+M", + "////jP///4z/////////1v///4z///+M////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////x/////L///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///9P////J////AP///wD///8A////AP///63////1////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///+e/////////yH///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////4P///+f///8B////AP///wD///8C////1////9z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////B/////b///+h////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Ef/////////l////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP////3////w////Ov///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9k////ZP///2T///9k////ZP///2T///9k////ZP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///84", + "////7v////3///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////P///6D///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+O////4P///wb///8A////CP///5z////u////2////03///8x////3P///+f///9k////AP///wD///8A", + "////AP///wD///8A////AP///wD///9+/////////3T///9o////aP///2j///9o////cv////////9/////AP///wD///8A////AP///wD///8A////AP////////+4////AP///wD///8A////AP///wD////k////7f///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+r/////////zX///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////7j///8A////AP///wD///8A////AP///zr/////////nf///wD///8A////AP///wD///8A////AP///wD///8A////AP////////+4////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD/////////uP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////pv////////83////AP///wD///8A////AP///wD///8A////uP////////8A////AP///wD///8A////AP///wD///8A////AP////////+4////AP///wD///8A////AP///wD///8A", + "////uP////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////+4////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////7j///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP////////+4////AP///wD///+Q/////////17///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////uP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////7j///8A////AP///8z////P////AP///83///+o", + "////AP///wD///+4/////////wD///8A////AP///wD///8A////AP////////+4////AP///wD///8A////ef////r///8i////rv////////8A////AP///wD///8A////AP///wD///8A////AP///wD///+u/////////yn///8A////AP///wD///8A////AP///wD///8q/////////6f///8A////AP///wD///8A////AP///wD///8A", + "/////////7j///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Cv///4D///+4////6P////7/////////sv///wn///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////uP///wD///8A////XP////////+N////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Bv///+P////k////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////uP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////q", + "////2f///wD///8A////AP///wD///8A////AP///8f////p////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////BP///+r////F////AP///8T////r////BP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///63////8////Fv////z///+I////AP///wD///8A", + "////lf///+n///8P/////f///57///8A////AP///wD///8A////AP///wD///+b////9////x////8p/////P///6f///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////uP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9B", + "/////////5b///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////sP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///2f/////////Pf///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////sP////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///7r////G////AP///wD///+z////x////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9m/////////+v///+e////fv///2/////Q/////////wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A/////////7v///8A////AP///wD///8A////AP///+H////t////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///+v////i////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////v////3P///wD///8A", + "////AP///wD///8A////tv////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////7f///+r///9o////aP///2j///9o////aP///2j///9o////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////7D///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///9L////7f///8b///+J////hP///4j///+o/////f///7P///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////7D///8A////AP///wD///8A////sP////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////sP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////+w////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A//////////////+o////7v///87///8H////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP////////+w////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////sP///wD///8A////AP///wD////A////8P///wD///8A////AP///wD///+w/////////wD///8A////AP///wD///8A/////////7D///8A////AP///wD///8A", + "////sP////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///+z////e////AP///wD///8A////AP///wD////f////7P///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////r////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///6//////////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////+w////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wr///94////7/////z///9c", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////+w////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////+w////AP///wD///8A////AP///7r/////////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///z3/////////bf///wD///96/////////zb///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+7////3////wD////L////nv///wD///+W////z////wD////j////uP///wD///8A////AP///wD///8A////AP///wD///8A////C////9v/////////2P///wn///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////av////////9A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+q////9P///yT///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A/////////7D///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////ZP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///7D/////////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////4P////f///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///6b/////////b////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////BP////////+1////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////v////gP///wD///8A////Y/////P///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////uP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD/////////ZP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Jv///5X////0////8P///0D///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///99////n////wD///8A////Qv////7///+r////VP///1L///+K////AP///wD///+g////fP///wD///8A////AP///wD///8A////Qf///y3///8O////dP///8r///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///3n/////////Tv///wD///94/////////07///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD//////////////////////////////////////////////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///33///+f////AP///wD/////////fP///wD///83////+////0n///8A////AP///6D///98////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////h/////P///9t////Yv///+r///+F////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////ZP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wT////H////kf///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//////////////5P///xX///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////", + "////rv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////HP///xz/////////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////Yv///7D///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////VP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///7L///+s", + "////I////6z///+r////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Tv////////94////AP///07/////////eP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////qv///8j///8B////F////+X///8S/////////1T///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///6r////I////Af///wD///8A////AP///wT////H////kf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Lf////z///9J////AP///xf////l////Ev////////9U////AP///wD///8A////AP///wD///8A////4f///8T///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////fv////////90////aP///2j///9o////aP///3L/////////f////wD///8A////AP///wD///8A////AP///wD///8A////AP///37/////////dP///2j///9o////aP///2j///9y/////////3////8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///9+/////////3T///9o////aP///2j///9o////cv////////9/////AP///wD///8A////AP///wD///8A////AP///wD///8A////fv////////90////aP///2j///9o////aP///3L/////////f////wD///8A////AP///wD///8A////AP///wD///8A////AP///37/////", + "////dP///2j///9o////aP///2j///9y/////////3////8A////AP///wD///8A////AP///wD///8A////AP///wD///9+/////////3T///9o////aP///2j///9o////cv////////9/////AP///wD///8A////AP///wD///8A////AP///wD///8A////OP////////+d////aP///2j///9o////aP////////+4////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///2L///+w////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////7j///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////+4////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////uP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////7j///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A/////////7j///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////+4////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////uP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////7j///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////7j///8A////AP///wD///8A////AP///zr/////////nf///wD///8A////AP///wD///8A", + "////AP///wD///8A/////////7j///8A////AP///wD///95////+v///yL///+u/////////wD///8A////AP///wD///8A////AP///wD///8A////AP///67/////////Kf///wD///8A////AP///wD///8A////AP///yr/////////p////wD///8A////AP///wD///8A////AP///wD///+u/////////yn///8A////AP///wD///8A", + "////AP///wD///8q/////////6f///8A////AP///wD///8A////AP///wD///8A////rv////////8p////AP///wD///8A////AP///wD///8A////Kv////////+n////AP///wD///8A////AP///wD///8A////AP///67/////////Kf///wD///8A////AP///wD///8A////AP///yr/////////p////wD///8A////AP///wD///8A", + "////AP///wD///+u/////////yn///8A////AP///wD///8A////AP///wD///8q/////////6f///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////tP////////+7////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///1z/////////nv///+z////C////Af///wD///8A", + "////AP///5P/////////R////wD///8A////AP///wD///8A////AP///wD////q////2f///wD///8A////AP///wD///8A////AP///8f////p////AP///wD///8A////AP///wD///8A////AP///wD///8A////6v///9n///8A////AP///wD///8A////AP///wD////H////6f///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///+r////Z////AP///wD///8A////AP///wD///8A////x////+n///8A////AP///wD///8A////AP///wD///8A////AP///wD////q////2f///wD///8A////AP///wD///8A////AP///8f////p////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////uP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP/////////V////aP///3r///+w/////v///9T///8N////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////sP///wD///8A////AP///wD///9y/////////6H///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////Zv/////////r////nv///37///9v////0P////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///2b/////////6////57///9+////b////9D/////////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9m/////////+v///+e////fv///2/////Q/////////wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////Zv/////////r////nv///37///9v////0P////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///2b/////////6////57///9+////b////9D/////////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9m", + "/////////+v///+e////fv///2/////Q/////////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Wf////3////W////e////1b///9A////Nf/////////n////aP///2j///9o////aP///2j///9o////AP///wD///8A////AP///wD///8A////AP///wD///9i////sP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD////t////6v///2j///9o////aP///2j///9o////aP///2j///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////7f///+r///9o////aP///2j///9o////aP///2j///9o////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///+3////q", + "////aP///2j///9o////aP///2j///9o////aP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////t////6v///2j///9o////aP///2j///9o////aP///2j///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////sP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP////////+w////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////+w////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////+w", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///+z////M////AP///wD///8A////AP///wL////z////2P///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////sP///wD///8A////AP///wD///+w/////////wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////7P///97///8A////AP///wD///8A////AP///9/////s////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///+z////e////AP///wD///8A////AP///wD////f////7P///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////s////3v///wD///8A", + "////AP///wD///8A////3////+z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////7P///97///8A////AP///wD///8A////AP///9/////s////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///+z////e////AP///wD///8A////AP///wD////f////7P///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8V////ZP///2T///9k////ZP///2T///9k////ZP///2T///8i////AP///wD///8A////AP///wD///8A////AP///wD///8A////xf///+r///9Y/////////1b///8A////HP/////////H////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////+w////AP///wD///8A", + "////AP///7r/////////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////sP///wD///8A////AP///wD///+6/////////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////7D///8A////AP///wD///8A////uv////////8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP////////+w////AP///wD///8A////AP///7r/////////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////av////////9A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////6////8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9q/////////0D///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////G////y////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///0T///9E////Zv////////9k////RP///0T///+q////3P///0T///9E////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////", + "////SP///wD///+4////7////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wL////I////3////wr////V////pP///wD///8A////rP///83///8A////AP///wD///8A////AP///5H/////////Y////wD///9o/////////77///8I////Cv////j///+p////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////uP////z///8K////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8K/////P///7f///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9Y////+v///7z///9x////t////7b///9w////u/////n///9h////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////9k////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Ef////f///+e////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////i////y////wD///8A////AP///wD////M////4////wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A/////////6T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////DP///9n////s////G////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///zL////6", + "////lP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////X/////7///85////AP///wD///8A/////////6T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Ff////r////d////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD////x////y////wD///8A////AP///wD///+6////5P///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Qv////////97////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///4f/////////cP///wD///8D////kf////////92", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////TP///8z////1////1f///0f////X////z////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8r////rP////n///+e////J////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A//////////////////////////////////////////////8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///yb///+d////+P///6v///8r////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///9z////i////DP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////uP///6L///8A////AP///4P////1////b////2r////1////zP///33///9w/////P///zT///8A////AP///wD///8A////AP///wD///8A////HP////3////////////////////////////////////9////Hf///wD///8A////AP///wD///8A////AP///wD/////////uP///wD///8A////AP///wD///8//////////7P///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////zv////3///8F////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////+4////AP///wD///8A////AP///wD///8I/////v///8L///8A////AP///wD///8A////AP///wD///8A////AP///wD/////", + "////uP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////7j///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///8r////8////BP///wD///8A////AP///2j///9o////aP///9X/////", + "////AP///wD///8A////AP///wD///8A////AP///wD/////////uP///wD///8A////AP///wD///8A////AP///7j/////////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////uP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP////////+4////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////zP///wT///82/////f///7n///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////7j///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP////////+4////AP///yH/////////e////wD///91////9f///wv///8A////uP////////8A////AP///wD///8A////AP///wD/////////uP///wD///8A////Ef///+////+W////AP///7f/////////AP///wD///8A////AP///wD///8A////AP///wD///8A////0P////r///8B", + "////AP///wD///8A////AP///wD///8A////Av////v////L////AP///wD///8A////AP///wD///8A////AP////////+4////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////KP///9T////+////tv///4H///+A////tf////7////d////H////wD///8A", + "////AP///wD///8A////AP///wD///8A/////////7j///8A////Cv///+T////m////Df///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////HP///7P/////////lv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "/////////7j///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////7j///8A////AP///wD///8A////AP///wD///+4/////////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///0j/////////c////wD///9x/////////0n///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wP////v////y////wD////H////z////wD///8A////AP///9r///+p////AP///9D////k////AP///wD///8A////AP///wD///8A////Ff///+////+q////sP////b///8d////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8Z", + "/////////8z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///7j////7////JP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////7D///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD////P////1P///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///7D/////////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///85/////////0L///8r", + "/////v///0n///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///z////+l////z////+z////4//////////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////+6////AP///wD///8A////AP///wD////d////7v///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////p////5v///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////7v///9////8A////AP///wD///8A////AP///7z/////////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///+r//////////////////////////////////////////P///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP////////+w////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///4n////////////////////+////4v///5////8W////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////+5////AP///wD///8A////AP///7D/////", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////7D///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////sP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP////////+8////7/////////8t////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////sP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////7n///8A////AP///wD///8A////wP////T///8A", + "////AP///wD///8A////sP////////8A////AP///wD///8A////AP////////+5////AP///wD///8A////AP///7D/////////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////t////3f///wD///8A////AP///wD///8A////3v///+v///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "/////////6b///9J////xv////X////h////pP///xb///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8X////ov///+D////2////x////0P///+p/////////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////uv///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///zH////i/////////7////82////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////sP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////", + "////sP///wD///8A////AP///wD///+w/////////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+b/////P///xf///8A////IP////7///+V////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8J////9////6H///8A////iP///9////8A////0f///5L///8A", + "////pP////b///8I////AP///wD///8A////AP///wD///8A////AP///wL///+//////////7v///8B////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///4T/////////of///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////E////+f////H////A////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Af////////+v////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////2T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///+v/////////wH///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8AAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", @@ -491,38 +3233,51 @@ const char* CAF_FIXED_ATLAS_FONT_12_PT_TEXTURE_IMAGE[] = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", - "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///9v///+G////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "/////////////////////////////////////////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////8U////ff////D///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8F////3v///1P///+8////pv///yP///+q////sv///wD///8A////AP///wD///8A", - "////uf///9f///8J////D////9D////a////Ff///xr////z////cP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+i////3f///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD////d////of///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///5v///+J////Rf///67///+u////Rf///4f///+h////AP///wD///8A////AP///wD///8A////AP///wD///8I/////////////////////////////////////////zD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///9l////8////w3///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///+H///+H////AP///wD///8A////iP///+P///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////YP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8W////2f///7f///8F////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////q////73///8A////AP///wD///8A////AP///wD///8A////AP///wD////J////r////0z///9M////TP///0z/////////j////0z///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wL////c////1v///wD///8A////AP///wD///8A////AP///wD///8A////AP///+z///+d////AP///wD///8A////hf///97///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///zz/////////Of///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////vf///9H///8G////AP///xD////W////rv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////q////83///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///5f////m////ef///w3///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////A////////////////////////////////////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////Df///3n////l////l////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////2////6////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////I////Y////wD///+o////uP///x7///+8////5////03///8m////3f///2r///8A////AP///wD///8A", - "////AP///wD///+H////////////////////////////////////iP///wD///8A////AP///wD///8A////AP////////90////AP///wD///8A////AP///8H////a////AP///wD///8A////AP///wD///8A////AP///wD////K////vP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "/////////3T///8A////AP///wD///8A////AP///8L////A////AP///wD///8A////AP///wD///8A////AP////////90////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////dP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////x////7z///8A////AP///wD///8A////MP///zD///+O/////////wD///8A////AP///wD///8A////AP////////90////AP///wD///8A////AP///3T/////////AP///wD///8A////AP///wD///8A////AP///wD///8A////IP////////9U////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A/////////3T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////90////AP///1T////8////N////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////dP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "/////////3T///8A////oP///6L///8A////n////37///8A////dP////////8A////AP///wD///8A////AP////////90////AP///wD///9X////8////xj///9y/////////wD///8A////AP///wD///8A////AP///wD////R////sv///wD///8A////AP///wD///8A////AP///7P////M////AP///wD///8A////AP///wD///8A", - "/////////3T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+N/////v///5L///9L////Sv///5D////+////hP///wD///8A////AP///wD///8A////AP///wD/////////dP///wD///9a/////////0f///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///85////7P///7j///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////IP////////9U////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////9////df///wD///8A////AP///wD///90/////f///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////u////5n///8A////lv///73///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Z////+7///8D////8f///yv///8A////NP///9z///8C////8f///13///8A////AP///wD///8A////AP///wD////E////nf///6T////P////Af///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///yv/////////W////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////vP///8j///8C////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////bP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////Jv////7///8/////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9s/////////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///1/////n////Ef///9v///9w////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8E////cP///8P////k////9/////7/////////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "/////////3D///8A////AP///wD///+E////+P///wD///8A////AP///wD///8A////AP///wD///8A////AP////f///+G////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////5////hP///wD///8A////AP///2//////////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////9////////////////////////////////////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////bP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////nP////////////////////L////B////Mf///wD///8A////AP///wD///8A////AP///wD///8A", - "/////////23///8A////AP///wD///9s/////////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////bP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////9s////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "/////////+7////7////2v///w3///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////9s////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////bf///wD///8A////AP///8D///+s////AP///wD///8A////bP////////8A////AP///wD///8A", - "/////////23///8A////AP///wD///9s/////////wD///8A////AP///wD///8A////AP///wD///8A////AP////f///+D////AP///wD///8A////hP////f///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////d////6z////1////2v///2L///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///2b////a////9f///63///91/////////wD///8A////AP///wD///8A////AP///wD///8A////AP////////9s////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////DP///5r////9////0v///yf///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP////////9s////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////9s////AP///wD///8A////bf////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///5b////X////AP///wH////e////kP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///w7////7////S////xH////7////LP///yH////+////Fv///07////7////Dv///wD///8A////AP///wD///8A////C/////P////w////Cf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8C////4P////P///8L////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///+y////yf///wL///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////2z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////LP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///2z/////////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///9n////p////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////c/////////xr///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////uP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////7v///4L///8A////AP///2b////i////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////Sf///2j///9o/////////9X///9o////aP///z////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////2T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8O////oP////7////s////u/////L///89////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////zP///1H///8A////AP///8D////L////AP///wD///8A////AP///wD///8A////Uv///8v///8A////AP///wD///8A////AP///43////f", + "////8v///73///9D////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8D////xP///+D///8K////Av///8P////g////Cv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////M////Uf///wD///8A/////////3z///8K////2v///5T///8A////AP///wD///9S////y////wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wX///+F////5P///+T///+D////Bf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///85////ZP///2T///9k/////////6D///9k////ZP///2L///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////Y////+7///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////HP///6b///+2////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////8X////A////9P///9X///9j////eP////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////xz///8c/////////wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///5r///8l/////P///1T///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8f////vv////P///+6////Gv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Cv///+D////D////Av///wr////g////wv///wL///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///x/////3////XP///wD///9z////fv////3///9U////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8f////9////1z///8A////AP///wD///8A////Y////+7///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+X", + "////1////wT///8A////c////37////9////VP///wD///8A////AP///wD///8A////AP///3//////////Y////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///xz////9/////////////////////////////////////f///x3///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8c/////f////////////////////////////////////3///8d////AP///wD///8A////AP///wD///8A////AP///wD///8A////HP////3////////////////////////////////////9////Hf///wD///8A////AP///wD///8A////AP///wD///8A////AP///xz////9////////////////", + "/////////////////////f///x3///8A////AP///wD///8A////AP///wD///8A////AP///wD///8c/////f////////////////////////////////////3///8d////AP///wD///8A////AP///wD///8A////AP///wD///8A////HP////3////////////////////////////////////9////Hf///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD////F////////////////////////////////////uP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8C////af///6v////Y////+/////X////Y////nP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////+4////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////uP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////7j///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP////////+4////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////+4////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////uP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////7j///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////+4////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP////////+4////AP///wD///8A////AP///wD///8I/////v///8L///8A////AP///wD///8A////AP///wD///8A////AP////////+4////AP///wD///8R////7////5b///8A////t/////////8A////AP///wD///8A////AP///wD///8A////AP///wD////Q////+v///wH///8A////AP///wD///8A////AP///wD///8C", + "////+////8v///8A////AP///wD///8A////AP///wD///8A////0P////r///8B////AP///wD///8A////AP///wD///8A////Av////v////L////AP///wD///8A////AP///wD///8A////AP///9D////6////Af///wD///8A////AP///wD///8A////AP///wL////7////y////wD///8A////AP///wD///8A////AP///wD////Q", + "////+v///wH///8A////AP///wD///8A////AP///wD///8C////+////8v///8A////AP///wD///8A////AP///wD///8A////0P////r///8B////AP///wD///8A////AP///wD///8A////Av////v////L////AP///wD///8A////AP///wD///8A////AP///wD///8A////c/////////+7/////////3r///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///+q/////////yj///9j/////////2L///8A////AP///wD///8r/////////6f///8A////AP///wD///8A////AP///wD///8A/////////7j///8A////AP///wD///8A////AP///wD///+4/////////wD///8A////AP///wD///8A////AP///wD///8A////AP////////+4", + "////AP///wD///8A////AP///wD///8A////uP////////8A////AP///wD///8A////AP///wD///8A////AP///wD/////////uP///wD///8A////AP///wD///8A////AP///7j/////////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////7j///8A////AP///wD///8A////AP///wD///+4/////////wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8Z/////////8z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////uP///wD///8A////AP///2z/////////g////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////7D///8A", + "////AP///yf///+9/////////73///8O////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8/////pf///8/////s////+P//////////////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////P////6X////P////7P////j//////////////wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///z////+l////z////+z////4//////////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8/////pf///8/////s////+P//////////////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////P////6X////P", + "////7P////j//////////////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///z////+l////z////+z////4//////////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8v////kv///8X////h////8/////v/////////////////////////////////////", + "/////f///wD///8A////AP///wD///8A////Bf///27////L////7v////X////a////ff///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////6v/////////////////////////////////////////8////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///+r/////////////////////", + "/////////////////////P///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////q//////////////////////////////////////////z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////6v/////////////////////////////////////////8////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A/////////7D///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////sP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////sP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////sP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////u////zf///wD///8A////AP///wD///8A////y/////b///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A/////////7n///8A////AP///wD///8A////sP////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///+3////d////AP///wD///8A////AP///wD////e////6////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////t////3f///wD///8A////AP///wD///8A", + "////3v///+v///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////7f///93///8A////AP///wD///8A////AP///97////r////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///+3////d////AP///wD///8A////AP///wD////e////6////wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD////t////3f///wD///8A////AP///wD///8A////3v///+v///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////OP//////////////////////////////////////////////WP///wD///8A////AP///wD///8A////AP///wD///8A////AP///+z////J////AP///6r////s////F////wD////f", + "////7P///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////sP///wD///8A////AP///wD///+w/////////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////7D///8A////AP///wD///8A////sP////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP////////+w////AP///wD///8A////AP///7D/////////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////sP///wD///8A////AP///wD///+w/////////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///4T/////////of///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////+m////Sf///8b////1////4f///6T///8W////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////hP////////+h////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", @@ -534,38 +3289,199 @@ const char* CAF_FIXED_ATLAS_FONT_12_PT_TEXTURE_IMAGE[] = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////6v///6b///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///8/////t////BP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////3T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///+X///9I////AP///wD///8v////7f///wD///8A////AP///wD///8A////AP///wD///8A////AP///wH///8w////MP////////+O////MP///yj///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////LP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wX///97////7f////D////4////Kv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////O////If///wD///+b////y////zH///8X////Rv///wD///8k////yv///wD///8A////AP///wD///8A", - "////of///9z////T////Zf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9/////sv///wD///9/////sv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////A////////////////////////////////////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///87///8h////AP///wD/////////QP///1T///+i////AP///yT////K////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////H////7v////y////uf///x3///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wH///8s////LP///yz/////////UP///yz///8s////CP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9F////2f///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8Z////if///67///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////uf///+T////v////sf///07/////////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP////D///8A////8P///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD/////////IP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///0X////e////3f///0D///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////s////37///8A////s////37///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////hf///7L///8E////v////yn/////////IP///wD///8A////AP///wD///8A////AP///wD///8A////AP///4X///+y////AP///wD///8A////AP///0X////Z////AP///wD///8A////AP///wD///8A////AP///wD///8A////hf///7L///8E////v////yn/////////IP///wD///8A////AP///wD///8A", - "////yv///6z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////h////////////////////////////////////4j///8A////AP///wD///8A////AP///wD///8A////AP///4f///////////////////////////////////+I////AP///wD///8A////AP///wD///8A", - "////AP///wD///+H////////////////////////////////////iP///wD///8A////AP///wD///8A////AP///wD///8A////h////////////////////////////////////4j///8A////AP///wD///8A////AP///wD///8A////AP///4f///////////////////////////////////+I////AP///wD///8A////AP///wD///8A", - "////AP///wD///+H////////////////////////////////////iP///wD///8A////AP///wD///8A////AP///wD///8A////M////////////////////////////////////3T///8A////AP///wD///8A////AP///wD///8A////AP///yb///+f////y/////P////5////4v///63///8A////AP///wD///8A////AP///wD///8A", - "/////////3T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////90////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////dP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "/////////3T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8g/////////1T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////IP////////9U////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///yD/////////VP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8g/////////1T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////3T///8A////AP///wD///8A////AP///8L////A////AP///wD///8A////AP///wD///8A", - "/////////3T///8A////AP///1f////z////GP///3L/////////AP///wD///8A////AP///wD///8A////AP///9H///+y////AP///wD///8A////AP///wD///8A////s////8z///8A////AP///wD///8A////AP///wD////R////sv///wD///8A////AP///wD///8A////AP///7P////M////AP///wD///8A////AP///wD///8A", - "////0f///7L///8A////AP///wD///8A////AP///wD///+z////zP///wD///8A////AP///wD///8A////AP///9H///+y////AP///wD///8A////AP///wD///8A////s////8z///8A////AP///wD///8A////AP///wD////R////sv///wD///8A////AP///wD///8A////AP///7P////M////AP///wD///8A////AP///wD///8A", - "////AP///yf///+4////Jv///7f///8n////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///6X////q////NP////z///9I////AP///wD///8G////6////5z///8A////AP///wD///8A////AP///wD////9////df///wD///8A////AP///wD///90/////f///wD///8A////AP///wD///8A////AP///wD///8A", - "/////f///3X///8A////AP///wD///8A////dP////3///8A////AP///wD///8A////AP///wD///8A////AP////3///91////AP///wD///8A////AP///3T////9////AP///wD///8A////AP///wD///8A////AP///wD////9////df///wD///8A////AP///wD///90/////f///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///yv/////////W////wD///8A////AP///wD///8A////AP///wD///8A////AP////////+O////M////0r///+n/////v///0v///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////bP///wD///8A////H////7v////5////R////wD///8A////AP///wD///8A////AP///wD///8A", - "////BP///3D////D////5P////f////+/////////wD///8A////AP///wD///8A////AP///wD///8A////AP///wT///9w////w////+T////3/////v////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8E////cP///8P////k////9/////7/////////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////BP///3D////D////5P////f////+/////////wD///8A////AP///wD///8A////AP///wD///8A////AP///wT///9w////w////+T////3/////v////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8E////cP///8P////k////9/////7/////////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////Cv///2X///+p////6P////v/////////////////////////////////////////AP///wD///8A////AP///wD///8/////xP////L////u////l////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////3////////////////////////////////////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////9////////////////////////////////////wD///8A////AP///wD///8A////AP///wD///8A////AP////f///////////////////////////////////8A////AP///wD///8A////AP///wD///8A////AP///wD////3////////////////////////////////////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP////////9s////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////9s////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////9s////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD/////////bP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////D///+E////AP///wD///8A////gv////T///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////bf///wD///8A////AP///2z/////////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////9////4P///8A////AP///wD///+E////9////wD///8A////AP///wD///8A////AP///wD///8A////AP////f///+D////AP///wD///8A////hP////f///8A////AP///wD///8A////AP///wD///8A////AP///wD////3////g////wD///8A////AP///4T////3////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////9////4P///8A////AP///wD///+E////9////wD///8A////AP///wD///8A////AP///wD///8A////AP////f///+D////AP///wD///8A////hP////f///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////9////3////8j////9f///yf///+C////9////wD///8A////AP///wD///8A////AP///wD///8A////AP////////9s////AP///wD///8A////bf////////8A////AP///wD///8A////AP///wD///8A////AP///wD/////////bP///wD///8A////AP///23/////////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "/////////2z///8A////AP///wD///9t/////////wD///8A////AP///wD///8A////AP///wD///8A////AP////////9s////AP///wD///8A////bf////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8C////4P////P///8L////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "/////////3f///+s////9f///9r///9i////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wL////g////8////wv///8A////AP///wD///8A////AP///wD///8A////AP///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "////AP///wD///8A////zf///9j///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///xH/////////Sf///wD///8A", + "////b////+3///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////1j///96/////f///6X///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wP///+L////5////+b///+N////Mv////v///+L////e/////X///95////gf////f///9u////AP///wD///8A", + "////AP///wD///8N////yv////3///+o/////v///8f///8M////AP///wD////H////5f///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///9/////f////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///9/////e////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Dv///w7///8A////AP///7r///+5////AP///wD///8M////EP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD/////////ZP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+i////9f///xD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////9v///77///8A////AP///wD///8A////v/////b///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////+k////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8w////+v///7L///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9w////e////6P////1////sP///yT///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+/////0P///wP///8A////AP////////+k////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////Af///33/////////ov///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////+v////3///80////AP///wD///8S////9P///7X///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wL////j////1v///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8I////vf////////+o////zv////////+c////Av///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////QP/////////P////Z////3r////k////4P///+3///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8w////sv////3///+r////Mv///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Mv///6v////8////sf///zD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9k", + "/////////7n///8I////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///9////9/////AP///wD////Z////uP///wD///8A////sf////////8L////AP///7f///+f////AP///wD///8A////AP///wD///8A////AP///wD///+2////9P///wz///8A////AP///wn////w////t////wD///8A", + "////AP///wD///8A////AP///wD///8A/////////9X///9o////aP///3X///+g////+P///9r///8l////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///+/////j////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////uP///wD///8A", + "////AP///wD///8A////AP///+f////n////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////9X///9o////aP///2j///9o////aP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP/////////V////aP///2j///9o////aP///2j///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD////u////4////wD///8A////AP///wD//////////////////////////////wD///8A////AP///wD///8A////AP///wD///8A/////////9X///9o////aP///2j///9o////aP///2j////V/////////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////7j///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////uP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A//////////////++////0f////T///8g////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP////////+4////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////uP///wD///91/////////yb///8A////H/////7///9Y////AP///7j/////////AP///wD///8A////AP///wD///8A/////////7j///8A////AP///4j////1", + "////Gf///wD///+4/////////wD///8A////AP///wD///8A////AP///wD///8A////AP////D////h////AP///wD///8A////AP///wD///8A////AP///wD////i////7v///wD///8A////AP///wD///8A////AP///wD////////////////////w////y////4////8S////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////Af///9P////3////Uv///wD///8A////AP///wD///9S////9////8r///8F////AP///wD///8A////AP///wD///8A////AP//////////////////////////////rf///w3///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8q////of////r/////", + "////s////w7///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////+4////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////+4////AP///wD///8A////AP///wD///8A////uP////////8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///+h/////v///x3///8A////Hf////7///+j////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///83/////////4j///8A////gv////7///8W////AP///x7/////////Zv///wD///+O/////////yz///8A////AP///wD///8A////AP///wD///9v//////////////+A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////kP//////////////Rf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8w/////v///6f///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP////////+w////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///82/////////23///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+w/////////wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///7f///++////ov///8r///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///6/////+////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////2P///wD///8A////AP///wD///8c/////////8v///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////vv////////8x////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///8v/////////HP///wD///8A////AP///wD////d/////////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////C", + "////8v///w7///8A////AP///wD///8A////0////9f///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////sP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////q////pv///wn///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD/////////1v///wD///8A////AP///wD////C////+f///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////+w////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "/////////7D///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////nf///z7////3////tP///wT///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////7D///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP/////////W////AP///wD///8A////AP///9L/////////D////wD///8A////AP///8H////6////AP///wD///8A////AP///wD/////////1v///wD///8A////AP///wD////C////+f///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////yP////////8a", + "////AP///wD///8A////Hf/////////C////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP/////////a////9f///5j///95////1f/////////l////D////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8Q////5//////////P////eP///5L////w////1f////////8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A/////////+f///8E////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////M////9////07///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////7D///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////7D///8A////AP///wD///8A////sP////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8I////8P///7r///8A////AP///wD////D////7f///wb///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////SP////////9h////AP///0P/////////Kf////3///9U////AP///2L/////////Rv///wD///8A////AP///wD///8A////AP///wD///93/////////6D/////////c////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wP////l", + "////4v////X///8N////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9K/////////3v///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///0D/////////fP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP////////9k////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////ff////////8/////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////S////2////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////9f///9z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///1H///9U/////////8////9U////VP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///6f////y", + "////a////2L////q////nP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///7T///////////////////////////////////+c////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////9k////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////pP////////+I////Cv///wH////O////yv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///+////8d////AP///wD////t", + "////i////wD///8A////AP///wD///8A////AP///x7////u////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///yH////y////h////wD///8g////8f///4f///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////7////x3///8A////AP/////////3", + "////9P////3///88////AP///wD///8A////Hv///+7///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////lP/////////////////////////////////////////8////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///53///97////Nv///7L////a////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+D////Yv///y3///+d////6////wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//////////////2v///4D///+P////8P///+T/////////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP////////8c////HP////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///99////0f////P///9U////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///4j////y////IP///wD///+I////8f///x////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////9U////hP///+T///8L////Bf///7z////5////VP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////VP///4T////k////C////53///97", + "////Nv///7L////a////AP///wD///8A////AP///wD///8A////AP///7D////w////8v///7j///8i////FP///+////9w////AP///wX///+8////+f///1T///8A////AP///wD///8A////AP///wD///8F////uv////7///9y////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////tv////T///8M////AP///wD///8J////8P///7f///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///7b////0////DP///wD///8A////Cf////D///+3////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+2////9P///wz///8A////AP///wn////w", + "////t////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////tv////T///8M////AP///wD///8J////8P///7f///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///7b////0////DP///wD///8A////Cf////D///+3////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///+2////9P///wz///8A////AP///wn////w////t////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Uv////////9U////AP///wD///8A/////////9X///9o////aP///2j///9o////aP///wD///8A////AP///wD///8c////v//////////V////mf///3L///9/////o////+f///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD/////////1f///2j///9o////aP///2j///9o////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////9X///9o////aP///2j///9o////aP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP/////////V", + "////aP///2j///9o////aP///2j///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////1f///2j///9o////aP///2j///9o////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////uP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////7j///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////+4////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////", + "////uP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///2j/////////1f///2j///9o////aP///wD///8A////AP///+f////n////AP///wD///8A////AP///wD///8A////AP///wD/////////uP///wD///8A////iP////X///8Z////AP///7j/////////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////8P///+H///8A////AP///wD///8A////AP///wD///8A////AP///+L////u////AP///wD///8A////AP///wD///8A////AP////D////h////AP///wD///8A////AP///wD///8A////AP///wD////i////7v///wD///8A////AP///wD///8A////AP///wD////w////4f///wD///8A", + "////AP///wD///8A////AP///wD///8A////4v///+7///8A////AP///wD///8A////AP///wD///8A////8P///+H///8A////AP///wD///8A////AP///wD///8A////AP///+L////u////AP///wD///8A////AP///wD///8A////AP////D////h////AP///wD///8A////AP///wD///8A////AP///wD////i////7v///wD///8A", + "////AP///wD///8A////AP///wD///8A////cf////////98////AP///3n/////////eP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////zf////j///8A////Af///8P////s////E////wD///8A////Av////v////L////AP///wD///8A////AP///wD///8A////AP////////+4////AP///wD///8A", + "////AP///wD///8A////uP////////8A////AP///wD///8A////AP///wD///8A////AP///wD/////////uP///wD///8A////AP///wD///8A////AP///7j/////////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////7j///8A////AP///wD///8A////AP///wD///+4/////////wD///8A////AP///wD///8A", + "////AP///wD///8A////AP////////+4////AP///wD///8A////AP///wD///8A////uP////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////kP//////////////Rf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////7j///8A////AP///wD///8D", + "////+P///9T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////+w////AP///0z////3////8f///2v///8C////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+v/////v///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////r/////7///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///6/////+////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+v", + "/////v///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////r/////7///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///6/////+////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8C/////f////H///8J////AP///wD///8A////z////93///8A////AP///wD///8A////A////8X/////////8P///5////+H////qP///7////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///8L////y////Dv///wD///8A////AP///wD////T", + "////1////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////C////8v///w7///8A////AP///wD///8A////0////9f///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////wv////L///8O////AP///wD///8A////AP///9P////X////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///8L////y////Dv///wD///8A////AP///wD////T////1////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////+w////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////7D///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////7D///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////7D///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////y////+3///8D////AP///wD///8A////Av///+n////s////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP/////////W////AP///wD///8A////AP///8L////5////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////I/////////xr///8A////AP///wD///8d/////////8L///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////yP////////8a////AP///wD///8A////Hf/////////C////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///8j/////////Gv///wD///8A////AP///x3/////////wv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////I", + "/////////xr///8A////AP///wD///8d/////////8L///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////yP////////8a////AP///wD///8A////Hf/////////C////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD////t////3f///wD///8U////6f///7L///8A////1f///+z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////7D///8A////AP///wD///8A////sP////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////+w", + "////AP///wD///8A////AP///7D/////////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////sP///wD///8A////AP///wD///+w/////////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////7D///8A////AP///wD///8A////sP////////8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wP////l////4v////X///8N////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////2v////X///+Y////ef///9X/////////5f///w////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////A////+X////i////9f///w3///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///9T////l////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////7////2r///8A////AP///03/////////Dv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Q////////////////////6P///8N////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9x", + "////9f///3n///+A////9////3P///+K////+////zX///+P////5f///+P///+F////Av///wD///8A////AP///wD///8A////AP///wj///+7//////////////9b////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD////w////z////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////P////7////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD////W////1f///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////2T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////Ov////////9t////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////f///+9////AP///wD///8A////AP///77////1////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////pP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///4b/////////RP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////////////////////nP///xj///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////KP////n///9v", + "////AP///wD/////////pP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////c////5X///95////lv///+X/////////6v///xn///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///+3////j////5P///3////9n////zv////7///87////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////iP////////8w////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///0j////7///////////////j////KP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///7f////z////Ef///wD///8A", + "////L/////z////5////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///82////uP////////+5////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////uf////////+3////Nf///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///3L////+////uP///wT///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////1////aP///wD///8A////9////4f///8A////AP///33/////////A////wD///95////3f///wD///8A", + "////AP///wD///8A////AP///wD///8A////Uv////////9g////AP///wD///9b/////////1T///8A////AP///wD///8A////AP///wD///8A////AP///////////////////////////////////83///80////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////u////5f///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////7j///8A////AP///wD///8A////AP///wD////h////8f///wD///8A////AP///wD///8A////AP///wD///8A////AP////////////////////////////////////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD/////////////////////////////////////////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////7P///+X///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//////////////////////////////////////////", + "//////////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////+4////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////7j///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP/////////F////3P////////9z////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////uP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////7j///8A////yv///9P///8A////AP///wD////G", + "////sf///wD///+4/////////wD///8A////AP///wD///8A////AP////////+3////AP///xr////2////iP///wD///8A////uP////////8A////AP///wD///8A////AP///wD///8A////AP///wD////w////4f///wD///8A////AP///wD///8A////AP///wD///8A////4f///+7///8A////AP///wD///8A////AP///wD///8A", + "/////////9X///9o////d////6P////4////6v///x3///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///1T/////////kf///wD///8A////AP///wD///8A////AP///5L/////////UP///wD///8A////AP///wD///8A////AP///wD/////////1f///2j///9x////mf////f////Z////G////wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wL///+O/////v/////////C////S////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////uP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////", + "////uP///wD///8A////AP///wD///8A////AP///7j/////////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8I////8v///8b///8A////AP///wD////G////8////wn///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////ff////////9F////AP///zr/////////XP///wD///9j", + "/////////yL///8A////S/////////9z////AP///wD///8A////AP///wD///8A////I///////////////Kv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////F/////b///+a////2P///8v///8B////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///6b////+////Mf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////sP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////nv////X///8Q////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////sP////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///82//////////3///9N////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Cv///wD///8A////AP///wL////a////4P///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A//////////////8/////AP///wD///8A////cv////////+E////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///2//////////l////wv///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+D/////////3b///8B", + "////AP///wD///9I//////////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////af////////91////AP///wD///8A////Lv////z///+V////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////7D///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////fv///9P///8l////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A//////////////85////AP///wD///8N////+v///9r///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////sP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////+w////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////6r///8A////Tv////v///+l////Av///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP////////+w////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD//////////////zn///8A////AP///xj////+/////////2v///8A////AP///wv////5////3P///wD///8A////AP///wD///8A//////////////85////AP///wD///8N", + "////+v///9r///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///3r/////////b////wD///8A////AP///3P/////////cP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD//////////////0X///8A////AP///wH///95/////////4P///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////h/////////9r////AP///wD///8A////PP//////////////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP/////////+////g////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////9P///8P///8A////AP///wD///8C", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////+w////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////+w////AP///wD///8A////AP///7D/////////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////Vv////////9g////AP///wD///8A////Z/////////9S////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///4//////////Iv///wD///8H////9v///5P/////////Fv///wD///8h/////////43///8A////AP///wD///8A////AP///wD///82////+v///6X///8A////pv////r///80", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9N/////////2f/////////ZP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///5r////6////Mv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///4f////c////yf///x3///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////ZP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///x3////I////3P///4f///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////y////83///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////P////h////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////4//////////////////////////////8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///0v////p////oP///+r////p////oP////j///9t////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////A////9r////J////9P///4////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD/////////ZP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////D///+4////AP///wD///8A////pv////X///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////v////Hf///wD///8A////7v///4v///8A////AP///wD///8A////AP///wD///8e////7v///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////Yf///5n///8A////AP///13///+a////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///+////8d////AP///wD/////////p////2X///+5////+f///yv///8A////AP///x7////u////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////ZP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9C////w/////P////P////O////wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////Zv///9f////4////1v///0////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////", + "////+v///wz///8A////AP///zf//////////////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wP///9O////df///2X/////////HP///xz/////////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///3D////+////VP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+Z////YP///wD///8A////m////13///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////VP///wv////l////g////wD///9H/////////1T///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////1T///8L////5f///4P///9C////w/////P////P////O////wD///8A////AP///wD///8A////AP///wD///+K////O////0b////P////wP///wD///9w////7////xT///8A////R/////////9U////AP///wD///8A////AP///wD///8A////AP///wj///+5", + "/////////2L///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///1L/////////YP///wD///8A////W/////////9U////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9S/////////2D///8A////AP///1v/////////VP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////Uv////////9g////AP///wD///9b/////////1T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///1L/////////YP///wD///8A////W/////////9U////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9S", + "/////////2D///8A////AP///1v/////////VP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Uv////////9g////AP///wD///9b/////////1T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wL////b////xP///wD///8A////AP//////////////////////////", + "//////////////8A////AP///wD///8A////wv////////+E////A////wD///8A////AP///wD///8B////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////////////////////////////////////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//////////////////////////", + "//////////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////////////////////////////////////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////////////////////////////////////wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A/////////7j///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////+4////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////uP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////7j///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///////////////////////////////////8A////AP///wD////h////8f///wD///8A////AP///wD///8A", + "////AP///wD///8A/////////7f///8A////Gv////b///+I////AP///wD///+4/////////wD///8A////AP///wD///8A////AP///wD///8A////AP////D////h////AP///wD///8A////AP///wD///8A////AP///wD////h////7v///wD///8A////AP///wD///8A////AP///wD////w////4f///wD///8A////AP///wD///8A", + "////AP///wD///8A////4f///+7///8A////AP///wD///8A////AP///wD///8A////8P///+H///8A////AP///wD///8A////AP///wD///8A////AP///+H////u////AP///wD///8A////AP///wD///8A////AP////D////h////AP///wD///8A////AP///wD///8A////AP///wD////h////7v///wD///8A////AP///wD///8A", + "////AP///wD////w////4f///wD///8A////AP///wD///8A////AP///wD///8A////4f///+7///8A////AP///wD///8A////AP///wD///8A////Kv////3///9+////AP///wD///8A////d/////7///8z////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///+/////g////AP///wD///8s////+v///57///8A", + "////AP///wD////i////7v///wD///8A////AP///wD///8A////AP///wD/////////uP///wD///8A////AP///wD///8A////AP///7j/////////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////7j///8A////AP///wD///8A////AP///wD///+4/////////wD///8A////AP///wD///8A////AP///wD///8A", + "////AP////////+4////AP///wD///8A////AP///wD///8A////uP////////8A////AP///wD///8A////AP///wD///8A////AP///wD/////////uP///wD///8A////AP///wD///8A////AP///7j/////////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////F/////b///+a////2P///8v///8B", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////+4////AP///wD///8A////AP///+H////1////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////sP///wD////j////2f///xz///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wr///8A////AP///wD///8C////2v///+D///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8K////AP///wD///8A////Av///9r////g////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Cv///wD///8A////AP///wL////a////4P///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wr///8A////AP///wD///8C////2v///+D///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8K////AP///wD///8A////Av///9r////g////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////Cv///wD///8A////AP///wL////a////4P///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wv///8A////AP///wD///8A////Mf//////////////Wf///wD///8A////Hf////n///+k////AP///wD///8A////AP///3T/////////kf///wf///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///9p/////////3X///8A////AP///wD///8u/////P///5X///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////af////////91////AP///wD///8A////Lv////z///+V////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///2n/////", + "////df///wD///8A////AP///y7////8////lf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9p/////////3X///8A////AP///wD///8u/////P///5X///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////sP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP////////+w////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////+w////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////+w", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///4H/////////X////wD///8A////AP///2P/////////1P///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD//////////////zn///8A////AP///w3////6////2v///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////ev////////9v////AP///wD///8A////c/////////9w////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///3r/////////b////wD///8A////AP///3P/////////cP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///96/////////2////8A", + "////AP///wD///9z/////////3D///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////ev////////9v////AP///wD///8A////c/////////9w////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///3r/////////b////wD///8A////AP///3P/////////cP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////yP////////8a////AP///0//////////Zf////r////E////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////+w////AP///wD///8A", + "////AP///7D/////////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////sP///wD///8A////AP///wD///+w/////////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////7D///8A////AP///wD///8A////sP////////8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP////////+w////AP///wD///8A////AP///7D/////////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9N/////////2f/////////ZP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A//////////////9F////AP///wD///8B", + "////ef////////+D////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///03/////////Z/////////9k////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", @@ -575,39 +3491,45 @@ const char* CAF_FIXED_ATLAS_FONT_12_PT_TEXTURE_IMAGE[] = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////b////8////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9E////RP///93///+n////RP///0T///9n/////////2P///9E////RP///wD///8A////AP///wD///8A////AP///wD///8W////vv//////////", + "////of///yj///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////0P///6T///8A////AP///63////Q////Cv///9/////K////Av///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8o////9f///9v////C/////////5b///8D////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////+////8b///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////xv////v///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////8v////H///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///5z///88////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////T////1P///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////k////y////wD///8A////AP///wD////M////3////wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A/////////6T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8V////+f///6v///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8K////Nv///8L////s", + "////M////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+E////8f///xn///8A/////v///6T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////L////w////6/////n////Z////l////xj///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD////Q////2f///0P////Q////9P///8z///9I////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///yv/////////iv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///z/////6////0////z7///8+////1f////H///8x", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////l////uv///wD///8A////AP///wD////G////7////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////zv///83///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///87////vv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///77///87////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Y/////////97////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////1P///4T///8A////AP///+H///+T////AP///wD///9k/////////w////8A////Yf////j///8A////AP///wD///8A////AP///wD///8A////AP///wX////o////wP///wD///8A////vf///+r///8F////AP///wD///8A////AP///wD///8A////AP///wD/////////uP///wD///8A////B////yX///+a////+////0////8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////yv////7///8I////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////+4////AP///wD///8A////AP///wD///8F/////f///8z///8A////AP///wD///8A////AP///wD///8A////AP///wD/////", + "////uP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////7j///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///8X////+////CP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD/////////uP///wD///8A////AP///wD///8A////AP///7j/////////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////uP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP////////+4////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////uP///zP////4////rP///wH///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////7j///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP////////+2////H/////////9+////AP///wD///8A////bv////n///8Q////t/////////8A////AP///wD///8A////AP///wD/////////s////wD///+X////7////xH///8A////AP///7j/////////AP///wD///8A////AP///wD///8A////AP///wD///8A////0f////r///8B", + "////AP///wD///8A////AP///wD///8A////Av////v////L////AP///wD///8A////AP///wD///8A////AP////////+4////AP///wD///8A////R/////////+n////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+u/////////yn///8A////AP///wD///8A////AP///wD///8q/////////6v///8A", + "////AP///wD///8A////AP///wD///8A/////////7j///8A////AP///wD///9B/////////6X///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///93/////////8r///80////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "/////////7j///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////7j///8A////AP///wD///8A////AP///wD///+4/////////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////VP////////9v////AP///wD///8A////cP////////9V////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///8L////5////Cf///wD///8D////7////6L///8A////qP///97///8A////AP///w3////7////uf///wD///8A////AP///wD///8A////AP///7f////5////8f///7f///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///4z////9", + "////Jv///1v/////////Vf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8j////+v///7j///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////7D///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////EP////X///+e////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///7D/////////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///7X////O", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///7j////L////iv///3H///+1/////////5D///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP/////////d////8////5X///95////0v/////////l////D////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8C////u//////////0////pf///4T///+x", + "////kf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Dv///+P/////////1f///3r///+Z////9f///9r/////////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wL////A/////////8v///98////jP///+/////m////E////wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///84////OP/////////B////OP///zj///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wL///+q/////v////v////Y////df///wL///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP/////////Y////7f///4////+B////2/////////+D", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////7D///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////sP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP////////+w////AP///wD///9e/////v///5X///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////sP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////8/////s////jv///4P////f/////////5f////1", + "////m////37////X/////////4f///8A////AP///wD///8A////AP/////////P////7f///4////+B////2/////////+D////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8I////1v/////////S////g////9X/////////y////wT///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "/////////9v///8A////AP///wD///8A////IP/////////K////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///8z/////////Gf///wD///8A////AP///wD////Y/////////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////lv///9/////M////lv///33///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///7n////9////lv///3f///+y////lf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///zj/////////wf///zj///84////M////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////", + "////sP///wD///8A////AP///wD///+w/////////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///7T////3////Dv///wD///8A////AP///xH////5////sf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////W////4v///wD///8A////AP///7v////y////2P///wD///8A", + "////AP///9/////U////AP///wD///8A////AP///wD///8N////3f///+P///8Q////AP///xH////k////2////wz///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////sv///+P///8C////4f///8b///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///yf///84", + "////OP///zj///9E////8f///9b///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////1////yv///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////2T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////Kv///9X/////////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8AAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////g////kv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///xT///8v////+////x3///9R////4////xT///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////H////7f////R////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///1/////W////Kv///8j////z////wv///yH///8A////AP///wD///8A////AP///yX////m////x////8L////m////IP///wD///8A////lv///9X///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////1////6P///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////o////9f///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////K////yf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP////////8s////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Cv////D///9r////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////2////ev///wD///8A////AP///3v////2////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A/////////2D///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///x/////o////lf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///zj///9J////lf///+3///9S////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////Hv///+n///9C////AP///wD///8A/////////2D///8A////AP///wD///8A////AP///wD///8A////AP///z7///9R////P////3H///+8/////////2f///8A////AP///wD///8A////AP///wD///8A////AP///wD////7////7P///3n///8t////V/////D///+H////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////yf///6j///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///y7////w////yf///1r////c////4P///x7///8A////AP///wD///8A////AP///wD///8A////AP///wD///8J////jv///+T////0////n////5P////v////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////I////6T////r////fP///w7///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8O////fP///+r///+j////Iv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///1r/////////d////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////7f///z////8A////6////2H///8A////Vv////////8D////AP///2T////H////AP///wD///8A////AP///wD///8A////Jf////////9W////AP///wD///9T/////////yb///8A////AP///wD///8A////AP///wD/////////jv///zD///8y////TP///6T////8////W////wD///8A////AP///wD///8A////AP///wD///8A", - "////7v///5z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////90////AP///wD///8A////AP///wD///+g////5////wD///8A////AP///wD///8A////AP///wD/////////jv///zD///8w////MP///zD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "/////////47///8w////MP///zD///8w////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///+3///+c////AP///wD///8A////AP////////////////////////8A////AP///wD///8A////AP///wD/////////jv///zD///8w////MP///zD///+O/////////wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///yD/////////VP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////90////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////2////0f////o////hv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "/////////3T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////90////BP///+3///9R////AP///0v////T////AP///3T/////////AP///wD///8A////AP///wD/////////dP///wD///8I////4P///3r///8A////dP////////8A////AP///wD///8A////AP///wD///8A", - "////8P///5n///8A////AP///wD///8A////AP///wD///+Z////7v///wD///8A////AP///wD///8A////AP///////////////f///+H///+2////Of///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8z/////////3D///8A////AP///wD///8A////bf////7///85////AP///wD///8A////AP///wD///8A", - "/////////////////////////+X///8t////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///0X///+3/////v///9P///8h////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///yD/////////VP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "/////////3T///8A////AP///wD///8A////dP////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////FP////z///9L////AP///0j////8////Fv///wD///8A////AP///wD///8A////AP///wD///8A////AP///6b///+4////AP///7r///9k////AP///2v///+m////AP///7z///+d////AP///wD///8A", - "////AP///wD///8A////Of////z////8////SP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+e/////////8T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///yH////0////cf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "/////////2z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///4/////U////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////bP////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8B////x////9P////Y////Bf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///9q/////////wD///8A////AP///wD///8A////AP///wD///8A////AP////////98////AP///wD///8A////qf///+H///8A////AP///wD///8A////AP///wD///8A////AP///wD////a////s////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////4////6v///8A////AP///wD///+A/////////wD///8A////AP///wD///8A////AP///wD///8A////AP///9v///+n////AP///wD///8A////hP///+b///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////2z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///+3///9q////Av///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////9+////AP///wD///8A////bv////3///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////2z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD/////////bP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////9n////0////8j///8K////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////bP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "/////////37///8A////AP///wD////C////u////wD///8A////AP///27////9////AP///wD///8A////AP////////9+////AP///wD///8A////bv////3///8A////AP///wD///8A////AP///wD///8A////AP///wD////h////p////wD///8A////AP///6r////c////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "//////////P///+E////R////7v/////////R////wD///8A////AP///wD///8A////AP///wD///8A////AP///0v/////////tP///0X///97////7f////////8A////AP///wD///8A////AP///wD///8A////AP///wD/////////hf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///6/////z////Z////wP///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////bP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////bP///wD///8A////AP///2z/////////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wb////u////e////wD///8A////gv///+r///8F////AP///wD///8A////AP///wD///8A////AP///wD///9P/////v///xH///8A////wf///3b///9n////zf///wD///8S/////v///07///8A////AP///wD///8A////AP///3b////0////9P///3H///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////SP///+X////q////Yf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////G/////H///9y////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Hv////////9U////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "/////////yz///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9V/////////x7///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", @@ -619,38 +3541,47 @@ const char* CAF_FIXED_ATLAS_FONT_12_PT_TEXTURE_IMAGE[] = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", - "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///+X///+a////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////y////n////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////H/////////+F////IP///yD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+f////0v///zb///8w////xv///53///8A////AP///wD///8A////AP///wD///8A////AP///wD///8I///////////////////////////////Y////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "/////////yz///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+e////9v///23///8H////nf///8L///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////4////wH///8A////6////1L///8A////AP///wD///8A////Af///+L///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Bf///9D///9l////Bf///9D///9l////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////j////Af///wD///8A/////////93////w////Vf///wD///8B////4v///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8I/////////////////////////////////////////zD///8A////AP///wD///8A////AP///wD///8A", - "////XP///0r///8J////ZP///+f///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///0v///8y////A////1X////s////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "//////////H///91////QP///5H////4/////////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////w////AP////D///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///6n///9s////+P///yD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////Zv///9D///8F////Zv///9D///8F////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////yn////f////Tv///yH///+y/////P///yD///8A////AP///wD///8A////AP///wD///8A////AP////////8p////3////07///9c////Sv///wn///9k////5////wD///8A////AP///wD///8A", - "////vP////L////z////yf///0T////f////Tv///yH///+y/////P///yD///8A////AP///wD///8A////AP///0r////+////cf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///yX/////////Vv///wD///8A////U/////////8m////AP///wD///8A////AP///wD///8A", - "////AP///wD///8l/////////1b///8A////AP///1P/////////Jv///wD///8A////AP///wD///8A////AP///wD///8A////Jf////////9W////AP///wD///9T/////////yb///8A////AP///wD///8A////AP///wD///8A////AP///yX/////////Vv///wD///8A////U/////////8m////AP///wD///8A////AP///wD///8A", - "////AP///wD///8l/////////1b///8A////AP///1P/////////Jv///wD///8A////AP///wD///8A////AP///wD///8A////Jf////////9W////AP///wD///9T/////////yb///8A////AP///wD///8A////AP///wD///8A////AP///wD///++////pP///wD///8A////AP////////+O////MP///zD///8w////MP///wD///8A", - "////AP///2H////2////0v///2v///9C////Pf///1z///+a////AP///wD///8A////AP///wD///8A////AP////////+O////MP///zD///8w////MP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////jv///zD///8w////MP///zD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "/////////47///8w////MP///zD///8w////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////+O////MP///zD///8w////MP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////IP////////9U////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///yD/////////VP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8g/////////1T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////IP////////9U////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////MP////////+O////MP///zD///8A////AP///wD///+g////5////wD///8A////AP///wD///8A////AP////////90////AP///wj////g////ev///wD///90/////////wD///8A////AP///wD///8A////AP///wD////w////mf///wD///8A////AP///wD///8A////AP///5n////u////AP///wD///8A////AP///wD///8A", - "////8P///5n///8A////AP///wD///8A////AP///wD///+Z////7v///wD///8A////AP///wD///8A////AP////D///+Z////AP///wD///8A////AP///wD///8A////mf///+7///8A////AP///wD///8A////AP///wD////w////mf///wD///8A////AP///wD///8A////AP///5n////u////AP///wD///8A////AP///wD///8A", - "////8P///5n///8A////AP///wD///8A////AP///wD///+Z////7v///wD///8A////AP///wD///8A////AP///0T////h////Kv///wD///8o////3////0X///8A////AP///wD///8A////AP///wD///8A////AP///wD////N////rv///wD///+U////2f///wb///8A////AP///7P////M////AP///wD///8A////AP///wD///8A", - "/////////3T///8A////AP///wD///8A////dP////////8A////AP///wD///8A////AP///wD///8A////AP////////90////AP///wD///8A////AP///3T/////////AP///wD///8A////AP///wD///8A////AP///wD/////////dP///wD///8A////AP///wD///90/////////wD///8A////AP///wD///8A////AP///wD///8A", - "/////////3T///8A////AP///wD///8A////dP////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+e/////////8T///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////dP///wD///8A////Af///8n////M////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "/////////2z///8A////SP////L////U////M////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////av////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///2r/////////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///9q/////////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////av////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///2r/////////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///9q/////////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////f///6f///8A////AP///wD///+E////5v///wD///8A////AP///wD///8z/////f///87///9h////V////3z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////2////6f///8A////AP///wD///+E////5v///wD///8A////AP///wD///8A////AP///wD///8A////AP///9v///+n////AP///wD///8A////hP///+b///8A////AP///wD///8A////AP///wD///8A////AP///wD////b////p////wD///8A////AP///4T////m////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////2////6f///8A////AP///wD///+E////5v///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////bP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////bP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD/////////bP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////2z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////K////tf///wD///8A////AP///7T////w////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "/////////37///8A////AP///wD///9u/////f///wD///8A////AP///wD///8A////AP///wD///8A////AP///+H///+n////AP///wD///8A////qv///9z///8A////AP///wD///8A////AP///wD///8A////AP///wD////h////p////wD///8A////AP///6r////c////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////4f///6f///8A////AP///wD///+q////3P///wD///8A////AP///wD///8A////AP///wD///8A////AP///+H///+n////AP///wD///8A////qv///9z///8A////AP///wD///8A////AP///wD///8A////AP///wD////h////p////wD///8A////AP///6r////c////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////Gv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///+H///+n////AP///5L///+v////mf///97///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////bP///wD///8A////AP///2z/////////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "/////////2z///8A////AP///wD///9s/////////wD///8A////AP///wD///8A////AP///wD///8A////AP////////9s////AP///wD///8A////bP////////8A////AP///wD///8A////AP///wD///8A////AP///wD/////////bP///wD///8A////AP///2z/////////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////SP///+X////q////Yf///wD///8A////AP///wD///8A////AP///wD///8A////AP/////////z////hP///0f///+7/////////0f///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9I////5f///+r///9h////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///8T///+/////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////b/////////x7///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////uP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+P////Zv///wD///8A////AP///wD///9p////h////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///1n/////////SP///4n////4////Hv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////h////tf///wD///8A////Pf////X////H////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////y////1H///8A////AP///8H////O////Af///wD///8A////AP///wD///8A////Uv///8v///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////L////Uf///wD///8A/////////3z///8A////Hv////////9q////AP///wD///9S////y////wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////2T///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////8L///8A////AP///wD///8A////1f////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///w3////K/////////////////////////xz///8c/////////wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A/////////1T///8A////Xf////f///8f////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////9U////AP///13////3////H////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////bf////L///8A", + "////Bf///9j///+W////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////DP///+P////Z////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8F////6P///8D///8A////AP///73////q////Bf///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////Bf///+j////A////AP///wD///+9////6v///wX///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wX////o////wP///wD///8A////vf///+r///8F////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8F////6P///8D///8A", + "////AP///73////q////Bf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Bf///+j////A////AP///wD///+9////6v///wX///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wX////o////wP///wD///8A////vf///+r///8F////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////a/////////80////AP///wD/////////uP///wD///8A////AP///wD///8A////AP///wD///8A////Sf////////+y////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////+4////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////uP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////7j///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP////////+4////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////+4////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////uP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////7j///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////+4////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP////////+4////AP///wD///8A////AP///wD///8F/////f///8z///8A////AP///wD///8A////AP///wD///8A////AP////////+z////AP///5f////v////Ef///wD///8A////uP////////8A////AP///wD///8A////AP///wD///8A////AP///wD////R////+v///wH///8A////AP///wD///8A////AP///wD///8C", + "////+////8v///8A////AP///wD///8A////AP///wD///8A////0f////r///8B////AP///wD///8A////AP///wD///8A////Av////v////L////AP///wD///8A////AP///wD///8A////AP///9H////6////Af///wD///8A////AP///wD///8A////AP///wL////7////y////wD///8A////AP///wD///8A////AP///wD////R", + "////+v///wH///8A////AP///wD///8A////AP///wD///8C////+////8v///8A////AP///wD///8A////AP///wD///8A////0f////r///8B////AP///wD///8A////AP///wD///8A////Av////v////L////AP///wD///8A////AP///wD///8A////AP///wD///8w////AP///wD///8A////AP///wD///8x////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD////w////4P///wD///8A////AP///4n////+////Pf///wD///8B////7v///+z///8A////AP///wD///8A////AP///wD///8A/////////7j///8A////AP///wD///8A////AP///wD///+4/////////wD///8A////AP///wD///8A////AP///wD///8A////AP////////+4", + "////AP///wD///8A////AP///wD///8A////uP////////8A////AP///wD///8A////AP///wD///8A////AP///wD/////////uP///wD///8A////AP///wD///8A////AP///7j/////////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////7j///8A////AP///wD///8A////AP///wD///+4/////////wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///4z////9////Jv///1v/////////Vf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////uP///wD///8A////AP///yD/////////3////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////7D///8A", + "////4v///8n///8G////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+4////y////4r///9x////tf////////+Q////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////uP///8v///+K////cf///7X/////////kP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///7j////L////iv///3H///+1/////////5D///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+4////y////4r///9x////tf////////+Q////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////uP///8v///+K", + "////cf///7X/////////kP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///7j////L////iv///3H///+1/////////5D///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+v////3f///5b///9z////gv///+L////d////sP////v///+r////e////93////1", + "////JP///wD///8A////AP///wD////A/////////y7///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Av///8D/////////y////3z///+M////7////+b///8T////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wL////A/////////8v///98", + "////jP///+/////m////E////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8C////wP/////////L////fP///4z////v////5v///xP///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Av///8D/////////y////3z///+M////7////+b///8T////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A/////////7D///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////sP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////sP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////sP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8N////4f////z///+g////df///6T////9/////P///6H///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A/////////8/////t////j////4H////b/////////4P///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wj////W/////////9L///+D////1f/////////L////BP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8I////1v/////////S////g////9X/////", + "////y////wT///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////CP///9b/////////0v///4P////V/////////8v///8E////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wj////W/////////9L///+D////1f/////////L////BP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8I////1v/////////S////g////9X/////////y////wT///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///0z///8S////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///3r/////////b////wD///8A////ov////r/////", + "////cP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////sP///wD///8A////AP///wD///+w/////////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////7D///8A////AP///wD///8A////sP////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP////////+w////AP///wD///8A////AP///7D/////////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////sP///wD///8A////AP///wD///+w/////////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////sv///+P///8C////4f///8b///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP/////////b////AP///wD///8A////AP///yD/////////yv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+y////4////wL////h////xv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", @@ -662,38 +3593,45 @@ const char* CAF_FIXED_ATLAS_FONT_12_PT_TEXTURE_IMAGE[] = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////5f///57///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////FP///+T///9Q////H/////z///8s////FP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///85//////////P////f////M////wD///8A////AP///wD///8A////AP///wD///8A////AP///yP////E////9P///8X///8o////1f///1////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////GP///+7/////////qP///wz///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///+7///+L////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///4z////t////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////7v///+3///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////LP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+R////1P///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////9////3r///8A////AP///wD///96////9P///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////9g////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////P/////////9G////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD//////////////+P///84////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9K////6v///yD///8A////AP////////9g////AP///wD///8A////AP///wD///8A////AP///wD////3////7f////b////w////xf///1b///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////7////5L///+Y////8f///+T///+N////CP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///1b////7////HP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////eP///////////////f///0v///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////if///+7///9W////LP///3b////s////+v///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////LP///7D////u////f////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9/////7v///7D///8s////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////c/////7///9H////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///+v///88////AP////T///9I////AP///zX/////////Cf///wD///8z////8////wD///8A////AP///wD///8A////AP///wD////D////sv///wD///8A////sf///8X///8A////AP///wD///8A////AP///wD///8A", - "///////////////////////////////2////aP///wD///8A////AP///wD///8A////AP///wD///8A////AP///+z///+d////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////dP///wD///8A////AP///wD///8A////nP///+////8A////AP///wD///8A////AP///wD///8A", - "////////////////////////////////////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///////////////////////////////////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////r////nv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "//////////////////////////////////////////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8g/////////1T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////dP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "/////////4n////k////3f///wb///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////90////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////dP///0P////2////Cv///wD///8G////8P///yj///90/////////wD///8A////AP///wD///8A", - "/////////3P///8A////e////9////8I////AP///3T/////////AP///wD///8A////AP///wD///8A////AP////H///+Y////AP///wD///8A////AP///wD///8A////mP///+7///8A////AP///wD///8A////AP///wD/////////jv///zP///9K////p/////7///9L////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////pP///+v///8H////AP///wD///8A////AP///wb////r////mv///wD///8A////AP///wD///8A////AP////////+O////MP///0X///+d////+P///0P///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////E////73/////////z////1////8G////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8g/////////1T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////90////AP///wD///8A////AP///3T/////////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///2f////0////CP///wD///8G////8v///2j///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD////l////gP///wD///+B////nf///wD///+i////b////wD///+D////3v///wD///8A////AP///wD///8A////AP///wz////u////9P///w3///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8r/////P///3D////7////Tf///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////cP////X///8i////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////9s////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wr////v////a////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///2z/////////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///zT////+////TP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////jf///+z///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////tP///wD///8A////AP///9v///+1////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////qv///+z///8B////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///7j////e////AP///wD///8A////uv////////8A////AP///wD///8A////AP///wD///8A////AP///wD///+j////7////wX///8A////AP///7j///+4////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP////////9s////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+J////pf///wn///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////v////wD///8A////AP///6T////G////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP////////9s////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////2z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////Zf///xn////d////t////wX///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "/////////2z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////+4////AP///wD///8D////8P///+v///8H////AP///wD///+i////yf///wD///8A////AP///wD/////////v////wD///8A////AP///6T////G////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////sf///9j///8A////AP///wD////b////qf///wD///8A////AP///wD///8A////AP///wD///8A////AP////////+4////AP///wD///8A////3v///7T///8A////AP///wD///8A////AP///wD///8A////AP///wD///+6////2v///wD///8A////AP///7T/////////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "/////////9n///8E////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////0////gP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////2z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "/////////2z///8A////AP///wD///9s/////////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9T/////v///yD///8A////AP///yT/////////UP///wD///8A////AP///wD///8A////AP///wD///8A////lP///9T///8A////AP///3T///+5////qf///4b///8A////AP///9H///+T////AP///wD///8A", - "////AP///zX////6////Y////2T////5////Mv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///63///+i////n////8P///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9n////9f///yL///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////S////7L////f////C////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////8s////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////DP///9////+y////S////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "////AP///wD///8A////4f////7///8B////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////////////////////////////////", + "//////////////////////////////8A////AP///wD///8A////AP///wD///8A////q/////r///9b/////////0j///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////L///93////AP///wD///96////8f///wD///9I/////////23///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////rv////z///8r////AP///3//////////ff///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///+7////i////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///+P////t////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////bP////////87////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////0P///9////8A////AP///wD///8A////3////8n///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////+k////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///9D////i////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8P////7////8L///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////CP///9z///+m////AP////r///+k////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////d", + "////sf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////pP////r///8I////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////zv///+L///8B////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD////E////6P///xH///8A////AP///xP////r////vv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////9f///6z///8A////AP///wD///8A////wv///8////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///9D////O", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD////H////3f///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///6z///+m////AP///wD///+r////1////wH///8A////V/////////8c////AP///27////o////AP///wD///8A////AP///wD///8A////AP///wD///8A////iv////7///8h////IP////7///+M////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A/////////7j///8A////AP///wD///8A////Av///97////S////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///6P/////////P////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////uP///wD///8A", + "////AP///wD///8A////Lf////////+m////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////7j///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////+4////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///+c/////////0D///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////7j///8A////AP///wD///8A////AP///wD///+4/////////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////7j///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////uP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////7j///8A////Xv////////+C////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP////////+4////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////sP///3P/////////Kv///wD///8A////AP///xn////9////Yf///7T/////////AP///wD///8A////AP///wD///8A/////////6v///8j////+v///3r///8A", + "////AP///wD///+4/////////wD///8A////AP///wD///8A////AP///wD///8A////AP///7D/////////Kf///wD///8A////AP///wD///8A////AP///yn/////////qP///wD///8A////AP///wD///8A////AP///wD/////////uP///wD///8A////AP///wD////s////5P///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////0P////r///8B////AP///wD///8A////AP///wD///8A////Av////v////Y////AP///wD///8A////AP///wD///8A////AP////////+4////AP///wD///8A////AP///+n////n////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////2////+v///8O////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////+4////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////+4////AP///wD///8A////AP///wD///8A////uP////////8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///67////+////Gv///wD///8A////AP///xv////+////rv///wD///8A////AP///wD///8A////AP///wD///8A////AP///w3////6////wP///wD///8A////AP///6z////m////Af///+n///+a////AP///wD///8A////xf////f///8J////AP///wD///8A////AP///1z/////////ff///2f/////", + "////XP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///xX////0////r////wD///8C////2P///9n///8E////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///5T/////////Qf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP////////+w////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///27/////////Nv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+w/////////wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9P////sf///+D////2////3P///4j///8K////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////qP///0r////H////9P///9////+h////Ff///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wP///9j////xf///+r////1////2v///4////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8U////nv///97////0////xP///0X///+l/////////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////A////3j////K////8////9j///+X////E////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////m////+f/////////////////////////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///93/////////8z///+A////yv////////90////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD/////////qv///0n////N////9P///7P///9b////B////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////+w////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "/////////7D///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////sP///wD///8A////AP///27/////////hP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////7D///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP////////90////Sf///83////2////zv///3n///8A////Pf///8L////0////u////2D///8I////AP///wD///8A////AP///wD/////////dP///0n////N////9P///7P///9b////B////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wr///+L", + "////0f////T////R////hP///wf///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////+7////AP///wD///8A////AP///wD////h////7f///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////v////3P///wD///8A////AP///wD///8A////tv////////8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A/////////2z///8g////tv////T////i////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8Z////pv///+n////y////yv///2T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////S////////////////", + "/////////+z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////7D///8A////AP///wD///8A////sP////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///xb////7////rP///wD///8A////AP///wD///8A////rv////r///8V////AP///wD///8A", + "////AP///wD///8A////AP///wD///8d/////////6P///8A////AP///wD///92/////////5r///8A////AP///wD///+d/////////xz///8A////AP///wD///8A////o/////7///9E////AP///wD///8A////Rf////7///+i////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Gv////z///+N", + "////AP///4T/////////KP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+0////////////////////////////////////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////JP///6D////+////Pv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP////////9k////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Pv////7///+K////Dv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", @@ -704,40 +3642,46 @@ const char* CAF_FIXED_ATLAS_FONT_12_PT_TEXTURE_IMAGE[] = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////g////jv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////8P///6P///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////z/////////////////////////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////t////5v////q////6f///5r///+1////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///+C////yf////T///8y////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////8v///3b///8A////AP///2X////0////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///+L///8B////AP///+v///9V////AP///wD///8A////AP///wH////i////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8x////qv///wD///8x////qv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////4v///wH///8A////AP////////9x////gf////n///8Z////Af///+L///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP////////8s////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///1z////M////9P///9T///9I////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///94////3f////f////X////Uv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////+i////AP///wD///8A////v/////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////E////1D///9P////8P///wD////w////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8T////of////////8g////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///6r///8x////AP///6r///8x////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////8g////Tv///9////8J////WP////////8g////AP///wD///8A////AP///wD///8A", - "////AP///wD/////////IP///07////f////Zv///8z////0////1P///0j///8A////AP///wD///8A////AP///03///8N////DP///33////e////Tv///9////8J////WP////////8g////AP///wD///8A////AP///wD///8A////ef////////9Y////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////w////7L///8A////AP///7H////F////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///8P///+y////AP///wD///+x////xf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////D////sv///wD///8A////sf///8X///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////w////7L///8A////AP///7H////F////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///8P///+y////AP///wD///+x////xf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////D////sv///wD///8A////sf///8X///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////Sv////r///8b////AP///wD///////////////////////////////////8A////AP///x7////3////qv///wb///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///////////////////////////////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////////////////////////////////////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///////////////////////////////////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///////////////////////////////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///yD/////////VP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8g/////////1T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////IP////////9U////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///yD/////////VP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//////////////////////////////AP///wD///8A////nP///+////8A////AP///wD///8A////AP///wD/////////c////wD///97////3////wj///8A////dP////////8A////AP///wD///8A////AP///wD///8A", - "////8f///5j///8A////AP///wD///8A////AP///wD///+Y////7v///wD///8A////AP///wD///8A////AP////H///+Y////AP///wD///8A////AP///wD///8A////mP///+7///8A////AP///wD///8A////AP///wD////x////mP///wD///8A////AP///wD///8A////AP///5j////u////AP///wD///8A////AP///wD///8A", - "////8f///5j///8A////AP///wD///8A////AP///wD///+Y////7v///wD///8A////AP///wD///8A////AP////H///+Y////AP///wD///8A////AP///wD///8A////mP///+7///8A////AP///wD///8A////AP///wD///9P////TP///wD///8A////AP///0T///9Z////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////7////5f///8A////Ef///+v///93////AP///wD///+Z////7v///wD///8A////AP///wD///8A////AP////////90////AP///wD///8A////AP///3T/////////AP///wD///8A////AP///wD///8A////AP///wD/////////dP///wD///8A////AP///wD///90/////////wD///8A////AP///wD///8A////AP///wD///8A", - "/////////3T///8A////AP///wD///8A////dP////////8A////AP///wD///8A////AP///wD///8A////AP////////90////AP///wD///8A////AP///3T/////////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8r/////P///3D////7////Tf///wD///8A////AP///wD///8A////AP///wD///8A", - "/////////3T///8A////AP///wD///+c////9P///wD///8A////AP///wD///8A////AP///wD///8A////AP////////9s////AP///+b///+n////Bf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///43////s////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///+N////7P///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////jf///+z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///43////s////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///+N////7P///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////jf///+z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Hv/////////v////Bf///wD///8A////uP///7f///8A////AP///wD///8A", - "////sf///+r///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///6P////v////Bf///wD///8A////uP///7j///8A////AP///wD///8A////AP///wD///8A////AP///wD///+j////7////wX///8A////AP///7j///+4////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////o////+////8F////AP///wD///+4////uP///wD///8A////AP///wD///8A////AP///wD///8A////AP///6P////v////Bf///wD///8A////uP///7j///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////2z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "/////////2z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////2z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////9s////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////Xf////3///9+////Pf///4X////+////2P///wD///8A////AP///wD///8A////AP///wD///8A////AP////////+/////AP///wD///8A////pP///8b///8A////AP///wD///8A////AP///wD///8A////AP///wD///+x////2P///wD///8A////AP///9v///+p////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////sf///9j///8A////AP///wD////b////qf///wD///8A////AP///wD///8A////AP///wD///8A////AP///7H////Y////AP///wD///8A////2////6n///8A////AP///wD///8A////AP///wD///8A////AP///wD///+x////2P///wD///8A////AP///9v///+p////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////sf///9j///8A////AP///wD////b////qf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///+T///8Z////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+x////2P///wD///8V////8f///+X///+s////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "/////////2z///8A////AP///wD///9s/////////wD///8A////AP///wD///8A////AP///wD///8A////AP////////9s////AP///wD///8A////bP////////8A////AP///wD///8A////AP///wD///8A////AP///wD/////////bP///wD///8A////AP///2z/////////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "/////////2z///8A////AP///wD///9s/////////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///63///+i////n////8P///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////uP///wD///8A////AP///97///+0////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////rf///6L///+f////w////wD///8A////AP///wD///8A////AP///wD///8A////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////o/////////91////Af///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////7j///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wH////T////0v///wD///8U////8////57///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////Yv////3///+H////rf////3////h////LP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///3v///+f////AP///wD///9E", + "/////v///6z///9T////af///3D///8A////AP///6D///96////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////e////5////8A////AP////////+f", + "////U////6f////7////HP///wD///8A////oP///3r///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP////////9k////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////+w////AP///wD///8A////AP///7n/////////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///9+//////////////////////////////8c////HP////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////9U////AP///wH////I////qf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////VP///wD///8B////yP///6n///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8E////LP///8X///+3////AP///wD///9K/////P///y3///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+g////+////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///4r////+////If///yD////+////jP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+K/////v///yH///8g/////v///4z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////iv////7///8h////IP////7///+M", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///4r////+////If///yD////+////jP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+K/////v///yH///8g/////v///4z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////iv////7///8h////IP////7///+M////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wr////t////pP///wD///8A/////////7j///8A////AP///wD///8A////AP///wD///8A////AP///6v/////////Nf///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD/////////uP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////7j///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////+4", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////uP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////uP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////7j///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////+4////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////", + "////uP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////uP///wD///8A////AP///wD///8A////Lf////////+m////AP///wD///8A////AP///wD///8A////AP///wD/////////q////yP////6////ev///wD///8A////AP///7j/////////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////sP////////8p////AP///wD///8A////AP///wD///8A////Kf////////+o////AP///wD///8A////AP///wD///8A////AP///7D/////////Kf///wD///8A////AP///wD///8A////AP///yn/////////qP///wD///8A////AP///wD///8A////AP///wD///+w/////////yn///8A", + "////AP///wD///8A////AP///wD///8p/////////6j///8A////AP///wD///8A////AP///wD///8A////sP////////8p////AP///wD///8A////AP///wD///8A////Kf////////+o////AP///wD///8A////AP///wD///8A////AP///7D/////////Kf///wD///8A////AP///wD///8A////AP///yn/////////qP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////0f////r///8B////AP///wD///8K////4P///9T///8F////J//////////G////AP///wD///8A////AP///wD///8A////AP////////+4////AP///wD///8A", + "////AP///wD///8A////uP////////8A////AP///wD///8A////AP///wD///8A////AP///wD/////////uP///wD///8A////AP///wD///8A////AP///7j/////////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////7j///8A////AP///wD///8A////AP///wD///+4/////////wD///8A////AP///wD///8A", + "////AP///wD///8A////AP////////+4////AP///wD///8A////AP///wD///8A////uP////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///xX////0////r////wD///8C////2P///9n///8E////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////7j///8A////AP///wD///95", + "/////////6r///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////+w////AP///0b////x////yv///yf///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////T////7H////g////9v///9z///+I////Cv///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///0////+x////4P////b////c////iP///wr///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9P////sf///+D////2////3P///4j///8K////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////T////7H////g////9v///9z///+I", + "////Cv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///0////+x////4P////b////c////iP///wr///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9P////sf///+D////2////3P///4j///8K////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////Sv///6b////X////9f///9f///+m////G////wT///+I////1////+v///+0////Kf///wD///8A////AP///wD///8A////6////+L///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8D////eP///8r////z////2P///5f///8T", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////A////3j////K////8////9j///+X////E////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wP///94////yv////P////Y////l////xP///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8D////eP///8r////z////2P///5f///8T////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////+w////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////7D///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////7D///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////7D///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///xL///+c////2/////L////L////dP////v///9T////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////90////Sf///83////0////s////1v///8H////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Cv///4v////R////9P///9H///+E////B////wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wr///+L////0f////T////R////hP///wf///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8K////i////9H////0////0f///4T///8H////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////Cv///4v////R////9P///9H///+E////B////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wr///+L////0f////T////R////hP///wf///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////j////Sv///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8I////1v/////////U////ef///6H/////////6////wX///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////7D///8A////AP///wD///8A////sP////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////+w", + "////AP///wD///8A////AP///7D/////////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////sP///wD///8A////AP///wD///+w/////////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////7D///8A////AP///wD///8A////sP////////8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////Gv////z///+N////AP///4T/////////KP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////u////wD///8A////AP///wD///8A////4f///+3///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8a", + "/////P///43///8A////hP////////8o////AP///wD///8A////AP///wD///8A////AP///wD///8A////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", @@ -747,38 +3691,49 @@ const char* CAF_FIXED_ATLAS_FONT_12_PT_TEXTURE_IMAGE[] = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", - "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///+r///+q////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP////////////////////////////////////////8A////AP///wD///8A////AP///wD///8A////AP///yb////M/////P////////9k////B////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+1////pf///yP///+q////tv///1P////f////Bv///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///2v////9////df///9P////X////Hv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////7////gP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///+A////+v///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////yz///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///+j/////////Df///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////hf///9f///8A////AP///wD////d////e////wD///8A////AP///wD///8A////AP///wD///8A////AP////D///+z////AP////////9I////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////z", + "////dv///wD///8A////ef////D///8A////AP///6f////y////G////wD///8A////AP///wD///8A////AP///wD///8A////AP////D////D////AP///wD///8A////z////+T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD////b/////f///wX///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wb////9////2////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////KP////////89////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///+T///+H////AP///wD///8A////iP///97///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////YP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///+4////vf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///xD///9e////9f///1z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///4b////R////C////wD////+////YP///wD///8A////AP///wD///8A////AP///wD///8A", - "////5f///2n///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///83///+x////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8D////4P///4f///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////Y/////v///98////HP///4D////5////U////wD///8A////AP///wD///8A////AP///wD///8A////AP///+D///+E////AP///wD///8A////l////+v///8A////AP///wD///8A////AP///wD///8A////AP///wD///9S////9////1H///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////N////7z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////vP///zb///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+u////yP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////B////Yf///wD////P////cf///wD///8l/////////xb///8A////NP///+7///8A////AP///wD///8A", - "////AP///wD///8A////Yf////r///8U////FP////r///9j////AP///wD///8A////AP///wD///8A////AP////////90////AP///wD///8S////T////+////90////AP///wD///8A////AP///wD///8A////AP///wD////F////wf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "/////////3T///8A////AP///wD///8A////AP///8D////G////AP///wD///8A////AP///wD///8A////AP////////90////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////dP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////wv///8T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////90////AP///wD///8A////AP///3T/////////AP///wD///8A////AP///wD///8A////AP///wD///8A////IP////////9U////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A/////////3T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////90////OP////X///9S////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////dP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "/////////3L///+V////r////wD///8A////AP///6P///99////c/////////8A////AP///wD///8A////AP////////9u////Gf////P///9V////AP///wD///90/////////wD///8A////AP///wD///8A////AP///wD////S////sv///wD///8A////AP///wD///8A////AP///7P////M////AP///wD///8A////AP///wD///8A", - "/////////3T///8A////AP///wH////J////zP///wD///8A////AP///wD///8A////AP///wD///8A////AP///9H///+y////AP///wD///8A////AP///wD///8A////s////9f///8A////AP///wD///8A////AP///wD/////////dP///wD///8A////AP///8X////J////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///6P////y////TP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////IP////////9U////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////dP///wD///8A////AP///wD///90/////////wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///+9////rf///wD///8A////AP///6z///++////AP///wD///8A////AP///wD///8A////AP///wD///8k/////////0j///8A////R////9X///8A////2f///zn///8A////S/////////8e////AP///wD///8A////AP///wD///+L////6////97///+N////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////sv///8j///8A////nP///9P///8C////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wL////G////vf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////bP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///9j////8////w3///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9s/////////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9Q////mf///1T///84////Yf////L///+p////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "//////////L///9/////Rv///7X/////////SP///wD///8A////AP///wD///8A////AP///wD///8A////AP///yz////8////1v///2f///9X////Zf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9H/////////77///9H////hf////P/////////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////Kf////n///+9////TP///37////9////Qf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wj/////////cP///wj///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Ev///9f////+////7f///6b///8S////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "/////////+////+W////Qv///3j////y////ef///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////bP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////9s////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "/////////2z///8A////If///+T///+n////Av///wD///8A////AP///wD///8A////AP///wD///8A////AP////////9s////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////7P///4j///9C////mf/////////Q////rv///0P///9y////8P///37///8A////AP///wD///8A", - "/////////+3///+W////Qv///3j////y////ef///wD///8A////AP///wD///8A////AP///wD///8A////AP///zn////9////uP///1L///+5////+////zD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////ff///wD///8A////AP///6z////g////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////5P///6j///8A////AP///wD///9//////////wD///8A////AP///wD///8A////AP///wD///8A////AP////////++////wf///17///9J////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////0f///8j///9D////W////2j///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////CP////////9w////CP///wf///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////9s////AP///wD///8A////bP////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////sv///8L///8A////AP///wD///8A////xv///7D///8A////AP///wD///8A////AP///wD///8A", - "////AP///9n///+Z////AP///wD///8n////8v///+r///8+////AP///wD///+S////2P///wD///8A////AP///w3////c////rv///wD///8A////r////9r///8M////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///xj////7////S////0f/////////Jf///wD///8A////AP///wD///8A////AP///wD///8A", - "////Bf///wj///8I////Cf///8T///+9////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP/////////g////Iv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////LP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8i////4P////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///w/////1////ov///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///5z/////////FP///wD///8A////F/////////+P////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+E////Yv///wD////7////pP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////D////8////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///8X////y////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9H", + "/////////0D////y////pP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////x////8r///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///1b/////////Vf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///3H/////////Pv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////8////7X///8A////AP///wD///8A////tv////P///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///9b////I////AP///wD///8A", + "////B////+7///+q////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////of////b///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+B////2v///wL///8A////L/////n///+j////Qv///4T/////////Kf///wD///+X////vv///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///yb/////////ff///37/////////KP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////+4////AP///wD///8A////AP///wD////T////8////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///87/////////73///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////7j///8A////AP///wD///8A////AP///6P/////////Uv///wD///8A////AP///wD///8A////AP///wD///8A////AP////////+4////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD/////////uP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Mv////3////D////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////+4////AP///wD///8A////AP///wD///8A", + "////uP////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////+4////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////7j///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP////////+4////AP///wD///+N/////////1j///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////uP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////6f////H////1v///wD///8A////AP///wD///8A", + "////v////7n///+s/////////wD///8A////AP///wD///8A////AP////////+h////pv///+j///8L////AP///wD///8A////uP////////8A////AP///wD///8A////AP///wD///8A////AP///wD///9V/////////5P///8A////AP///wD///8A////AP///wD///+P/////////0j///8A////AP///wD///8A////AP///wD///8A", + "/////////7j///8A////AP///wD///8L////8/////D///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////D////h////AP///wD///8A////AP///wD///8A////AP///wD////i////8v///wD///8A////AP///wD///8A////AP///wD/////////uP///wD///8A////AP///wD////n////7v///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////X////J////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////uP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////", + "////uP///wD///8A////AP///wD///8A////AP///7j/////////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///w/////4////wv///wD///8A////AP///wD///8A////xf////j///8P////AP///wD///8A////AP///wD///8A////AP///wD///9N/////////33///8A////AP///wD///9l/////////1D/////", + "////Vv///wD///8A////AP///4L/////////R////wD///8A////AP///xX////s////0v///wX///8B////wf///+z///8V////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+I/////////zv///8A////AP///1v/////////ZP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8X////9P///8n///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////sP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////V////zv///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////sP////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A/////////63///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////r/////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8B/////////7D///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////3/////T///8H////AP///wb////0////2v///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////7D///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////+w////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////7D///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP////////+w////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////tf///wD///8A////AP///wD///8A////3f///+7///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////7v///9////8A////AP///wD///8A////AP///7z/////////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////B////+T///+w////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///3v/////////Lf///wD///8m/////////4n///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8h/////////5T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////ZP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///5T/////////Df///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", @@ -790,40 +3745,44 @@ const char* CAF_FIXED_ATLAS_FONT_12_PT_TEXTURE_IMAGE[] = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////2////4L///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///8z////w////Bv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////3T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8J////7P///1T///+S////s////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///9r///9/////AP///yv////b////vP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////N////If///wD///+d////z////zH///8h////Qf///wD///8k////yf///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///zX////6/////////9n///+A////mv///5H///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////+7////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9Q/////////1////8A////AP///4f////8////Kf///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///xL////Q/////////+X///95////D////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8W////7v///0X///8A////AP///0X////E////8v///+T///+R////AP///0b////u////Ff///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///83///8h////AP///wD/////////Tf///0z////7////Gv///yT////J////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////LP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////bv///wD///8A////AP///4H/////////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////KP///+j///////////////D///8A////8P///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///xb////u////Rf///wD//////////////+////+z////Yf///wD///8A////Rv///+7///8V////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+c////PP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////", + "////sP///wD///8A////AP///wD///+w/////////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////zP//////////////////////////////HP///xz/////////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD/////////IP///wD///+z////hP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////yD///8A////s////4T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wH///9p////1v///wD///+z////hP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///+y////1v///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///2H////6////FP///xT////6////Y////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9h////+v///xT///8U////+v///2P///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////Yf////r///8U////FP////r///9j////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///2H////6////FP///xT////6////Y////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9h////+v///xT///8U////+v///2P///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////Yf////r///8U////FP////r///9j////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wH////U////h////wD///8A/////////3T///8A////AP///wD///8A////AP///wD///+X////9P///xj///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "/////////3T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////90////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////dP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "/////////3T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8g/////////1T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////IP////////9U////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///yD/////////VP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8g/////////1T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////3T///8A////AP///wD///8A////AP///8D////G////AP///wD///8A////AP///wD///8A", - "/////////27///8Z////8////1X///8A////AP///3T/////////AP///wD///8A////AP///wD///8A////AP///9L///+y////AP///wD///8A////AP///wD///8A////s////8z///8A////AP///wD///8A////AP///wD////S////sv///wD///8A////AP///wD///8A////AP///7P////M////AP///wD///8A////AP///wD///8A", - "////0v///7L///8A////AP///wD///8A////AP///wD///+z////zP///wD///8A////AP///wD///8A////AP///9L///+y////AP///wD///8A////AP///wD///8A////s////8z///8A////AP///wD///8A////AP///wD////S////sv///wD///8A////AP///wD///8A////AP///7P////M////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////H///+Y////AP///wD///9l////8////xv///8A////pv///+3///8A////AP///wD///8A////AP///wD/////////dP///wD///8A////AP///wD///90/////////wD///8A////AP///wD///8A////AP///wD///8A", - "/////////3T///8A////AP///wD///8A////dP////////8A////AP///wD///8A////AP///wD///8A////AP////////90////AP///wD///8A////AP///3T/////////AP///wD///8A////AP///wD///8A////AP///wD/////////dP///wD///8A////AP///wD///90/////////wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////sv///8j///8A////nP///9P///8C////AP///wD///8A////AP///wD///8A////AP////////90////AP///wD///8D////5P///9j///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////bP///wD////b////mf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////UP///5n///9U////OP///2H////y////qf///wD///8A////AP///wD///8A////AP///wD///8A////AP///1D///+Z////VP///zj///9h////8v///6n///8A////AP///wD///8A////AP///wD///8A////AP///wD///9Q////mf///1T///84////Yf////L///+p////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////UP///5n///9U////OP///2H////y////qf///wD///8A////AP///wD///8A////AP///wD///8A////AP///1D///+Z////VP///zj///9h////8v///6n///8A////AP///wD///8A////AP///wD///8A////AP///wD///9Q////mf///1T///84////Yf////L///+p////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////gf///3v///9G////Pv///7f////o////7v///73///9M////fv////z///8+////AP///wD///8A////AP///97///+w////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8p////+f///73///9M////fv////3///9B////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////Kf////n///+9////TP///37////9////Qf///wD///8A////AP///wD///8A////AP///wD///8A////AP///yn////5////vf///0z///9+/////f///0H///8A////AP///wD///8A////AP///wD///8A////AP///wD///8p////+f///73///9M////fv////3///9B////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP////////9s////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////9s////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////9s////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD/////////bP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9u////2v////D///+z////yP///6D///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////7f///5b///9C////eP////L///95////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////Of////3///+4////Uv///7n////7////MP///wD///8A////AP///wD///8A////AP///wD///8A////AP///zn////9////uP///1L///+5////+////zD///8A////AP///wD///8A////AP///wD///8A////AP///wD///85/////f///7j///9S////uf////v///8w////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////Of////3///+4////Uv///7n////7////MP///wD///8A////AP///wD///8A////AP///wD///8A////AP///zn////9////uP///1L///+5////+////zD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////Of////3///+3////RP///7v/////////Of///wD///8A////AP///wD///8A////AP///wD///8A////AP////////9s////AP///wD///8A////bP////////8A////AP///wD///8A////AP///wD///8A////AP///wD/////////bP///wD///8A////AP///2z/////////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "/////////2z///8A////AP///wD///9s/////////wD///8A////AP///wD///8A////AP///wD///8A////AP////////9s////AP///wD///8A////bP////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///xj////7////S////0f/////////Jf///wD///8A////AP///wD///8A////AP///wD///8A", - "/////////33///8A////AP///wD///+s////4P///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////GP////v///9L////R/////////8l////AP///wD///8A////AP///wD///8A////AP///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////VP///wD///8A////OP////7///89////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////1T///8A////AP///zj////+////Pf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A///////////////k////Ff///wD///8A////AP///7f///+8////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8m/////////33///9+/////////yj///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Jv////////99////fv////////8o////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///yb/////////ff///37/////////KP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8m/////////33///9+/////////yj///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////Jv////////99////fv////////8o////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///yb/////////ff///37/////////KP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////hP////r///8a////AP////////+4////AP///wD///8A", + "////AP///wD///8A////AP///wD////O/////f///wX///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////7j///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////+4////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////uP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////7j///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A/////////7j///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////+4////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////uP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////7j///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////7j///8A////AP///wD///8A////AP///6P/////////Uv///wD///8A////AP///wD///8A", + "////AP///wD///8A/////////6H///+m////6P///wv///8A////AP///wD///+4/////////wD///8A////AP///wD///8A////AP///wD///8A////AP///1X/////////k////wD///8A////AP///wD///8A////AP///4//////////SP///wD///8A////AP///wD///8A////AP///wD///9V/////////5P///8A////AP///wD///8A", + "////AP///wD///+P/////////0j///8A////AP///wD///8A////AP///wD///8A////Vf////////+T////AP///wD///8A////AP///wD///8A////j/////////9I////AP///wD///8A////AP///wD///8A////AP///1X/////////k////wD///8A////AP///wD///8A////AP///4//////////SP///wD///8A////AP///wD///8A", + "////AP///wD///9V/////////5P///8A////AP///wD///8A////AP///wD///+P/////////0j///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///7D/////////KP///wD///8A////AP///03/////", + "////eP///1//////////oP///wD///8A////AP///wD///8A////AP///wD/////////uP///wD///8A////AP///wD///8A////AP///7j/////////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////7j///8A////AP///wD///8A////AP///wD///+4/////////wD///8A////AP///wD///8A////AP///wD///8A", + "////AP////////+4////AP///wD///8A////AP///wD///8A////uP////////8A////AP///wD///8A////AP///wD///8A////AP///wD/////////uP///wD///8A////AP///wD///8A////AP///7j/////////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+I/////////zv///8A////AP///1v/////", + "////ZP///wD///8A////AP///wD///8A////AP///wD///8A////AP/////////V////aP///4X////X//////////X///8j////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////sP///wD///8A////Hv///8D////z////Pf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wT///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///+n////m////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///6D////c////Bf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////BP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wT///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wr///+L////0f////b////f////oP///93///8y////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///3v/////////Lf///wD///8m/////////4n///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////7X///8A////AP///wD///8A", + "////AP///93////u////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////e/////////8t////AP///yb/////////if///wD///8A////AP///wD///8A////AP///wD///8A////AP///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", @@ -832,42 +3791,48 @@ const char* CAF_FIXED_ATLAS_FONT_12_PT_TEXTURE_IMAGE[] = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////v////tv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////hf///6P///8A////pf///3v///8A////AP///wD///8A////AP///wD///8A////AP///wD////J////wv///xj/////////FP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////8P///0L///8A////Rf///+////8A////y////2v///8A////AP///wD///8A////AP///wD///8A////AP///wD////Z////o////wD///8J////yP///7r///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////7P///6L///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////o////+v///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wj///8B////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///++////p////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////J////p////wD///8A////AP///6n////B////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A/////////2D///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////gf////D///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///5f////d////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8D////v////6v///8B////+P///2D///8A////AP///wD///8A////AP///wD///8A////AP///9L///99////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+W////7v///wf///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///3H////t////Cf///wD///8A////AP///wD///8A////AP///wD///8A////AP///9////+N////AP///wD///8A////k////9n///8A////AP///wD///8A////AP///wD///8A////AP///wD////1////af///wD///8A////AP///3z////L////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////VP////f///9T////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Yf////b///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////k////5n///8A////Zv///+H///8r////Lf////////8k////AP///13////E////AP///wD///8A////AP///wD///8A////AP///wv////z////a////2v////0////DP///wD///8A////AP///wD///8A////AP///wD/////////dP///wD///8A////AP///wD///+J////6P///wD///8A////AP///wD///8A////AP///wD///8A", - "////jP////j///8f////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////90////AP///wD///8A////AP///xT////y////l////wD///8A////AP///wD///8A////AP///wD/////////dP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "/////////3T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///4j////5////JP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////dP///wD///8A////AP///wD///90/////////wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///yD/////////VP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////90////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////dP///wD///9Z////9v///zn///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "/////////3T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////9s////5f///17///8A////AP///wD///9P////0v///2//////////AP///wD///8A////AP///wD/////////ZP///6D////C////AP///wD///8A////dP////////8A////AP///wD///8A////AP///wD///8A", - "////pf///+r///8H////AP///wD///8A////AP///wb////q////nf///wD///8A////AP///wD///8A////AP////////90////AP///wD///8A////nP////T///8A////AP///wD///8A////AP///wD///8A////AP///wD////w////mf///wD///8A////AP///wD///8A////AP///5n////y////AP///wD///8A////AP///wD///8A", - "/////////3T///8A////AP///wD///+W////9P///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////s////jP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///yD/////////VP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "/////////3T///8A////AP///wD///8A////dP////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8W/////P///1////8A////AP///wD///9e/////P///xf///8A////AP///wD///8A////AP///wD///8A////Y/////7///8R////AP///w/////8////IP////n///8I////AP///xP/////////Xv///wD///8A", - "////AP///wD///8q////+v///2T///9P////+////yv///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////PP////////9F////AP///x/////5////X////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Kf////j///9k////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "/////////2z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////zf///5f///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////bP////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////Rf///7D////g////+P///+L///+b////E////wD///8A////AP///wD///8A////AP///wD///8A////AP////////93////sP////X////Z////Yv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Ov///8D////w////6////6b///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///2D////Y////8////6n///90/////////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///82////wf////H////N////UP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////J////////////////////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///6b////p////Yv///17////o////pf///wD///8A////AP///wD///8A////AP///wD///8A////AP////////9z////nf////D////V////ff///xP///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////2z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD/////////bP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////9s////AP///wD///8p////6////5X///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////bP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "/////////0r///+l////9P///93///+B////Bf///4r////o////3v///4P///8W////AP///wD///8A////AP////////9I////nf////D////V////ff///xP///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////SP///8v////y////yf///0D///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "/////////27///8A////AP///wD///+E////+P///wD///8A////AP///wD///8A////AP///wD///8A////AP////n///+E////AP///wD///8A////b/////////8A////AP///wD///8A////AP///wD///8A////AP///wD/////////Nf///3/////t////5////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///zL////H////9f///97///99////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///9n////////////////////w////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////bP///wD///8A////AP///2z/////////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////Ff////v///9m////AP///wD///8A////AP///2f////6////Ff///wD///8A////AP///wD///8A////AP///x7/////////Xf///wD///8A////AP///9r////y////Bf///wD///8A////U/////////8d////AP///wD///+j////5v///xP///8A////AP///xP////m////ov///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///94////6P///wT///8D////5f///4f///8A////AP///wD///8A////AP///wD///8A////AP///7z//////////////////////////////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8e////k/////f///8U////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "/////////yz///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8U////9////3v///8M////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////v/////////xr///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///1/////5////A////wD///8A////t////6H///8A////AP///wD///8A////AP///wD///8A////AP///wD////n////0////wD/////", + "////SP///wD///8A////Af///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////1f///6T///8A////AP///6z////N////AP///wD///8X////7v///67///8A////AP///wD///8A////AP///wD///8A////AP///wD////o////4v///wP///8A////Af///9D////n////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////sf////////8j////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8k/////////7D///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////nv////f///8S////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9M/////////3P///8A////AP///3n/////////OP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////mf////////9y////8////6T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///0v///80////AP///wD///8S////8v///8z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8y////Mv///wD///8A////AP///xT////v", + "////1P///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///6j////B////5////6T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///7L////j////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8H////4P///+D///8a////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8Y/////P///5n///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///9L////1////EP///wD///8A////Ev////b////Q", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+W/////f///yz///8A////AP///2//////////Rf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD////O////zf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8b////A////wD///8A////Bf///9n////R////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////G/////b///9Z////AP///wD///85////wf////T////t////wP///x7///8B////0f///5P///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////wv///9H////R////xf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////uP///wD///8A////AP///wD///9A/////////8r///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///67/////////jf///wT///8A////AP///wD///8F////EP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////+4////AP///wD///8A////AP///2j////9////vv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////", + "////uP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////7j///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+U/////////5r///8K////AP///wD///8A////AP///wj///8F", + "////AP///wD///8A////AP///wD///8A////AP///wD/////////uP///wD///8A////AP///wD///8A////AP///7j/////////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////uP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP////////+4////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////uP///wD///8A////A////7j////2////Nf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////7j///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP////////+2/////v///4L///8A////AP///wD///8A////AP///2f////7////tf////////8A////AP///wD///8A////AP///wD/////////wv////7///9s////AP///wD///8A////AP///7j/////////AP///wD///8A////AP///wD///8A////AP///wD///8A////Af///9P////4", + "////V////wD///8A////AP///wD///9R////9v///8P///8A////AP///wD///8A////AP///wD///8A////AP////////+4////AP///wD///8A////Yf/////////C////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////w////4f///wD///8A////AP///wD///8A////AP///wD///8A////4f///+7///8A", + "////AP///wD///8A////AP///wD///8A/////////7j///8A////AP///wD///86/////////8H///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////O/////f///yH///8A////AP///wD///8G////CP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "/////////7j///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////7j///8A////AP///wD///8A////AP///wD///+4/////////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9h/////////2z///8A////AP///wD///8A////AP///2//////////YP///wD///8A", + "////AP///wD///8A////AP///wD///8A////k/////////86////AP///wD///8A////Hv/////////E/////v///xP///8A////AP///wD///8//////////47///8A////AP///wD///+l/////f///zb///8A////AP///yb////4////pf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8T////8////8b///8A", + "////AP///wD///8D////2P///+P///8I////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///4L/////////Uv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////7D///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///89/////////2f///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///7D/////////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////+w////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///7D/////////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP////X///+2////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////b////C////AP///wD///8A////wv////X///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////+w////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////sP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP////////+w////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////sP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "/////////9X///8A////AP///wD///8A////HP/////////L////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///8v/////////HP///wD///8A////AP///wD////d/////////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+R////sP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wH////e////zv///wD///8A////AP///8j////m////A////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////+w////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////2T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///+w/////////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8AAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", @@ -875,38 +3840,52 @@ const char* CAF_FIXED_ATLAS_FONT_12_PT_TEXTURE_IMAGE[] = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", - "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///9b///92////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9h/////////8////99////Qv///2H///9b////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP////////90////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////av///+b///8E////H/////v///83////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9B////6////8D////9////v////xv///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////dP///4b///8A////Dv///5n////m////8P///6P///8A////iv///3L///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///90////hv///wD///8A//////////7////S////dv///wD///+K////cv///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////yz///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///8b////w////MP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////TP///9H///////////////L///+k////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////k////4v///wL///8A////AP///wL///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////y////+T///8F////AP///wD///8T////8v///63///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+x////9////2b///8E////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///07////n////Rv///wD///8A////AP///wD///8A////AP///0b////n////Tf///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "/////////2z///8A////AP///wD///9t/////////wD///8A////AP///wD///8A////AP///wD///8A////AP///6X////////////////////w////AP////D///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Tv///+f///9G////AP///wD///8A////AP///wD///8A////Rv///+f///9N////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////yD///8A////If///+////8m////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////8g////AP///yH////v////Jv///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///9z////z////6P///yj///8A////If///+////8m////AP///wD///8A////AP///wD///8A////AP///wD///8A////X/////v///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8L////8////2v///9r////9P///wz///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////C/////P///9r////a/////T///8M////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wv////z////a////2v////0////DP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8L////8////2v///9r////9P///wz///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////C/////P///9r////a/////T///8M////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wv////z////a////2v////0////DP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////YP///+7///8L////AP////////90////AP///wD///8A////AP///wD///8A", - "////yv///7z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////90////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////dP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "/////////3T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////90////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////IP////////9U////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///yD/////////VP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8g/////////1T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////IP////////9U////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP////////90////AP///wD///8A////AP///xT////y////l////wD///8A////AP///wD///8A////AP////////9k////oP///8L///8A////AP///wD///90/////////wD///8A////AP///wD///8A////AP///wD///+l////6v///wf///8A////AP///wD///8A////Bv///+r///+d////AP///wD///8A////AP///wD///8A", - "////pf///+r///8H////AP///wD///8A////AP///wb////q////nf///wD///8A////AP///wD///8A////AP///6X////q////B////wD///8A////AP///wD///8G////6v///53///8A////AP///wD///8A////AP///wD///+l////6v///wf///8A////AP///wD///8A////Bv///+r///+d////AP///wD///8A////AP///wD///8A", - "////pf///+r///8H////AP///wD///8A////AP///wb////q////nf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////S////sv///wD///8A////Av///8v///+n////AP///93////I////AP///wD///8A////AP///wD///8A", - "/////////3T///8A////AP///wD///8A////dP////////8A////AP///wD///8A////AP///wD///8A////AP////////90////AP///wD///8A////AP///3T/////////AP///wD///8A////AP///wD///8A////AP///wD/////////dP///wD///8A////AP///wD///90/////////wD///8A////AP///wD///8A////AP///wD///8A", - "/////////3T///8A////AP///wD///8A////dP////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////PP////////9F////AP///x/////5////X////wD///8A////AP///wD///8A////AP///wD/////////jv///zL///9k////sP////////9w////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "/////////2z///8A////M////+T///+t////DP///wD///8A////AP///wD///8A////AP///wD///8A////AP///0X///+w////4P////j////i////m////xP///8A////AP///wD///8A////AP///wD///8A////AP///wD///9F////sP///+D////4////4v///5v///8T////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////Rf///7D////g////+P///+L///+b////E////wD///8A////AP///wD///8A////AP///wD///8A////AP///0X///+w////4P////j////i////m////xP///8A////AP///wD///8A////AP///wD///8A////AP///wD///9F////sP///+D////4////4v///5v///8T////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////Rf///7D////g////+P///+L///+b////E////wD///8A////AP///wD///8A////AP///wD///8A////AP///2v////E////7P///+r///+7////J////y3///+9////8P///8z///9N////AP///wD///8A////AP///wD////3////hv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///zb////B////8f///83///9Q////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///82////wf////H////N////UP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Nv///8H////x////zf///1D///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///zb////B////8f///83///9Q////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////bP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////bP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD/////////bP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////2z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////E/////r///9P////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "/////////0j///+d////8P///9X///99////E////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9I////y/////L////J////QP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////SP///8v////y////yf///0D///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///0j////L////8v///8n///9A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9I////y/////L////J////QP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////SP///8v////y////yf///0D///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9I////yv////T////O////yv///1L///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////bP///wD///8A////AP///2z/////////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "/////////2z///8A////AP///wD///9s/////////wD///8A////AP///wD///8A////AP///wD///8A////AP////////9s////AP///wD///8A////bP////////8A////AP///wD///8A////AP///wD///8A////AP///wD/////////bP///wD///8A////AP///2z/////////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///94////6P///wT///8D////5f///4f///8A////AP///wD///8A////AP///wD///8A////AP////////9u////AP///wD///8A////hP////j///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///3j////o////BP///wP////l////h////wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////7D///8A////AP///wD///8A////sP////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///+v//////////////////////////////xz///8c/////////wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///5r///8l/////P///1T///8A////AP///wD///+k////zf///wL///8A////AP///wD///8A////AP///wD///8A////AP///wD///+a////Jf////z///9U////AP///wD///8A////pP///83///8C////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8c////pv///7b///8A", + "////AP///wD///8p////+////0////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///8L////R////0f///8X///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD////C////0f///9H////F////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////wv///9H////R////xf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///8L////R", + "////0f///8X///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////C////0f///9H////F////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////wv///9H////R////xf///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///xj////4////hf///wD/////////uP///wD///8A////AP///wD///8A////AP///wD///8A////7////+P///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////+4////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////uP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////7j///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP////////+4////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////+4////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////uP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////7j///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////+4////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP////////+4////AP///wD///8A////AP///2j////9////vv///wD///8A////AP///wD///8A////AP///wD///8A////AP/////////C/////v///2z///8A////AP///wD///8A////uP////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8B////0/////j///9X////AP///wD///8A////AP///1H////2", + "////w////wD///8A////AP///wD///8A////AP///wD///8A////Af///9P////4////V////wD///8A////AP///wD///9R////9v///8P///8A////AP///wD///8A////AP///wD///8A////AP///wH////T////+P///1f///8A////AP///wD///8A////Uf////b////D////AP///wD///8A////AP///wD///8A////AP///wD///8B", + "////0/////j///9X////AP///wD///8A////AP///1H////2////w////wD///8A////AP///wD///8A////AP///wD///8A////Af///9P////4////V////wD///8A////AP///wD///9R////9v///8P///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///9V/////////5P///8A////AP///wD///8A////sP////X///+1/////////0n///8A////AP///wD///8A////AP///wD///8A/////////7j///8A////AP///wD///8A////AP///wD///+4/////////wD///8A////AP///wD///8A////AP///wD///8A////AP////////+4", + "////AP///wD///8A////AP///wD///8A////uP////////8A////AP///wD///8A////AP///wD///8A////AP///wD/////////uP///wD///8A////AP///wD///8A////AP///7j/////////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////7j///8A////AP///wD///8A////AP///wD///+4/////////wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8T////8////8b///8A////AP///wD///8D////2P///+P///8I////AP///wD///8A////AP///wD///8A////AP///wD////////////////////3////1f///57///8e////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////+v///7X///8A", + "////AP///wD///8H////3v///9T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///xL////B////yP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////K////wv///xL///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD////B////rf///wv///8M////r////8H///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////r////Kf///wD///9F////2f///9P///8h////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///8T///+N", + "////AP///4/////A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Wf///+r////n////U////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///++/////////zH///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Ev///8H////I////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////K", + "////wv///xL///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///8H///+t////C////wz///+v////wf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////E////jf///wD///+P////wP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8S////wf///8j///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////K////wv///xL///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////wf///63///8L////DP///6/////B", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///8T///+N////AP///4/////A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///6j///96////Bv///3j/////////Uf///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///+v///8p////AP///0X////Z////0////yH///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8S////wf///8j///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////yv///8L///8S", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////B////rf///wv///8M////r////8H///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////r////Kf///wD///9F////2f///9P///8h////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///8T///+N////AP///4/////A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///xL////B////yP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////yv///8L///8S////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD////B////rf///wv///8M////r////8H///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///8T///+N////AP///4/////A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wH////e////zv///wD///8A////AP///8j////m", + "////A////wD///8A////AP///wD///8A////AP///wD///8A////AP/////////V////AP///wD///8A////AP///xz/////////y////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Af///97////O////AP///wD///8A////yP///+b///8D////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", @@ -918,38 +3897,44 @@ const char* CAF_FIXED_ATLAS_FONT_12_PT_TEXTURE_IMAGE[] = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////9P///8L///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///1/////J////AP///3////+h////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////8////3b///8A/////////xT///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////L///9C////AP///0X////u////AP///0f////n////Cv///wD///8A////AP///wD///8A////AP///wD///8A////9f///3////8A////AP///3n////y////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///9P////L////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///8z////S////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////9v////////8n////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///85/////////yP///8A", + "////AP///5H////H////AP///wD///8A////AP///wD///8A////AP///wD///8A////hP/////////B/////////6L///+h////4v///2H///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///3v////1////ef///4D////3////a////wD///8A////AP///2X/////////Tv///wD///8A////AP///wD///8A", + "////AP///wD///8A////kP////////+/////eP///7H/////////kv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///3z/////////RP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Rf////////97////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////VP////n///8W////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////f////+X///8G////AP///wj////o////cf///wD///8A////AP///wD///8A////AP///wD///8A////AP///57///94////Af////z///9g////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8R////B////wD///8A////AP///5z////e////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////CP///wD///8A////AP///wD///+N////7f///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///xj////n////cf///+////9g////AP///wD///8A////AP///wD///8A////AP///wD///+/////kv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////N/////////90////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8N////8P///2b///8A////AP///wD///8A////AP///wD///8A////AP///wD////u////iv///wD///8A////AP///4z////t////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////0f///5n///8A////AP///wD////J////if///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9S////9////1H///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///zf/////////cP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////Bf///77////3////mP///5z////5////rP///wH///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///97/////v////7///+k////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+9////+P///6r///9+////0/////////9Z////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////wf////3///+4////hv///4T////f/////////17///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8Z////8P////n///+k////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+c", + "////+////4z///+M////jP///4z///+M////Av///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///zf////1////8v///5v///94////iv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///4z///+M////jP///4z///+M////jP///+r////t////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///9d/////////9////+T////l////+H/////////Xf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////G/////D////p////hv///6H////8////uv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////0P///87///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////w////+D///+d", + "////hP///87/////////Yv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+F////2f///w3///8A////AP///wD///8A////AP///wD///8A////X/////v///8r////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///17//////////////2H///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A/////////9X///9o////aP///4P///+4////7/////7///9V////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8R////rP/////////W////lf///3T///+W////5P///6P///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////1f///2j///9r", + "////j////8j/////////x////yD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////9X///9o////aP///2j///9o////aP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP/////////V////aP///2j///9o////aP///2j///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////Cv///4/////9////4P///6L///91////eP///6j////v////af///wD///8A////AP///wD///8A////AP///wD///8A/////////7j///8A////AP///wD///8A////AP///wD///+4/////////wD///8A////AP///wD///8A////AP///wD///8A////AP///wT///82/////////83///8l", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////uP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////7j///8A////AP///wD///8Q////2f///+X///8a////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP////////+4////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////9v////////8u////AP///wD///8A////AP///wD///8U////+/////b/////////AP///wD///8A////AP///wD///8A///////////////f////Bv///wD///8A", + "////AP///wD///+4/////////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8o////1P////7///+6////hP///4H///+4/////v///8r///8f////AP///wD///8A////AP///wD///8A////AP///wD/////////1f///2j///+B////x/////z////9////PP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////0f////r///8B////AP///wD///8A////AP///wD///8A////Av////v////L////AP///wD///8A////AP///wD///8A////AP/////////V////aP///3H///+Z////9P////z///88////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////UP////7////p////nP///3f///+d", + "////6v///3L///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////aP///2j///9o////aP/////////V////aP///2j///9o////aP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////+4////AP///wD///8A////AP///wD///8A////uP////////8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////uv////3///8Y////AP///wD///8A////AP///wD///8a/////v///7n///8A////AP///wD///8A////AP///wD///8A////AP///9j////y////BP///wD///8A////AP///wD////X/////////87///8A////AP///wD///8A////Bv////X////V////AP///wD///9K/////////47///8A////AP///wD///8A", + "////e/////////9J////AP///wD///8A////AP///wD///8A////AP///wD///8A////hP////////9S////AP///wD///8A////AP///1z/////////dP///wD///8A////AP///wD///8A////AP///wD///8A////aP///2j///9o////aP///2j///91/////v///9f///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP////////+w////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////pf////L///8M////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+w/////////wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///3v////k////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///yP////z////Iv///wH///98////4/////f////M////Hv///wD///+v////j////wD///8A////AP///wD///8A////AP///wD///8A////nf///8H////C////oP///wD///8A////AP///wD///8A////AP///wD///8A", - "/////////3T///8A////AP///wD///8A////u////+b///8A////AP///wD///8A////AP///wD///8A////AP///xT////u////sv///wj///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////dP///wD///8A////AP///wL///+e////9f///x7///8A////AP///wD///8A////AP///wD///8A", - "/////////3T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////90////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8O////4////7v///8O////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "/////////3T///8A////AP///wD///8A////dP////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8g/////////1T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////dP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "/////////3T///8A////AP///4H////r////JP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////90////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////mP////v///8R////AP///wD///8A////CP////L///+M/////////wD///8A////AP///wD///8A", - "/////////4v////8////Mv///wD///8A////AP///3T/////////AP///wD///8A////AP///wD///8A////AP///zP/////////cP///wD///8A////AP///wD///9t/////f///yn///8A////AP///wD///8A////AP///wD/////////dP///wD///8A////A////+T////Y////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////8f///5j///8A////AP///wD///8A////AP///wD///+Y////7v///wD///8A////AP///wD///8A////AP////////90////AP///wD///8A////wf///9n///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////5v///6f///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8g/////////1T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////90////AP///wD///8A////AP///3T/////////AP///wD///8A////AP///wD///8A////AP///wD///8A////af////z///8T////AP///wD///8A////E/////z///9p////AP///wD///8A////AP///wD///8A", - "////AP///6L////Y////AP///wD///8A////1P///4T////M////AP///wD///8A////2v///5////8A////AP///wD///8A////vv///8j///8B////AP///7f////A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///8b////A////AP///wD///8A////l////+H///8H////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///97////8P///xr///8A////AP///wD///8A////AP///wD///8A////AP////////9s////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////N/////////8t////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///2z/////////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////av///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////a/////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP////////9s////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////y////kv///wD///8A////lP///+7///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////bP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////2z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////bP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "/////////2z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////97////AP///wD///8A////qf///+H///8A////AP///wD///8A////AP///wD///8A////AP///wD////j////q////wD///8A////AP///4D/////////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8G////4v///2z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////sP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+w/////////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////Z////2P///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////U////8P///wT///8A////BP////D////L////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD/////////sP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Bf///9j///+T////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "/////////7D///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////sP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////7D///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8B////3P///43///8A////AP///4j////l////A////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///xT/////////Xf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////8s////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Xf////////8I////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//////////////O////wD///8A////AP///3L/////////hP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+D/////////3b///8B////AP///wD///9I//////////////8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Hf///zz///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9F/////////27///8A", + "////AP///wD///9r/////////0z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////sP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP////////9k////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////sP////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", @@ -960,39 +3945,47 @@ const char* CAF_FIXED_ATLAS_FONT_12_PT_TEXTURE_IMAGE[] = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///2z////b///////////////u////pv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////1////h////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////Av///9v///+E////AP///wD///+l////uf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////bf////3///+v////Pf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wz////W////Nv///wD///8A////AP///wD///8A////N////9b///8M////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////DP///9b///82////AP///wD///8A////AP///wD///83////1v///wz///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wj///8B////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////9s////AP///wD///8A////bP////////8A////AP///wD///8A////AP///wD///8A////AP///wD////f////////////////////8P///wD////w////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////8g////AP///wD///98////u////wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD/////////IP///wD///8A////fP///7v///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Gf///4n///+u////AP///wD///98////u////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///53////B////wv///6D///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+d////wf///8L///+g////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////nf///8H////C////oP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///53////B////wv///6D///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+d////wf///8L///+g////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////nf///8H////C////oP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wb////l////av///wD/////////dP///wD///8A////AP///wD///8A////AP///+7///+c////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////dP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "/////////3T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////90////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////dP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///yD/////////VP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8g/////////1T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////IP////////9U////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///yD/////////VP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////dP///wD///8A////AP///wL///+e////9f///x7///8A////AP///wD///8A////AP///wD/////////i/////z///8y////AP///wD///8A////dP////////8A////AP///wD///8A////AP///wD///8A", - "////M/////////9w////AP///wD///8A////AP///23////9////Kf///wD///8A////AP///wD///8A////AP///zP/////////cP///wD///8A////AP///wD///9t/////f///yn///8A////AP///wD///8A////AP///wD///8z/////////3D///8A////AP///wD///8A////bf////3///8p////AP///wD///8A////AP///wD///8A", - "////M/////////9w////AP///wD///8A////AP///23////9////Kf///wD///8A////AP///wD///8A////AP///zP/////////cP///wD///8A////AP///wD///9t/////f///yn///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////pf///+r///8H////AP///wD///83/////f///1P/////////m////wD///8A////AP///wD///8A////AP////////90////AP///wD///8A////AP///3T/////////AP///wD///8A////AP///wD///8A////AP///wD/////////dP///wD///8A////AP///wD///90/////////wD///8A////AP///wD///8A////AP///wD///8A", - "/////////3T///8A////AP///wD///8A////dP////////8A////AP///wD///8A////AP///wD///8A////AP////////90////AP///wD///8A////AP///3T/////////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///8b////A////AP///wD///8A////l////+H///8H////AP///wD///8A////AP///wD///8A", - "////////////////////6////8f///9g////Af///wD///8A////AP///wD///8A////AP///wD///8A////AP////////9s////AP///wD///8U////0////6f///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////A////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////2v///7P///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///6f///+A////Cf///5/////O////Af///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8D////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////A////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////C////7v///y////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////53///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////kf////////+z////gP///8n///9P////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////R/////////92////AP///wD///8A////AP///4X/////////Nf///wD///8A////AP///wD///8A////AP///wD///8A////AP////////9k////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////7v///7L///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Tv///+7///+g", + "////Uv///x7///8e////Uv///6D////u////Tf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9O////7v///6D///9S", + "////Hv///x7///9S////oP///+7///9N////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////+w////AP///wD///8A////AP///7D/////////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD////1//////////////////////////////8c////HP////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8B////3P///43///8A////AP///4j////l////A////wD///8A////AP///wD///8A////AP///wD/////////e////wD///8A////AP///6n////h////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wH////c////jf///wD///8A////iP///+X///8D////AP///wD///8A////AP///wD///8A////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///99////0f////P///9U////AP///wD///8A////HP////X///9i////AP///wD///8A////AP///wD///8A////AP///wD///8A////ff///9H////z////VP///wD///8A////AP///xz////1", + "////Yv///wD///8A////AP///wD///8A////AP///wD///8A////AP///4P///9i////Lf///53////r////AP///wD///8A////AP///5H////b////Bv///wD///8A////AP///wD///8A////AP///wD///8A////AP///zD////x////xv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///9e//////////////9h////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Xv//////////////Yf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///17//////////////2H///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9e//////////////9h////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Xv//////////////Yf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///17//////////////2H///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////nf///+z///9o/////////9X///9o////aP///2j///9o////aP///wD///8A////AP///+7////l////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD/////////1f///2j///9o////aP///2j///9o////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////9X///9o////aP///2j///9o////aP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP/////////V", + "////aP///2j///9o////aP///2j///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////1f///2j///9o////aP///2j///9o////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////BP///zb/////////zf///yX///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wT///82/////////83///8l////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8E////Nv/////////N////Jf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////BP///zb/////", + "////zf///yX///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////1f///2j///9r////j////8j/////////x////yD///8A////AP///wD///8A////AP///wD///8A////AP///wD//////////////9////8G////AP///wD///8A////AP///7j/////////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///yj////U/////v///7r///+E////gf///7j////+////yv///x////8A////AP///wD///8A////AP///wD///8A////AP///wD///8o////1P////7///+6////hP///4H///+4/////v///8r///8f////AP///wD///8A////AP///wD///8A////AP///wD///8A////KP///9T////+", + "////uv///4T///+B////uP////7////K////H////wD///8A////AP///wD///8A////AP///wD///8A////AP///yj////U/////v///7r///+E////gf///7j////+////yv///x////8A////AP///wD///8A////AP///wD///8A////AP///wD///8o////1P////7///+6////hP///4H///+4/////v///8r///8f////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Af///9P////4////V////wD///8A////AP///x3////0/////////7f///8A////AP///wD///8A////AP///wD///8A////AP////////+4////AP///wD///8A", + "////AP///wD///8A////uP////////8A////AP///wD///8A////AP///wD///8A////AP///wD/////////uP///wD///8A////AP///wD///8A////AP///7j/////////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////7j///8A////AP///wD///8A////AP///wD///+4/////////wD///8A////AP///wD///8A", + "////AP///wD///8A////AP////////+4////AP///wD///8A////AP///wD///8A////uP////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////hP////////9S////AP///wD///8A////AP///1z/////////dP///wD///8A////AP///wD///8A////AP///wD///8A/////////7j///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///9L////k////Cf///wD///8A////Av///9P////n////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///xH////R////9////yX///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////Jv////f////P////EP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Ev///9z////E////xf///9z///8S////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////rP///7z///+V////+////5b///+8", + "////p////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////E////i////wD///+P////zv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///+n///89////Qv///+X///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////b/////////+X////C////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Ef///9H////3////Jf///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Jv////f////P////EP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8S////3P///8T////F////3P///xL///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////xP///4v///8A////j////87///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8R////0f////f///8l////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Jv////f////P////EP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///xL////c////xP///8X////c////Ev///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////E////i////wD///+P////zv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///9I////4f///+X/////////hf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+s////vP///5X////7////lv///7z///+n////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8R////0f////f///8l////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///yb////3////z////xD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Ev///9z////E////xf///9z///8S////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////rP///7z///+V////+////5b///+8////p////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////E////i////wD///+P////zv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///xH////R////9////yX///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///yb////3////z////xD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Ev///9z////E////xf///9z///8S////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////E////i////wD///+P////zv///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///9F/////////27///8A////AP///wD///9r/////////0z///8A////AP///wD///8A////AP///wD///8A////AP///wD//////////////zv///8A////AP///wD///9y/////////4T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///0X/////", + "////bv///wD///8A////AP///2v/////////TP///wD///8A////AP///wD///8A////AP///wD///8A////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", @@ -1003,38 +3996,48 @@ const char* CAF_FIXED_ATLAS_FONT_12_PT_TEXTURE_IMAGE[] = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", - "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////n////O////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///85////7v///wD///9Z////x////wD///8A////AP///wD///8A////AP///wD///8A////AP///6z////n////cf////////9a////gP///1L///8A////AP///wD///8A////AP///wD///8A////AP///wD///+8////pv///yP///+q////sf///wD///8A////wP///3f///8A////AP///wD///8A////AP///wD///8A", - "////AP///7v////h////Wf///0r////c////uv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+c////8////wH///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wH////0////m////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////3/////////Nf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////E/////////9J////AP///wD///9r////7f///wD///8A////AP///wD///8A////AP///wD///8A////AP///wP///90////1v/////////3////1////6j///9K////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8F", + "////j////+b////i////gv///wL///8A////AP///wD///8B////w////+L///8M////AP///wD///8A////AP///wD///8A////AP///wf///9/////2v////b////e////h////wn///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8x/////////47///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///47/////////MP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wT////m////ef///wD///8A////AP///wD///8A////AP///wD///8A////AP///yH////w////p////0z///+s////6P///xf///8A////AP///wD///8A////AP///wD///8A////AP///wD///83////1v///63////3////YP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////uP///9r///9v////RP///3r////7////ff///wD///8A////AP///wD///8A////AP///wD///8A////AP///7f////A////Zv///0L///9y////9v///5n///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////QP///+/////z////YP///wD///8A////AP///wD///8A////AP///wD///8A", - "////rP///7////9M////TP///0z///9M////Df///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+U/////P///5P///9K////R////w7///8A////AP///wD///8A////AP///wD///8A////AP///wD///9M////TP///0z///9M////TP///7r////V////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////nP////L///99////Sf///37////z////mv///wD///8A////AP///wD///8A////AP///wD///8A////AP///2X////6////eP///0j///+m////8f///xj///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////VP////f///9T////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///5j///+G////UP///2b////u////kf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////iP///8b///8Z////AP///wD///8A////AP///wD///9V////7f///xX///8A////AP///wD///8A", - "////AP///wD///8A////AP///zv////7////+////z7///8A////AP///wD///8A////AP///wD///8A////AP////////+O////MP///zX///9f////l/////////+Q////AP///wD///8A////AP///wD///8A////AP///wD///8A////Tf///+7////R////af///z3///9R////kP///3v///8A////AP///wD///8A////AP///wD///8A", - "/////////47///8w////Pf///2T////I////9////2H///8A////AP///wD///8A////AP///wD///8A////AP////////+O////MP///zD///8w////MP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////jv///zD///8w////MP///zD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///zr////e////4f///3X///9J////OP///1z///+f////Vv///wD///8A////AP///wD///8A////AP////////90////AP///wD///8A////AP///3T/////////AP///wD///8A////AP///wD///8A////AP///wD///8A////KP////////9c////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A/////////3T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////90////AP///wD///8A////p////9v///8U////AP///wD///8A////AP///wD///8A////AP///wD/////////dP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "/////////9z///+8////AP///wD///8A////AP///wD///+n////2f////////8A////AP///wD///8A////AP/////////2////n////wD///8A////AP///wD///90/////////wD///8A////AP///wD///8A////AP///wD///8A////jP////7///+V////Tf///0r///+R/////f///33///8A////AP///wD///8A////AP///wD///8A", - "/////////47///8y////ZP///7D/////////cv///wD///8A////AP///wD///8A////AP///wD///8A////AP///9L///+y////AP///wD///8A////AP///wD///8A////s////8z///8A////AP///wD///8A////AP///wD/////////jv///zH///9F////m/////////90////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///4r////6////hf///0H///9R////kv///1n///8A////AP///wD///8A////AP///wD///8A////AP///zD///8w////Sv////////90////MP///zD///8Y////AP///wD///8A////AP///wD///8A////AP///wD/////////dP///wD///8A////AP///wD///90/////////wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///7/////B////AP///wD///8A////AP///wD////C////v////wD///8A////AP///wD///8A////AP///wD////h////oP///wD///8A////AP///5v////f////lf///wD///8A////AP///6H////f////AP///wD///8A////Wf////3///8z////AP///wD///8m////+f///1n///8A////AP///wD///8A////AP///wD///8A", - "////AP///1H/////////Pf///wD///8A////AP///xz////4////cf///wD///8A////AP///wD///8A////AP///zD///8w////MP///zD///8w////NP///+T///+x////AP///wD///8A////AP///wD///8A////AP///wD/////////bP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///6H////D////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9s/////////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "/////////2z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///2z/////////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////t////dv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////6f///43///8A////AP///4z////o////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "/////////2z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wX////b////Wf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////9s////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "/////////2z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////9s////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////r////wD///8A////AP///9v///+1////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////uP///97///8A////AP///wD///+6/////////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///4r///9o////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Q/////////8s////AP///wD///8o/////////0v///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////2z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////LP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///2z/////////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "////AP///wD///8A////z////9f///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8O////mf///9/////c////kf///wf///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///1z////5////pP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////Cf///3z////Z////9v///9H///9d////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///w////95////zf////T////t////xP///1H///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///2v/////////pP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////h////////////////////////////////////wT///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Hf///57////W////+f///+X///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD//////////////////////////////////////////////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///0z///++////7f///+/////C////T////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8l////tP///+z////b", + "////jf///wb///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///0T///+o////3f////P////N////Xv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Df///9L////X////KP///wD///8A////AP///wD///8A////R////+z///+N////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8J////8P////L///8L////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP/////////////////////////y////3f///6n///9C////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9b////pv///9b////3", + "////4f///7f///9e////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////////////////v///+D///+0////bf///wP///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////////////////////////////////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD/////////////////////////////////////////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////N////5f////D////7v////H////a////pf///0f///8A////AP///wD///8A////AP///wD///8A////AP////////+4////AP///wD///8A////AP///wD///8A", + "////uP////////8A////AP///wD///8A////AP///wD///8A////AP///wD///+W/////////////////////////07///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////7j///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP////////+4////AP///wD///8A////AP///yj////w////y////wn///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////uP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A///////////////Z////AP///wD///8A////AP///wD///8A", + "////AP///7j//////////////wD///8A////AP///wD///8A////AP//////////////X////wD///8A////AP///wD///8A////uP////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wr///9+////tv///+b////o////tv///3r///8G////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////////////////////+P///9n///+o////Mf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///7D/////////Kf///wD///8A////AP///wD///8A////AP///yn/////////qP///wD///8A////AP///wD///8A////AP///wD////////////////////3////2////6r///8z////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9D////uv///+j////1////2v///6v///9I////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////////////////////////////////////////////////////8A////AP///wD///8A////AP///wD///8A////AP///wD////8", + "////tf///wD///8A////AP///wD///8A////AP///7j/////////AP///wD///8A////AP///wD///8A////AP///wD///8A////F/////z///+/////AP///wD///8A////AP///wD///8A////AP///8P////8////Fv///wD///8A////AP///wD///8A////AP///x3/////////tf///wD///8A////AP///wD///8A////kP////////+K", + "////AP///wD///8A////AP///wD///+5/////////xz///8M////4f///97///8K////AP///wD///8A////AP///wX////R////4f///wz///8A////AP///wD///8A////AP///wD///8A////EP////H////b////Av///wD///8A////AP///wD///8D////2P///+3///8P////AP///wD///8A////AP///wD///8A////AP//////////", + "////////////////////////////////////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////sP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////FP////j///+X////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////sP////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A/////////7D///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////sP////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////h/////////+Z////cv///2X///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////av////////+p////Uv///6b/////////uP///zv///8C////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////7D///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wX////Y////pP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////+w////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////7D///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP////////+w////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////0P////D///+U////ef///9L/////////5f///w////8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////Dv///+P/////////1f///3r///+Z////9P///8//////////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////qf////r///8U////AP///wD///8A////E/////n///+t////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A/////////7D///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////ZP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///7D/////////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", @@ -1046,38 +4049,44 @@ const char* CAF_FIXED_ATLAS_FONT_12_PT_TEXTURE_IMAGE[] = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////zv///8v///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////9c////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////sf///+v///9Y////SP///4b///87////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///1L////9////Hv///wD///8A////L/////////87////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///+b///+B////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////LP///9v///9v////Fv///wD///8W////cP///9v///8s////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////+Y////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wv///+X////6f///+r///+2", + "////M////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///8L////y////D////wD///8A////AP///wD///8S////8f///7z///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD/////////ZP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///6r////9////nf///3P///+I////xv///37///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8V////ev///8v////u////7v///8v///96////Ff///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8s////2////2////8W////AP///xb///9w////2////yz///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///xX///96////y////+7////u////y////3r///8V////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////bP///wD///8A////AP///2z/////////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////+P////////////////////D///8A////8P///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////", + "////sP///wD///8A////AP///wD///+w/////////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////1///////////////////////////////HP///xz/////////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////qf///2z////4////IP///wD///8A////B////9r///9W////AP///wD///8A////AP///wD///8A////AP///6n///9s////+P///yD///8A////AP///wf////a////Vv///wD///8A////AP///wD///8A////AP///wD///9L////Mv///wP///9V////7P///wD///8A////B////9r///9W////AP///wD///8A////AP///wD///8A", - "////AP///wD////K////z////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///87////+/////v///8+////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////O/////v////7////Pv///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///zv////7////+////z7///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///87////+/////v///8+////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////O/////v////7////Pv///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///zv////7////+////z7///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////d////9r///8w/////////47///8w////MP///zD///8w////AP///wD////s////nf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "/////////47///8w////MP///zD///8w////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////+O////MP///zD///8w////MP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////jv///zD///8w////MP///zD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "/////////47///8w////MP///zD///8w////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8o/////////1z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////KP////////9c////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///yj/////////XP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8o/////////1z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////47///8w////Pf///2T////I////9////2H///8A////AP///wD///8A////AP///wD///8A", - "//////////b///+f////AP///wD///8A////AP///3T/////////AP///wD///8A////AP///wD///8A////AP///wD///+M/////v///5X///9N////Sv///5H////9////ff///wD///8A////AP///wD///8A////AP///wD///8A////jP////7///+V////Tf///0r///+R/////f///33///8A////AP///wD///8A////AP///wD///8A", - "////AP///4z////+////lf///03///9K////kf////3///99////AP///wD///8A////AP///wD///8A////AP///wD///+M/////v///5X///9N////Sv///5H////9////ff///wD///8A////AP///wD///8A////AP///wD///8A////jP////7///+V////Tf///0r///+R/////f///33///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///zP/////////cP///wD///8A////AP///5/////z////+////yb///8A////AP///wD///8A////AP///wD/////////dP///wD///8A////AP///wD///90/////////wD///8A////AP///wD///8A////AP///wD///8A", - "/////////3T///8A////AP///wD///8A////dP////////8A////AP///wD///8A////AP///wD///8A////AP////////90////AP///wD///8A////AP///3T/////////AP///wD///8A////AP///wD///8A////AP///wD/////////dP///wD///8A////AP///wD///90/////////wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///1H/////////Pf///wD///8A////AP///xz////4////cf///wD///8A////AP///wD///8A////AP////////90////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////m////hP///wD///8A////AP///33////w////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////YP///9b///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///9b///9g////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///8v///9h////AP///2P////J////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///+X///8F////A////5n////k////M////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////yv///1L///8A////VP///8f///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///1n////c////2v///1P///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///6r////s////Af///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9g////1v///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////1v///2D///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////L////Yf///wD///9j////yf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////yv///1L///8A////VP///8f///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///2D////W////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///9b///9g////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////L////Yf///wD///9j////yf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////yv///1L///8A////VP///8f///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///84////vv///+f////z////Kf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////5f///wX///8D////mf///+T///8z////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////YP///9b///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///9b///9g////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////y////2H///8A////Y////8n///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///+X///8F////A////5n////k////M////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////K////Uv///wD///9U////x////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////YP///9b///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////W////YP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///8v///9h////AP///2P////J////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////K////Uv///wD///9U////x////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Q/////////8s////AP///wD///8o/////////0v///8A////AP///wD///8A////AP///wD///8A", - "/////////6////8A////AP///wD////b////tf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9D/////////yz///8A////AP///yj/////////S////wD///8A////AP///wD///8A////AP///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///3D////+////VP///wD///8A////AP///wD///9+////6P///w3///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///9w/////v///1T///8A////AP///wD///8A////fv///+j///8N////AP///wD///8A////AP///wD///8A////AP///wD///9m////1/////j////W////T////wD///8A////AP///wD///8R////7P///3b///8A////AP///wD///8A////AP///wD///8A////AP///wD///8v", + "////7v///8L///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Cf////D////y////C////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wn////w////8v///wv///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8J////8P////L///8L////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Cf////D////y////C////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wn////w////8v///wv///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9j//////////////9e////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///yr////+////////////////////////////////", + "//////////////8A////AP///wD////K/////v///wj///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////////////////////////////////////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//////////////////////////", + "//////////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////////////////////////////////////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////////////////////////////////////wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///5b/////////////////////////Tv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+W/////////////////////////07///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////lv////////////////////////9O", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///5b/////////////////////////Tv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////////////////v///+D///+0////bf///wP///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A//////////////9f////AP///wD///8A////AP///wD///+4/////////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Cv///37///+2////5v///+j///+2////ev///wb///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wr///9+////tv///+b////o", + "////tv///3r///8G////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8K////fv///7b////m////6P///7b///96////Bv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Cv///37///+2////5v///+j///+2////ev///wb///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wr///9+////tv///+b////o////tv///3r///8G////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8o////1P////7///+6////hP///3f///+t", + "////+/////////9r////AP///wD///8A////AP///wD///8A////AP///wD////8////tf///wD///8A////AP///wD///8A////AP///7j/////////AP///wD///8A////AP///wD///8A////AP///wD///8A/////P///7X///8A////AP///wD///8A////AP///wD///+4/////////wD///8A////AP///wD///8A////AP///wD///8A", + "////AP////z///+1////AP///wD///8A////AP///wD///8A////uP////////8A////AP///wD///8A////AP///wD///8A////AP///wD////8////tf///wD///8A////AP///wD///8A////AP///7j/////////AP///wD///8A////AP///wD///8A////AP///wD///8A////EP////H////b////Av///wD///8A////AP///wD///8D", + "////2P///+3///8P////AP///wD///8A////AP///wD///8A////AP////////+4////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9t/////////83///94////c////73/////////jP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///+//////////4L///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+C/////////73///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///80/////f////3///80////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///yX////T////2////0b///8A////LP///+j///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD////o////P////0L////m////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wL///+7//////////T///+l////hP///7H///+R////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///7//////////gv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+C/////////73///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///zT////9/////f///zT///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////v/////////+C////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///+C/////////73///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////NP////3////9////NP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////S////9f////2////7P///87///9K////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Jf///9P////b////Rv///wD///8s////6P///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////v/////////+C////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////gv////////+9////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///80", + "/////f////3///80////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///yX////T////2////0b///8A////LP///+j///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+//////////4L///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////gv////////+9////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///80/////f////3///80////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////qf////r///8U////AP///wD///8A////E/////n///+t////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////9j////w////lP///3n////S", + "/////////+X///8P////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+p////+v///xT///8A////AP///wD///8T////+f///63///8A////AP///wD///8A////AP///wD///8A////AP///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", @@ -1088,38 +4097,48 @@ const char* CAF_FIXED_ATLAS_FONT_12_PT_TEXTURE_IMAGE[] = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", - "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////+////2v///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////E/////////8V////M////+3///8A////AP///wD///8A////AP///wD///8A////AP///wD///8M////iP///9v/////////8f///8r///9j////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////KP///8j////z////wP///x////8A////AP///zv////t////D////wD///8A////AP///wD///8A////AP///wD///8c////rP///+z////w////sf///x3///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////Wf////////8t////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8t/////////1j///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////", + "////SP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///8/////v////Cv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wn////u////z////wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////gf///+D///8C////AP///wD///8A////AP///wD///8A////AP///wD///8A////PP///8D////v////u////y7///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wf///+I/////P///2D///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///xf///+O////3v////f////Z////df///wP///8A////AP///wD///8A////AP///wD///8A////AP///wD///8q////n////+T////4////2v///4b///8K////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///96/////////2D///8A////AP///wD///8A////AP///wD///8A////AP///5n//////////////////////////////yz///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Av///2L////I////8f////L///8e////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "/////////////////////////////////////////wD///8A////AP///wD///8A////AP///wD///8A////AP///wf///+E////3f////f////d////hf///wf///8A////AP///wD///8A////AP///wD///8A////AP///wD///8B////av///9X////x////vf///yn///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9n////xP////D////k////kf///wv///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wT///+F////5////3P///9A////HP///0H///+Y////7v///03///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////2P///9v///8A////AP///wD///8A////AP///wD///8A////AP///wD////////////////////9////6v///8r///9x////A////wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8b////l////8j////z////7P///8v///92////AP///wD///8A////AP///wD///8A////AP////////////////////j////S////ov///yX///8A////AP///wD///8A////AP///wD///8A////AP///wD///////////////////////////////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////////////////////////////////////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Cf///3n///+3////4P////j////l////vv///17///8A////AP///wD///8A////AP///wD/////////dP///wD///8A////AP///wD///90/////////wD///8A////AP///wD///8A////AP///wD///8A", - "////Zv////z//////////////5f///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////90////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////dP///wD///8A////AP///wj////H////x////wn///8A////AP///wD///8A////AP///wD///8A", - "/////////3T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP//////////////bP///wD///8A////AP///wD///8A////Uv//////////////AP///wD///8A////AP///wD/////////8////xn///8A////AP///wD///8A////dP////////8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///9V////s////+X////n////sv///03///8A////AP///wD///8A////AP///wD///8A////AP///////////////////+v////H////Yv///wH///8A////AP///wD///8A////AP///wD///8A////AP///wD///+l////6v///wf///8A////AP///wD///8A////Bv///+r///+d////AP///wD///8A////AP///wD///8A", - "////////////////////7P///8r///9k////Af///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8E////eP///9b////2////6f///8b///9d////AP///wD///8A////AP///wD///8A////AP///wD/////////////////////////////////////////gP///wD///8A////AP///wD///8A////AP///wD///8A", - "/////P///3L///8A////AP///wD///8A////dP////////8A////AP///wD///8A////AP///wD///8A////AP///xf////9////c////wD///8A////AP///wD///8A////c/////3///8X////AP///wD///8A////AP///wD///8g/////////2j///8A////AP///wD///9h/////////1////8A////AP///wD///9o/////////x////8A", - "////Df///+X///+Y////AP///wD///8A////AP///4j////l////Df///wD///8A////AP///wD///8A////AP///wP////X////uf///wD///8A////AP///wD///8A////kf///+z///8O////AP///wD///8A////AP///wD//////////////////////////////////////////////wD///8A////AP///wD///8A////AP///wD///8A", - "/////////2z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///xP////3////Wf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////bP////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////9s////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///9s/////////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////vf///87///87////PP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///53////g////Pf///zv////f////uf///xH///8A////AP///wD///8A////AP///wD///8A////AP////////9s////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8E////3v///2T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD/////////bP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////9s////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////bP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "/////////+z///97////Rv///7X/////////SP///wD///8A////AP///wD///8A////AP///wD///8A////AP///0f/////////vv///0f///+F////7v////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///6j////M////AP///wD///8A////AP///8j///+t////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////9s////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "/////////yz///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9s/////////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8J////oP////P///+s////eP///03///9u////qv////3///+T////Cf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP////////+4////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9V/////////5P///8A////AP///wD///8A////AP///wD///+P/////////0j///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////7D///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///7D/////////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////+w////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///7D/////////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wz///+Z////6P////X///+3////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wH///9r////1P////n/////////////////////////JP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////+w////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////sP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP////////+w////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////sP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "/////////3T///9B////xP////T////g////o////xb///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8U////nv///97////0////wv///0D///9w/////////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////FP////n///+v////AP///wD///8A////AP///wD///+v////+v///xX///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///+////+/////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////2T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///+/////7v///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8AAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", @@ -1131,38 +4150,46 @@ const char* CAF_FIXED_ATLAS_FONT_12_PT_TEXTURE_IMAGE[] = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", - "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///8v////I////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////WP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///xb///+l////6////+/////F////Rf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////G////tP///wD///8A////AP///wD///+3////vv///wD///8A////AP///wD///8A////AP///wD///8A", - "/////////yz///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////O////xP///0z///8/////b////1z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8V////iP///9j////g////2P///4j///8V////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///xX///+I////2P///+D////Y////iP///xX///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "/////////2z///8A////AP///wD///9s/////////wD///8A////AP///wD///8A////AP///wD///8A////AP///+z////////////////////w////AP////D///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////2T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8K////hf///9n////2////5v///7z///9Y////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///xP///+h/////////yD///8A////AP///wD///9F////5P///w3///8A////AP///wD///8A////AP///wD///8T////of////////8g////AP///wD///8A////Rf///+T///8N////AP///wD///8A////AP///wD///8A", - "////eP///93////3////1////1L///8A////AP///wD///9F////5P///w3///8A////AP///wD///8A////AP///wD///8A////x////8z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///9j////b////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD////Y////2////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////2P///9v///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///9j////b////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD////Y////2////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9a//////////////9U////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///w/////y/////////////////////////////////////////wD///8A", - "////xf///8H///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///////////////////////////////////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///////////////////////////////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////////////////////////////////////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///////////////////////////////////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9m/////P//////////////l////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////Zv////z//////////////5f///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///2b////8//////////////+X////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9m/////P//////////////l////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP////////////////////j////S////ov///yX///8A////AP///wD///8A////AP///wD///8A////AP/////////z////Gf///wD///8A////AP///wD///90/////////wD///8A////AP///wD///8A////AP///wD///8A////AP///1X///+z////5f///+f///+y////Tf///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///9V////s////+X////n////sv///03///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Vf///7P////l////5////7L///9N////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///1X///+z////5f///+f///+y////Tf///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///9V////s////+X////n////sv///03///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////jP////7///+V////TP///0H///+Z/////////7H///8A////AP///wD///8A////AP///wD///8A", - "/////P///3L///8A////AP///wD///8A////dP////////8A////AP///wD///8A////AP///wD///8A////AP////z///9y////AP///wD///8A////AP///3T/////////AP///wD///8A////AP///wD///8A////AP///wD////8////cv///wD///8A////AP///wD///90/////////wD///8A////AP///wD///8A////AP///wD///8A", - "/////P///3L///8A////AP///wD///8A////dP////////8A////AP///wD///8A////AP///wD///8A////AP///wP////X////uf///wD///8A////AP///wD///8A////kf///+z///8O////AP///wD///8A////AP///wD/////////dP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////mv////D///9g////Nv///1f////k////tf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Mf////j///9W////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9W////+P///y7///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8n////8f///3D////x////JP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+5////cf///6n///+q////dP///7P///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///8n///9R////AP///1T////T////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD////h////EP///xX////e////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8s/////P///9b///9n////V////2X///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8x////+P///1b///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///1b////4////Lv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////J/////H///9w////8f///yT///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///8n///9R////AP///1T////T////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///zH////4////Vv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9W////+P///y7///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////J/////H///9w////8f///yT///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///8n///9R////AP///1T////T////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///2/////4////7v///2v///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///7n///9x////qf///6r///90////s////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Mf////j///9W////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9W////+P///y7///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///yf////x////cP////H///8k////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+5////cf///6n///+q////dP///7P///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////yf///1H///8A////VP///9P///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Mf////j///9W////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////Vv////j///8u////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8n////8f///3D////x////JP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////yf///1H///8A////VP///9P///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///6j////M////AP///wD///8A////AP///8j///+t////AP///wD///8A////AP///wD///8A////AP/////////u////e////0b///+1/////////0j///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////qP///8z///8A////AP///wD///8A////yP///63///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////7D///8A////AP///wD///8A////sP////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///6n//////////////////////////////xz///8c/////////wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////BP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////6f///z3///9C////5f///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////o/////////8/////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////BP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8E////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wr///9+////tv///+b////w////zf///3j////G////3f///wP///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///2P////K", + "////7/////L////P////c////wP///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8D////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////WP///+j////j////Uf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////A////2P////F////6v////X////a////j////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///5////+d////Hv///w3///9/////jP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wP///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8D////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////FP////n///+v////AP///wD///8A////AP///wD///+v", + "////+v///xX///8A////AP///wD///8A////AP///wD///8A////AP////////+q////Qf///8T////0////4P///6P///8W////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8U////+f///6////8A////AP///wD///8A////AP///6/////6////Ff///wD///8A////AP///wD///8A////AP///wD///8A", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", @@ -1175,8 +4202,9 @@ const char* CAF_FIXED_ATLAS_FONT_12_PT_TEXTURE_IMAGE[] = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A/////////xT///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wf////q////rf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////rf///+j///8G////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////0j///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9X/////////2b///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9i/////////1f///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", @@ -1184,28 +4212,35 @@ const char* CAF_FIXED_ATLAS_FONT_12_PT_TEXTURE_IMAGE[] = "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///z3///+Y////zP////P////P////mv///xv///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9L////jv///8X////y////0f///5////9B////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////dP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////M/////////9w////AP///wD///8A////AP///23////9////Kf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////uP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////9s////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///2z/////////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////bP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////bP////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///y/////M////9////8T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8O////mv///+f////////////////////9////Gf///wD///8A////AP///wD///8A////AP///wD/////////bP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////2z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////bP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "/////////2z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////9M////qf////P////Z////Yv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////YP///9j////z////pf///0n/////////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////Af///9P////4////V////wD///8A////AP///wD///9R////9v///8P///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///xT////5////bP///wD///8A////AP///wD///9o////+v///xX///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD////5////cf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////8s////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////cv////j///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP/////////P////ZP///2T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////ZP///2T////P/////////wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+u/////P///4H///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP////////9k////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+C/////P///6n///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", @@ -1218,37 +4253,45 @@ const char* CAF_FIXED_ATLAS_FONT_12_PT_TEXTURE_IMAGE[] = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////8s////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////I////67////r////9P///9L///9w////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////9k////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////9s////AP///wD///8A////bP////////8A////AP///wD///8A////AP///wD///8A////AP///wD////N////////////////////8P///wD////w////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8q/////P////////////////////////+G////hv////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////A////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////4f///xD///8V////3v///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///4z////4////H////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8S////wf///8j///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///8r////C////Ev///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////wf///63///8L////DP///6/////B", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///+v///8p////AP///0X////Z////0////yH///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////xP///43///8A////j////8D///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///+j///8/////Qv///+b///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///zv/////////vf///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///xL////B////yP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////K////wv///xL///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////B", + "////rf///wv///8M////r////8H///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////xP///43///8A////j////8D///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///xL////B////yP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////yv///8L///8S////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////B////rf///wv///8M////r////8H///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///8T///+N", + "////AP///4/////A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///+v///8p////AP///0X////Z////0////yH///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///xL////B////yP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////yv///8L///8S////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////B", + "////rf///wv///8M////r////8H///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////6////yn///8A////Rf///9n////T////If///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////E////jf///wD///+P////wP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////If///xr///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8S", + "////wf///8j///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////yv///8L///8S////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////B////rf///wv///8M////r////8H///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///8T///+N////AP///4/////A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///8r////C////Ev///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wP///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8D////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///9V////s////+X////w////xP///5P////1////E////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wr///+O////4f////j////k////m////xT///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///8/////e////Av///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////Av///97////M////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///4H/////////gf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////N////+X///+X////A////wb////j////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////4f///xX///8X////4P///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///zr////A////8P///+v///+m////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////z////97///8C////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8C////3v///8z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///+B/////////4H///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////P////3v///wL///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////Av///97////M////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+B/////////4H///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///+p////Pv///yv///+V////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///83////5f///5f///8D////Bv///+P///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///8/////e////Av///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////Av///97////M////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////gf////////+B////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////N////+X///+X////A////wb////j////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///8/////e////Av///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wL////e////zP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///4H/////////gf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///xT////5////bP///wD///8A////AP///wD///9o////+v///xX///8A////AP///wD///8A////AP///wD/////////dv///6n////z////2f///2L///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////FP////n///9s////AP///wD///8A////AP///2j////6////Ff///wD///8A////AP///wD///8A////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////r////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", @@ -1260,11 +4303,9 @@ const char* CAF_FIXED_ATLAS_FONT_12_PT_TEXTURE_IMAGE[] = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////8U////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////dv////////83////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////Nf////////9y////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///73////R////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////y////7////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", @@ -1273,24 +4314,34 @@ const char* CAF_FIXED_ATLAS_FONT_12_PT_TEXTURE_IMAGE[] = "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A/////////3T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+M/////v///5X///9N////Sv///5H////9////ff///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////hf///yz///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///yz///+F/////////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////7j///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8o////1P////7///+6////hP///4H///+4/////v///8r///8f////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////////////////////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP////////////////////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////w////8z///8/////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////LP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////P////83///+/////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////F////6j////t////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////ZP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////7f///6b///8V////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", @@ -1303,37 +4354,45 @@ const char* CAF_FIXED_ATLAS_FONT_12_PT_TEXTURE_IMAGE[] = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////LP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD/////////ZP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////bv////////////////////T///9A////9P///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///zj///+/////7f//////////////////////////////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////YP///9b///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////W////YP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///8v///9h////AP///2P////J////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///+X///8F////A////5n////k////M////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////yv///1L///8A////VP///8f///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///+H///8V////F////+D///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8U////7v///7L///8I////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///9g////1v///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////1v///2D///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////y////2H///8A////Y////8n///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///8r///9S////AP///1T////H////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////YP///9b///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///9b///9g////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////y////2H///8A////Y////8n///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///8r///9S////AP///1T////H////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD////l////Bf///wP///+Z////5P///zP///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9g////1v///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////1v///2D///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////y////2H///8A////Y////8n///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////5f///wX///8D////mf///+T///8z////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////K////Uv///wD///9U////x////wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Jv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9g////1v///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////1v///2D///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////y////2H///8A////Y////8n///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///8r///9S////AP///1T////H////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD////W////YP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///8A////A////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///1j////b////1////1H///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8R////0f////f///8l////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8m////9////8////8Q////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///xL////c////xP///8X////c////Ev///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+s////vP///5X////7////lv///7z///+n////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///8T///+L////AP///4/////O////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9Y////6P///+P///9R////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////rv////////+N////BP///wD///8A////AP///wX///8Q////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///xH////R////9////yX///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Jv////f////P", + "////EP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Ev///9z////E////xf///9z///8S////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///8T///+L////AP///4/////O////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///xH////R////9////yX///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///yb////3////z////xD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Ev///9z////E////xf///9z///8S", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////E////i////wD///+P////zv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///+s////vP///5X////7////lv///7z///+n////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///xH////R////9////yX///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///yb////3", + "////z////xD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Ev///9z////E////xf///9z///8S////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///6z///+8////lf////v///+W////vP///6f///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////xP///4v///8A////j////87///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8R////0f////f///8l////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///yb////3////z////xD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////Ev///9z////E////xf///9z///8S////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////E////i////wD///+P////zv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8m////9////8////8Q", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8D////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///8A////A////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "/////////2z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///8r////C////Ev///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////7D///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///8T///+N////AP///4/////A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", @@ -1347,7 +4406,6 @@ const char* CAF_FIXED_ATLAS_FONT_12_PT_TEXTURE_IMAGE[] = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wP////F////v////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///7z////G////Av///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", @@ -1358,24 +4416,33 @@ const char* CAF_FIXED_ATLAS_FONT_12_PT_TEXTURE_IMAGE[] = "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////90////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///1X///+z////5f///+f///+y////Tf///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////////////////////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///////////////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP////////+4////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wr///9+////tv///+b////o////tv///3r///8G////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wX////b////Wf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///yH///+x////7////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "/////////yz///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///+////+w////H////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wX////Y////k////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////2T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8AAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", @@ -1389,28 +4456,29 @@ const char* CAF_FIXED_ATLAS_FONT_12_PT_TEXTURE_IMAGE[] = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "/////////yz///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////2T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wX///+L////5v////////////////////////8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Mf////j///9W////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///8A////Vv////j///8u////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8n////8f///3D////x////JP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+5////cf///6n///+q////dP///7P///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///8n///9R////AP///1T////T////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///9Y////2////9f///9R////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///03////u////0f///2n///89////Uf///5D///97////AP///wD///8A////AP///wD///8A////AP///wD///8x////+P///1b///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///1b////4////Lv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///yf////x////cP////H///8k////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////J////Uf///wD///9U////0////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Mf////j///9W////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///9W////+P///y7///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///yf////x////cP////H///8k////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////J////Uf///wD///9U////0////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////uf///3H///+p////qv///3T///+z////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8x////+P///1b///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///1b////4////Lv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///yf////x////cP////H///8k////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///7n///9x////qf///6r///90////s////wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////yf///1H///8A////VP///9P///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8x////+P///1b///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///1b////4////Lv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///yf////x////cP////H///8k////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD////J////Uf///wD///9U////0////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Vv////j///8u////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////v/////////+C////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///4L/////////vf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////NP////3////9////NP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Jf///9P////b", + "////Rv///wD///8s////6P///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///xH///+s/////////9b///+V////dP///5b////k////o////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+//////////4L///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+C/////////73///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///80/////f////3///80////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+//////////4L///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////gv////////+9////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///80/////f////3///80////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Jf///9P////b////Rv///wD///8s////6P///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///+//////////4L///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////gv////////+9////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///80/////f////3///80////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8l////0////9v///9G////AP///yz////o////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////v/////////+C////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////gv////////+9////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///80/////f////3///80////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///4L/////////vf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", @@ -1418,7 +4486,14 @@ const char* CAF_FIXED_ATLAS_FONT_12_PT_TEXTURE_IMAGE[] = "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD////W////YP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////9s////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////K////Uv///wD///9U////x////wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8m////9////8////8Q", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////+w////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD////E////i////wD///+P////zv///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", @@ -1454,14 +4529,22 @@ const char* CAF_FIXED_ATLAS_FONT_12_PT_TEXTURE_IMAGE[] = "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8E////3v///2T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8F", + "////2P///6T///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////8s////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP////////9k////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", @@ -1474,7 +4557,7 @@ const char* CAF_FIXED_ATLAS_FONT_12_PT_TEXTURE_IMAGE[] = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////8s////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP////////9k////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", @@ -1483,28 +4566,20 @@ const char* CAF_FIXED_ATLAS_FONT_12_PT_TEXTURE_IMAGE[] = "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///8/////e////Av///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wL////e////zP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///4H/////////gf///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////N////+X///+X////A////wb////j////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////G////5f////I////8////+z////L////dv///wD///8A////AP///wD///8A////AP///wD///8A////z////97///8C////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8C////3v///8z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////gf////////+B////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///8/////e////Av///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Av///97////M////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////gf////////+B////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///zf////l////l////wP///8G////4////wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////z////97///8C////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8C////3v///8z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////gf////////+B////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///83////5f///5f///8D////Bv///+P///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////z////97///8C////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8C////3v///8z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////gf////////+B////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wL////e////zP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wP///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///1v///+m////1v////f////h////t////17///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wP///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////A////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////Vv////j///8u////AP///wD///8A////AP///wD///8A////AP///wD/////////bP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////yf///1H///8A////VP///9P///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", @@ -1517,6 +4592,7 @@ const char* CAF_FIXED_ATLAS_FONT_12_PT_TEXTURE_IMAGE[] = "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///4L/////////vf///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////sP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", @@ -1545,7 +4621,6 @@ const char* CAF_FIXED_ATLAS_FONT_12_PT_TEXTURE_IMAGE[] = "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////LP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", @@ -1559,7 +4634,6 @@ const char* CAF_FIXED_ATLAS_FONT_12_PT_TEXTURE_IMAGE[] = "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////LP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", @@ -1568,14 +4642,12 @@ const char* CAF_FIXED_ATLAS_FONT_12_PT_TEXTURE_IMAGE[] = "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD/////////ZP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////A////wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///8A////AP///wP///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8D////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", @@ -1587,13 +4659,47 @@ const char* CAF_FIXED_ATLAS_FONT_12_PT_TEXTURE_IMAGE[] = "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD/////////ZP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", - "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wL////e////zP///wD///8A////AP///wD///8A////AP///wD///8A", - "/////////2z///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wA=" + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A/////////7D///8A////AP///wD///8A", + "////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wD///8A////AP///wA=" }; // Texture image block count -const size_t CAF_FIXED_ATLAS_FONT_12_PT_TEXTURE_IMAGE_BLOCK_COUNT = 1451; +const size_t CAF_FIXED_ATLAS_FONT_14_PT_TEXTURE_IMAGE_BLOCK_COUNT = 2027; + // Fixed Atlas Font: Droid Sans Regular (24pt) // Exported by FreeType Font Extractor 1.0.0 @@ -18079,20 +21185,20 @@ FixedAtlasFont::FixedAtlasFont(FontSize size) break; } - case FixedAtlasFont::POINT_SIZE_16: + case FixedAtlasFont::POINT_SIZE_10: { fontLoaded = load( - CVF_FIXED_ATLAS_FONT_LARGE_NAME, - CVF_FIXED_ATLAS_FONT_LARGE_NUM_GLYPHS, - CVF_FIXED_ATLAS_FONT_LARGE_HORIZONTAL_BEARINGS_X, - CVF_FIXED_ATLAS_FONT_LARGE_HORIZONTAL_BEARINGS_Y, - CVF_FIXED_ATLAS_FONT_LARGE_HORIZONTAL_ADVANCES, - CVF_FIXED_ATLAS_FONT_LARGE_CHARACTER_WIDTHS, - CVF_FIXED_ATLAS_FONT_LARGE_CHARACTER_HEIGHTS, - CVF_FIXED_ATLAS_FONT_LARGE_TEXTURE_IMAGE_WIDTH, - CVF_FIXED_ATLAS_FONT_LARGE_TEXTURE_IMAGE_HEIGHT, - CVF_FIXED_ATLAS_FONT_LARGE_TEXTURE_IMAGE_BLOCK_COUNT, - CVF_FIXED_ATLAS_FONT_LARGE_TEXTURE_IMAGE); + CAF_FIXED_ATLAS_FONT_10_PT_NAME, + CAF_FIXED_ATLAS_FONT_10_PT_NUM_GLYPHS, + CAF_FIXED_ATLAS_FONT_10_PT_HORIZONTAL_BEARINGS_X, + CAF_FIXED_ATLAS_FONT_10_PT_HORIZONTAL_BEARINGS_Y, + CAF_FIXED_ATLAS_FONT_10_PT_HORIZONTAL_ADVANCES, + CAF_FIXED_ATLAS_FONT_10_PT_CHARACTER_WIDTHS, + CAF_FIXED_ATLAS_FONT_10_PT_CHARACTER_HEIGHTS, + CAF_FIXED_ATLAS_FONT_10_PT_TEXTURE_IMAGE_WIDTH, + CAF_FIXED_ATLAS_FONT_10_PT_TEXTURE_IMAGE_HEIGHT, + CAF_FIXED_ATLAS_FONT_10_PT_TEXTURE_IMAGE_BLOCK_COUNT, + CAF_FIXED_ATLAS_FONT_10_PT_TEXTURE_IMAGE); break; } @@ -18115,6 +21221,42 @@ FixedAtlasFont::FixedAtlasFont(FontSize size) break; } + case FixedAtlasFont::POINT_SIZE_14: + { + fontLoaded = load( + CAF_FIXED_ATLAS_FONT_14_PT_NAME, + CAF_FIXED_ATLAS_FONT_14_PT_NUM_GLYPHS, + CAF_FIXED_ATLAS_FONT_14_PT_HORIZONTAL_BEARINGS_X, + CAF_FIXED_ATLAS_FONT_14_PT_HORIZONTAL_BEARINGS_Y, + CAF_FIXED_ATLAS_FONT_14_PT_HORIZONTAL_ADVANCES, + CAF_FIXED_ATLAS_FONT_14_PT_CHARACTER_WIDTHS, + CAF_FIXED_ATLAS_FONT_14_PT_CHARACTER_HEIGHTS, + CAF_FIXED_ATLAS_FONT_14_PT_TEXTURE_IMAGE_WIDTH, + CAF_FIXED_ATLAS_FONT_14_PT_TEXTURE_IMAGE_HEIGHT, + CAF_FIXED_ATLAS_FONT_14_PT_TEXTURE_IMAGE_BLOCK_COUNT, + CAF_FIXED_ATLAS_FONT_14_PT_TEXTURE_IMAGE); + + break; + } + + case FixedAtlasFont::POINT_SIZE_16: + { + fontLoaded = load( + CVF_FIXED_ATLAS_FONT_LARGE_NAME, + CVF_FIXED_ATLAS_FONT_LARGE_NUM_GLYPHS, + CVF_FIXED_ATLAS_FONT_LARGE_HORIZONTAL_BEARINGS_X, + CVF_FIXED_ATLAS_FONT_LARGE_HORIZONTAL_BEARINGS_Y, + CVF_FIXED_ATLAS_FONT_LARGE_HORIZONTAL_ADVANCES, + CVF_FIXED_ATLAS_FONT_LARGE_CHARACTER_WIDTHS, + CVF_FIXED_ATLAS_FONT_LARGE_CHARACTER_HEIGHTS, + CVF_FIXED_ATLAS_FONT_LARGE_TEXTURE_IMAGE_WIDTH, + CVF_FIXED_ATLAS_FONT_LARGE_TEXTURE_IMAGE_HEIGHT, + CVF_FIXED_ATLAS_FONT_LARGE_TEXTURE_IMAGE_BLOCK_COUNT, + CVF_FIXED_ATLAS_FONT_LARGE_TEXTURE_IMAGE); + + break; + } + case FixedAtlasFont::POINT_SIZE_24: { fontLoaded = load( diff --git a/Fwk/AppFwk/cafVizExtensions/cafFixedAtlasFont.h b/Fwk/AppFwk/cafVizExtensions/cafFixedAtlasFont.h index 0756ce5de5..2fbae0cabd 100644 --- a/Fwk/AppFwk/cafVizExtensions/cafFixedAtlasFont.h +++ b/Fwk/AppFwk/cafVizExtensions/cafFixedAtlasFont.h @@ -63,7 +63,9 @@ class FixedAtlasFont : public cvf::Font enum FontSize { POINT_SIZE_8, // 8pt + POINT_SIZE_10, POINT_SIZE_12, + POINT_SIZE_14, POINT_SIZE_16, // 16pt POINT_SIZE_24, POINT_SIZE_32 @@ -71,12 +73,12 @@ class FixedAtlasFont : public cvf::Font public: explicit FixedAtlasFont(FontSize size); - virtual ~FixedAtlasFont(); + ~FixedAtlasFont() override; - virtual const cvf::String& name() const; - virtual cvf::ref getGlyph(wchar_t character); - virtual cvf::uint advance(wchar_t character, wchar_t nextCharacter); - virtual bool isEmpty(); + const cvf::String& name() const override; + cvf::ref getGlyph(wchar_t character) override; + cvf::uint advance(wchar_t character, wchar_t nextCharacter) override; + bool isEmpty() override; private: // Load/unload font diff --git a/Fwk/AppFwk/cafVizExtensions/cafHexGridIntersectionTools/cafHexGridIntersectionTools.cpp b/Fwk/AppFwk/cafVizExtensions/cafHexGridIntersectionTools/cafHexGridIntersectionTools.cpp index a7934f5935..99f6efa329 100644 --- a/Fwk/AppFwk/cafVizExtensions/cafHexGridIntersectionTools/cafHexGridIntersectionTools.cpp +++ b/Fwk/AppFwk/cafVizExtensions/cafHexGridIntersectionTools/cafHexGridIntersectionTools.cpp @@ -2,7 +2,7 @@ #include "cafHexGridIntersectionTools.h" #include "cvfPlane.h" -#include +#include #include diff --git a/Fwk/AppFwk/cafVizExtensions/cafOverlayScalarMapperLegend.h b/Fwk/AppFwk/cafVizExtensions/cafOverlayScalarMapperLegend.h index 2cb28c654d..60d7553b6f 100644 --- a/Fwk/AppFwk/cafVizExtensions/cafOverlayScalarMapperLegend.h +++ b/Fwk/AppFwk/cafVizExtensions/cafOverlayScalarMapperLegend.h @@ -78,7 +78,7 @@ class OverlayScalarMapperLegend : public caf::TitledOverlayFrame public: OverlayScalarMapperLegend(Font* font); - virtual ~OverlayScalarMapperLegend(); + ~OverlayScalarMapperLegend() override; void setScalarMapper(const ScalarMapper* scalarMapper); @@ -86,7 +86,7 @@ class OverlayScalarMapperLegend : public caf::TitledOverlayFrame enum NumberFormat { AUTO, SCIENTIFIC, FIXED}; void setTickFormat(NumberFormat format); - virtual cvf::Vec2ui preferredSize() override; + cvf::Vec2ui preferredSize() override; protected: void render(OpenGLContext* oglContext, const Vec2i& position, const Vec2ui& size) override; diff --git a/Fwk/AppFwk/cafVizExtensions/cafOverlayScaleLegend.cpp b/Fwk/AppFwk/cafVizExtensions/cafOverlayScaleLegend.cpp new file mode 100644 index 0000000000..f748a1e846 --- /dev/null +++ b/Fwk/AppFwk/cafVizExtensions/cafOverlayScaleLegend.cpp @@ -0,0 +1,790 @@ +//################################################################################################## +// +// Custom Visualization Core library +// Copyright (C) 2018- Ceetron Solutions AS +// +// This library may be used under the terms of either the GNU General Public License or +// the GNU Lesser General Public License as follows: +// +// GNU General Public License Usage +// This library 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 3 of the License, or +// (at your option) any later version. +// +// This library 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 at <> +// for more details. +// +// GNU Lesser General Public License Usage +// This library 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.1 of the License, or +// (at your option) any later version. +// +// This library 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 at <> +// for more details. +// +//################################################################################################## + + +#include "cvfBase.h" +#include "cafOverlayScaleLegend.h" +#include "cvfOpenGL.h" +#include "cvfOpenGLResourceManager.h" +#include "cvfGeometryBuilderDrawableGeo.h" +#include "cvfGeometryUtils.h" +#include "cvfViewport.h" +#include "cvfCamera.h" +#include "cvfTextDrawer.h" +#include "cvfFont.h" +#include "cvfShaderProgram.h" +#include "cvfShaderProgramGenerator.h" +#include "cvfShaderSourceProvider.h" +#include "cvfShaderSourceRepository.h" +#include "cvfUniform.h" +#include "cvfMatrixState.h" +#include "cvfBufferObjectManaged.h" +#include "cvfGlyph.h" +#include "cvfRenderStateDepth.h" +#include "cvfRenderStateLine.h" + +#include "cafInternalLegendRenderTools.h" +#include "cafTickMarkGenerator.h" + +#ifndef CVF_OPENGL_ES +#include "cvfRenderState_FF.h" +#endif + +#include "cvfScalarMapper.h" +#include +#include "cvfRenderStateBlending.h" +#include +#include + +namespace caf { + +using namespace cvf; + +//================================================================================================== +/// +/// \class cvf::OverlayColorLegend +/// \ingroup Render +/// +/// +/// +//================================================================================================== + +//-------------------------------------------------------------------------------------------------- +/// Constructor +//-------------------------------------------------------------------------------------------------- +OverlayScaleLegend::OverlayScaleLegend(Font* font) + : TitledOverlayFrame(font, 200, 200) + , m_tickNumberPrecision(4) + , m_numberFormat(AUTO) + , m_Layout(Vec2ui(200u, 200u)) + , m_font(font) + , m_orientation(HORIZONTAL) + , m_currentScale(1.0) +{ + CVF_ASSERT(font); + CVF_ASSERT(!font->isEmpty()); +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +OverlayScaleLegend::~OverlayScaleLegend() +{ + // Empty destructor to avoid errors with undefined types when cvf::ref's destructor gets called +} + +//-------------------------------------------------------------------------------------------------- +/// Hardware rendering using shader programs +//-------------------------------------------------------------------------------------------------- +void OverlayScaleLegend::render(OpenGLContext* oglContext, const Vec2i& position, const Vec2ui& size) +{ + renderGeneric(oglContext, position, size, false); +} + + +//-------------------------------------------------------------------------------------------------- +/// Software rendering using software +//-------------------------------------------------------------------------------------------------- +void OverlayScaleLegend::renderSoftware(OpenGLContext* oglContext, const Vec2i& position, const Vec2ui& size) +{ + renderGeneric(oglContext, position, size, true); +} + +//-------------------------------------------------------------------------------------------------- +/// Set up camera/viewport and render +//-------------------------------------------------------------------------------------------------- +void OverlayScaleLegend::renderGeneric(OpenGLContext* oglContext, const Vec2i& position, const Vec2ui& size, bool software) +{ + if (size.x() <= 0 || size.y() <= 0) + { + return; + } + + Camera camera; + camera.setViewport(position.x(), position.y(), size.x(), size.y()); + camera.setProjectionAsPixelExact2D(); + camera.setViewMatrix(Mat4d::IDENTITY); + camera.applyOpenGL(); + camera.viewport()->applyOpenGL(oglContext, Viewport::CLEAR_DEPTH); + + m_Layout = LayoutInfo(size); + layoutInfo(&m_Layout); + m_textDrawer = new TextDrawer(this->font()); + + // Set up text drawer + float maxLegendRightPos = 0; + if(m_orientation == HORIZONTAL) + setupHorizontalTextDrawer(m_textDrawer.p(), &m_Layout ); + else + setupVerticalTextDrawer(m_textDrawer.p(), &m_Layout); + + Vec2f backgroundSize(size); + + // Do the actual rendering + if (software) + { + if ( this->backgroundEnabled() ) + { + InternalLegendRenderTools::renderBackgroundImmediateMode(oglContext, + backgroundSize, + this->backgroundColor(), + this->backgroundFrameColor()); + } + renderLegendImmediateMode(oglContext, &m_Layout); + m_textDrawer->renderSoftware(oglContext, camera); + } + else + { + const MatrixState matrixState(camera); + if ( this->backgroundEnabled() ) + { + InternalLegendRenderTools::renderBackgroundUsingShaders(oglContext, + matrixState, + backgroundSize, + this->backgroundColor(), + this->backgroundFrameColor()); + } + renderLegendUsingShaders(oglContext, &m_Layout, matrixState); + m_textDrawer->render(oglContext, camera); + } + + CVF_CHECK_OGL(oglContext); +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void OverlayScaleLegend::setupHorizontalTextDrawer(TextDrawer* textDrawer, const LayoutInfo* layout) +{ + CVF_ASSERT(layout); + + textDrawer->setVerticalAlignment(TextDrawer::CENTER); + textDrawer->setTextColor(this->textColor()); + + m_visibleTickLabels.clear(); + + const float textY = layout->axisStartPt.y() + layout->majorTickSize / 2.0f + layout->tickTextLeadSpace + layout->charHeight; + + const float overlapTolerance = 1.2f * layout->charWidth; + float lastVisibleTextX = 0.0; + + size_t numTicks = layout->ticks.size(); + size_t numMajorTicks = std::count_if(layout->ticks.begin(), layout->ticks.end(), [](const LayoutInfo::Tick& t) {return t.isMajor; }); + size_t it; + for (it = 0; it < numTicks; it++) + { + if(/*numMajorTicks > 4 && */!layout->ticks[it].isMajor) continue; + + double tickValue = layout->ticks[it].domainValue; + String valueString; + switch (m_numberFormat) + { + case FIXED: + valueString = String::number(tickValue, 'f', m_tickNumberPrecision); + break; + case SCIENTIFIC: + valueString = String::number(tickValue, 'e', m_tickNumberPrecision); + break; + default: + valueString = String::number(tickValue); + break; + } + + auto textSize = m_font->textExtent(valueString); + float textX = static_cast(layout->axisStartPt.x() + layout->ticks[it].displayValue - textSize.x() / 2.0f); + + // Always draw first and last tick label. For all others, skip drawing if text ends up + // on top of the previous label. + if (it != 0 && it != (numTicks - 1)) + { + if (cvf::Math::abs(textX - lastVisibleTextX) < overlapTolerance) + { + m_visibleTickLabels.push_back(false); + continue; + } + // Make sure it does not overlap the last tick as well + + float lastTickY = static_cast(layout->axisStartPt.y() + layout->axisLength); + + if (cvf::Math::abs(textX - lastTickY) < overlapTolerance) + { + m_visibleTickLabels.push_back(false); + continue; + } + } + + + Vec2f pos(textX, textY); + textDrawer->addText(valueString, pos); + + lastVisibleTextX = textX; + m_visibleTickLabels.push_back(true); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void OverlayScaleLegend::setupVerticalTextDrawer(TextDrawer* textDrawer, const LayoutInfo* layout) +{ + CVF_ASSERT(layout); + + textDrawer->setVerticalAlignment(TextDrawer::CENTER); + textDrawer->setTextColor(this->textColor()); + + m_visibleTickLabels.clear(); + + const float textX = layout->axisStartPt.x() + layout->majorTickSize / 2.0f + layout->tickTextLeadSpace; + + const float overlapTolerance = 1.2f * layout->charHeight; + float lastVisibleTextY = 0.0; + + size_t numTicks = layout->ticks.size(); + size_t it; + for (it = 0; it < numTicks; it++) + { + if (numTicks > 4 && !layout->ticks[it].isMajor) continue; + + float textY = static_cast(layout->axisStartPt.y() + layout->ticks[it].displayValue); + + // Always draw first and last tick label. For all others, skip drawing if text ends up + // on top of the previous label. + if (it != 0 && it != (numTicks - 1)) + { + if (cvf::Math::abs(textY - lastVisibleTextY) < overlapTolerance) + { + m_visibleTickLabels.push_back(false); + continue; + } + // Make sure it does not overlap the last tick as well + + float lastTickY = static_cast(layout->axisStartPt.y() + layout->axisLength); + + if (cvf::Math::abs(textY - lastTickY) < overlapTolerance) + { + m_visibleTickLabels.push_back(false); + continue; + } + } + + double tickValue = layout->ticks[it].domainValue; + String valueString; + switch (m_numberFormat) + { + case FIXED: + valueString = String::number(tickValue, 'f', m_tickNumberPrecision); + break; + case SCIENTIFIC: + valueString = String::number(tickValue, 'e', m_tickNumberPrecision); + break; + default: + valueString = String::number(tickValue); + break; + } + + Vec2f pos(textX, textY); + textDrawer->addText(valueString, pos); + + lastVisibleTextY = textY; + m_visibleTickLabels.push_back(true); + } +} + +//-------------------------------------------------------------------------------------------------- +/// Draw the legend using shader programs +//-------------------------------------------------------------------------------------------------- +void OverlayScaleLegend::renderLegendUsingShaders(OpenGLContext* oglContext, LayoutInfo* layout, const MatrixState& matrixState) +{ + CVF_CALLSITE_OPENGL(oglContext); + + CVF_TIGHT_ASSERT(layout); + CVF_TIGHT_ASSERT(layout->overallLegendSize.x() > 0); + CVF_TIGHT_ASSERT(layout->overallLegendSize.y() > 0); + + RenderStateDepth depth(false); + depth.applyOpenGL(oglContext); + RenderStateLine line(static_cast(this->lineWidth())); + line.applyOpenGL(oglContext); + + // All vertices. Initialized here to set Z to zero once and for all. + static float vertexArray[] = + { + 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f + }; + + // Per vector convenience pointers + float* v0 = &vertexArray[0]; + float* v1 = &vertexArray[3]; + float* v2 = &vertexArray[6]; + float* v3 = &vertexArray[9]; + float* v4 = &vertexArray[12]; + + // Connects + static const ushort trianglesConnects[] = { 0, 1, 4, 0, 4, 3 }; + + ref shaderProgram = oglContext->resourceManager()->getLinkedUnlitColorShaderProgram(oglContext); + CVF_TIGHT_ASSERT(shaderProgram.notNull()); + + if (shaderProgram->useProgram(oglContext)) + { + shaderProgram->clearUniformApplyTracking(); + shaderProgram->applyFixedUniforms(oglContext, matrixState); + } + + glBindBuffer(GL_ARRAY_BUFFER, 0); + glEnableVertexAttribArray(ShaderProgram::VERTEX); + glVertexAttribPointer(ShaderProgram::VERTEX, 3, GL_FLOAT, GL_FALSE, 0, vertexArray); + + // Draw axis + { + v0[0] = layout->axisStartPt.x(); + v0[1] = layout->axisStartPt.y(); + + if (m_orientation == HORIZONTAL) + { + v1[0] = v0[0] + layout->axisLength; + v1[1] = v0[1]; + } + else + { + v1[0] = v0[0]; + v1[1] = v0[1] + layout->axisLength; + } + + static const ushort axisConnects[] = { 0, 1 }; + + UniformFloat uniformColor("u_color", Color4f(this->lineColor())); + shaderProgram->applyUniform(oglContext, uniformColor); + +#ifdef CVF_OPENGL_ES + glDrawElements(GL_LINES, 2, GL_UNSIGNED_SHORT, axisConnects); +#else + glDrawRangeElements(GL_LINES, 0, 3, 2, GL_UNSIGNED_SHORT, axisConnects); +#endif + } + + // Draw ticks + for (const auto& tickInfo : layout->ticks) + { + float currTickSize = tickInfo.isMajor ? layout->majorTickSize : layout->minorTickSize; + + if (m_orientation == HORIZONTAL) + { + v0[0] = layout->axisStartPt.x() + static_cast(tickInfo.displayValue); + v0[1] = layout->axisStartPt.y() - currTickSize / 2.0f; + v1[0] = v0[0]; + v1[1] = v0[1] + currTickSize; + } + else + { + v0[0] = layout->axisStartPt.x() - currTickSize / 2.0f; + v0[1] = layout->axisStartPt.y() + static_cast(tickInfo.displayValue); + v1[0] = v0[0] + currTickSize; + v1[1] = v0[1]; + } + + static const ushort tickConnects[] = {0, 1}; + + UniformFloat uniformColor("u_color", Color4f(this->lineColor())); + shaderProgram->applyUniform(oglContext, uniformColor); + +#ifdef CVF_OPENGL_ES + glDrawElements(GL_LINES, 2, GL_UNSIGNED_SHORT, axisConnects); +#else + glDrawRangeElements(GL_LINES, 0, 3, 2, GL_UNSIGNED_SHORT, tickConnects); +#endif + } + + glDisableVertexAttribArray(ShaderProgram::VERTEX); + + CVF_TIGHT_ASSERT(shaderProgram.notNull()); + shaderProgram->useNoProgram(oglContext); + + // Reset render states + RenderStateDepth resetDepth; + resetDepth.applyOpenGL(oglContext); + + RenderStateLine resetLine; + resetLine.applyOpenGL(oglContext); + + CVF_CHECK_OGL(oglContext); +} + +//-------------------------------------------------------------------------------------------------- +/// Draw the legend using immediate mode OpenGL +//-------------------------------------------------------------------------------------------------- +void OverlayScaleLegend::renderLegendImmediateMode(OpenGLContext* oglContext, LayoutInfo* layout) +{ +#if 0 +#ifdef CVF_OPENGL_ES + CVF_UNUSED(layout); + CVF_FAIL_MSG("Not supported on OpenGL ES"); +#else + CVF_TIGHT_ASSERT(layout); + CVF_TIGHT_ASSERT(layout->overallLegendSize.x() > 0); + CVF_TIGHT_ASSERT(layout->overallLegendSize.y() > 0); + + RenderStateDepth depth(false); + depth.applyOpenGL(oglContext); + + RenderStateLighting_FF lighting(false); + lighting.applyOpenGL(oglContext); + + // All vertices. Initialized here to set Z to zero once and for all. + static float vertexArray[] = + { + 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 0.0f, + }; + + // Per vector convenience pointers + float* v0 = &vertexArray[0]; + float* v1 = &vertexArray[3]; + float* v2 = &vertexArray[6]; + float* v3 = &vertexArray[9]; + float* v4 = &vertexArray[12]; + + // Constant coordinates + v0[0] = v3[0] = layout->tickStartX; + v1[0] = v4[0] = layout->tickMidX; + + // Render color bar as one colored quad per pixel + + int legendHeightPixelCount = static_cast(layout->tickYPixelPos->get(m_tickValues.size() - 1) - layout->tickYPixelPos->get(0) + 0.01); + if (m_scalarMapper.notNull()) + { + int iPx; + for (iPx = 0; iPx < legendHeightPixelCount; iPx++) + { + const Color3ub& clr = m_scalarMapper->mapToColor(m_scalarMapper->domainValue((iPx+0.5)/legendHeightPixelCount)); + float y0 = static_cast(layout->colorBarRect.min().y() + iPx); + float y1 = static_cast(layout->colorBarRect.min().y() + iPx + 1); + + // Dynamic coordinates for rectangle + v0[1] = v1[1] = y0; + v3[1] = v4[1] = y1; + + // Draw filled rectangle elements + glColor3ubv(clr.ptr()); + glBegin(GL_TRIANGLE_FAN); + glVertex3fv(v0); + glVertex3fv(v1); + glVertex3fv(v4); + glVertex3fv(v3); + glEnd(); + } + } + + // Render frame + + // Dynamic coordinates for tickmarks-lines + bool isRenderingFrame = true; + if (isRenderingFrame) + { + v0[0] = v2[0] = layout->colorBarRect.min().x()-0.5f; + v1[0] = v3[0] = layout->colorBarRect.max().x()-0.5f; + v0[1] = v1[1] = layout->colorBarRect.min().y()-0.5f; + v2[1] = v3[1] = layout->colorBarRect.max().y()-0.5f; + + glColor3fv(this->textColor().ptr()); + glBegin(GL_LINES); + glVertex3fv(v0); + glVertex3fv(v1); + glVertex3fv(v1); + glVertex3fv(v3); + glVertex3fv(v3); + glVertex3fv(v2); + glVertex3fv(v2); + glVertex3fv(v0); + glEnd(); + + } + + // Render tickmarks + bool isRenderingTicks = true; + + if (isRenderingTicks) + { + // Constant coordinates + v0[0] = layout->tickStartX; + v1[0] = layout->tickMidX - 0.5f*(layout->tickEndX - layout->tickMidX) - 0.5f; + v2[0] = layout->tickMidX; + v3[0] = layout->tickEndX - 0.5f*(layout->tickEndX - layout->tickMidX) - 0.5f; + v4[0] = layout->tickEndX; + + size_t ic; + for (ic = 0; ic < m_tickValues.size(); ic++) + { + float y0 = static_cast(layout->colorBarRect.min().y() + layout->tickYPixelPos->get(ic) - 0.5f); + + // Dynamic coordinates for tickmarks-lines + v0[1] = v1[1] = v2[1] = v3[1] = v4[1] = y0; + + glColor3fv(this->textColor().ptr()); + glBegin(GL_LINES); + if ( m_visibleTickLabels[ic]) + { + glVertex3fv(v0); + glVertex3fv(v4); + } + else + { + glVertex3fv(v2); + glVertex3fv(v3); + } + glEnd(); + } + } + + // Reset render states + RenderStateLighting_FF resetLighting; + resetLighting.applyOpenGL(oglContext); + RenderStateDepth resetDepth; + resetDepth.applyOpenGL(oglContext); + + CVF_CHECK_OGL(oglContext); +#endif // CVF_OPENGL_ES +#endif // 0 +} + +//-------------------------------------------------------------------------------------------------- +/// Get layout information +//-------------------------------------------------------------------------------------------------- +void OverlayScaleLegend::layoutInfo(LayoutInfo* layout) +{ + CVF_TIGHT_ASSERT(layout); + + // Input values + float marginAlongAxis = 8.0f; + float marginAcrossAxis = 8.0f; + float tickTextLeadSpace = 5.0f; + float majorTickSize = 9.0f; + float minorTickSize = 5.0f; + + ref glyph = this->font()->getGlyph(L'A'); + layout->charWidth = static_cast(glyph->width()); + layout->charHeight = static_cast(glyph->height()); + layout->lineSpacing = layout->charHeight*1.5f; + layout->tickTextLeadSpace = tickTextLeadSpace; + layout->majorTickSize = majorTickSize; + layout->minorTickSize = minorTickSize; + + double overallSizeValue; + float marginValue; + + if (m_orientation == HORIZONTAL) + { + layout->margins = Vec2f(marginAlongAxis, marginAcrossAxis); + overallSizeValue = layout->overallLegendSize.x(); + marginValue = layout->margins.x(); + layout->axisStartPt = {layout->margins.x() + layout->charWidth / 2.0f, + layout->margins.y() + layout->majorTickSize / 2.0f}; + } + else + { + layout->margins = Vec2f(marginAcrossAxis, marginAlongAxis); + overallSizeValue = layout->overallLegendSize.y(); + marginValue = layout->margins.y(); + layout->axisStartPt = {layout->margins.x() + layout->majorTickSize / 2.0f, + layout->margins.y() + layout->charHeight / 2.0f}; + } + + layout->axisLength = static_cast(overallSizeValue) + - 2 * marginValue + - static_cast(this->titleStrings().size()) * layout->lineSpacing + - layout->lineSpacing; + + auto currentScale = m_currentScale != 0.0 ? m_currentScale : 1.0; + + layout->ticks.clear(); + size_t numTicks = m_ticksInDomain.size(); + + if (numTicks > 1) + { + double tickSpacingInDomain = m_ticksInDomain[1] - m_ticksInDomain[0]; + bool finished = false; + for (size_t i = 0; i < numTicks; i++) + { + size_t intermediateTickCount = i == 0 ? 9 : 1; + + // Add one extra tick per domain tick + for (size_t j = 0; j < intermediateTickCount + 1; j++) + { + double tickInDomain = m_ticksInDomain[i] + ((double)j * tickSpacingInDomain / (double)(intermediateTickCount + 1)); + double tickInDisplay = tickInDomain * currentScale; + + if (tickInDisplay < layout->axisLength) + { + bool isCenterTick = (j == (intermediateTickCount + 1) / 2); + bool isMajorTick = j == 0 || isCenterTick; + layout->ticks.emplace_back(LayoutInfo::Tick(tickInDisplay, tickInDomain, isMajorTick)); + + if (i == 0 && isCenterTick) break; + } + else + { + finished = true; + break; + } + } + if (finished) break; + } + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void OverlayScaleLegend::setTickPrecision(int precision) +{ + m_tickNumberPrecision = precision; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void OverlayScaleLegend::setTickFormat(NumberFormat format) +{ + m_numberFormat = format; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void OverlayScaleLegend::setOrientation(Orientation orientation) +{ + m_orientation = orientation; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +caf::OverlayScaleLegend::Orientation OverlayScaleLegend::orientation() const +{ + return m_orientation; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +cvf::Vec2ui OverlayScaleLegend::preferredSize() +{ + uint preferredXSize = 100; + uint preferredYSize = 100; + return { (unsigned int)(std::ceil(preferredXSize)), (unsigned int)(std::ceil(preferredYSize)) }; + +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void OverlayScaleLegend::setDisplayCoordTransform(const caf::DisplayCoordTransform* displayCoordTransform) +{ + m_dispalyCoordsTransform = displayCoordTransform; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void OverlayScaleLegend::updateFromCamera(const Camera* camera) +{ + auto windowSize = Vec2ui(camera->viewport()->width(), camera->viewport()->height()); + + Vec3d windowOrigoInDomain; + Vec3d windowMaxInDomain; + camera->unproject(Vec3d(0, 0, 0), &windowOrigoInDomain); + camera->unproject(Vec3d(windowSize.x(), windowSize.y(), 0), &windowMaxInDomain); + + if (m_dispalyCoordsTransform.notNull()) + { + windowOrigoInDomain = m_dispalyCoordsTransform->transformToDomainCoord(windowOrigoInDomain); + windowMaxInDomain = m_dispalyCoordsTransform->transformToDomainCoord(windowMaxInDomain); + } + + Vec3d windowOrigoPoint; + Vec3d windowMaxPoint; + camera->project(windowOrigoInDomain, &windowOrigoPoint); + camera->project(windowMaxInDomain, &windowMaxPoint); + + double minStepSizeInDomain; + double windowOrigoInDomainValue; + double windowMaxInDomainValue; + double windowOrigoPointValue; + double windowMaxPointValue; + int tickMaxCount; + + auto textSize = m_font->textExtent(String::number(-1.999e-17)); + if (m_orientation == HORIZONTAL) + { + windowOrigoInDomainValue = windowOrigoInDomain.x(); + windowMaxInDomainValue = windowMaxInDomain.x(); + windowOrigoPointValue = windowOrigoPoint.x(); + windowMaxPointValue = windowMaxPoint.x(); + tickMaxCount = windowSize.x() / (2 * textSize.x()); + } + else + { + windowOrigoInDomainValue = windowOrigoInDomain.y(); + windowMaxInDomainValue = windowMaxInDomain.y(); + windowOrigoPointValue = windowOrigoPoint.y(); + windowMaxPointValue = windowMaxPoint.y(); + tickMaxCount = windowSize.y() / (2 * textSize.x()); + } + + m_currentScale = (windowMaxPointValue - windowOrigoPointValue) / (windowMaxInDomainValue - windowOrigoInDomainValue); + minStepSizeInDomain = (windowMaxInDomainValue - windowOrigoInDomainValue) / tickMaxCount; + + caf::TickMarkGenerator tickCreator(windowOrigoInDomainValue, windowMaxInDomainValue, minStepSizeInDomain); + auto ticks = tickCreator.tickMarkValues(); + + m_ticksInDomain.clear(); + for (const auto& tick : ticks) + { + m_ticksInDomain.push_back(tick - ticks.front()); + } +} + +} // namespace cvf + diff --git a/Fwk/AppFwk/cafVizExtensions/cafOverlayScaleLegend.h b/Fwk/AppFwk/cafVizExtensions/cafOverlayScaleLegend.h new file mode 100644 index 0000000000..6f3ec84077 --- /dev/null +++ b/Fwk/AppFwk/cafVizExtensions/cafOverlayScaleLegend.h @@ -0,0 +1,165 @@ +//################################################################################################## +// +// Custom Visualization Core library +// Copyright (C) 2018- Ceetron Solutions AS +// +// This library may be used under the terms of either the GNU General Public License or +// the GNU Lesser General Public License as follows: +// +// GNU General Public License Usage +// This library 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 3 of the License, or +// (at your option) any later version. +// +// This library 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 at <> +// for more details. +// +// GNU Lesser General Public License Usage +// This library 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.1 of the License, or +// (at your option) any later version. +// +// This library 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 at <> +// for more details. +// +//################################################################################################## + + +#pragma once + +#include "cafDisplayCoordTransform.h" +#include "cafTitledOverlayFrame.h" +#include "cvfOverlayItem.h" +#include "cvfArray.h" +#include "cvfCamera.h" +#include "cvfString.h" +#include "cvfRect.h" + +#include + +namespace cvf { +class Font; +class ShaderProgram; +class MatrixState; +class TextDrawer; +class ScalarMapper; +} + +namespace caf { + + +//================================================================================================== +// +// Overlay color legend +// +//================================================================================================== +class OverlayScaleLegend : public caf::TitledOverlayFrame +{ + using Font = cvf::Font; + using OpenGLContext = cvf::OpenGLContext; + using Vec2i = cvf::Vec2i; + using Vec2ui = cvf::Vec2ui; + using String = cvf::String; + using MatrixState = cvf::MatrixState; + using Vec2f = cvf::Vec2f; + using TextDrawer = cvf::TextDrawer; + using Camera = cvf::Camera; + +public: + enum Orientation {HORIZONTAL, VERTICAL}; + +public: + OverlayScaleLegend(Font* font); + ~OverlayScaleLegend() override; + + void setTickPrecision(int precision); + enum NumberFormat { AUTO, SCIENTIFIC, FIXED}; + void setTickFormat(NumberFormat format); + void setOrientation(Orientation orientation); + Orientation orientation() const; + + cvf::Vec2ui preferredSize() override; + + void setDisplayCoordTransform(const caf::DisplayCoordTransform* displayCoordTransform); + void updateFromCamera(const Camera* camera); + +protected: + void render(OpenGLContext* oglContext, const Vec2i& position, const Vec2ui& size) override; + void renderSoftware(OpenGLContext* oglContext, const Vec2i& position, const Vec2ui& size) override; + + struct LayoutInfo + { + struct Tick + { + Tick(double displayValue, double domainValue, bool isMajor) + : displayValue(displayValue) + , domainValue(domainValue) + , isMajor(isMajor) {} + double displayValue; + double domainValue; + bool isMajor; + }; + + LayoutInfo(const Vec2ui& setSize) + { + overallLegendSize = setSize; + } + + float charWidth; + float charHeight; + float lineSpacing; + Vec2f margins; + float tickTextLeadSpace; + + //Rectf colorBarRect; + Vec2f axisStartPt; + float axisLength; + float majorTickSize; + float minorTickSize; + + std::vector ticks; + + Vec2ui overallLegendSize; + }; + + void layoutInfo(LayoutInfo* layout); + + void renderGeneric(OpenGLContext* oglContext, + const Vec2i& position, + const Vec2ui& size, + bool software); + void renderLegendUsingShaders(OpenGLContext* oglContext, + LayoutInfo* layout, + const MatrixState& matrixState); + void renderLegendImmediateMode(OpenGLContext* oglContext, + LayoutInfo* layout); + void setupHorizontalTextDrawer(TextDrawer* textDrawer, const LayoutInfo* layout); + void setupVerticalTextDrawer(TextDrawer* textDrawer, const LayoutInfo* layout); + +protected: + std::vector m_visibleTickLabels; // Skip tick labels ending up on top of previous visible label + int m_tickNumberPrecision; + NumberFormat m_numberFormat; + + Orientation m_orientation; + LayoutInfo m_Layout; + cvf::ref m_textDrawer; + + cvf::ref m_font; + + cvf::cref m_dispalyCoordsTransform; + double m_currentScale; // [pixels/length] + std::vector m_ticksInDomain; +}; + +} diff --git a/Fwk/AppFwk/cafVizExtensions/cafTitledOverlayFrame.cpp b/Fwk/AppFwk/cafVizExtensions/cafTitledOverlayFrame.cpp index 5745dd2206..e13bf802d6 100644 --- a/Fwk/AppFwk/cafVizExtensions/cafTitledOverlayFrame.cpp +++ b/Fwk/AppFwk/cafVizExtensions/cafTitledOverlayFrame.cpp @@ -87,6 +87,14 @@ namespace caf { m_textColor = color; } + //-------------------------------------------------------------------------------------------------- + /// + //-------------------------------------------------------------------------------------------------- + void TitledOverlayFrame::setFont(cvf::Font* font) + { + m_font = font; + } + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- diff --git a/Fwk/AppFwk/cafVizExtensions/cafTitledOverlayFrame.h b/Fwk/AppFwk/cafVizExtensions/cafTitledOverlayFrame.h index 6852622c2e..b0c626378e 100644 --- a/Fwk/AppFwk/cafVizExtensions/cafTitledOverlayFrame.h +++ b/Fwk/AppFwk/cafVizExtensions/cafTitledOverlayFrame.h @@ -56,12 +56,13 @@ namespace caf { { public: TitledOverlayFrame(cvf::Font* font, unsigned int width = 100, unsigned int height = 200); - virtual ~TitledOverlayFrame(); + ~TitledOverlayFrame() override; void setRenderSize(const cvf::Vec2ui& size); cvf::Vec2ui renderSize() const; void setTextColor(const cvf::Color3f& color); + void setFont(cvf::Font* font); void setLineColor(const cvf::Color3f& lineColor); void setLineWidth(int lineWidth); @@ -85,7 +86,7 @@ namespace caf { cvf::Font* font(); private: - cvf::Vec2ui sizeHint() override final; // Will return the size to use for rendering, and is really not a hint. + cvf::Vec2ui sizeHint() final; // Will return the size to use for rendering, and is really not a hint. cvf::Vec2ui m_renderSize; // The rendered size of the color legend area in pixels cvf::Color3f m_textColor; diff --git a/Fwk/AppFwk/cafVizExtensions/cafTransparentWBRenderConfiguration.cpp b/Fwk/AppFwk/cafVizExtensions/cafTransparentWBRenderConfiguration.cpp index f98be873c9..784c1c5c40 100644 --- a/Fwk/AppFwk/cafVizExtensions/cafTransparentWBRenderConfiguration.cpp +++ b/Fwk/AppFwk/cafVizExtensions/cafTransparentWBRenderConfiguration.cpp @@ -64,8 +64,8 @@ using namespace cvf; m_renderConf = new caf::TransparentWBRenderConfiguration; m_renderConf->setUpRenderSequence(m_renderingSequence.p()); - // Cerate overly item if needed - cvf::OverlyItem* overlayItem; // = new someTtem + // Cerate overlay item if needed + cvf::OverlayItem* overlayItem; // = new someTtem m_renderConf->overlayRendering()->addOverlayItem(overlayItem); } @@ -128,8 +128,8 @@ class RenderPassPreparator : public cvf::DynamicUniformSet CVF_ASSERT(renderConfiguration); m_renderConfiguration = renderConfiguration; } - virtual cvf::UniformSet* uniformSet() { return nullptr; } - virtual void update(cvf::Rendering* rendering) + cvf::UniformSet* uniformSet() override { return nullptr; } + void update(cvf::Rendering* rendering) override { m_renderConfiguration->updateEffectsForRendering(rendering); } @@ -151,7 +151,7 @@ class RenderQueueFilter : public cvf::RenderQueueSorterBasic m_isOpaquePass = isOpaquePass; } - virtual void sort(cvf::RenderQueue* renderQueue) const + void sort(cvf::RenderQueue* renderQueue) const override { using namespace cvf; std::vector* renderItems = renderQueue->renderItemsForSorting(); diff --git a/Fwk/AppFwk/cafVizExtensions/cafTransparentWBRenderConfiguration.h b/Fwk/AppFwk/cafVizExtensions/cafTransparentWBRenderConfiguration.h index 7db966c6c2..cb81d016ff 100644 --- a/Fwk/AppFwk/cafVizExtensions/cafTransparentWBRenderConfiguration.h +++ b/Fwk/AppFwk/cafVizExtensions/cafTransparentWBRenderConfiguration.h @@ -28,7 +28,7 @@ namespace caf { public: TransparentWBRenderConfiguration(); - virtual ~TransparentWBRenderConfiguration(); + ~TransparentWBRenderConfiguration() override; void resize(int width, int height); void prepareForRendering(); // UpdateCameras and scene ... @@ -79,14 +79,14 @@ namespace caf { public: WBTransparencySurfaceEffectGenerator(const cvf::Color4f& color, caf::PolygonOffset polygonOffset, bool useSpecular); - ~WBTransparencySurfaceEffectGenerator(); + ~WBTransparencySurfaceEffectGenerator() override; protected: - virtual bool isEqual(const EffectGenerator* other) const; - virtual EffectGenerator* copy() const; + bool isEqual(const EffectGenerator* other) const override; + EffectGenerator* copy() const override; - virtual void updateForShaderBasedRendering(cvf::Effect* effect) const; - virtual void updateForFixedFunctionRendering(cvf::Effect* effect) const; + void updateForShaderBasedRendering(cvf::Effect* effect) const override; + void updateForFixedFunctionRendering(cvf::Effect* effect) const override; private: void updateCommonEffect(cvf::Effect* effect) const; diff --git a/Fwk/CMakeLists.txt b/Fwk/CMakeLists.txt index 84845ecf4a..1de607cd14 100644 --- a/Fwk/CMakeLists.txt +++ b/Fwk/CMakeLists.txt @@ -1,10 +1,14 @@ -cmake_minimum_required (VERSION 2.8) +cmake_minimum_required (VERSION 2.8.12) project (TestCafAndVizFwk) -find_package (Qt4 COMPONENTS QtCore QtGui QtMain QtOpenGl REQUIRED) -include (${QT_USE_FILE}) - +find_package(Qt5 CONFIG COMPONENTS Core) +if (Qt5Core_FOUND) + find_package(Qt5 CONFIG REQUIRED Core Gui OpenGL Widgets) +else() + find_package(Qt4 COMPONENTS QtCore QtGui QtMain QtOpenGL REQUIRED) + include(${QT_USE_FILE}) +endif(Qt5Core_FOUND) # Libraries add_subdirectory(AppFwk/cafProjectDataModel/cafPdmCore) diff --git a/Fwk/VizFwk/CMakeLists.txt b/Fwk/VizFwk/CMakeLists.txt index a799c645e1..f977e4e8f1 100644 --- a/Fwk/VizFwk/CMakeLists.txt +++ b/Fwk/VizFwk/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 2.8) +cmake_minimum_required(VERSION 2.8.12) project(VizFramework) @@ -47,6 +47,7 @@ add_subdirectory(LibUtilities) option(CEE_BUILD_GUI_QT "Build GUI library for Qt" ON) if (CEE_BUILD_GUI_QT) + option(CEE_USE_QT5 "Use Qt5" OFF) add_subdirectory(LibGuiQt) endif() diff --git a/Fwk/VizFwk/LibCore/CMakeLists.txt b/Fwk/VizFwk/LibCore/CMakeLists.txt index 0637746261..b16ca5e051 100644 --- a/Fwk/VizFwk/LibCore/CMakeLists.txt +++ b/Fwk/VizFwk/LibCore/CMakeLists.txt @@ -107,3 +107,7 @@ target_include_directories(${PROJECT_NAME} set(PROJECT_FILES ${CEE_HEADER_FILES} ${CEE_SOURCE_FILES}) source_group("" FILES ${PROJECT_FILES}) + +#if (COMMAND ri_apply_cotire) + #ri_apply_cotire() +#endif() diff --git a/Fwk/VizFwk/LibGeometry/CMakeLists.txt b/Fwk/VizFwk/LibGeometry/CMakeLists.txt index c18b0bd727..8ebce7b1f1 100644 --- a/Fwk/VizFwk/LibGeometry/CMakeLists.txt +++ b/Fwk/VizFwk/LibGeometry/CMakeLists.txt @@ -65,3 +65,7 @@ target_link_libraries ( ${PROJECT_NAME} set(PROJECT_FILES ${CEE_HEADER_FILES} ${CEE_SOURCE_FILES}) source_group("" FILES ${PROJECT_FILES}) + +#if (COMMAND ri_apply_cotire) +# ri_apply_cotire() +#endif() diff --git a/Fwk/VizFwk/LibGuiQt/CMakeLists.txt b/Fwk/VizFwk/LibGuiQt/CMakeLists.txt index b699af4960..f1d63e863c 100644 --- a/Fwk/VizFwk/LibGuiQt/CMakeLists.txt +++ b/Fwk/VizFwk/LibGuiQt/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 2.8) +cmake_minimum_required(VERSION 2.8.12) project(LibGuiQt) @@ -10,9 +10,12 @@ if (CMAKE_COMPILER_IS_GNUCXX) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-long-long") endif() - -find_package(Qt4 REQUIRED) -include(${QT_USE_FILE}) +if (CEE_USE_QT5) + find_package(Qt5 COMPONENTS Core Gui OpenGL Widgets REQUIRED) +else() + find_package(Qt4 COMPONENTS QtCore QtGui QtOpenGL REQUIRED) + include(${QT_USE_FILE}) +endif(CEE_USE_QT5) set(CEE_HEADER_FILES cvfqtBasicAboutDialog.h @@ -41,6 +44,19 @@ target_include_directories(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR} ) +if ( NOT CMAKE_AUTOMOC ) + if (CEE_USE_QT5) + qt5_wrap_cpp(MOC_SOURCE_FILES ${MOC_HEADER_FILES} ) + + else() + qt4_wrap_cpp(MOC_SOURCE_FILES ${MOC_HEADER_FILES} ) + endif() +endif() + +if (CEE_USE_QT5) + set(QT_LIBRARIES Qt5::Core Qt5::OpenGL Qt5::Widgets) +endif() + target_link_libraries ( ${PROJECT_NAME} LibCore LibGeometry @@ -51,3 +67,9 @@ target_link_libraries ( ${PROJECT_NAME} ) set(PROJECT_FILES ${CEE_HEADER_FILES} ${CEE_SOURCE_FILES}) source_group("" FILES ${PROJECT_FILES}) + +#if (COMMAND ri_apply_cotire) +# set_source_files_properties (cvfqtOpenGLWidget.cpp PROPERTIES COTIRE_EXCLUDED TRUE) +# set_source_files_properties (cvfqtOpenGLContext.cpp PROPERTIES COTIRE_EXCLUDED TRUE) +# ri_apply_cotire() +#endif() diff --git a/Fwk/VizFwk/LibGuiQt/cvfqtBasicAboutDialog.cpp b/Fwk/VizFwk/LibGuiQt/cvfqtBasicAboutDialog.cpp index 765f19ee91..dc7ee7eb28 100644 --- a/Fwk/VizFwk/LibGuiQt/cvfqtBasicAboutDialog.cpp +++ b/Fwk/VizFwk/LibGuiQt/cvfqtBasicAboutDialog.cpp @@ -41,10 +41,16 @@ #include "cvfqtBasicAboutDialog.h" #include +#include +#if QT_VERSION >= 0x050000 +#include +#include +#include +#else #include #include #include - +#endif namespace cvfqt { @@ -212,7 +218,7 @@ void BasicAboutDialog::create() QLabel* appVersionLabel = new QLabel(this); QFont appVersionFont(appVersionLabel->font()); appVersionFont.setPointSize(8); - appVersionFont.setBold(TRUE); + appVersionFont.setBold(true); appVersionLabel->setFont(appVersionFont); appVersionLabel->setText(appVer); appInfoLayout->addWidget(appVersionLabel); @@ -225,7 +231,7 @@ void BasicAboutDialog::create() appCopyrightLabel->setTextFormat(Qt::RichText); QFont appCopyrightFont(appCopyrightLabel->font()); appCopyrightFont.setPointSize(8); - appCopyrightFont.setBold(TRUE); + appCopyrightFont.setBold(true); appCopyrightLabel->setFont(appCopyrightFont); appCopyrightLabel->setText(m_appCopyright); appInfoLayout->addWidget(appCopyrightLabel); @@ -306,8 +312,8 @@ void BasicAboutDialog::create() bottomLayout->addItem(spacer2); QPushButton* buttonOk = new QPushButton("&OK", this); - buttonOk->setAutoDefault(TRUE); - buttonOk->setDefault(TRUE); + buttonOk->setAutoDefault(true); + buttonOk->setDefault(true); buttonOk->setFocus(); connect(buttonOk, SIGNAL(clicked()), this, SLOT(accept()) ); bottomLayout->addWidget(buttonOk); diff --git a/Fwk/VizFwk/LibGuiQt/cvfqtBasicAboutDialog.h b/Fwk/VizFwk/LibGuiQt/cvfqtBasicAboutDialog.h index ebbfe715d4..747eb267df 100644 --- a/Fwk/VizFwk/LibGuiQt/cvfqtBasicAboutDialog.h +++ b/Fwk/VizFwk/LibGuiQt/cvfqtBasicAboutDialog.h @@ -37,7 +37,12 @@ #pragma once +#include +#if QT_VERSION >= 0x050000 +#include +#else #include +#endif class QGridLayout; diff --git a/Fwk/VizFwk/LibGuiQt/cvfqtPerformanceInfoHud.cpp b/Fwk/VizFwk/LibGuiQt/cvfqtPerformanceInfoHud.cpp index c3470c7a84..a0e7c238d4 100644 --- a/Fwk/VizFwk/LibGuiQt/cvfqtPerformanceInfoHud.cpp +++ b/Fwk/VizFwk/LibGuiQt/cvfqtPerformanceInfoHud.cpp @@ -42,7 +42,12 @@ #include "cvfqtPerformanceInfoHud.h" #include "cvfOpenGLResourceManager.h" +#include +#if QT_VERSION >= 0x050000 +#include +#else #include +#endif #include namespace cvfqt { diff --git a/Fwk/VizFwk/LibGuiQt/cvfqtUtils.h b/Fwk/VizFwk/LibGuiQt/cvfqtUtils.h index 75c77a55a9..d91cc99cb1 100644 --- a/Fwk/VizFwk/LibGuiQt/cvfqtUtils.h +++ b/Fwk/VizFwk/LibGuiQt/cvfqtUtils.h @@ -41,7 +41,11 @@ #include "cvfTextureImage.h" #include +#if QT_VERSION >= 0x050000 +#include +#else #include +#endif namespace cvfqt { diff --git a/Fwk/VizFwk/LibRender/CMakeLists.txt b/Fwk/VizFwk/LibRender/CMakeLists.txt index 73466d5e69..3d2871a930 100644 --- a/Fwk/VizFwk/LibRender/CMakeLists.txt +++ b/Fwk/VizFwk/LibRender/CMakeLists.txt @@ -188,3 +188,12 @@ target_link_libraries ( ${PROJECT_NAME} set(PROJECT_FILES ${CEE_HEADER_FILES} ${CEE_SOURCE_FILES}) source_group("" FILES ${PROJECT_FILES}) + +#if (COMMAND ri_apply_cotire) +# set_source_files_properties (cvfOpenGLCapabilities.cpp PROPERTIES COTIRE_EXCLUDED TRUE) +# set_source_files_properties (cvfOpenGLContext.cpp PROPERTIES COTIRE_EXCLUDED TRUE) +# set_source_files_properties (cvfOpenGLContextGroup.cpp PROPERTIES COTIRE_EXCLUDED TRUE) +# set_source_files_properties (cvfOpenGLResourceManager.cpp PROPERTIES COTIRE_EXCLUDED TRUE) +# set_source_files_properties (cvfOpenGL.cpp PROPERTIES COTIRE_EXCLUDED TRUE) +# ri_apply_cotire() +#endif() diff --git a/Fwk/VizFwk/LibRender/cvfDrawableText.cpp b/Fwk/VizFwk/LibRender/cvfDrawableText.cpp index a00ab3f356..7ea34edc59 100644 --- a/Fwk/VizFwk/LibRender/cvfDrawableText.cpp +++ b/Fwk/VizFwk/LibRender/cvfDrawableText.cpp @@ -189,14 +189,23 @@ void DrawableText::setUseDepthBuffer(bool useDepthBuffer) //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void DrawableText::addText(const String& text, const Vec3f& position) +void DrawableText::addText(const String& text, const Vec3f& position, const Vec3f& direction) { m_positions.push_back(position); m_texts.push_back(text); - m_boundingBox.add(position); + m_directions.push_back(direction); + m_boundingBox.add(position); } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +size_t DrawableText::numberOfTexts() const +{ + return m_texts.size(); +} + //-------------------------------------------------------------------------------------------------- /// Main shader based rendering path for the geometry //-------------------------------------------------------------------------------------------------- @@ -269,6 +278,27 @@ BoundingBox DrawableText::boundingBox() const } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +cvf::BoundingBox DrawableText::textBoundingBox(const String& text, const Vec3f& position, const Vec3f& direction /*= Vec3f::X_AXIS*/) +{ + ref glyph = m_font->getGlyph(L'A'); + Vec2f textExtent(m_font->textExtent(text)); + short verticalAlignment = TextDrawer::calculateVerticalAlignmentOffset(*m_font, m_verticalAlignment); + float glyphMarginX = 0.25f * static_cast(glyph->width()); + float glyphMarginY = 0.25f * static_cast(glyph->height()); + + BoundingBox textBox; + std::array corners = TextDrawer::textCorners(*glyph, cvf::Vec2f::ZERO, textExtent, verticalAlignment, direction, glyphMarginX, glyphMarginY); + for (size_t i = 0; i < corners.size(); i++) + { + const Vec3f& corner = corners[i]; + textBox.add(position + corner); + } + return textBox; +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -293,7 +323,7 @@ void DrawableText::renderText(OpenGLContext* oglContext, ShaderProgram* shaderPr CVF_ASSERT(!shaderProgram || ShaderProgram::supportedOpenGL(oglContext)); if (m_texts.size() == 0) return; - CVF_ASSERT(m_positions.size() == m_texts.size()); + CVF_ASSERT(m_positions.size() == m_texts.size() && m_positions.size() == m_directions.size()); if (m_checkPosVisible) { @@ -342,17 +372,19 @@ void DrawableText::renderText(OpenGLContext* oglContext, ShaderProgram* shaderPr Mat4d modelViewProjectionMatrix = Mat4d(matrixState.modelViewProjectionMatrix()); std::vector projCoords; std::vector textsToDraw; // Text strings to be drawn + std::vector directions; size_t pos; for (pos = 0; pos < m_positions.size(); pos++) { Vec3d proj; GeometryUtils::project(modelViewProjectionMatrix, matrixState.viewportPosition(), matrixState.viewportSize(), Vec3d(m_positions[pos]), &proj); - + CVF_ASSERT(!proj.isUndefined()); if (!m_checkPosVisible || labelAnchorVisible(oglContext, proj, m_positions[pos], shaderProgram == NULL)) { // Note: Need to adjust for the current viewport, as the coords returned from project are in global windows coordinates projCoords.push_back(Vec3f(static_cast(proj.x() - matrixState.viewportPosition().x()), static_cast(proj.y() - matrixState.viewportPosition().y()), static_cast(1.0 - 2.0*proj.z()))); // Map z into 1 .. -1 textsToDraw.push_back(m_texts[pos]); + directions.push_back(m_directions[pos]); } } @@ -389,7 +421,7 @@ void DrawableText::renderText(OpenGLContext* oglContext, ShaderProgram* shaderPr for (i = 0; i < textsToDraw.size(); i++) { Vec3f pos = projCoords[i]; - drawer.addText(textsToDraw[i], pos); + drawer.addText(textsToDraw[i], pos, directions[i]); } if (shaderProgram) diff --git a/Fwk/VizFwk/LibRender/cvfDrawableText.h b/Fwk/VizFwk/LibRender/cvfDrawableText.h index beb75a568f..ffc08e69c8 100644 --- a/Fwk/VizFwk/LibRender/cvfDrawableText.h +++ b/Fwk/VizFwk/LibRender/cvfDrawableText.h @@ -65,8 +65,8 @@ class DrawableText : public Drawable void setFont(Font* font); ref font() const; - void addText(const String& text, const Vec3f& position); - + void addText(const String& text, const Vec3f& position, const Vec3f& direction = Vec3f::X_AXIS); + size_t numberOfTexts() const; void setVerticalAlignment(TextDrawer::Alignment alignment); void setTextColor(const Color3f& color); void setBackgroundColor(const Color3f& color); @@ -87,6 +87,7 @@ class DrawableText : public Drawable virtual size_t faceCount() const; virtual BoundingBox boundingBox() const; + BoundingBox textBoundingBox(const String& text, const Vec3f& position, const Vec3f& direction = Vec3f::X_AXIS); virtual bool rayIntersectCreateDetail(const Ray& ray, Vec3d* intersectionPoint, ref* hitDetail) const; bool rayIntersect(const Ray& ray, const Camera& camera, Vec3d* intersectionPoint); @@ -103,6 +104,8 @@ class DrawableText : public Drawable private: std::vector m_positions; // Coordinate of the lower left corner of where to place the text in pixel coordinates std::vector m_texts; // Text strings to be drawn + std::vector m_directions; // Text direction + ref m_font; // Font used to draw text TextDrawer::Alignment m_verticalAlignment; diff --git a/Fwk/VizFwk/LibRender/cvfGlyph.cpp b/Fwk/VizFwk/LibRender/cvfGlyph.cpp index ffe0a9f696..25e129beef 100644 --- a/Fwk/VizFwk/LibRender/cvfGlyph.cpp +++ b/Fwk/VizFwk/LibRender/cvfGlyph.cpp @@ -72,7 +72,9 @@ Glyph::Glyph(wchar_t character) m_horizontalBearingY(0), m_horizontalAdvance(0), m_textureImage(new TextureImage), - m_textureCoordinates(new FloatArray(8)) + m_textureCoordinates(new FloatArray(8)), + m_minFilter(NEAREST), + m_magFilter(NEAREST) { // Lower left m_textureCoordinates->set(0, 0.0f); @@ -345,8 +347,23 @@ void Glyph::setupAndBindTexture(OpenGLContext* oglContext, bool software) // Use fixed function texture setup ref texture = new Texture2D_FF(m_textureImage.p()); texture->setWrapMode(Texture2D_FF::CLAMP); - texture->setMinFilter(Texture2D_FF::NEAREST); - texture->setMagFilter(Texture2D_FF::NEAREST); + if (m_minFilter == NEAREST) + { + texture->setMinFilter(Texture2D_FF::NEAREST); + } + else + { + texture->setMinFilter(Texture2D_FF::LINEAR); + } + + if (m_magFilter == NEAREST) + { + texture->setMagFilter(Texture2D_FF::NEAREST); + } + else + { + texture->setMagFilter(Texture2D_FF::LINEAR); + } ref textureMapping = new RenderStateTextureMapping_FF(texture.p()); textureMapping->setTextureFunction(RenderStateTextureMapping_FF::MODULATE); @@ -359,8 +376,23 @@ void Glyph::setupAndBindTexture(OpenGLContext* oglContext, bool software) { ref sampler = new Sampler; sampler->setWrapMode(Sampler::CLAMP_TO_EDGE); - sampler->setMinFilter(Sampler::NEAREST); - sampler->setMagFilter(Sampler::NEAREST); + if (m_minFilter == NEAREST) + { + sampler->setMinFilter(Sampler::NEAREST); + } + else + { + sampler->setMinFilter(Sampler::LINEAR); + } + + if (m_magFilter == NEAREST) + { + sampler->setMagFilter(Sampler::NEAREST); + } + else + { + sampler->setMagFilter(Sampler::LINEAR); + } ref texture = new Texture(m_textureImage.p()); @@ -377,4 +409,20 @@ void Glyph::setupAndBindTexture(OpenGLContext* oglContext, bool software) } } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void Glyph::setMinFilter(TextureFilter filter) +{ + m_minFilter = filter; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void Glyph::setMagFilter(TextureFilter filter) +{ + m_magFilter = filter; +} + } // namespace cvf diff --git a/Fwk/VizFwk/LibRender/cvfGlyph.h b/Fwk/VizFwk/LibRender/cvfGlyph.h index 3356098ed5..8e5302240a 100644 --- a/Fwk/VizFwk/LibRender/cvfGlyph.h +++ b/Fwk/VizFwk/LibRender/cvfGlyph.h @@ -55,6 +55,12 @@ class OpenGLContext; class Glyph : public Object { public: + enum TextureFilter + { + NEAREST, + LINEAR + }; + Glyph(wchar_t character); virtual ~Glyph(); @@ -78,6 +84,9 @@ class Glyph : public Object void setupAndBindTexture(OpenGLContext* oglContext, bool software); + void setMinFilter(TextureFilter filter); + void setMagFilter(TextureFilter filter); + private: wchar_t m_character; // Character this glyph is generated from @@ -95,6 +104,10 @@ class Glyph : public Object ref m_textureImage; // Pre-rendered image of m_character ref m_textureCoordinates; // Texture coordinates of where in the m_texgtureImage to find the given pre-rendered character ref m_textureBindings; // For shader based rendering this is a TextureBindings object, while software rendering uses RenderStateTextureMapping_FF instead + + // Texture filter options + TextureFilter m_minFilter; + TextureFilter m_magFilter; }; } // namespace cvf diff --git a/Fwk/VizFwk/LibRender/cvfTextDrawer.cpp b/Fwk/VizFwk/LibRender/cvfTextDrawer.cpp index 8106d4918a..a4c4350c71 100644 --- a/Fwk/VizFwk/LibRender/cvfTextDrawer.cpp +++ b/Fwk/VizFwk/LibRender/cvfTextDrawer.cpp @@ -99,13 +99,14 @@ TextDrawer::~TextDrawer() // -------------------------------------------------------------------------------------------------- /// Add text to be drawn // -------------------------------------------------------------------------------------------------- -void TextDrawer::addText(const String& text, const Vec2f& pos) +void TextDrawer::addText(const String& text, const Vec2f& pos, const Vec2f& dir) { CVF_ASSERT(!text.isEmpty()); CVF_ASSERT(!pos.isUndefined()); m_texts.push_back(text); m_positions.push_back(Vec3f(pos)); + m_directions.push_back(Vec3f(dir)); } @@ -115,13 +116,14 @@ void TextDrawer::addText(const String& text, const Vec2f& pos) /// Note: The Z coordinate needs to correspond with the orthographic projection that is setup /// to render the text. So the range should be <1..-1> with 1 being closest to the near plane. //-------------------------------------------------------------------------------------------------- -void TextDrawer::addText(const String& text, const Vec3f& pos) +void TextDrawer::addText(const String& text, const Vec3f& pos, const Vec3f& dir) { CVF_ASSERT(!text.isEmpty()); CVF_ASSERT(!pos.isUndefined()); m_texts.push_back(text); m_positions.push_back(pos); + m_directions.push_back(dir); } @@ -132,6 +134,7 @@ void TextDrawer::removeAllTexts() { m_texts.clear(); m_positions.clear(); + m_directions.clear(); } @@ -170,44 +173,7 @@ void TextDrawer::setVerticalAlignment(TextDrawer::Alignment alignment) CVF_ASSERT(m_font.notNull()); CVF_ASSERT(!m_font->isEmpty()); - switch (alignment) - { - case TextDrawer::TOP: - { - // Character assumed to reach all the way up - ref glyph_top = m_font->getGlyph(L'`'); - m_verticalAlignment = static_cast(-glyph_top->horizontalBearingY()); - break; - } - - case TextDrawer::CENTER: - { - // Center around A - ref glyph_top = m_font->getGlyph(L'A'); - m_verticalAlignment = static_cast(-((glyph_top->horizontalBearingY() + 1) >> 1)); - break; - } - - case TextDrawer::BASELINE: - { - m_verticalAlignment = 0; - break; - } - - case TextDrawer::BOTTOM: - { - // Character assumed to reach all the way down - ref glyph_bottom = m_font->getGlyph(L'g'); - m_verticalAlignment = static_cast(static_cast(glyph_bottom->height()) + glyph_bottom->horizontalBearingY()); - break; - } - - default: - { - CVF_FAIL_MSG("Unsupported alignment type"); - break; - } - } + m_verticalAlignment = calculateVerticalAlignmentOffset(*m_font, alignment); } @@ -307,7 +273,7 @@ void TextDrawer::renderSoftware(OpenGLContext* oglContext, const MatrixState& ma void TextDrawer::doRender2d(OpenGLContext* oglContext, const MatrixState& matrixState, bool softwareRendering) { CVF_CALLSITE_OPENGL(oglContext); - CVF_ASSERT(m_positions.size() == m_texts.size()); + CVF_ASSERT(m_positions.size() == m_texts.size() && m_positions.size() == m_directions.size()); static const ushort connects[] = { 0, 1, 2, 0, 2, 3 }; static const ushort lineConnects[] = { 0, 1, 1, 2, 2, 3, 3, 0 }; @@ -315,11 +281,11 @@ void TextDrawer::doRender2d(OpenGLContext* oglContext, const MatrixState& matrix float vertexArray[12]; float textureCoords[8]; // Will be updated for each glyph - float* v1 = &vertexArray[0]; - float* v2 = &vertexArray[3]; - float* v3 = &vertexArray[6]; - float* v4 = &vertexArray[9]; - v1[2] = v2[2] = v3[2] = v4[2] = 0.0f; + std::array vertices = { &vertexArray[0], &vertexArray[3], &vertexArray[6], &vertexArray[9] }; + for (size_t i = 0; i < vertices.size(); ++i) + { + vertices[i][2] = 0.0f; + } // Prepare 2D pixel exact projection to draw texts Camera projCam; @@ -374,7 +340,7 @@ void TextDrawer::doRender2d(OpenGLContext* oglContext, const MatrixState& matrix // Use a fixed line spacing float lineSpacing = m_font->lineSpacing(); - Vec2f offset(0,0); + Vec2f offset(0, 0); // Render background and border // ------------------------------------------------------------------------- @@ -401,27 +367,24 @@ void TextDrawer::doRender2d(OpenGLContext* oglContext, const MatrixState& matrix // Figure out margin ref glyph = m_font->getGlyph(L'A'); - float charHeight = static_cast(glyph->height()); - float charWidth = static_cast(glyph->width()); - - offset.x() = cvf::Math::floor(charWidth/2.0f); - offset.y() = cvf::Math::floor(charHeight/2.0f); - + float glyphMarginX = cvf::Math::floor(0.5f * static_cast(glyph->width())); + float glyphMarginY = cvf::Math::floor(0.5f * static_cast(glyph->height())); size_t numTexts = m_texts.size(); for (size_t i = 0; i < numTexts; i++) { Vec3f pos = m_positions[i]; - String text = m_texts[i]; - Vec2ui textExtent = m_font->textExtent(text); - Vec3f min = pos;//Vec3f(textBB.min()); - Vec3f max = Vec3f(min.x() + static_cast(textExtent.x()) + offset.x()*2.0f, min.y() + static_cast(textExtent.y()) + offset.y()*2.0f, 0.0f); + String text = m_texts[i]; + Vec2f textExtent(m_font->textExtent(text)); + std::array corners = textCorners(*glyph, cvf::Vec2f::ZERO, textExtent, m_verticalAlignment, m_directions[i], glyphMarginX, glyphMarginY); - // Draw the background triangle - v1[0] = min.x(); v1[1] = min.y(); v1[2] = pos.z(); - v2[0] = max.x(); v2[1] = min.y(); v2[2] = pos.z(); - v3[0] = max.x(); v3[1] = max.y(); v3[2] = pos.z(); - v4[0] = min.x(); v4[1] = max.y(); v4[2] = pos.z(); + for (size_t v = 0; v < vertices.size(); ++v) + { + for (int c = 0; c < 3; ++c) + { + vertices[v][c] = pos[c] + corners[v][c]; + } + } if (m_drawBackground) { @@ -432,10 +395,10 @@ void TextDrawer::doRender2d(OpenGLContext* oglContext, const MatrixState& matrix glDisable(GL_TEXTURE_2D); glColor3fv(m_backgroundColor.ptr()); glBegin(GL_TRIANGLE_FAN); - glVertex3fv(v1); - glVertex3fv(v2); - glVertex3fv(v3); - glVertex3fv(v4); + for (size_t v = 0; v < vertices.size(); ++v) + { + glVertex3fv(vertices[v]); + } glEnd(); #endif } @@ -456,10 +419,10 @@ void TextDrawer::doRender2d(OpenGLContext* oglContext, const MatrixState& matrix #ifndef CVF_OPENGL_ES glColor3fv(m_borderColor.ptr()); glBegin(GL_LINE_LOOP); - glVertex3fv(v1); - glVertex3fv(v2); - glVertex3fv(v3); - glVertex3fv(v4); + for (size_t v = 0; v < vertices.size(); ++v) + { + glVertex3fv(vertices[v]); + } glEnd(); #endif } @@ -523,16 +486,16 @@ void TextDrawer::doRender2d(OpenGLContext* oglContext, const MatrixState& matrix size_t i, j; for (i = 0; i < numTexts; i++) { - Vec3f pos = m_positions[i]; - - String text = m_texts[i]; + Vec3f pos = m_positions[i]; + Vec3f textDir = m_directions[i]; + String text = m_texts[i]; // Need to round off to integer positions to avoid buggy text drawing on iPad2 pos.x() = cvf::Math::floor(pos.x()); pos.y() = cvf::Math::floor(pos.y()); // Cursor incrementor - Vec2f cursor(pos); + Vec2f cursor(Vec2f::ZERO); cursor += offset; std::vector lines = text.split("\n"); @@ -547,30 +510,27 @@ void TextDrawer::doRender2d(OpenGLContext* oglContext, const MatrixState& matrix { character = line[j]; ref glyph = m_font->getGlyph(character); + cvf::Vec2f glyphExtent(static_cast(glyph->width()), static_cast(glyph->height())); + std::array corners = textCorners(*glyph, cursor, glyphExtent, m_verticalAlignment, textDir); - float textureWidth = static_cast(glyph->width()); - float textureHeight = static_cast(glyph->height()); - - // Lower left corner - v1[0] = cursor.x() + static_cast(glyph->horizontalBearingX()); - v1[1] = cursor.y() + static_cast(glyph->horizontalBearingY()) - textureHeight + static_cast(m_verticalAlignment); - v1[2] = pos.z(); - - // Lower right corner - v2[0] = v1[0] + textureWidth; - v2[1] = v1[1]; - v2[2] = pos.z(); - - // Upper right corner - v3[0] = v2[0]; - v3[1] = v1[1] + textureHeight; - v3[2] = pos.z(); - - // Upper left corner - v4[0] = v1[0]; - v4[1] = v3[1]; - v4[2] = pos.z(); - + for (size_t v = 0; v < vertices.size(); ++v) + { + for (int c = 0; c < 3; ++c) + { + vertices[v][c] = pos[c] + corners[v][c]; + } + } + if (textDir.dot(cvf::Vec3f::X_AXIS) < 0.9 && textDir.dot(cvf::Vec3f::Y_AXIS) < 0.9) + { + glyph->setMinFilter(Glyph::LINEAR); + glyph->setMagFilter(Glyph::LINEAR); + } + else + { + glyph->setMinFilter(Glyph::NEAREST); + glyph->setMagFilter(Glyph::NEAREST); + } + glyph->setupAndBindTexture(oglContext, softwareRendering); // Get texture coordinates @@ -592,19 +552,19 @@ void TextDrawer::doRender2d(OpenGLContext* oglContext, const MatrixState& matrix // First triangle in quad glTexCoord2fv(&textureCoordinatesPtr[0]); - glVertex3fv(v1); + glVertex3fv(vertices[0]); glTexCoord2fv(&textureCoordinatesPtr[2]); - glVertex3fv(v2); + glVertex3fv(vertices[1]); glTexCoord2fv(&textureCoordinatesPtr[4]); - glVertex3fv(v3); + glVertex3fv(vertices[2]); // Second triangle in quad glTexCoord2fv(&textureCoordinatesPtr[0]); - glVertex3fv(v1); + glVertex3fv(vertices[0]); glTexCoord2fv(&textureCoordinatesPtr[4]); - glVertex3fv(v3); + glVertex3fv(vertices[2]); glTexCoord2fv(&textureCoordinatesPtr[6]); - glVertex3fv(v4); + glVertex3fv(vertices[3]); glEnd(); #endif @@ -623,7 +583,7 @@ void TextDrawer::doRender2d(OpenGLContext* oglContext, const MatrixState& matrix } // CR - cursor.x() = pos.x() + offset.x(); + cursor.x() = offset.x(); cursor.y() += lineSpacing; } } @@ -693,4 +653,76 @@ bool TextDrawer::pickText(const Vec3f& pickCoord2d, const String& text, const Ve return false; } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +short TextDrawer::calculateVerticalAlignmentOffset(Font& font, Alignment alignment) +{ + switch (alignment) + { + case TextDrawer::TOP: + { + // Character assumed to reach all the way up + ref glyph_top = font.getGlyph(L'`'); + return static_cast(-glyph_top->horizontalBearingY()); + } + + case TextDrawer::CENTER: + { + // Center around A + ref glyph_top = font.getGlyph(L'A'); + return static_cast(-((glyph_top->horizontalBearingY() + 1) >> 1)); + } + + case TextDrawer::BASELINE: + { + return 0; + } + + case TextDrawer::BOTTOM: + { + // Character assumed to reach all the way down + ref glyph_bottom = font.getGlyph(L'g'); + return static_cast(static_cast(glyph_bottom->height()) + glyph_bottom->horizontalBearingY()); + } + + default: + { + CVF_FAIL_MSG("Unsupported alignment type"); + break; + } + } + return 0; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::array TextDrawer::textCorners(const Glyph& glyph, const Vec2f& textStart, const Vec2f& textExtent, short verticalAlignment, const Vec3f& textDirection, float marginX, float marginY) +{ + Vec3f tangent = textDirection; + if (tangent.x() < 0.0f) tangent *= -1.0f; + Vec2f tan2d(tangent.x(), tangent.y()); + Vec3f normal(-tan2d.perpendicularVector(), tangent.z()); + + float x1 = textStart.x() + static_cast(glyph.horizontalBearingX()) - marginY; + float y1 = textStart.y() + static_cast(glyph.horizontalBearingY()) - static_cast(glyph.height()) + static_cast(verticalAlignment) - marginY; + + float x2 = x1 + textExtent.x() + 2.0f * marginX; + float y2 = y1 + textExtent.y() + 2.0f * marginY; + + // Lower left corner + Vec3f c1 = tangent * x1 + normal * y1; + // Lower right corner + Vec3f c2 = tangent * x2 + normal * y1; + // Upper right corner + Vec3f c3 = tangent * x2 + normal * y2; + // Upper left corner + Vec3f c4 = tangent * x1 + normal * y2; + + + std::array retArr = { c1, c2, c3, c4 }; + return retArr; +} + } // namespace cvf diff --git a/Fwk/VizFwk/LibRender/cvfTextDrawer.h b/Fwk/VizFwk/LibRender/cvfTextDrawer.h index 00c4da1a35..1ceabd0f6e 100644 --- a/Fwk/VizFwk/LibRender/cvfTextDrawer.h +++ b/Fwk/VizFwk/LibRender/cvfTextDrawer.h @@ -39,12 +39,15 @@ #include "cvfObject.h" #include "cvfString.h" +#include "cvfVector2.h" #include "cvfVector3.h" #include "cvfColor3.h" +#include namespace cvf { +class Glyph; class Font; class ShaderProgram; class MatrixState; @@ -72,8 +75,8 @@ class TextDrawer : public Object TextDrawer(Font* font); virtual ~TextDrawer(); - void addText(const String& text, const Vec2f& pos); - void addText(const String& text, const Vec3f& pos); + void addText(const String& text, const Vec2f& pos, const Vec2f& dir = Vec2f::X_AXIS); + void addText(const String& text, const Vec3f& pos, const Vec3f& dir = Vec3f::X_AXIS); void removeAllTexts(); void setVerticalAlignment(Alignment alignment); @@ -96,7 +99,10 @@ class TextDrawer : public Object void renderSoftware(OpenGLContext* oglContext, const MatrixState& matrixState); static bool pickText(const Vec3f& pickCoord2d, const String& text, const Vec3f& pos, Font* font); + + static short calculateVerticalAlignmentOffset(Font& font, Alignment alignment); + static std::array textCorners(const Glyph& glyph, const Vec2f& textStart, const Vec2f& textExtent, short verticalAlignment, const Vec3f& textDirection, float marginX = 0.0, float marginY = 0.0); private: void doRender2d(OpenGLContext* oglContext, const MatrixState& matrixState, bool softwareRendering); @@ -104,6 +110,7 @@ class TextDrawer : public Object ref m_font; // Font used to draw text std::vector m_positions; // Coordinate of the lower left corner of where to place each individual text strings std::vector m_texts; // Text strings to be drawn + std::vector m_directions; // Clockwise rotations around the position in radians bool m_drawBackground; bool m_drawBorder; diff --git a/Fwk/VizFwk/LibViewing/CMakeLists.txt b/Fwk/VizFwk/LibViewing/CMakeLists.txt index 28f5937fbd..c78e39442e 100644 --- a/Fwk/VizFwk/LibViewing/CMakeLists.txt +++ b/Fwk/VizFwk/LibViewing/CMakeLists.txt @@ -84,3 +84,7 @@ target_link_libraries ( ${PROJECT_NAME} set(PROJECT_FILES ${CEE_HEADER_FILES} ${CEE_SOURCE_FILES}) source_group("" FILES ${PROJECT_FILES}) + +#if (COMMAND ri_apply_cotire) +# ri_apply_cotire() +#endif() diff --git a/Fwk/VizFwk/LibViewing/cvfRendering.cpp b/Fwk/VizFwk/LibViewing/cvfRendering.cpp index 52035a3707..ea57866a66 100644 --- a/Fwk/VizFwk/LibViewing/cvfRendering.cpp +++ b/Fwk/VizFwk/LibViewing/cvfRendering.cpp @@ -870,6 +870,11 @@ size_t Rendering::overlayItemCount() const void Rendering::addOverlayItem(OverlayItem* overlayItem) { CVF_ASSERT(overlayItem); + + for (size_t i = 0; i < overlayItemCount(); i++) + { + if (this->overlayItem(i) == overlayItem) return; + } m_overlayItems.push_back(overlayItem); } diff --git a/Fwk/VizFwk/TestApps/Qt/QtMinimal/CMakeLists.txt b/Fwk/VizFwk/TestApps/Qt/QtMinimal/CMakeLists.txt index 414d4f097e..c5c3adb36d 100644 --- a/Fwk/VizFwk/TestApps/Qt/QtMinimal/CMakeLists.txt +++ b/Fwk/VizFwk/TestApps/Qt/QtMinimal/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 2.8) +cmake_minimum_required(VERSION 2.8.12) project(QtMinimal) @@ -12,9 +12,15 @@ endif() find_package(OpenGL) -find_package(Qt4 COMPONENTS QtCore QtGui QtOpenGL REQUIRED) -include(${QT_USE_FILE}) - +if (CEE_USE_QT5) + find_package(Qt5 COMPONENTS Core Gui OpenGL Widgets REQUIRED) +else() + find_package(Qt4 COMPONENTS QtCore QtGui QtOpenGL REQUIRED) + include(${QT_USE_FILE}) + if (QT4_FOUND) + message(STATUS "Found Qt4") + endif(QT4_FOUND) +endif(CEE_USE_QT5) include_directories(${LibCore_SOURCE_DIR}) include_directories(${LibGeometry_SOURCE_DIR}) @@ -40,22 +46,36 @@ QMWidget.h # Run MOC on the headers add_definitions(-DCVF_USING_CMAKE) set(MOC_SOURCE_FILES) -qt4_wrap_cpp(MOC_SOURCE_FILES ${MOC_HEADER_FILES} ) +if (CEE_USE_QT5) + qt5_wrap_cpp(MOC_SOURCE_FILES ${MOC_HEADER_FILES} ) + set(QT_LIBRARIES Qt5::Core Qt5::Gui Qt5::OpenGL Qt5::Widgets) +else() + qt4_wrap_cpp(MOC_SOURCE_FILES ${MOC_HEADER_FILES} ) +endif() + add_executable(${PROJECT_NAME} ${CEE_SOURCE_FILES} ${MOC_SOURCE_FILES}) target_link_libraries(${PROJECT_NAME} ${CEE_LIBS} ${OPENGL_LIBRARIES} ${QT_LIBRARIES}) - -# Copy Qt Dlls -if (MSVC) - set (QTLIBLIST QtCore QtGui QtOpenGl) - foreach (qtlib ${QTLIBLIST}) - - # Debug - execute_process(COMMAND cmake -E copy_if_different ${QT_BINARY_DIR}/${qtlib}d4.dll ${CMAKE_BINARY_DIR}/Debug/${qtlib}d4.dll) - - # Release - execute_process(COMMAND cmake -E copy_if_different ${QT_BINARY_DIR}/${qtlib}4.dll ${CMAKE_BINARY_DIR}/Release/${qtlib}4.dll) - endforeach( qtlib ) -endif(MSVC) +if (CEE_USE_QT5) + foreach (qtlib ${QT_LIBRARIES}) + add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_if_different $ $ + ) + endforeach(qtlib) + # Copy Qt Dlls +else() + # Copy Qt Dlls + if (MSVC) + set (QTLIBLIST QtCore QtGui QtOpenGl) + foreach (qtlib ${QTLIBLIST}) + + # Debug + execute_process(COMMAND cmake -E copy_if_different ${QT_BINARY_DIR}/${qtlib}d4.dll ${CMAKE_BINARY_DIR}/Debug/${qtlib}d4.dll) + + # Release + execute_process(COMMAND cmake -E copy_if_different ${QT_BINARY_DIR}/${qtlib}4.dll ${CMAKE_BINARY_DIR}/Release/${qtlib}4.dll) + endforeach( qtlib ) + endif(MSVC) +endif(CEE_USE_QT5) diff --git a/Fwk/VizFwk/TestApps/Qt/QtMinimal/QMMain.cpp b/Fwk/VizFwk/TestApps/Qt/QtMinimal/QMMain.cpp index 652c929743..5e7a334a62 100644 --- a/Fwk/VizFwk/TestApps/Qt/QtMinimal/QMMain.cpp +++ b/Fwk/VizFwk/TestApps/Qt/QtMinimal/QMMain.cpp @@ -39,7 +39,12 @@ #include "QMMainWindow.h" -#include "QtGui/QApplication" +#include +#if QT_VERSION >= 0x050000 +#include +#else +#include +#endif //-------------------------------------------------------------------------------------------------- diff --git a/Fwk/VizFwk/TestApps/Qt/QtMinimal/QMMainWindow.cpp b/Fwk/VizFwk/TestApps/Qt/QtMinimal/QMMainWindow.cpp index 1d8a2a7991..4c28ef5f60 100644 --- a/Fwk/VizFwk/TestApps/Qt/QtMinimal/QMMainWindow.cpp +++ b/Fwk/VizFwk/TestApps/Qt/QtMinimal/QMMainWindow.cpp @@ -42,13 +42,19 @@ #include "QMMainWindow.h" #include "QMWidget.h" - +#if QT_VERSION >= 0x050000 +#include +#include +#include +#include +#include +#else #include #include #include #include #include - +#endif using cvf::ref; diff --git a/Fwk/VizFwk/TestApps/Qt/QtMinimal/QMMainWindow.h b/Fwk/VizFwk/TestApps/Qt/QtMinimal/QMMainWindow.h index 144304239f..56272b94ba 100644 --- a/Fwk/VizFwk/TestApps/Qt/QtMinimal/QMMainWindow.h +++ b/Fwk/VizFwk/TestApps/Qt/QtMinimal/QMMainWindow.h @@ -40,7 +40,12 @@ #include "cvfObject.h" #include "cvfOpenGLContextGroup.h" +#include +#if QT_VERSION >= 0x050000 +#include +#else #include +#endif class QMWidget; diff --git a/Fwk/VizFwk/TestApps/Qt/QtMinimal/QMWidget.cpp b/Fwk/VizFwk/TestApps/Qt/QtMinimal/QMWidget.cpp index b82b96f023..1e9ad82a15 100644 --- a/Fwk/VizFwk/TestApps/Qt/QtMinimal/QMWidget.cpp +++ b/Fwk/VizFwk/TestApps/Qt/QtMinimal/QMWidget.cpp @@ -44,7 +44,11 @@ #include "cvfqtOpenGLContext.h" +#if QT_VERSION >= 0x050000 +#include +#else #include +#endif using cvf::ref; diff --git a/Fwk/VizFwk/TestApps/Qt/QtMultiView/CMakeLists.txt b/Fwk/VizFwk/TestApps/Qt/QtMultiView/CMakeLists.txt index 56c1a44252..2f05703921 100644 --- a/Fwk/VizFwk/TestApps/Qt/QtMultiView/CMakeLists.txt +++ b/Fwk/VizFwk/TestApps/Qt/QtMultiView/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 2.8) +cmake_minimum_required(VERSION 2.8.12) project(QtMultiView) @@ -12,9 +12,15 @@ endif() find_package(OpenGL) -find_package(Qt4 COMPONENTS QtCore QtGui QtOpenGL REQUIRED) -include(${QT_USE_FILE}) - +if (CEE_USE_QT5) + find_package(Qt5 COMPONENTS Core Gui OpenGL Widgets REQUIRED) +else() + find_package(Qt4 COMPONENTS QtCore QtGui QtOpenGL REQUIRED) + include(${QT_USE_FILE}) + if (QT4_FOUND) + message(STATUS "Found Qt4") + endif(QT4_FOUND) +endif(CEE_USE_QT5) include_directories(${LibCore_SOURCE_DIR}) include_directories(${LibGeometry_SOURCE_DIR}) @@ -42,10 +48,34 @@ QMVWidget.h # Run MOC on the headers add_definitions(-DCVF_USING_CMAKE) set(MOC_SOURCE_FILES) -qt4_wrap_cpp(MOC_SOURCE_FILES ${MOC_HEADER_FILES} ) - +if (CEE_USE_QT5) + qt5_wrap_cpp(MOC_SOURCE_FILES ${MOC_HEADER_FILES} ) + set(QT_LIBRARIES Qt5::Core Qt5::Gui Qt5::OpenGL Qt5::Widgets) +else() + qt4_wrap_cpp(MOC_SOURCE_FILES ${MOC_HEADER_FILES} ) +endif(CEE_USE_QT5) add_executable(${PROJECT_NAME} ${CEE_SOURCE_FILES} ${MOC_SOURCE_FILES}) target_link_libraries(${PROJECT_NAME} ${CEE_LIBS} ${OPENGL_LIBRARIES} ${QT_LIBRARIES}) - +if (CEE_USE_QT5) + foreach (qtlib ${QT_LIBRARIES}) + add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_if_different $ $ + ) + endforeach(qtlib) + # Copy Qt Dlls +else() + # Copy Qt Dlls + if (MSVC) + set (QTLIBLIST QtCore QtGui QtOpenGl) + foreach (qtlib ${QTLIBLIST}) + + # Debug + execute_process(COMMAND cmake -E copy_if_different ${QT_BINARY_DIR}/${qtlib}d4.dll ${CMAKE_BINARY_DIR}/Debug/${qtlib}d4.dll) + + # Release + execute_process(COMMAND cmake -E copy_if_different ${QT_BINARY_DIR}/${qtlib}4.dll ${CMAKE_BINARY_DIR}/Release/${qtlib}4.dll) + endforeach( qtlib ) + endif(MSVC) +endif(CEE_USE_QT5) \ No newline at end of file diff --git a/Fwk/VizFwk/TestApps/Qt/QtMultiView/QMVMain.cpp b/Fwk/VizFwk/TestApps/Qt/QtMultiView/QMVMain.cpp index 883cc51efe..fe9aac16e9 100644 --- a/Fwk/VizFwk/TestApps/Qt/QtMultiView/QMVMain.cpp +++ b/Fwk/VizFwk/TestApps/Qt/QtMultiView/QMVMain.cpp @@ -39,7 +39,11 @@ #include "QMVMainWindow.h" -#include "QtGui/QApplication" +#if QT_VERSION >= 0x050000 +#include +#else +#include +#endif #include "QtOpenGL/qgl.h" diff --git a/Fwk/VizFwk/TestApps/Qt/QtMultiView/QMVMainWindow.cpp b/Fwk/VizFwk/TestApps/Qt/QtMultiView/QMVMainWindow.cpp index ec6c70b23e..f7a22acfee 100644 --- a/Fwk/VizFwk/TestApps/Qt/QtMultiView/QMVMainWindow.cpp +++ b/Fwk/VizFwk/TestApps/Qt/QtMultiView/QMVMainWindow.cpp @@ -45,6 +45,15 @@ #include "QMVFactory.h" #include +#if QT_VERSION >= 0x050000 +#include +#include +#include +#include +#include +#include +#include +#else #include #include #include @@ -52,6 +61,7 @@ #include #include #include +#endif using cvf::ref; diff --git a/Fwk/VizFwk/TestApps/Qt/QtMultiView/QMVMainWindow.h b/Fwk/VizFwk/TestApps/Qt/QtMultiView/QMVMainWindow.h index 3f435d79bc..e92294926e 100644 --- a/Fwk/VizFwk/TestApps/Qt/QtMultiView/QMVMainWindow.h +++ b/Fwk/VizFwk/TestApps/Qt/QtMultiView/QMVMainWindow.h @@ -41,7 +41,12 @@ #include "cvfCollection.h" #include "cvfDrawableGeo.h" +#include +#if QT_VERSION >= 0x050000 +#include +#else #include +#endif class QMVWidget; diff --git a/Fwk/VizFwk/TestApps/Qt/QtMultiView/QMVWidget.cpp b/Fwk/VizFwk/TestApps/Qt/QtMultiView/QMVWidget.cpp index cd6e692f48..f0a5bcef96 100644 --- a/Fwk/VizFwk/TestApps/Qt/QtMultiView/QMVWidget.cpp +++ b/Fwk/VizFwk/TestApps/Qt/QtMultiView/QMVWidget.cpp @@ -44,7 +44,11 @@ #include "cvfqtOpenGLContext.h" +#if QT_VERSION >= 0x050000 +#include +#else #include +#endif using cvf::ref; diff --git a/Fwk/VizFwk/TestApps/Qt/QtSnippetRunner/CMakeLists.txt b/Fwk/VizFwk/TestApps/Qt/QtSnippetRunner/CMakeLists.txt index 64f32e8be2..db9697617c 100644 --- a/Fwk/VizFwk/TestApps/Qt/QtSnippetRunner/CMakeLists.txt +++ b/Fwk/VizFwk/TestApps/Qt/QtSnippetRunner/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 2.8) +cmake_minimum_required(VERSION 2.8.12) project(QtSnippetRunner) @@ -12,9 +12,15 @@ endif() find_package(OpenGL) -find_package(Qt4 COMPONENTS QtCore QtGui QtOpenGL REQUIRED) -include(${QT_USE_FILE}) - +if (CEE_USE_QT5) + find_package(Qt5 COMPONENTS Core Gui OpenGL Widgets REQUIRED) +else() + find_package(Qt4 COMPONENTS QtCore QtGui QtOpenGL REQUIRED) + include(${QT_USE_FILE}) + if (QT4_FOUND) + message(STATUS "Found Qt4") + endif(QT4_FOUND) +endif(CEE_USE_QT5) include_directories(${LibCore_SOURCE_DIR}) include_directories(${LibGeometry_SOURCE_DIR}) @@ -24,7 +30,7 @@ include_directories(${LibGuiQt_SOURCE_DIR}) include_directories(${LibUtilities_SOURCE_DIR}) include_directories(${SnippetsBasis_SOURCE_DIR}) -set(CEE_LIBS SnippetsBasis freetype LibFreeType LibUtilities LibGuiQt LibViewing LibRender LibGeometry LibIo LibCore) +set(CEE_LIBS SnippetsBasis freetype LibFreeType LibUtilities LibGuiQt LibViewing LibRender LibGeometry LibIo LibCore opengl32) include_directories(${SnippetsModules_SOURCE_DIR}) set(CEE_LIBS LibStructGrid ${CEE_LIBS}) @@ -52,10 +58,35 @@ QSRSnippetWidget.h # Run MOC on the headers add_definitions(-DCVF_USING_CMAKE) set(MOC_SOURCE_FILES) -qt4_wrap_cpp(MOC_SOURCE_FILES ${MOC_HEADER_FILES} ) +if (CEE_USE_QT5) + qt5_wrap_cpp(MOC_SOURCE_FILES ${MOC_HEADER_FILES} ) + set(QT_LIBRARIES Qt5::Core Qt5::Gui Qt5::OpenGL Qt5::Widgets) +else() + qt4_wrap_cpp(MOC_SOURCE_FILES ${MOC_HEADER_FILES} ) +endif(CEE_USE_QT5) add_executable(${PROJECT_NAME} ${CEE_SOURCE_FILES} ${MOC_SOURCE_FILES}) target_link_libraries(${PROJECT_NAME} ${CEE_LIBS} ${OPENGL_LIBRARIES} ${QT_LIBRARIES}) - +if (CEE_USE_QT5) + foreach (qtlib ${QT_LIBRARIES}) + add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_if_different $ $ + ) + endforeach(qtlib) + # Copy Qt Dlls +else() + # Copy Qt Dlls + if (MSVC) + set (QTLIBLIST QtCore QtGui QtOpenGl) + foreach (qtlib ${QTLIBLIST}) + + # Debug + execute_process(COMMAND cmake -E copy_if_different ${QT_BINARY_DIR}/${qtlib}d4.dll ${CMAKE_BINARY_DIR}/Debug/${qtlib}d4.dll) + + # Release + execute_process(COMMAND cmake -E copy_if_different ${QT_BINARY_DIR}/${qtlib}4.dll ${CMAKE_BINARY_DIR}/Release/${qtlib}4.dll) + endforeach( qtlib ) + endif(MSVC) +endif(CEE_USE_QT5) diff --git a/Fwk/VizFwk/TestApps/Qt/QtSnippetRunner/QSRMainWindow.cpp b/Fwk/VizFwk/TestApps/Qt/QtSnippetRunner/QSRMainWindow.cpp index efd01f62f1..09de80fe8b 100644 --- a/Fwk/VizFwk/TestApps/Qt/QtSnippetRunner/QSRMainWindow.cpp +++ b/Fwk/VizFwk/TestApps/Qt/QtSnippetRunner/QSRMainWindow.cpp @@ -539,11 +539,11 @@ void QSRMainWindow::slotSaveFrameBufferToFile() if (img.save(fileName)) { - cvf::Trace::show("Image saved to: %s", (const char*)fileName.toAscii()); + cvf::Trace::show("Image saved to: %s", (const char*)fileName.toLatin1()); } else { - cvf::Trace::show("FAILED to saved image: %s", (const char*)fileName.toAscii()); + cvf::Trace::show("FAILED to saved image: %s", (const char*)fileName.toLatin1()); } } diff --git a/Fwk/VizFwk/TestApps/Qt/QtSnippetRunner/QSRMainWindow.h b/Fwk/VizFwk/TestApps/Qt/QtSnippetRunner/QSRMainWindow.h index 304ac80e5f..ac5b6e81a1 100644 --- a/Fwk/VizFwk/TestApps/Qt/QtSnippetRunner/QSRMainWindow.h +++ b/Fwk/VizFwk/TestApps/Qt/QtSnippetRunner/QSRMainWindow.h @@ -45,7 +45,12 @@ #include "cvfuTestSnippet.h" #include "cvfuSnippetFactory.h" +#include +#if QT_VERSION >= 0x050000 +#include +#else #include +#endif class QSRSnippetWidget; diff --git a/Fwk/VizFwk/TestApps/Qt/QtSnippetRunner/QSRPropertiesPanel.cpp b/Fwk/VizFwk/TestApps/Qt/QtSnippetRunner/QSRPropertiesPanel.cpp index 2ecf709bb6..14f04099ed 100644 --- a/Fwk/VizFwk/TestApps/Qt/QtSnippetRunner/QSRPropertiesPanel.cpp +++ b/Fwk/VizFwk/TestApps/Qt/QtSnippetRunner/QSRPropertiesPanel.cpp @@ -42,6 +42,17 @@ #include "cvfuSnippetPropertyPublisher.h" #include "cvfqtUtils.h" +#if QT_VERSION >= 0x050000 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#else #include #include #include @@ -51,7 +62,7 @@ #include #include #include - +#endif //================================================================================================== diff --git a/Fwk/VizFwk/TestApps/Qt/QtSnippetRunner/QSRPropertiesPanel.h b/Fwk/VizFwk/TestApps/Qt/QtSnippetRunner/QSRPropertiesPanel.h index 6ccf39c5f7..906952849c 100644 --- a/Fwk/VizFwk/TestApps/Qt/QtSnippetRunner/QSRPropertiesPanel.h +++ b/Fwk/VizFwk/TestApps/Qt/QtSnippetRunner/QSRPropertiesPanel.h @@ -45,7 +45,11 @@ #include "cvfuSnippetPropertyPublisher.h" #include +#if QT_VERSION >= 0x050000 +#include +#else #include +#endif class QSRSnippetWidget; class QComboBox; diff --git a/Fwk/VizFwk/TestApps/Qt/QtSnippetRunner/QSRRunPanel.cpp b/Fwk/VizFwk/TestApps/Qt/QtSnippetRunner/QSRRunPanel.cpp index 9ca3ed03f3..293cb67d10 100644 --- a/Fwk/VizFwk/TestApps/Qt/QtSnippetRunner/QSRRunPanel.cpp +++ b/Fwk/VizFwk/TestApps/Qt/QtSnippetRunner/QSRRunPanel.cpp @@ -43,12 +43,19 @@ #include "cvfuTestSnippet.h" #include "cvfqtUtils.h" +#if QT_VERSION >= 0x050000 +#include +#include +#include +#include +#include +#else #include #include #include #include #include - +#endif using cvfu::TestSnippet; using cvfu::SnippetInfo; using cvfu::SnippetRegistry; diff --git a/Fwk/VizFwk/TestApps/Qt/QtSnippetRunner/QSRRunPanel.h b/Fwk/VizFwk/TestApps/Qt/QtSnippetRunner/QSRRunPanel.h index 7c0d283588..47d6918210 100644 --- a/Fwk/VizFwk/TestApps/Qt/QtSnippetRunner/QSRRunPanel.h +++ b/Fwk/VizFwk/TestApps/Qt/QtSnippetRunner/QSRRunPanel.h @@ -43,7 +43,12 @@ #include "cvfuSnippetFactory.h" +#include +#if QT_VERSION >= 0x050000 +#include +#else #include +#endif class QDockWidget; class QLabel; diff --git a/Fwk/VizFwk/TestApps/Qt/QtSnippetRunner/QSRStdInclude.h b/Fwk/VizFwk/TestApps/Qt/QtSnippetRunner/QSRStdInclude.h index 868620a95e..c25fd79d5b 100644 --- a/Fwk/VizFwk/TestApps/Qt/QtSnippetRunner/QSRStdInclude.h +++ b/Fwk/VizFwk/TestApps/Qt/QtSnippetRunner/QSRStdInclude.h @@ -1,6 +1,14 @@ #pragma once +#include +#include +#if QT_VERSION >= 0x050000 +#include +#else +#include +#endif + #include "cvfLibCore.h" #include "cvfLibRender.h" #include "cvfLibGeometry.h" @@ -10,8 +18,6 @@ #include "cvfuSnippetFactory.h" #include "cvfuInputEvents.h" -#include -#include // Introduce name of commonly used classes (that are unlikely to create clashes) from the cvf namespace. // We allow the use of using-declarations in this include file since its sole usage is as a precompiled header file. diff --git a/Fwk/VizFwk/Tests/LibCore_UnitTests/CMakeLists.txt b/Fwk/VizFwk/Tests/LibCore_UnitTests/CMakeLists.txt index d9bdf9d046..69f599ef24 100644 --- a/Fwk/VizFwk/Tests/LibCore_UnitTests/CMakeLists.txt +++ b/Fwk/VizFwk/Tests/LibCore_UnitTests/CMakeLists.txt @@ -48,6 +48,7 @@ cvfVector4-Test.cpp LibCore_UnitTests.cpp ) +add_definitions(-D_SILENCE_TR1_NAMESPACE_DEPRECATION_WARNING) add_executable(${PROJECT_NAME} ${CEE_SOURCE_FILES}) target_link_libraries(${PROJECT_NAME} ${CEE_LIBS} ${CEE_PLATFORM_LIBS}) diff --git a/Fwk/VizFwk/Tests/LibGeometry_UnitTests/CMakeLists.txt b/Fwk/VizFwk/Tests/LibGeometry_UnitTests/CMakeLists.txt index 3db9d045ff..81d805d618 100644 --- a/Fwk/VizFwk/Tests/LibGeometry_UnitTests/CMakeLists.txt +++ b/Fwk/VizFwk/Tests/LibGeometry_UnitTests/CMakeLists.txt @@ -36,6 +36,7 @@ cvfVertexWelder-Test.cpp LibGeometry_UnitTests.cpp ) +add_definitions(-D_SILENCE_TR1_NAMESPACE_DEPRECATION_WARNING) add_executable(${PROJECT_NAME} ${CEE_SOURCE_FILES}) target_link_libraries(${PROJECT_NAME} ${CEE_LIBS} ${CEE_PLATFORM_LIBS} ) diff --git a/Fwk/VizFwk/Tests/LibGuiQt_UnitTests/CMakeLists.txt b/Fwk/VizFwk/Tests/LibGuiQt_UnitTests/CMakeLists.txt index ca7b6b35a3..073d674b64 100644 --- a/Fwk/VizFwk/Tests/LibGuiQt_UnitTests/CMakeLists.txt +++ b/Fwk/VizFwk/Tests/LibGuiQt_UnitTests/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 2.8) +cmake_minimum_required(VERSION 2.8.12) project(LibGuiQt_UnitTests) @@ -7,8 +7,15 @@ project(LibGuiQt_UnitTests) find_package(OpenGL) -find_package(Qt4 COMPONENTS QtCore QtGui QtOpenGL REQUIRED) -include(${QT_USE_FILE}) +if (CEE_USE_QT5) + find_package(Qt5 COMPONENTS Core Gui OpenGL Widgets REQUIRED) +else() + find_package(Qt4 COMPONENTS QtCore QtGui QtOpenGL REQUIRED) + include(${QT_USE_FILE}) + if (QT4_FOUND) + message(STATUS "Found Qt4") + endif(QT4_FOUND) +endif(CEE_USE_QT5) include_directories(${LibCore_SOURCE_DIR}) include_directories(${LibIo_SOURCE_DIR}) @@ -27,6 +34,16 @@ cvfqtUtils-Test.cpp LibGuiQt_UnitTests.cpp ) +if (CEE_USE_QT5) + set(QT_LIBRARIES Qt5::Core Qt5::OpenGL Qt5::Widgets) +endif(CEE_USE_QT5) + + +if (MSVC AND (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 19.11)) + # VS 2017 : Disable warnings from from gtest code, using deprecated code related to TR1 + add_definitions(-D_SILENCE_TR1_NAMESPACE_DEPRECATION_WARNING) +endif() + add_executable(${PROJECT_NAME} ${CEE_SOURCE_FILES}) target_link_libraries(${PROJECT_NAME} ${CEE_LIBS} ${OPENGL_LIBRARIES} ${QT_LIBRARIES} ${CEE_PLATFORM_LIBS}) diff --git a/Fwk/VizFwk/Tests/LibGuiQt_UnitTests/cvfqtUtils-Test.cpp b/Fwk/VizFwk/Tests/LibGuiQt_UnitTests/cvfqtUtils-Test.cpp index 07f7f48c7f..87b661a0ab 100644 --- a/Fwk/VizFwk/Tests/LibGuiQt_UnitTests/cvfqtUtils-Test.cpp +++ b/Fwk/VizFwk/Tests/LibGuiQt_UnitTests/cvfqtUtils-Test.cpp @@ -51,7 +51,7 @@ TEST(UtilsTest, toQString) const cvf::String str("abc"); QString qStr = cvfqt::Utils::toQString(str); - EXPECT_STREQ(str.toAscii().ptr(), (const char*)qStr.toAscii()); + EXPECT_STREQ(str.toAscii().ptr(), (const char*)qStr.toLatin1()); } diff --git a/Fwk/VizFwk/Tests/LibIo_UnitTests/CMakeLists.txt b/Fwk/VizFwk/Tests/LibIo_UnitTests/CMakeLists.txt index 1010330b95..d9ce18323a 100644 --- a/Fwk/VizFwk/Tests/LibIo_UnitTests/CMakeLists.txt +++ b/Fwk/VizFwk/Tests/LibIo_UnitTests/CMakeLists.txt @@ -20,6 +20,11 @@ cvfXml-Test.cpp LibIo_UnitTests.cpp ) +if (MSVC AND (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 19.11)) + # VS 2017 : Disable warnings from from gtest code, using deprecated code related to TR1 + add_definitions(-D_SILENCE_TR1_NAMESPACE_DEPRECATION_WARNING) +endif() + add_executable(${PROJECT_NAME} ${CEE_SOURCE_FILES}) target_link_libraries(${PROJECT_NAME} ${CEE_LIBS} ${CEE_PLATFORM_LIBS} ) diff --git a/Fwk/VizFwk/Tests/LibRegGrid2D_UnitTests/CMakeLists.txt b/Fwk/VizFwk/Tests/LibRegGrid2D_UnitTests/CMakeLists.txt index 058a3d6c9b..88260c2114 100644 --- a/Fwk/VizFwk/Tests/LibRegGrid2D_UnitTests/CMakeLists.txt +++ b/Fwk/VizFwk/Tests/LibRegGrid2D_UnitTests/CMakeLists.txt @@ -25,6 +25,11 @@ cvfRegGrid2DGeometry-Test.cpp LibRegGrid2D_UnitTests.cpp ) +if (MSVC AND (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 19.11)) + # VS 2017 : Disable warnings from from gtest code, using deprecated code related to TR1 + add_definitions(-D_SILENCE_TR1_NAMESPACE_DEPRECATION_WARNING) +endif() + add_executable(${PROJECT_NAME} ${CEE_SOURCE_FILES}) target_link_libraries(${PROJECT_NAME} ${CEE_LIBS} ${OPENGL_LIBRARIES} ${CEE_PLATFORM_LIBS}) diff --git a/Fwk/VizFwk/Tests/LibRender_UnitTests/CMakeLists.txt b/Fwk/VizFwk/Tests/LibRender_UnitTests/CMakeLists.txt index a530fcc5e0..6fda5381ab 100644 --- a/Fwk/VizFwk/Tests/LibRender_UnitTests/CMakeLists.txt +++ b/Fwk/VizFwk/Tests/LibRender_UnitTests/CMakeLists.txt @@ -49,6 +49,11 @@ cvfViewport-Test.cpp LibRender_UnitTests.cpp ) +if (MSVC AND (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 19.11)) + # VS 2017 : Disable warnings from from gtest code, using deprecated code related to TR1 + add_definitions(-D_SILENCE_TR1_NAMESPACE_DEPRECATION_WARNING) +endif() + add_executable(${PROJECT_NAME} ${CEE_SOURCE_FILES}) target_link_libraries(${PROJECT_NAME} ${CEE_LIBS} ${OPENGL_LIBRARIES} ${CEE_PLATFORM_LIBS}) diff --git a/Fwk/VizFwk/Tests/LibStructGrid_UnitTests/CMakeLists.txt b/Fwk/VizFwk/Tests/LibStructGrid_UnitTests/CMakeLists.txt index c629a773fb..ad48954fd1 100644 --- a/Fwk/VizFwk/Tests/LibStructGrid_UnitTests/CMakeLists.txt +++ b/Fwk/VizFwk/Tests/LibStructGrid_UnitTests/CMakeLists.txt @@ -23,6 +23,11 @@ cvfRectilinearGrid-Test.cpp LibStructGrid_UnitTests.cpp ) +if (MSVC AND (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 19.11)) + # VS 2017 : Disable warnings from from gtest code, using deprecated code related to TR1 + add_definitions(-D_SILENCE_TR1_NAMESPACE_DEPRECATION_WARNING) +endif() + add_executable(${PROJECT_NAME} ${CEE_SOURCE_FILES}) target_link_libraries(${PROJECT_NAME} ${CEE_LIBS} ${OPENGL_LIBRARIES} ${CEE_PLATFORM_LIBS}) diff --git a/Fwk/VizFwk/Tests/LibUtilities_UnitTests/CMakeLists.txt b/Fwk/VizFwk/Tests/LibUtilities_UnitTests/CMakeLists.txt index 08d65f87b1..061fbc2466 100644 --- a/Fwk/VizFwk/Tests/LibUtilities_UnitTests/CMakeLists.txt +++ b/Fwk/VizFwk/Tests/LibUtilities_UnitTests/CMakeLists.txt @@ -26,6 +26,11 @@ cvfuTestSnippet-Test.cpp LibUtilities_UnitTests.cpp ) +if (MSVC AND (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 19.11)) + # VS 2017 : Disable warnings from from gtest code, using deprecated code related to TR1 + add_definitions(-D_SILENCE_TR1_NAMESPACE_DEPRECATION_WARNING) +endif() + add_executable(${PROJECT_NAME} ${CEE_SOURCE_FILES}) target_link_libraries(${PROJECT_NAME} ${CEE_LIBS} ${OPENGL_LIBRARIES} ${CEE_PLATFORM_LIBS}) diff --git a/Fwk/VizFwk/Tests/LibViewing_UnitTests/CMakeLists.txt b/Fwk/VizFwk/Tests/LibViewing_UnitTests/CMakeLists.txt index edeebeaca3..d2f23b36b5 100644 --- a/Fwk/VizFwk/Tests/LibViewing_UnitTests/CMakeLists.txt +++ b/Fwk/VizFwk/Tests/LibViewing_UnitTests/CMakeLists.txt @@ -37,6 +37,11 @@ cvfScene-Test.cpp LibViewing_UnitTests.cpp ) +if (MSVC AND (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 19.11)) + # VS 2017 : Disable warnings from from gtest code, using deprecated code related to TR1 + add_definitions(-D_SILENCE_TR1_NAMESPACE_DEPRECATION_WARNING) +endif() + add_executable(${PROJECT_NAME} ${CEE_SOURCE_FILES}) target_link_libraries(${PROJECT_NAME} ${CEE_LIBS} ${OPENGL_LIBRARIES} ${CEE_PLATFORM_LIBS}) diff --git a/OctavePlugin/CMakeLists.txt b/OctavePlugin/CMakeLists.txt index e06f3af84f..89064dd7a4 100644 --- a/OctavePlugin/CMakeLists.txt +++ b/OctavePlugin/CMakeLists.txt @@ -40,15 +40,6 @@ if (${CMAKE_SYSTEM_NAME} MATCHES "Linux") set (RPATH_COMMAND "-Wl,-rpath,'\\$$ORIGIN'") endif() -if (${CMAKE_SYSTEM_NAME} MATCHES "Windows") - set (QT_LIBRARY_POSTFIX 4) - - if (CMAKE_CL_64) - option(RESINSIGHT_OCTAVE_PLUGIN_32_BIT "Windows Only: Set 32-bit MSVC compiler environment while running mkoctfile" OFF) - mark_as_advanced(FORCE RESINSIGHT_OCTAVE_PLUGIN_32_BIT) - endif() -endif() - # recreate the magic that CMake does for MacOS X frameworks in the # include list when we call mkoctfile as a custom command if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin") @@ -80,44 +71,85 @@ if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin") endif () endif () -# Find location of Octave based on mkoctfile -find_program(RESINSIGHT_OCTAVE_PLUGIN_MKOCTFILE mkoctfile) -if(RESINSIGHT_OCTAVE_PLUGIN_MKOCTFILE) - get_filename_component(RESINSIGHT_OCTAVE_BIN_DIR ${RESINSIGHT_OCTAVE_PLUGIN_MKOCTFILE} PATH) - STRING(REPLACE "/bin" "" OCTAVE_HOME ${RESINSIGHT_OCTAVE_BIN_DIR}) +message (STATUS "Compiling Octave plugins using : ${OCTAVE_MKOCTFILE}") + +if (${CMAKE_SYSTEM_NAME} MATCHES "Windows") + option(RESINSIGHT_OCTAVE_PLUGIN_QT "Compile Octave plugin using Qt located insided Octave root folder" ON) +endif(${CMAKE_SYSTEM_NAME} MATCHES "Windows") + +if(RESINSIGHT_OCTAVE_PLUGIN_QT) + + message(STATUS "Compiling Octave plugins using custom Qt located at ${OCTAVE_ROOT_DIR}") + + if (EXISTS ${OCTAVE_ROOT_DIR}/qt5) + SET(OCTAVE_QT_INCLUDE_DIR ${OCTAVE_ROOT_DIR}/qt5/include) + SET(OCTAVE_QT_QTCORE_INCLUDE_DIR ${OCTAVE_ROOT_DIR}/qt5/include/QtCore) + SET(OCTAVE_QT_QTNETWORK_INCLUDE_DIR ${OCTAVE_ROOT_DIR}/qt5/include/QtNetwork) + SET(OCTAVE_QT_LIBRARY_DIR ${OCTAVE_ROOT_DIR}/qt5/lib) + SET(OCTAVE_QT_QTCORE_LIB Qt5Core) + SET(OCTAVE_QT_QTNETWORK_LIB Qt5Network) + else () + SET(OCTAVE_QT_INCLUDE_DIR ${OCTAVE_ROOT_DIR}/include) + SET(OCTAVE_QT_QTCORE_INCLUDE_DIR ${OCTAVE_ROOT_DIR}/include/QtCore) + SET(OCTAVE_QT_QTNETWORK_INCLUDE_DIR ${OCTAVE_ROOT_DIR}/include/QtNetwork) + SET(OCTAVE_QT_LIBRARY_DIR ${OCTAVE_ROOT_DIR}/lib) + SET(OCTAVE_QT_QTCORE_LIB QtCore4) + SET(OCTAVE_QT_QTNETWORK_LIB QtNetwork4) + endif(EXISTS ${OCTAVE_ROOT_DIR}/qt5) + else() - message(WARNING "Failed to find mkoctfile, no Octave plugins will be compiled. Please specify RESINSIGHT_OCTAVE_PLUGIN_MKOCTFILE") -endif() + if (Qt5Core_FOUND) + message(STATUS "Compiling Octave plugins using system Qt5") -set(RESINSIGHT_OCTAVE_PLUGIN_QMAKE "" CACHE FILEPATH "Windows Only: Set this equal to RESINSIGHT_OCTAVE_PLUGIN_MKOCTFILE") -if(RESINSIGHT_OCTAVE_PLUGIN_QMAKE) - get_filename_component(OCTAVE_QMAKE_DIR ${RESINSIGHT_OCTAVE_PLUGIN_QMAKE} PATH) + SET(OCTAVE_QT_QTCORE_INCLUDE_DIR ${Qt5Core_INCLUDE_DIRS}) + SET(OCTAVE_QT_QTNETWORK_INCLUDE_DIR ${Qt5Network_INCLUDE_DIRS}) + SET(OCTAVE_QT_LIBRARY_DIR ${QT_LIBRARY_DIR}) + SET(OCTAVE_QT_QTCORE_LIB Qt5Core) + SET(OCTAVE_QT_QTNETWORK_LIB Qt5Network) - STRING(REPLACE "/bin" "" OCTAVE_QT_ROOT ${OCTAVE_QMAKE_DIR}) + else() + message(STATUS "Compiling Octave plugins using system Qt4 - include path located at ${QT_QMAKE_EXECUTABLE}") - message(STATUS "Compiling Octave plugins using custom Qt located at ${OCTAVE_QT_ROOT}") + SET(OCTAVE_QT_QTCORE_INCLUDE_DIR ${QT_QTCORE_INCLUDE_DIR}) + SET(OCTAVE_QT_QTNETWORK_INCLUDE_DIR ${QT_QTNETWORK_INCLUDE_DIR}) + SET(OCTAVE_QT_LIBRARY_DIR ${QT_LIBRARY_DIR}) - SET(OCTAVE_QT_INCLUDE_DIR ${OCTAVE_QT_ROOT}/include) - SET(OCTAVE_QT_QTCORE_INCLUDE_DIR ${OCTAVE_QT_ROOT}/include/QtCore) - SET(OCTAVE_QT_QTNETWORK_INCLUDE_DIR ${OCTAVE_QT_ROOT}/include/QtNetwork) - SET(OCTAVE_QT_LIBRARY_DIR ${OCTAVE_QT_ROOT}/lib) -else() - set (RESINSIGHT_OCTAVE_PLUGIN_QMAKE ${QT_QMAKE_EXECUTABLE}) + if (${CMAKE_SYSTEM_NAME} MATCHES "Windows") + SET(OCTAVE_QT_QTCORE_LIB QtCore4) + SET(OCTAVE_QT_QTNETWORK_LIB QtNetwork4) + else() + SET(OCTAVE_QT_QTCORE_LIB QtCore) + SET(OCTAVE_QT_QTNETWORK_LIB QtNetwork) + endif(${CMAKE_SYSTEM_NAME} MATCHES "Windows") - message(STATUS "Compiling Octave plugins using system Qt - include path located at ${RESINSIGHT_OCTAVE_PLUGIN_QMAKE}") + endif(Qt5Core_FOUND) - SET(OCTAVE_QT_INCLUDE_DIR ${QT_INCLUDE_DIR}) - SET(OCTAVE_QT_QTCORE_INCLUDE_DIR ${QT_QTCORE_INCLUDE_DIR}) - SET(OCTAVE_QT_QTNETWORK_INCLUDE_DIR ${QT_QTNETWORK_INCLUDE_DIR}) - SET(OCTAVE_QT_LIBRARY_DIR ${QT_LIBRARY_DIR}) -endif() +endif(RESINSIGHT_OCTAVE_PLUGIN_QT) + +list (APPEND MKOCTFILE_INCLUDE_DIRS ${OCTAVE_QT_INCLUDE_DIR}) +list (APPEND MKOCTFILE_INCLUDE_DIRS ${OCTAVE_QT_QTCORE_INCLUDE_DIR}) +list (APPEND MKOCTFILE_INCLUDE_DIRS ${OCTAVE_QT_QTNETWORK_INCLUDE_DIR}) + + +# Add socket interface source code folder +list (APPEND MKOCTFILE_INCLUDE_DIRS ${ResInsight_SOURCE_DIR}/ApplicationCode/SocketInterface) + +list (REMOVE_DUPLICATES MKOCTFILE_INCLUDE_DIRS) +foreach (item ${MKOCTFILE_INCLUDE_DIRS}) + list (APPEND MKOCTFILE_INCLUDE_TEMP -I${item}) +endforeach (item) + +string( REPLACE ";" " " MKOCTFILE_INCLUDE_TEMP "${MKOCTFILE_INCLUDE_TEMP}" ) + +# Use special command to avoid double quoting in add_custom_command() +separate_arguments(MKOCTFILE_INCLUDE_COMMAND_STRING WINDOWS_COMMAND "${MKOCTFILE_INCLUDE_TEMP}") # Clear the list of binary oct files to be produced set(OCTAVE_BINARY_OCT_FILES) -if (RESINSIGHT_OCTAVE_PLUGIN_QMAKE AND RESINSIGHT_OCTAVE_PLUGIN_MKOCTFILE) +if (OCTAVE_MKOCTFILE) foreach(srcFileName IN LISTS CPP_SOURCES) if(NOT IS_ABSOLUTE "${srcFileName}") @@ -129,27 +161,24 @@ if (RESINSIGHT_OCTAVE_PLUGIN_QMAKE AND RESINSIGHT_OCTAVE_PLUGIN_MKOCTFILE) set(octFileName "${CMAKE_CURRENT_BINARY_DIR}/${baseFilename}.oct") if (${CMAKE_SYSTEM_NAME} MATCHES "Windows") - if (CMAKE_CL_64 AND RESINSIGHT_OCTAVE_PLUGIN_32_BIT) - SET(RESINSIGHT_VCVARS_32BIT_CMD call "\"%VS100COMNTOOLS%../../VC/vcvarsall.bat\"" x86) - endif() add_custom_command( OUTPUT "${octFileName}" - COMMAND ${RESINSIGHT_VCVARS_32BIT_CMD} - COMMAND set "OCTAVE_HOME=${OCTAVE_HOME}" + COMMAND set "OCTAVE_HOME=${OCTAVE_ROOT_DIR}" COMMAND set "PATH=%OCTAVE_HOME%\\bin;%PATH%" - COMMAND mkoctfile -I${OCTAVE_QT_QTNETWORK_INCLUDE_DIR} - -I${OCTAVE_QT_QTCORE_INCLUDE_DIR} - -I${OCTAVE_QT_INCLUDE_DIR} - -I${ResInsight_SOURCE_DIR}/ApplicationCode/SocketInterface - ${RPATH_COMMAND} -L${OCTAVE_QT_LIBRARY_DIR} -lQtCore${QT_LIBRARY_POSTFIX} -lQtNetwork${QT_LIBRARY_POSTFIX} - -o "${octFileName}" "${srcFileName}" + COMMAND ${OCTAVE_MKOCTFILE} + ${MKOCTFILE_INCLUDE_COMMAND_STRING} + ${RPATH_COMMAND} + -L${OCTAVE_QT_LIBRARY_DIR} + -l${OCTAVE_QT_QTCORE_LIB} + -l${OCTAVE_QT_QTNETWORK_LIB} + -o "${octFileName}" "${srcFileName}" DEPENDS "${srcFileName}" COMMENT "===> Generating ${octFileName}" ) elseif (${CMAKE_SYSTEM_NAME} MATCHES "Darwin") add_custom_command( OUTPUT "${octFileName}" - COMMAND ${RESINSIGHT_OCTAVE_PLUGIN_MKOCTFILE} + COMMAND ${OCTAVE_MKOCTFILE} ${QT_INCLUDES} ${QT_FRAMEWORKS} -I${ResInsight_SOURCE_DIR}/ApplicationCode/SocketInterface @@ -163,9 +192,14 @@ if (RESINSIGHT_OCTAVE_PLUGIN_QMAKE AND RESINSIGHT_OCTAVE_PLUGIN_MKOCTFILE) else() add_custom_command( OUTPUT "${octFileName}" - COMMAND OCTAVE_HOME=${OCTAVE_HOME} ${RESINSIGHT_OCTAVE_PLUGIN_MKOCTFILE} - -I${OCTAVE_QT_QTNETWORK_INCLUDE_DIR} -I${OCTAVE_QT_QTCORE_INCLUDE_DIR} -I${OCTAVE_QT_INCLUDE_DIR} -I${ResInsight_SOURCE_DIR}/ApplicationCode/SocketInterface ${RPATH_COMMAND} - -L${OCTAVE_QT_LIBRARY_DIR} -lQtCore -lQtNetwork -o "${octFileName}" "${srcFileName}" + COMMAND OCTAVE_HOME=${OCTAVE_ROOT_DIR} + ${OCTAVE_MKOCTFILE} + ${MKOCTFILE_INCLUDE_COMMAND_STRING} + ${RPATH_COMMAND} + -L${OCTAVE_QT_LIBRARY_DIR} + -l${OCTAVE_QT_QTCORE_LIB} + -l${OCTAVE_QT_QTNETWORK_LIB} + -o "${octFileName}" "${srcFileName}" DEPENDS "${srcFileName}" COMMENT "===> Generating ${octFileName}" ) @@ -175,42 +209,21 @@ if (RESINSIGHT_OCTAVE_PLUGIN_QMAKE AND RESINSIGHT_OCTAVE_PLUGIN_MKOCTFILE) endforeach() - add_custom_target(octave_plugins ALL DEPENDS - "${CMAKE_CURRENT_BINARY_DIR}/riGetActiveCellProperty.oct" - "${CMAKE_CURRENT_BINARY_DIR}/riSetActiveCellProperty.oct" - "${CMAKE_CURRENT_BINARY_DIR}/riGetActiveCellInfo.oct" - "${CMAKE_CURRENT_BINARY_DIR}/riGetMainGridDimensions.oct" - "${CMAKE_CURRENT_BINARY_DIR}/riGetNNCConnections.oct" - "${CMAKE_CURRENT_BINARY_DIR}/riGetNNCPropertyNames.oct" - "${CMAKE_CURRENT_BINARY_DIR}/riGetDynamicNNCValues.oct" - "${CMAKE_CURRENT_BINARY_DIR}/riGetStaticNNCValues.oct" - "${CMAKE_CURRENT_BINARY_DIR}/riGetCurrentCase.oct" - "${CMAKE_CURRENT_BINARY_DIR}/riGetCaseGroups.oct" - "${CMAKE_CURRENT_BINARY_DIR}/riGetSelectedCases.oct" - "${CMAKE_CURRENT_BINARY_DIR}/riGetSelectedCells.oct" - "${CMAKE_CURRENT_BINARY_DIR}/riGetCases.oct" - "${CMAKE_CURRENT_BINARY_DIR}/riGetTimeStepDates.oct" - "${CMAKE_CURRENT_BINARY_DIR}/riGetTimeStepDays.oct" - "${CMAKE_CURRENT_BINARY_DIR}/riGetGridDimensions.oct" - "${CMAKE_CURRENT_BINARY_DIR}/riGetCoarseningInfo.oct" - "${CMAKE_CURRENT_BINARY_DIR}/riGetCellCenters.oct" - "${CMAKE_CURRENT_BINARY_DIR}/riGetActiveCellCenters.oct" - "${CMAKE_CURRENT_BINARY_DIR}/riGetCellCorners.oct" - "${CMAKE_CURRENT_BINARY_DIR}/riGetActiveCellCorners.oct" - "${CMAKE_CURRENT_BINARY_DIR}/riGetGridProperty.oct" - "${CMAKE_CURRENT_BINARY_DIR}/riSetGridProperty.oct" - "${CMAKE_CURRENT_BINARY_DIR}/riGetGridPropertyForSelectedCells.oct" - "${CMAKE_CURRENT_BINARY_DIR}/riGetPropertyNames.oct" - "${CMAKE_CURRENT_BINARY_DIR}/riGetWellNames.oct" - "${CMAKE_CURRENT_BINARY_DIR}/riGetWellStatus.oct" - "${CMAKE_CURRENT_BINARY_DIR}/riGetWellCells.oct" - "${CMAKE_CURRENT_BINARY_DIR}/riSetNNCProperty.oct" +# Create depencedy string represeting the full path to all generated oct-files +foreach (item ${CPP_SOURCES}) + string( REPLACE ".cpp" ".oct" item ${item}) + list (APPEND DEPENDENCY_STRING ${CMAKE_CURRENT_BINARY_DIR}/${item}) +endforeach (item) + +#message("DEPENDENCY_STRING : ${DEPENDENCY_STRING}") + +add_custom_target(octave_plugins ALL DEPENDS + ${DEPENDENCY_STRING} SOURCES ${CPP_SOURCES} riSettings.h ) - # Copy Octave generated *.oct files to application folder, will make it possible to use Octave functions # directly from the location of the ResInsight binaries if (true) @@ -259,6 +272,6 @@ if (RESINSIGHT_OCTAVE_PLUGIN_QMAKE AND RESINSIGHT_OCTAVE_PLUGIN_MKOCTFILE) ) endif (RESINSIGHT_PRIVATE_INSTALL) -endif (RESINSIGHT_OCTAVE_PLUGIN_QMAKE AND RESINSIGHT_OCTAVE_PLUGIN_MKOCTFILE) +endif (OCTAVE_MKOCTFILE) diff --git a/OctavePlugin/riGetActiveCellCenters.cpp b/OctavePlugin/riGetActiveCellCenters.cpp index 862172ba0a..b97016d54c 100644 --- a/OctavePlugin/riGetActiveCellCenters.cpp +++ b/OctavePlugin/riGetActiveCellCenters.cpp @@ -112,7 +112,7 @@ DEFUN_DLD (riGetActiveCellCenters, args, nargout, if (nargin == 1) { - if (args(0).is_numeric_type()) + if (riOctavePlugin::isOctaveValueNumeric(args(0))) { caseId = args(0).uint_value(); } @@ -123,7 +123,7 @@ DEFUN_DLD (riGetActiveCellCenters, args, nargout, } else if (nargin == 2) { - if (args(0).is_numeric_type()) + if (riOctavePlugin::isOctaveValueNumeric(args(0))) { caseId = args(0).uint_value(); porosityModel = args(1).string_value(); diff --git a/OctavePlugin/riGetActiveCellCorners.cpp b/OctavePlugin/riGetActiveCellCorners.cpp index d018310285..9dac8d02a6 100644 --- a/OctavePlugin/riGetActiveCellCorners.cpp +++ b/OctavePlugin/riGetActiveCellCorners.cpp @@ -112,7 +112,7 @@ DEFUN_DLD (riGetActiveCellCorners, args, nargout, if (nargin == 1) { - if (args(0).is_numeric_type()) + if (riOctavePlugin::isOctaveValueNumeric(args(0))) { caseId = args(0).uint_value(); } @@ -123,7 +123,7 @@ DEFUN_DLD (riGetActiveCellCorners, args, nargout, } else if (nargin == 2) { - if (args(0).is_numeric_type()) + if (riOctavePlugin::isOctaveValueNumeric(args(0))) { caseId = args(0).uint_value(); porosityModel = args(1).string_value(); diff --git a/OctavePlugin/riGetActiveCellInfo.cpp b/OctavePlugin/riGetActiveCellInfo.cpp index 8a9f4bc8eb..bd703906be 100644 --- a/OctavePlugin/riGetActiveCellInfo.cpp +++ b/OctavePlugin/riGetActiveCellInfo.cpp @@ -129,7 +129,7 @@ DEFUN_DLD (riGetActiveCellInfo, args, nargout, if (nargin > 0) { - if (args(0).is_numeric_type()) + if (riOctavePlugin::isOctaveValueNumeric(args(0))) { unsigned int argCaseId = args(0).uint_value(); caseId = argCaseId; @@ -142,7 +142,7 @@ DEFUN_DLD (riGetActiveCellInfo, args, nargout, if (nargin > 1) { - if (args(1).is_numeric_type()) + if (riOctavePlugin::isOctaveValueNumeric(args(1))) { unsigned int argCaseId = args(1).uint_value(); caseId = argCaseId; diff --git a/OctavePlugin/riGetActiveCellProperty.cpp b/OctavePlugin/riGetActiveCellProperty.cpp index 7c2551aad4..b9861ad590 100644 --- a/OctavePlugin/riGetActiveCellProperty.cpp +++ b/OctavePlugin/riGetActiveCellProperty.cpp @@ -27,11 +27,11 @@ void getActiveCellProperty(Matrix& propertyFrames, const QString &serverName, qu QString command; command += "GetActiveCellProperty " + QString::number(caseId) + " " + propertyName + " " + porosityModel; - for (int i = 0; i < requestedTimeSteps.length(); ++i) + for (int i = 0; i < requestedTimeSteps.numel(); ++i) { if (i == 0) command += " "; command += QString::number(static_cast(requestedTimeSteps.elem(i)) - 1); // To make the index 0-based - if (i != requestedTimeSteps.length() -1) command += " "; + if (i != requestedTimeSteps.numel() -1) command += " "; } QByteArray cmdBytes = command.toLatin1(); @@ -139,7 +139,7 @@ DEFUN_DLD (riGetActiveCellProperty, args, nargout, argIndices.push_back(3); // Check if we have a CaseId: - if (!args(argIndices[0]).is_numeric_type()) + if (!riOctavePlugin::isOctaveValueNumeric(args(argIndices[0]))) { argIndices[0] = -1; for (size_t aIdx = 1; aIdx < argIndices.size(); ++aIdx) @@ -148,7 +148,7 @@ DEFUN_DLD (riGetActiveCellProperty, args, nargout, // Check if we have a Requested TimeSteps - if (!(nargin > argIndices[2] && (args(argIndices[2]).is_matrix_type() || args(argIndices[2]).is_numeric_type()) && !args(argIndices[2]).is_string())) + if (!(nargin > argIndices[2] && (args(argIndices[2]).is_matrix_type() || riOctavePlugin::isOctaveValueNumeric(args(argIndices[2]))) && !args(argIndices[2]).is_string())) { argIndices[2] = -1; for (size_t aIdx = 3; aIdx < argIndices.size(); ++aIdx) diff --git a/OctavePlugin/riGetCoarseningInfo.cpp b/OctavePlugin/riGetCoarseningInfo.cpp index 1961bcc786..0993047f9e 100644 --- a/OctavePlugin/riGetCoarseningInfo.cpp +++ b/OctavePlugin/riGetCoarseningInfo.cpp @@ -107,7 +107,7 @@ DEFUN_DLD (riGetCoarseningInfo, args, nargout, qint64 caseId = -1; if (nargin > 0) { - if (args(0).is_numeric_type()) + if (riOctavePlugin::isOctaveValueNumeric(args(0))) { unsigned int argCaseId = args(0).uint_value(); caseId = argCaseId; diff --git a/OctavePlugin/riGetDynamicNNCValues.cpp b/OctavePlugin/riGetDynamicNNCValues.cpp index 15e6e2893e..3d30f00a26 100644 --- a/OctavePlugin/riGetDynamicNNCValues.cpp +++ b/OctavePlugin/riGetDynamicNNCValues.cpp @@ -26,11 +26,11 @@ void getDynamicNNCValues(Matrix& propertyFrames, const QString &serverName, quin QString command; command += "GetDynamicNNCValues " + QString::number(caseId) + " " + propertyName; - for (int i = 0; i < requestedTimeSteps.length(); ++i) + for (int i = 0; i < requestedTimeSteps.numel(); ++i) { if (i == 0) command += " "; command += QString::number(static_cast(requestedTimeSteps.elem(i)) - 1); // To make the index 0-based - if (i != requestedTimeSteps.length() -1) command += " "; + if (i != requestedTimeSteps.numel() -1) command += " "; } QByteArray cmdBytes = command.toLatin1(); @@ -133,7 +133,7 @@ DEFUN_DLD (riGetDynamicNNCValues, args, nargout, argIndices.push_back(2); // Check if we have a CaseId: - if (!args(argIndices[0]).is_numeric_type()) + if (!riOctavePlugin::isOctaveValueNumeric(args(argIndices[0]))) { argIndices[0] = -1; for (size_t aIdx = 1; aIdx < argIndices.size(); ++aIdx) diff --git a/OctavePlugin/riGetGridDimensions.cpp b/OctavePlugin/riGetGridDimensions.cpp index 83e123dacb..17b4ecf2f6 100644 --- a/OctavePlugin/riGetGridDimensions.cpp +++ b/OctavePlugin/riGetGridDimensions.cpp @@ -111,7 +111,7 @@ DEFUN_DLD (riGetGridDimensions, args, nargout, qint64 caseId = -1; if (nargin > 0) { - if (args(0).is_numeric_type()) + if (riOctavePlugin::isOctaveValueNumeric(args(0))) { unsigned int argCaseId = args(0).uint_value(); caseId = argCaseId; diff --git a/OctavePlugin/riGetGridProperty.cpp b/OctavePlugin/riGetGridProperty.cpp index 7b5db5ed40..61c39fd1b4 100644 --- a/OctavePlugin/riGetGridProperty.cpp +++ b/OctavePlugin/riGetGridProperty.cpp @@ -27,11 +27,11 @@ void getGridProperty(NDArray& propertyFrames, const QString &serverName, quint16 QString command; command += "GetGridProperty " + QString::number(caseId) + " " + QString::number(gridIdx) + " " + propertyName + " " + porosityModel; - for (qint64 i = 0; i < requestedTimeSteps.length(); ++i) + for (qint64 i = 0; i < requestedTimeSteps.numel(); ++i) { if (i == 0) command += " "; command += QString::number(static_cast(requestedTimeSteps.elem(i)) - 1); // To make the index 0-based - if (i != requestedTimeSteps.length() -1) command += " "; + if (i != requestedTimeSteps.numel() -1) command += " "; } QByteArray cmdBytes = command.toLatin1(); @@ -163,7 +163,7 @@ DEFUN_DLD (riGetGridProperty, args, nargout, // Check if we have a Requested TimeSteps - if (!(nargin > argIndices[3] && (args(argIndices[3]).is_matrix_type() || args(argIndices[3]).is_numeric_type()) && !args(argIndices[3]).is_string())) + if (!(nargin > argIndices[3] && (args(argIndices[3]).is_matrix_type() || riOctavePlugin::isOctaveValueNumeric(args(argIndices[3]))) && !args(argIndices[3]).is_string())) { argIndices[3] = -1; for (size_t aIdx = 3; aIdx < argIndices.size(); ++aIdx) diff --git a/OctavePlugin/riGetGridPropertyForSelectedCells.cpp b/OctavePlugin/riGetGridPropertyForSelectedCells.cpp index 7d23ea399c..e32adbdc03 100644 --- a/OctavePlugin/riGetGridPropertyForSelectedCells.cpp +++ b/OctavePlugin/riGetGridPropertyForSelectedCells.cpp @@ -27,11 +27,11 @@ void getGridPropertyForSelectedCells(Matrix& propertyFrames, const QString &serv QString command; command += "GetGridPropertyForSelectedCells " + QString::number(caseId) + " " + propertyName + " " + porosityModel; - for (int i = 0; i < requestedTimeSteps.length(); ++i) + for (int i = 0; i < requestedTimeSteps.numel(); ++i) { if (i == 0) command += " "; command += QString::number(static_cast(requestedTimeSteps.elem(i)) - 1); // To make the index 0-based - if (i != requestedTimeSteps.length() - 1) command += " "; + if (i != requestedTimeSteps.numel() - 1) command += " "; } QByteArray cmdBytes = command.toLatin1(); @@ -139,7 +139,7 @@ DEFUN_DLD (riGetGridPropertyForSelectedCells, args, nargout, argIndices.push_back(3); // Check if we have a CaseId: - if (!args(argIndices[0]).is_numeric_type()) + if (!riOctavePlugin::isOctaveValueNumeric(args(argIndices[0]))) { argIndices[0] = -1; for (size_t aIdx = 1; aIdx < argIndices.size(); ++aIdx) @@ -148,7 +148,7 @@ DEFUN_DLD (riGetGridPropertyForSelectedCells, args, nargout, // Check if we have a Requested TimeSteps - if (!(nargin > argIndices[2] && (args(argIndices[2]).is_matrix_type() || args(argIndices[2]).is_numeric_type()) && !args(argIndices[2]).is_string())) + if (!(nargin > argIndices[2] && (args(argIndices[2]).is_matrix_type() || riOctavePlugin::isOctaveValueNumeric(args(argIndices[2]))) && !args(argIndices[2]).is_string())) { argIndices[2] = -1; for (size_t aIdx = 3; aIdx < argIndices.size(); ++aIdx) diff --git a/OctavePlugin/riGetNNCConnections.cpp b/OctavePlugin/riGetNNCConnections.cpp index 1610c68cea..181928ecca 100644 --- a/OctavePlugin/riGetNNCConnections.cpp +++ b/OctavePlugin/riGetNNCConnections.cpp @@ -115,7 +115,7 @@ DEFUN_DLD(riGetNNCConnections, args, nargout, if (nargin > 0) { - if (args(0).is_numeric_type()) + if (riOctavePlugin::isOctaveValueNumeric(args(0))) { unsigned int argCaseId = args(0).uint_value(); caseId = argCaseId; diff --git a/OctavePlugin/riGetStaticNNCValues.cpp b/OctavePlugin/riGetStaticNNCValues.cpp index 85f4497a97..82fcc1f540 100644 --- a/OctavePlugin/riGetStaticNNCValues.cpp +++ b/OctavePlugin/riGetStaticNNCValues.cpp @@ -114,7 +114,7 @@ DEFUN_DLD (riGetStaticNNCValues, args, nargout, argIndices.push_back(1); // Check if we have a CaseId: - if (!args(argIndices[0]).is_numeric_type()) + if (!riOctavePlugin::isOctaveValueNumeric(args(argIndices[0]))) { argIndices[0] = -1; for (size_t aIdx = 1; aIdx < argIndices.size(); ++aIdx) diff --git a/OctavePlugin/riGetTimeStepDates.cpp b/OctavePlugin/riGetTimeStepDates.cpp index e856a8df87..494e41cf02 100644 --- a/OctavePlugin/riGetTimeStepDates.cpp +++ b/OctavePlugin/riGetTimeStepDates.cpp @@ -126,7 +126,7 @@ DEFUN_DLD (riGetTimeStepDates, args, nargout, qint64 caseId = -1; if (nargin > 0) { - if (args(0).is_numeric_type()) + if (riOctavePlugin::isOctaveValueNumeric(args(0))) { unsigned int argCaseId = args(0).uint_value(); caseId = argCaseId; diff --git a/OctavePlugin/riGetTimeStepDays.cpp b/OctavePlugin/riGetTimeStepDays.cpp index fa72b69236..3edf12f183 100644 --- a/OctavePlugin/riGetTimeStepDays.cpp +++ b/OctavePlugin/riGetTimeStepDays.cpp @@ -99,7 +99,7 @@ DEFUN_DLD (riGetTimeStepDays, args, nargout, qint64 caseId = -1; if (nargin > 0) { - if (args(0).is_numeric_type()) + if (riOctavePlugin::isOctaveValueNumeric(args(0))) { unsigned int argCaseId = args(0).uint_value(); caseId = argCaseId; diff --git a/OctavePlugin/riGetWellCells.cpp b/OctavePlugin/riGetWellCells.cpp index 09991c404b..a4acbe52e7 100644 --- a/OctavePlugin/riGetWellCells.cpp +++ b/OctavePlugin/riGetWellCells.cpp @@ -167,7 +167,7 @@ DEFUN_DLD (riGetWellCells, args, nargout, return octave_value(); } - if (!args(argIndices[2]).is_numeric_type()) // Check if the TimeStep argument is actually a number + if (!riOctavePlugin::isOctaveValueNumeric(args(argIndices[2]))) // Check if the TimeStep argument is actually a number { error("riGetWellCells: The last argument must be a timestep index.\n"); print_usage(); diff --git a/OctavePlugin/riGetWellStatus.cpp b/OctavePlugin/riGetWellStatus.cpp index 6c10b23a70..7093d97487 100644 --- a/OctavePlugin/riGetWellStatus.cpp +++ b/OctavePlugin/riGetWellStatus.cpp @@ -24,11 +24,11 @@ void getWellStatus(std::vector& wellTypes, std::vector& wellStatus QString command; command += QString("GetWellStatus") + " " + QString::number(caseId) + " " + wellName; - for (int i = 0; i < requestedTimeSteps.length(); ++i) + for (int i = 0; i < requestedTimeSteps.numel(); ++i) { if (i == 0) command += " "; command += QString::number(static_cast(requestedTimeSteps.elem(i)) - 1); // To make the index 0-based - if (i != requestedTimeSteps.length() -1) command += " "; + if (i != requestedTimeSteps.numel() -1) command += " "; } QByteArray cmdBytes = command.toLatin1(); @@ -136,7 +136,7 @@ DEFUN_DLD (riGetWellStatus, args, nargout, // Check if we have a Requested TimeSteps int lastArgumentIndex = argIndices[2] ; - if (!(nargin > argIndices[2] && (args(argIndices[2]).is_matrix_type() || args(argIndices[2]).is_numeric_type()))) + if (!(nargin > argIndices[2] && (args(argIndices[2]).is_matrix_type() || riOctavePlugin::isOctaveValueNumeric(args(argIndices[2]))))) { argIndices[2] = -1; } diff --git a/OctavePlugin/riSetActiveCellProperty.cpp b/OctavePlugin/riSetActiveCellProperty.cpp index 1aedda4c5f..7546e216d3 100644 --- a/OctavePlugin/riSetActiveCellProperty.cpp +++ b/OctavePlugin/riSetActiveCellProperty.cpp @@ -6,6 +6,10 @@ #include "riSettings.h" #include "RiaSocketDataTransfer.cpp" // NB! Include cpp-file to avoid linking of additional file in oct-compile configuration +#ifdef WIN32 +#include +#endif //WIN32 + void setEclipseProperty(const Matrix& propertyFrames, const QString &hostName, quint16 port, const qint64& caseId, QString propertyName, const int32NDArray& requestedTimeSteps, QString porosityModel) @@ -27,11 +31,11 @@ void setEclipseProperty(const Matrix& propertyFrames, const QString &hostName, q QString command; command += "SetActiveCellProperty " + QString::number(caseId) + " " + propertyName + " " + porosityModel; - for (int i = 0; i < requestedTimeSteps.length(); ++i) + for (int i = 0; i < requestedTimeSteps.numel(); ++i) { if (i == 0) command += " "; command += QString::number(static_cast(requestedTimeSteps.elem(i)) - 1); // To make the index 0-based - if (i != requestedTimeSteps.length() -1) command += " "; + if (i != requestedTimeSteps.numel() -1) command += " "; } QByteArray cmdBytes = command.toLatin1(); @@ -92,7 +96,9 @@ void setEclipseProperty(const Matrix& propertyFrames, const QString &hostName, q #ifdef WIN32 // TODO: Due to synchronization issues seen on Windows 10, it is required to do a sleep here to be able to catch disconnect // signals from the socket. No sleep causes the server to hang. + Sleep(100); + #endif //WIN32 return; @@ -154,7 +160,7 @@ DEFUN_DLD (riSetActiveCellProperty, args, nargout, argIndices.push_back(4); // Check if we have a CaseId: - if (!args(argIndices[1]).is_numeric_type()) + if (!riOctavePlugin::isOctaveValueNumeric(args(argIndices[1]))) { argIndices[1] = -1; for (size_t aIdx = 2; aIdx < argIndices.size(); ++aIdx) @@ -199,11 +205,11 @@ DEFUN_DLD (riSetActiveCellProperty, args, nargout, if (argIndices[3] >= 0) requestedTimeSteps = args(argIndices[3]).int32_array_value(); if (argIndices[4] >= 0) porosityModel = args(argIndices[4]).string_value(); - if (requestedTimeSteps.length()) + if (requestedTimeSteps.numel()) { int timeStepCount = mxDims.elem(1); - if (requestedTimeSteps.length() != timeStepCount) + if (requestedTimeSteps.numel() != timeStepCount) { error("riSetActiveCellProperty: The number of timesteps in the input matrix must match the number of timesteps in the TimeStepIndices array."); print_usage(); diff --git a/OctavePlugin/riSetGridProperty.cpp b/OctavePlugin/riSetGridProperty.cpp index 890c9f2f51..6b8a259ec7 100644 --- a/OctavePlugin/riSetGridProperty.cpp +++ b/OctavePlugin/riSetGridProperty.cpp @@ -6,6 +6,10 @@ #include "riSettings.h" #include "RiaSocketDataTransfer.cpp" // NB! Include cpp-file to avoid linking of additional file in oct-compile configuration +#ifdef WIN32 +#include +#endif //WIN32 + void setEclipseProperty(const NDArray& propertyFrames, const QString &hostName, quint16 port, const qint64& caseId, const qint64& gridIndex, QString propertyName, const int32NDArray& timeStepIndices, QString porosityModel) @@ -26,11 +30,11 @@ void setEclipseProperty(const NDArray& propertyFrames, const QString &hostName, QString command = QString("SetGridProperty %1 %2 %3 %4").arg(caseId).arg(gridIndex).arg(propertyName).arg(porosityModel); - for (int i = 0; i < timeStepIndices.length(); ++i) + for (int i = 0; i < timeStepIndices.numel(); ++i) { if (i == 0) command += " "; command += QString::number(static_cast(timeStepIndices.elem(i)) - 1); // To make the index 0-based - if (i != timeStepIndices.length() -1) command += " "; + if (i != timeStepIndices.numel() -1) command += " "; } QByteArray cmdBytes = command.toLatin1(); @@ -114,7 +118,9 @@ void setEclipseProperty(const NDArray& propertyFrames, const QString &hostName, #ifdef WIN32 // TODO: Due to synchronization issues seen on Windows 10, it is required to do a sleep here to be able to catch disconnect // signals from the socket. No sleep causes the server to hang. + Sleep(100); + #endif //WIN32 return; @@ -231,7 +237,7 @@ DEFUN_DLD (riSetGridProperty, args, nargout, if (argIndices[4] >= 0) timeStepIndices = args(argIndices[4]).int32_array_value(); if (argIndices[5] >= 0) porosityModel = args(argIndices[5]).string_value(); - if (timeStepIndices.length() > 1) + if (timeStepIndices.numel() > 1) { if (mxDims.length() == 3) { @@ -241,7 +247,7 @@ DEFUN_DLD (riSetGridProperty, args, nargout, } int timeStepCount = mxDims.elem(3); - if (timeStepIndices.length() != timeStepCount) + if (timeStepIndices.numel() != timeStepCount) { error("riSetGridProperty: The number of time steps in the input matrix must match the number of time steps in the TimeStepIndices array."); print_usage(); diff --git a/OctavePlugin/riSetNNCProperty.cpp b/OctavePlugin/riSetNNCProperty.cpp index c4803bd171..f5f38cf929 100644 --- a/OctavePlugin/riSetNNCProperty.cpp +++ b/OctavePlugin/riSetNNCProperty.cpp @@ -6,6 +6,10 @@ #include "riSettings.h" #include "RiaSocketDataTransfer.cpp" // NB! Include cpp-file to avoid linking of additional file in oct-compile configuration +#ifdef WIN32 +#include +#endif //WIN32 + void setNNCProperty(const Matrix& propertyFrames, const QString &hostName, quint16 port, const qint64& caseId, QString propertyName, const int32NDArray& requestedTimeSteps) @@ -27,11 +31,11 @@ void setNNCProperty(const Matrix& propertyFrames, const QString &hostName, quint QString command; command += "SetNNCProperty " + QString::number(caseId) + " " + propertyName; - for (int i = 0; i < requestedTimeSteps.length(); ++i) + for (int i = 0; i < requestedTimeSteps.numel(); ++i) { if (i == 0) command += " "; command += QString::number(static_cast(requestedTimeSteps.elem(i)) - 1); // To make the index 0-based - if (i != requestedTimeSteps.length() -1) command += " "; + if (i != requestedTimeSteps.numel() -1) command += " "; } QByteArray cmdBytes = command.toLatin1(); @@ -92,7 +96,9 @@ void setNNCProperty(const Matrix& propertyFrames, const QString &hostName, quint #ifdef WIN32 // TODO: Due to synchronization issues seen on Windows 10, it is required to do a sleep here to be able to catch disconnect // signals from the socket. No sleep causes the server to hang. + Sleep(100); + #endif //WIN32 return; @@ -153,7 +159,7 @@ DEFUN_DLD (riSetNNCProperty, args, nargout, argIndices.push_back(3); // Check if we have a CaseId: - if (!args(argIndices[1]).is_numeric_type()) + if (!riOctavePlugin::isOctaveValueNumeric(args(argIndices[1]))) { argIndices[1] = -1; for (size_t aIdx = 2; aIdx < argIndices.size(); ++aIdx) @@ -176,11 +182,11 @@ DEFUN_DLD (riSetNNCProperty, args, nargout, if (argIndices[2] >= 0) propertyName = args(argIndices[2]).char_matrix_value().row_as_string(0); if (argIndices[3] >= 0) requestedTimeSteps = args(argIndices[3]).int32_array_value(); - if (requestedTimeSteps.length()) + if (requestedTimeSteps.numel()) { int timeStepCount = mxDims.elem(1); - if (requestedTimeSteps.length() != timeStepCount) + if (requestedTimeSteps.numel() != timeStepCount) { error("riSetNNCProperty: The number of time steps in the input matrix must match the number of time steps in the TimeStepIndices array."); print_usage(); diff --git a/OctavePlugin/riSettings.h b/OctavePlugin/riSettings.h index ee31729355..cfd51f0e29 100644 --- a/OctavePlugin/riSettings.h +++ b/OctavePlugin/riSettings.h @@ -66,5 +66,15 @@ namespace riOctavePlugin char cellIndex_I[] = "I"; char cellIndex_J[] = "J"; char cellIndex_K[] = "K"; + + bool isOctaveValueNumeric(const octave_value& value) + { +#if (OCTAVE_MAJOR_VERSION >= 4 && OCTAVE_MINOR_VERSION >= 4) + return value.isnumeric(); +#else + return value.is_numeric_type(); +#endif + } + } diff --git a/README.md b/README.md index a83b1fee87..67fc0a1d56 100644 --- a/README.md +++ b/README.md @@ -6,15 +6,15 @@ The user interface is tailored for efficient interpretation of reservoir simulat The main input data is *.GRID and *.EGRID files along with their *.INIT and restart files *.XNNN and *.UNRST. ResInsight also supports selected parts of Eclipse input files and can read grid information and corresponding cell property data sets. -ResInsight has been co-developed by Statoil ASA, Ceetron Solutions AS, and Ceetron AS with the aim to provide a versatile tool for professionals who need to visualize and process reservoir models. The software is copyrighted by Ceetron and Statoil and licensed under GPL 3+. See COPYING for details. +ResInsight has been co-developed by Equinor ASA, Ceetron Solutions AS, and Ceetron AS with the aim to provide a versatile tool for professionals who need to visualize and process reservoir models. The software is copyrighted by Ceetron and Equinor and licensed under GPL 3+. See COPYING for details. ### Dependencies -ResInsight uses the Statoil/libecl (formerly Ensambles/ert) library to access Eclipse result files, and the two projects collaborates closely. The source code of the approved libecl version is embedded in the ResInsight source code tree, making downloading and building simple. +ResInsight uses the Equinor/libecl (formerly Ensambles/ert) library to access Eclipse result files, and the two projects collaborates closely. The source code of the approved libecl version is embedded in the ResInsight source code tree, making downloading and building simple. ResInsight also features an interface to Octave for retrieval of data from ResInsight, processing using Octave, and communication of data back into ResInsight for further handling and visualization. Octave : [http://www.gnu.org/software/octave/](http://www.gnu.org/software/octave/) -Statoil/libecl : [https://github.com/Statoil/libecl](https://github.com/Statoil/libecl) +Equinor/libecl : [https://github.com/Equinor/libecl](https://github.com/Equinor/libecl) ### Supported Platforms ResInsight is designed cross-platform from the start. Efforts have been made to ensure that code will compile and run on Linux and Windows platforms. Tested platforms are currently 64 bit RHEL6 and Windows 7/8/10, and we have also received reports on successful builds on Ubuntu based systems. diff --git a/ResInsightVersion.cmake b/ResInsightVersion.cmake index 57eda7827b..99c66ec8aa 100644 --- a/ResInsightVersion.cmake +++ b/ResInsightVersion.cmake @@ -1,16 +1,16 @@ -set(RESINSIGHT_MAJOR_VERSION 2018) -set(RESINSIGHT_MINOR_VERSION 11) -set(RESINSIGHT_PATCH_VERSION 2) +set(RESINSIGHT_MAJOR_VERSION 2019) +set(RESINSIGHT_MINOR_VERSION 04) +set(RESINSIGHT_PATCH_VERSION 0) # Opional text with no restrictions -#set(RESINSIGHT_VERSION_TEXT "-patch_RC04") +#set(RESINSIGHT_VERSION_TEXT "-rc1") # Optional text # Must be unique and increasing within one combination of major/minor/patch version # The uniqueness of this text is independent of RESINSIGHT_VERSION_TEXT # Format of text must be ".xx" -#set(RESINSIGHT_DEV_VERSION ".12") +#set(RESINSIGHT_DEV_VERSION ".01") # https://github.com/CRAVA/crava/tree/master/libs/nrlib set(NRLIB_GITHUB_SHA "ba35d4359882f1c6f5e9dc30eb95fe52af50fd6f") diff --git a/ThirdParty/Ert/lib/CMakeLists.txt b/ThirdParty/Ert/lib/CMakeLists.txt index a57e50e212..b0fb796a1c 100644 --- a/ThirdParty/Ert/lib/CMakeLists.txt +++ b/ThirdParty/Ert/lib/CMakeLists.txt @@ -183,6 +183,13 @@ target_include_directories(ecl ${CMAKE_CURRENT_BINARY_DIR}/include ) + +if (NOT INSTALL_ERT) + # set git info to zero, to avoid recompile of libecl files at every commit + set(GIT_COMMIT 0) + set(GIT_COMMIT_SHORT 0) +endif() + target_compile_definitions(ecl PRIVATE -DGIT_COMMIT=${GIT_COMMIT} -DGIT_COMMIT_SHORT=${GIT_COMMIT_SHORT} diff --git a/ThirdParty/Ert/lib/ecl/ecl_grid.cpp b/ThirdParty/Ert/lib/ecl/ecl_grid.cpp index ed0830b8ff..c01ece639a 100644 --- a/ThirdParty/Ert/lib/ecl/ecl_grid.cpp +++ b/ThirdParty/Ert/lib/ecl/ecl_grid.cpp @@ -3021,23 +3021,19 @@ static ecl_grid_type * ecl_grid_alloc_EGRID__( ecl_grid_type * main_grid , const eclipse_version = main_grid->eclipse_version; } - // If ACTNUM and ext_actnum are not present - that is is interpreted as all active. - const int * actnum_data; - std::vector actnum_product; - if (ecl_file_get_num_named_kw(ecl_file , ACTNUM_KW) > grid_nr) { - actnum_kw = ecl_file_iget_named_kw( ecl_file , ACTNUM_KW , grid_nr); - actnum_data = ecl_kw_get_int_ptr(actnum_kw); - if (ext_actnum) { - int size = ecl_kw_get_size(actnum_kw); - actnum_product.resize(size); - for (int i = 0; i < size; i++) - actnum_product[i] = actnum_data[i] * ext_actnum[i]; - actnum_data = actnum_product.data(); - } + /* + If ext_actnum is present that is used as ACTNUM, and the file is not checked + for an ACTNUM keyword at all. + */ + const int * actnum_data = NULL; + if (ext_actnum) + actnum_data = ext_actnum; + else { + if (ecl_file_get_num_named_kw(ecl_file, ACTNUM_KW) > grid_nr) { + actnum_kw = ecl_file_iget_named_kw(ecl_file, ACTNUM_KW, grid_nr); + actnum_data = ecl_kw_get_int_ptr(actnum_kw); + } } - else - actnum_data = ext_actnum; - if (grid_nr == 0) { /* MAPAXES and COARSENING only apply to the global grid. */ @@ -6947,7 +6943,7 @@ void ecl_grid_fprintf_grdecl2(ecl_grid_type * grid , FILE * stream , ert_ecl_uni fprintf(stream , "\n"); } - if (grid->use_mapaxes) { + if (grid->mapaxes != NULL) { ecl_kw_type * mapaxes_kw = ecl_grid_alloc_mapaxes_kw( grid ); ecl_kw_fprintf_grdecl( mapaxes_kw , stream ); ecl_kw_free( mapaxes_kw ); diff --git a/ThirdParty/Ert/lib/ecl/ecl_smspec.cpp b/ThirdParty/Ert/lib/ecl/ecl_smspec.cpp index a5611ce938..dbefb53bd9 100644 --- a/ThirdParty/Ert/lib/ecl/ecl_smspec.cpp +++ b/ThirdParty/Ert/lib/ecl/ecl_smspec.cpp @@ -325,7 +325,7 @@ int * ecl_smspec_alloc_mapping( const ecl_smspec_type * self, const ecl_smspec_t const smspec_node_type * ecl_smspec_iget_node( const ecl_smspec_type * smspec , int index ) { - return (const smspec_node_type*)vector_iget_const( smspec->smspec_nodes , index ); + return (const smspec_node_type*)vector_safe_iget_const( smspec->smspec_nodes , index ); } int ecl_smspec_num_nodes( const ecl_smspec_type * smspec) { @@ -822,18 +822,21 @@ static void ecl_smspec_install_special_keys( ecl_smspec_type * ecl_smspec , smsp switch(var_type) { case(ECL_SMSPEC_COMPLETION_VAR): - /* Three level indexing: variable -> well -> string(cell_nr)*/ - if (!hash_has_key(ecl_smspec->well_completion_var_index , well)) - hash_insert_hash_owned_ref(ecl_smspec->well_completion_var_index , well , hash_alloc() , hash_free__); + if (well) { - hash_type * cell_hash = (hash_type*)hash_get(ecl_smspec->well_completion_var_index , well); - char cell_str[16]; - sprintf(cell_str , "%d" , num); - if (!hash_has_key(cell_hash , cell_str)) - hash_insert_hash_owned_ref(cell_hash , cell_str , hash_alloc() , hash_free__); + /* Three level indexing: variable -> well -> string(cell_nr)*/ + if (!hash_has_key(ecl_smspec->well_completion_var_index , well)) + hash_insert_hash_owned_ref(ecl_smspec->well_completion_var_index , well , hash_alloc() , hash_free__); { - hash_type * var_hash = (hash_type*)hash_get(cell_hash , cell_str); - hash_insert_ref(var_hash , keyword , smspec_node ); + hash_type * cell_hash = (hash_type*)hash_get(ecl_smspec->well_completion_var_index , well); + char cell_str[16]; + sprintf(cell_str , "%d" , num); + if (!hash_has_key(cell_hash , cell_str)) + hash_insert_hash_owned_ref(cell_hash , cell_str , hash_alloc() , hash_free__); + { + hash_type * var_hash = (hash_type*)hash_get(cell_hash , cell_str); + hash_insert_ref(var_hash , keyword , smspec_node ); + } } } break; @@ -866,11 +869,14 @@ static void ecl_smspec_install_special_keys( ecl_smspec_type * ecl_smspec , smsp ecl_smspec->num_regions = util_int_max(ecl_smspec->num_regions , num); break; case (ECL_SMSPEC_WELL_VAR): - if (!hash_has_key(ecl_smspec->well_var_index , well)) - hash_insert_hash_owned_ref(ecl_smspec->well_var_index , well , hash_alloc() , hash_free__); + if (well) { - hash_type * var_hash = (hash_type*)hash_get(ecl_smspec->well_var_index , well); - hash_insert_ref(var_hash , keyword , smspec_node ); + if (!hash_has_key(ecl_smspec->well_var_index , well)) + hash_insert_hash_owned_ref(ecl_smspec->well_var_index , well , hash_alloc() , hash_free__); + { + hash_type * var_hash = (hash_type*)hash_get(ecl_smspec->well_var_index , well); + hash_insert_ref(var_hash , keyword , smspec_node ); + } } break; case(ECL_SMSPEC_MISC_VAR): diff --git a/ThirdParty/Ert/lib/ecl/ecl_sum_data.cpp b/ThirdParty/Ert/lib/ecl/ecl_sum_data.cpp index 7cf72a309c..b1bc8dba62 100644 --- a/ThirdParty/Ert/lib/ecl/ecl_sum_data.cpp +++ b/ThirdParty/Ert/lib/ecl/ecl_sum_data.cpp @@ -1087,8 +1087,11 @@ static void ecl_sum_data_init_double_vector__(const ecl_sum_data_type * data, in data_file->get_data(params_index, index_node.length, &output_data[offset]); else { const smspec_node_type * smspec_node = ecl_smspec_iget_node(data->smspec, main_params_index); - for (int i=0; i < index_node.length; i++) - output_data[offset + i] = smspec_node_get_default(smspec_node); + if (smspec_node) + { + for (int i=0; i < index_node.length; i++) + output_data[offset + i] = smspec_node_get_default(smspec_node); + } } offset += index_node.length; } diff --git a/ThirdParty/Ert/lib/ecl/smspec_node.cpp b/ThirdParty/Ert/lib/ecl/smspec_node.cpp index 786dd87430..98bf35b597 100644 --- a/ThirdParty/Ert/lib/ecl/smspec_node.cpp +++ b/ThirdParty/Ert/lib/ecl/smspec_node.cpp @@ -188,7 +188,7 @@ std::string smspec_alloc_completion_ijk_key( const char * join_string , const st join_string , i , j , k ); else - return NULL; + return std::string(); } @@ -202,7 +202,7 @@ std::string smspec_alloc_completion_num_key( const char * join_string , const st join_string , num ); else - return NULL; + return std::string(); } /* @@ -265,7 +265,7 @@ std::string smspec_alloc_segment_key( const char * join_string , const std::stri join_string , num ); else - return NULL; + return std::string(); } @@ -278,7 +278,7 @@ std::string smspec_alloc_local_well_key( const char * join_string , const std::s join_string , wgname.c_str()); else - return NULL; + return std::string(); } std::string smspec_alloc_local_completion_key( const char * join_string, const std::string& keyword , const std::string& lgr_name , const std::string& wgname , int i , int j , int k) { @@ -292,7 +292,7 @@ std::string smspec_alloc_local_completion_key( const char * join_string, const s join_string , i,j,k); else - return NULL; + return std::string(); } /*****************************************************************/ diff --git a/ThirdParty/Ert/lib/util/util.c b/ThirdParty/Ert/lib/util/util.c index 53a0c8584a..9ae01521b7 100644 --- a/ThirdParty/Ert/lib/util/util.c +++ b/ThirdParty/Ert/lib/util/util.c @@ -2153,6 +2153,8 @@ int util_fmove( FILE * stream , long offset , long shift) { #ifdef HAVE_WINDOWS__ACCESS bool util_access(const char * entry, int mode) { + if (!entry) return false; + return (_access(entry, mode) == 0); } @@ -2160,6 +2162,8 @@ bool util_access(const char * entry, int mode) { #ifdef HAVE_POSIX_ACCESS bool util_access(const char * entry, mode_t mode) { + if (!entry) return false; + return (access(entry, mode) == 0); } #endif diff --git a/ThirdParty/Qwt/CHANGES-6.1 b/ThirdParty/Qwt/CHANGES-6.1 new file mode 100644 index 0000000000..79b0188fe8 --- /dev/null +++ b/ThirdParty/Qwt/CHANGES-6.1 @@ -0,0 +1,166 @@ +========= +Qwt 6.1.3 +========= + +1) QwtPlotMagnifier, QwtPlotZoomer + + - handling of non linear transformations ( f.e logarithmic ) + +2) Date/Time scales + + - QwtDate::ceil(), QwtDate::weekNumber(), QwtDate::utcOffset() fixed + - QwtDateScaleEngine fixed when aligning to months + +3) QwtPlotLayout + + - layout bug for legends witdh visisble scrollbars fixed + +4) Plot items + + - hiding QwtPlotLegendItem without entries + - QwtPlotShapeItem render code fixed + +5) QwtPlotGLCanvas + + - slightly improved, nevertheless better use + Qwt 6.2 when being interested in OpenGL + +6) Other + + - QwtGraphic boundingRect updates fixed + - QwtSyntheticPointData::x() fixed + - QwtLogScaleEngine::divideScale ignoring stepSize parameter for ranges + below one "decade" + - QwtPlotAbstractBarChart::getCanvasMarginHint fixed + +========= +Qwt 6.1.2 +========= + +1) Qt 5.4 compatibility + + - QT_STATIC_CONST + "QT_STATIC_CONST" replaced by "static const" + +2) build environment + + - QMAKELIBDIRFLAGS + using QMAKELIBDIRFLAGS to avoid conflicts with already + installed linux distro packages + +3) color maps + + - QwtLinearColorMap + handling of alpha values added + + - QwtAlphaColorMap + basic functinality fixed + + - QwtPainter + QwtPainter::drawColorBar() fixed for semi transparent colors. + +4) QwtPlot and friends + + - QwtLegend + layout issue fixed + + - QwtLogScaleEngine + tick duplicates fixed + + - QwtPainter + internal chunk size for drawing polylines with the raster paint engine + reduced from 20 to 6 ( faster ). + +Qwt 6.1.1 +========= + +1) build environment + + - Shadow builds + qmake project files to allow shadow builds + + - pkg-config + QwtPkgConfig config option added to qwtconfig.pri to enable generation + of pkg-config files ( default setting is: disabled ) + +2) scales + + - QwtDateScaleEngine + Aligning/Autoscaling improved. + + - QwtLinearScaleEngines + Trying to avoid overruns for huge intervals ( > max double ) in divideScale(). + + - QwtAbstractScaleDraw/QwtScaleDraw + Layout issues fixed. + + - QwtRoundScaleDraw + Performance for specific use cases improved. + +3) controls + + - QwtAbstractSlider/QwtCounter + Fixes for tiny step sizes. + + - QwtDial/QwtKnob + Rounding instead of flooring, when translating values to angles. + + - QwtKnob/QwtThermo + Missing updates, when changing the scale draw. + + - QwtWheel + Aligning of values improved. + +4) QwtPlot and friends + + - QwtPlot + Disabling auto-replot in the destructor. + QwtPlot::setPlotLayout() fixed. + Calculation in QwtPlot::canvasMap fixed for disabled axes. + QwtPlot::autoRefresh() when attaching/detaching a plot item. + + - QwtLegend + Clipping code fixed in QwtLegend::renderLegend(). + + - QwtPlotRenderer + Order of setting printer properties changed to work around a Qt 4.8 bug. + + - QwtGraphic + Handling of RenderPensUnscaled flag fixed to respect initial + painter transformations ( non cosmetic pens on legend icons will + be scaled according to paint device resolution - f.e high dpi printouts - now ). + + - QwtPainter + Painter transformation for simple rich texts fixed. + Applying alpha values, when drawing color bars. + + - QwtPicker + Work around a Qt bug when creating an event filter inside of an + event filter ( calling the event filter twice ). + + - QwtPickerMachine + Ignoring autorepeated key events. + + - QwtPlotCurve + Paint order of curve pen and brush inverted ( pen on top of brush ). + + - QwtPlotAbstractBarChart + Using layoutHint() as minimum sample width in AutoAdjustSamples mode. + + - QwtPlotBarChart/QwtPlotMultiBarChart + Caluclation of boundingRect() fixed. + + - QwtPlotScaleItem + Internal cache removed to avoid out of sync situations + + - QwtPlotSpectroCurve + Losing alpha values from the color map fixed. + + - QwtPlotTextLabel + No internal caches for record/replay paint devices ( QPicture/QwtGraphic ). + + - QwtRasterData + Handling of NaN values added, when calculating contour lines. + + - QwtSymbol + Pin point translations fixed. diff --git a/ThirdParty/Qwt/designer/designer.pro b/ThirdParty/Qwt/designer/designer.pro index c269e9da27..7d44a44bfe 100644 --- a/ThirdParty/Qwt/designer/designer.pro +++ b/ThirdParty/Qwt/designer/designer.pro @@ -8,6 +8,7 @@ ################################################################ QWT_ROOT = $${PWD}/.. +QWT_OUT_ROOT = $${OUT_PWD}/.. include ( $${QWT_ROOT}/qwtconfig.pri ) include ( $${QWT_ROOT}/qwtbuild.pri ) @@ -29,7 +30,6 @@ CONFIG( debug_and_release ) { contains(QWT_CONFIG, QwtDesigner) { CONFIG += qt plugin - CONFIG += warn_on greaterThan(QT_MAJOR_VERSION, 4) { @@ -52,7 +52,6 @@ contains(QWT_CONFIG, QwtDesigner) { contains(QWT_CONFIG, QwtDll) { contains(QWT_CONFIG, QwtDesignerSelfContained) { - QWT_CONFIG += include_src } @@ -85,17 +84,7 @@ contains(QWT_CONFIG, QwtDesigner) { # into the plugin. Not supported on Windows ! QMAKE_RPATHDIR *= $${QWT_INSTALL_LIBS} - - contains(QWT_CONFIG, QwtFramework) { - - LIBS += -F$${QWT_ROOT}/lib - } - else { - - LIBS += -L$${QWT_ROOT}/lib - } - - qwtAddLibrary(qwt) + qwtAddLibrary($${QWT_OUT_ROOT}/lib, qwt) contains(QWT_CONFIG, QwtDll) { diff --git a/ThirdParty/Qwt/doc/Doxyfile b/ThirdParty/Qwt/doc/Doxyfile index d1e55dd67a..bd9b020ab1 100644 --- a/ThirdParty/Qwt/doc/Doxyfile +++ b/ThirdParty/Qwt/doc/Doxyfile @@ -1,110 +1,121 @@ -# Doxyfile 1.8.1 +# Doxyfile 1.8.6 # This file describes the settings to be used by the documentation system # doxygen (www.doxygen.org) for a project. # -# All text after a hash (#) is considered a comment and will be ignored. +# All text after a double hash (##) is considered a comment and is placed in +# front of the TAG it is preceding. +# +# All text after a single hash (#) is considered a comment and will be ignored. # The format is: -# TAG = value [value, ...] -# For lists items can also be appended using: -# TAG += value [value, ...] -# Values that contain spaces should be placed between quotes (" "). +# TAG = value [value, ...] +# For lists, items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (\" \"). #--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- # This tag specifies the encoding used for all characters in the config file -# that follow. The default is UTF-8 which is also the encoding used for all -# text before the first occurrence of this tag. Doxygen uses libiconv (or the -# iconv built into libc) for the transcoding. See -# http://www.gnu.org/software/libiconv for the list of possible encodings. +# that follow. The default is UTF-8 which is also the encoding used for all text +# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv +# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv +# for the list of possible encodings. +# The default value is: UTF-8. DOXYFILE_ENCODING = UTF-8 -# The PROJECT_NAME tag is a single word (or sequence of words) that should -# identify the project. Note that if you do not use Doxywizard you need -# to put quotes around the project name if it contains spaces. +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by +# double-quotes, unless you are using Doxywizard) that should identify the +# project for which the documentation is generated. This name is used in the +# title of most generated pages and in a few other places. +# The default value is: My Project. PROJECT_NAME = "Qwt User's Guide" -# The PROJECT_NUMBER tag can be used to enter a project or revision number. -# This could be handy for archiving the generated documentation or -# if some version control system is used. +# The PROJECT_NUMBER tag can be used to enter a project or revision number. This +# could be handy for archiving the generated documentation or if some version +# control system is used. PROJECT_NUMBER = $(QWTVERSION) # Using the PROJECT_BRIEF tag one can provide an optional one line description -# for a project that appears at the top of each page and should give viewer -# a quick idea about the purpose of the project. Keep the description short. +# for a project that appears at the top of each page and should give viewer a +# quick idea about the purpose of the project. Keep the description short. PROJECT_BRIEF = -# With the PROJECT_LOGO tag one can specify an logo or icon that is -# included in the documentation. The maximum height of the logo should not -# exceed 55 pixels and the maximum width should not exceed 200 pixels. -# Doxygen will copy the logo to the output directory. +# With the PROJECT_LOGO tag one can specify an logo or icon that is included in +# the documentation. The maximum height of the logo should not exceed 55 pixels +# and the maximum width should not exceed 200 pixels. Doxygen will copy the logo +# to the output directory. PROJECT_LOGO = -# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) -# base path where the generated documentation will be put. -# If a relative path is entered, it will be relative to the location -# where doxygen was started. If left blank the current directory will be used. +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path +# into which the generated documentation will be written. If a relative path is +# entered, it will be relative to the location where doxygen was started. If +# left blank the current directory will be used. OUTPUT_DIRECTORY = -# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create -# 4096 sub-directories (in 2 levels) under the output directory of each output -# format and will distribute the generated files over these directories. -# Enabling this option can be useful when feeding doxygen a huge amount of -# source files, where putting all generated files in the same directory would -# otherwise cause performance problems for the file system. +# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create 4096 sub- +# directories (in 2 levels) under the output directory of each output format and +# will distribute the generated files over these directories. Enabling this +# option can be useful when feeding doxygen a huge amount of source files, where +# putting all generated files in the same directory would otherwise causes +# performance problems for the file system. +# The default value is: NO. CREATE_SUBDIRS = NO # The OUTPUT_LANGUAGE tag is used to specify the language in which all # documentation generated by doxygen is written. Doxygen will use this # information to generate all constant output in the proper language. -# The default language is English, other supported languages are: -# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, -# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German, -# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English -# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, -# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak, -# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese. +# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese, +# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States), +# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian, +# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages), +# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian, +# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian, +# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish, +# Ukrainian and Vietnamese. +# The default value is: English. OUTPUT_LANGUAGE = English -# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will -# include brief member descriptions after the members that are listed in -# the file and class documentation (similar to JavaDoc). -# Set to NO to disable this. +# If the BRIEF_MEMBER_DESC tag is set to YES doxygen will include brief member +# descriptions after the members that are listed in the file and class +# documentation (similar to Javadoc). Set to NO to disable this. +# The default value is: YES. BRIEF_MEMBER_DESC = YES -# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend -# the brief description of a member or function before the detailed description. -# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# If the REPEAT_BRIEF tag is set to YES doxygen will prepend the brief +# description of a member or function before the detailed description +# +# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the # brief descriptions will be completely suppressed. +# The default value is: YES. REPEAT_BRIEF = YES -# This tag implements a quasi-intelligent brief description abbreviator -# that is used to form the text in various listings. Each string -# in this list, if found as the leading text of the brief description, will be -# stripped from the text and the result after processing the whole list, is -# used as the annotated text. Otherwise, the brief description is used as-is. -# If left blank, the following values are used ("$name" is automatically -# replaced with the name of the entity): "The $name class" "The $name widget" -# "The $name file" "is" "provides" "specifies" "contains" -# "represents" "a" "an" "the" +# This tag implements a quasi-intelligent brief description abbreviator that is +# used to form the text in various listings. Each string in this list, if found +# as the leading text of the brief description, will be stripped from the text +# and the result, after processing the whole list, is used as the annotated +# text. Otherwise, the brief description is used as-is. If left blank, the +# following values are used ($name is automatically replaced with the name of +# the entity):The $name class, The $name widget, The $name file, is, provides, +# specifies, contains, represents, a, an and the. ABBREVIATE_BRIEF = # If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then -# Doxygen will generate a detailed section even if there is only a brief +# doxygen will generate a detailed section even if there is only a brief # description. +# The default value is: NO. ALWAYS_DETAILED_SEC = NO @@ -112,169 +123,204 @@ ALWAYS_DETAILED_SEC = NO # inherited members of a class in the documentation of that class as if those # members were ordinary class members. Constructors, destructors and assignment # operators of the base classes will not be shown. +# The default value is: NO. INLINE_INHERITED_MEMB = NO -# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full -# path before files name in the file list and in the header files. If set -# to NO the shortest path that makes the file name unique will be used. +# If the FULL_PATH_NAMES tag is set to YES doxygen will prepend the full path +# before files name in the file list and in the header files. If set to NO the +# shortest path that makes the file name unique will be used +# The default value is: YES. FULL_PATH_NAMES = NO -# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag -# can be used to strip a user-defined part of the path. Stripping is -# only done if one of the specified strings matches the left-hand part of -# the path. The tag can be used to show relative paths in the file list. -# If left blank the directory from which doxygen is run is used as the -# path to strip. +# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path. +# Stripping is only done if one of the specified strings matches the left-hand +# part of the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the path to +# strip. +# +# Note that you can specify absolute paths here, but also relative paths, which +# will be relative from the directory where doxygen is started. +# This tag requires that the tag FULL_PATH_NAMES is set to YES. STRIP_FROM_PATH = -# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of -# the path mentioned in the documentation of a class, which tells -# the reader which header file to include in order to use a class. -# If left blank only the name of the header file containing the class -# definition is used. Otherwise one should specify the include paths that -# are normally passed to the compiler using the -I flag. +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the +# path mentioned in the documentation of a class, which tells the reader which +# header file to include in order to use a class. If left blank only the name of +# the header file containing the class definition is used. Otherwise one should +# specify the list of include paths that are normally passed to the compiler +# using the -I flag. STRIP_FROM_INC_PATH = -# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter -# (but less readable) file names. This can be useful if your file system -# doesn't support long names like on DOS, Mac, or CD-ROM. +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but +# less readable) file names. This can be useful is your file systems doesn't +# support long names like on DOS, Mac, or CD-ROM. +# The default value is: NO. SHORT_NAMES = NO -# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen -# will interpret the first line (until the first dot) of a JavaDoc-style -# comment as the brief description. If set to NO, the JavaDoc -# comments will behave just like regular Qt-style comments -# (thus requiring an explicit @brief command for a brief description.) +# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the +# first line (until the first dot) of a Javadoc-style comment as the brief +# description. If set to NO, the Javadoc-style will behave just like regular Qt- +# style comments (thus requiring an explicit @brief command for a brief +# description.) +# The default value is: NO. JAVADOC_AUTOBRIEF = NO -# If the QT_AUTOBRIEF tag is set to YES then Doxygen will -# interpret the first line (until the first dot) of a Qt-style -# comment as the brief description. If set to NO, the comments -# will behave just like regular Qt-style comments (thus requiring -# an explicit \brief command for a brief description.) +# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first +# line (until the first dot) of a Qt-style comment as the brief description. If +# set to NO, the Qt-style will behave just like regular Qt-style comments (thus +# requiring an explicit \brief command for a brief description.) +# The default value is: NO. QT_AUTOBRIEF = NO -# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen -# treat a multi-line C++ special comment block (i.e. a block of //! or /// -# comments) as a brief description. This used to be the default behaviour. -# The new default is to treat a multi-line C++ comment block as a detailed -# description. Set this tag to YES if you prefer the old behaviour instead. +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a +# multi-line C++ special comment block (i.e. a block of //! or /// comments) as +# a brief description. This used to be the default behavior. The new default is +# to treat a multi-line C++ comment block as a detailed description. Set this +# tag to YES if you prefer the old behavior instead. +# +# Note that setting this tag to YES also means that rational rose comments are +# not recognized any more. +# The default value is: NO. MULTILINE_CPP_IS_BRIEF = NO -# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented -# member inherits the documentation from any documented member that it -# re-implements. +# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the +# documentation from any documented member that it re-implements. +# The default value is: YES. INHERIT_DOCS = YES -# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce -# a new page for each member. If set to NO, the documentation of a member will -# be part of the file/class/namespace that contains it. +# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce a +# new page for each member. If set to NO, the documentation of a member will be +# part of the file/class/namespace that contains it. +# The default value is: NO. SEPARATE_MEMBER_PAGES = NO -# The TAB_SIZE tag can be used to set the number of spaces in a tab. -# Doxygen uses this value to replace tabs by spaces in code fragments. +# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen +# uses this value to replace tabs by spaces in code fragments. +# Minimum value: 1, maximum value: 16, default value: 4. TAB_SIZE = 4 -# This tag can be used to specify a number of aliases that acts -# as commands in the documentation. An alias has the form "name=value". -# For example adding "sideeffect=\par Side Effects:\n" will allow you to -# put the command \sideeffect (or @sideeffect) in the documentation, which -# will result in a user-defined paragraph with heading "Side Effects:". -# You can put \n's in the value part of an alias to insert newlines. +# This tag can be used to specify a number of aliases that act as commands in +# the documentation. An alias has the form: +# name=value +# For example adding +# "sideeffect=@par Side Effects:\n" +# will allow you to put the command \sideeffect (or @sideeffect) in the +# documentation, which will result in a user-defined paragraph with heading +# "Side Effects:". You can put \n's in the value part of an alias to insert +# newlines. ALIASES = # This tag can be used to specify a number of word-keyword mappings (TCL only). -# A mapping has the form "name=value". For example adding -# "class=itcl::class" will allow you to use the command class in the -# itcl::class meaning. +# A mapping has the form "name=value". For example adding "class=itcl::class" +# will allow you to use the command class in the itcl::class meaning. TCL_SUBST = -# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C -# sources only. Doxygen will then generate output that is more tailored for C. -# For instance, some of the names that are used will be different. The list -# of all members will be omitted, etc. +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources +# only. Doxygen will then generate output that is more tailored for C. For +# instance, some of the names that are used will be different. The list of all +# members will be omitted, etc. +# The default value is: NO. OPTIMIZE_OUTPUT_FOR_C = NO -# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java -# sources only. Doxygen will then generate output that is more tailored for -# Java. For instance, namespaces will be presented as packages, qualified -# scopes will look different, etc. +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or +# Python sources only. Doxygen will then generate output that is more tailored +# for that language. For instance, namespaces will be presented as packages, +# qualified scopes will look different, etc. +# The default value is: NO. OPTIMIZE_OUTPUT_JAVA = NO # Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran -# sources only. Doxygen will then generate output that is more tailored for -# Fortran. +# sources. Doxygen will then generate output that is tailored for Fortran. +# The default value is: NO. OPTIMIZE_FOR_FORTRAN = NO # Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL -# sources. Doxygen will then generate output that is tailored for -# VHDL. +# sources. Doxygen will then generate output that is tailored for VHDL. +# The default value is: NO. OPTIMIZE_OUTPUT_VHDL = NO # Doxygen selects the parser to use depending on the extension of the files it -# parses. With this tag you can assign which parser to use for a given extension. -# Doxygen has a built-in mapping, but you can override or extend it using this -# tag. The format is ext=language, where ext is a file extension, and language -# is one of the parsers supported by doxygen: IDL, Java, Javascript, CSharp, C, -# C++, D, PHP, Objective-C, Python, Fortran, VHDL, C, C++. For instance to make +# parses. With this tag you can assign which parser to use for a given +# extension. Doxygen has a built-in mapping, but you can override or extend it +# using this tag. The format is ext=language, where ext is a file extension, and +# language is one of the parsers supported by doxygen: IDL, Java, Javascript, +# C#, C, C++, D, PHP, Objective-C, Python, Fortran, VHDL. For instance to make # doxygen treat .inc files as Fortran files (default is PHP), and .f files as C -# (default is Fortran), use: inc=Fortran f=C. Note that for custom extensions -# you also need to set FILE_PATTERNS otherwise the files are not read by doxygen. +# (default is Fortran), use: inc=Fortran f=C. +# +# Note For files without extension you can use no_extension as a placeholder. +# +# Note that for custom extensions you also need to set FILE_PATTERNS otherwise +# the files are not read by doxygen. EXTENSION_MAPPING = -# If MARKDOWN_SUPPORT is enabled (the default) then doxygen pre-processes all -# comments according to the Markdown format, which allows for more readable +# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments +# according to the Markdown format, which allows for more readable # documentation. See http://daringfireball.net/projects/markdown/ for details. -# The output of markdown processing is further processed by doxygen, so you -# can mix doxygen, HTML, and XML commands with Markdown formatting. -# Disable only in case of backward compatibilities issues. +# The output of markdown processing is further processed by doxygen, so you can +# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in +# case of backward compatibilities issues. +# The default value is: YES. MARKDOWN_SUPPORT = YES +# When enabled doxygen tries to link words that correspond to documented +# classes, or namespaces to their corresponding documentation. Such a link can +# be prevented in individual cases by by putting a % sign in front of the word +# or globally by setting AUTOLINK_SUPPORT to NO. +# The default value is: YES. + +AUTOLINK_SUPPORT = YES + # If you use STL classes (i.e. std::string, std::vector, etc.) but do not want -# to include (a tag file for) the STL sources as input, then you should -# set this tag to YES in order to let doxygen match functions declarations and -# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. -# func(std::string) {}). This also makes the inheritance and collaboration +# to include (a tag file for) the STL sources as input, then you should set this +# tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); +# versus func(std::string) {}). This also make the inheritance and collaboration # diagrams that involve STL classes more complete and accurate. +# The default value is: NO. BUILTIN_STL_SUPPORT = NO # If you use Microsoft's C++/CLI language, you should set this option to YES to # enable parsing support. +# The default value is: NO. CPP_CLI_SUPPORT = NO -# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. -# Doxygen will parse them like normal C++ but will assume all classes use public -# instead of private inheritance when no explicit protection keyword is present. +# Set the SIP_SUPPORT tag to YES if your project consists of sip (see: +# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen +# will parse them like normal C++ but will assume all classes use public instead +# of private inheritance when no explicit protection keyword is present. +# The default value is: NO. SIP_SUPPORT = NO -# For Microsoft's IDL there are propget and propput attributes to indicate getter -# and setter methods for a property. Setting this option to YES (the default) -# will make doxygen replace the get and set methods by a property in the -# documentation. This will only work if the methods are indeed getting or -# setting a simple type. If this is not the case, or you want to show the -# methods anyway, you should set this option to NO. +# For Microsoft's IDL there are propget and propput attributes to indicate +# getter and setter methods for a property. Setting this option to YES will make +# doxygen to replace the get and set methods by a property in the documentation. +# This will only work if the methods are indeed getting or setting a simple +# type. If this is not the case, or you want to show the methods anyway, you +# should set this option to NO. +# The default value is: YES. IDL_PROPERTY_SUPPORT = YES @@ -282,67 +328,61 @@ IDL_PROPERTY_SUPPORT = YES # tag is set to YES, then doxygen will reuse the documentation of the first # member in the group (if any) for the other members of the group. By default # all members of a group must be documented explicitly. +# The default value is: NO. DISTRIBUTE_GROUP_DOC = NO -# Set the SUBGROUPING tag to YES (the default) to allow class member groups of -# the same type (for instance a group of public functions) to be put as a -# subgroup of that type (e.g. under the Public Functions section). Set it to -# NO to prevent subgrouping. Alternatively, this can be done per class using -# the \nosubgrouping command. +# Set the SUBGROUPING tag to YES to allow class member groups of the same type +# (for instance a group of public functions) to be put as a subgroup of that +# type (e.g. under the Public Functions section). Set it to NO to prevent +# subgrouping. Alternatively, this can be done per class using the +# \nosubgrouping command. +# The default value is: YES. SUBGROUPING = YES -# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and -# unions are shown inside the group in which they are included (e.g. using -# @ingroup) instead of on a separate page (for HTML and Man pages) or -# section (for LaTeX and RTF). +# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions +# are shown inside the group in which they are included (e.g. using \ingroup) +# instead of on a separate page (for HTML and Man pages) or section (for LaTeX +# and RTF). +# +# Note that this feature does not work in combination with +# SEPARATE_MEMBER_PAGES. +# The default value is: NO. INLINE_GROUPED_CLASSES = NO -# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and -# unions with only public data fields will be shown inline in the documentation -# of the scope in which they are defined (i.e. file, namespace, or group -# documentation), provided this scope is documented. If set to NO (the default), -# structs, classes, and unions are shown on a separate page (for HTML and Man -# pages) or section (for LaTeX and RTF). +# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions +# with only public data fields or simple typedef fields will be shown inline in +# the documentation of the scope in which they are defined (i.e. file, +# namespace, or group documentation), provided this scope is documented. If set +# to NO, structs, classes, and unions are shown on a separate page (for HTML and +# Man pages) or section (for LaTeX and RTF). +# The default value is: NO. INLINE_SIMPLE_STRUCTS = NO -# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum -# is documented as struct, union, or enum with the name of the typedef. So +# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or +# enum is documented as struct, union, or enum with the name of the typedef. So # typedef struct TypeS {} TypeT, will appear in the documentation as a struct # with name TypeT. When disabled the typedef will appear as a member of a file, -# namespace, or class. And the struct will be named TypeS. This can typically -# be useful for C code in case the coding convention dictates that all compound +# namespace, or class. And the struct will be named TypeS. This can typically be +# useful for C code in case the coding convention dictates that all compound # types are typedef'ed and only the typedef is referenced, never the tag name. +# The default value is: NO. TYPEDEF_HIDES_STRUCT = NO -# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to -# determine which symbols to keep in memory and which to flush to disk. -# When the cache is full, less often used symbols will be written to disk. -# For small to medium size projects (<1000 input files) the default value is -# probably good enough. For larger projects a too small cache size can cause -# doxygen to be busy swapping symbols to and from disk most of the time -# causing a significant performance penalty. -# If the system has enough physical memory increasing the cache will improve the -# performance by keeping more symbols in memory. Note that the value works on -# a logarithmic scale so increasing the size by one will roughly double the -# memory usage. The cache size is given by this formula: -# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0, -# corresponding to a cache size of 2^16 = 65536 symbols. - -SYMBOL_CACHE_SIZE = 0 - -# Similar to the SYMBOL_CACHE_SIZE the size of the symbol lookup cache can be -# set using LOOKUP_CACHE_SIZE. This cache is used to resolve symbols given -# their name and scope. Since this can be an expensive process and often the -# same symbol appear multiple times in the code, doxygen keeps a cache of -# pre-resolved symbols. If the cache is too small doxygen will become slower. -# If the cache is too large, memory is wasted. The cache size is given by this -# formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range is 0..9, the default is 0, -# corresponding to a cache size of 2^16 = 65536 symbols. +# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This +# cache is used to resolve symbols given their name and scope. Since this can be +# an expensive process and often the same symbol appears multiple times in the +# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small +# doxygen will become slower. If the cache is too large, memory is wasted. The +# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range +# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536 +# symbols. At the end of a run doxygen will report the cache usage and suggest +# the optimal cache size from a speed point of view. +# Minimum value: 0, maximum value: 9, default value: 0. LOOKUP_CACHE_SIZE = 0 @@ -351,341 +391,392 @@ LOOKUP_CACHE_SIZE = 0 #--------------------------------------------------------------------------- # If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in -# documentation are documented, even if no documentation was available. -# Private class members and static file members will be hidden unless -# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES +# documentation are documented, even if no documentation was available. Private +# class members and static file members will be hidden unless the +# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES. +# Note: This will also disable the warnings about undocumented members that are +# normally produced when WARNINGS is set to YES. +# The default value is: NO. EXTRACT_ALL = NO -# If the EXTRACT_PRIVATE tag is set to YES all private members of a class -# will be included in the documentation. +# If the EXTRACT_PRIVATE tag is set to YES all private members of a class will +# be included in the documentation. +# The default value is: NO. EXTRACT_PRIVATE = NO -# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal scope will be included in the documentation. +# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal +# scope will be included in the documentation. +# The default value is: NO. EXTRACT_PACKAGE = NO -# If the EXTRACT_STATIC tag is set to YES all static members of a file -# will be included in the documentation. +# If the EXTRACT_STATIC tag is set to YES all static members of a file will be +# included in the documentation. +# The default value is: NO. EXTRACT_STATIC = NO -# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) -# defined locally in source files will be included in the documentation. -# If set to NO only classes defined in header files are included. +# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) defined +# locally in source files will be included in the documentation. If set to NO +# only classes defined in header files are included. Does not have any effect +# for Java sources. +# The default value is: YES. EXTRACT_LOCAL_CLASSES = NO -# This flag is only useful for Objective-C code. When set to YES local -# methods, which are defined in the implementation section but not in -# the interface are included in the documentation. -# If set to NO (the default) only methods in the interface are included. +# This flag is only useful for Objective-C code. When set to YES local methods, +# which are defined in the implementation section but not in the interface are +# included in the documentation. If set to NO only methods in the interface are +# included. +# The default value is: NO. EXTRACT_LOCAL_METHODS = NO # If this flag is set to YES, the members of anonymous namespaces will be # extracted and appear in the documentation as a namespace called -# 'anonymous_namespace{file}', where file will be replaced with the base -# name of the file that contains the anonymous namespace. By default -# anonymous namespaces are hidden. +# 'anonymous_namespace{file}', where file will be replaced with the base name of +# the file that contains the anonymous namespace. By default anonymous namespace +# are hidden. +# The default value is: NO. EXTRACT_ANON_NSPACES = NO -# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all -# undocumented members of documented classes, files or namespaces. -# If set to NO (the default) these members will be included in the -# various overviews, but no documentation section is generated. -# This option has no effect if EXTRACT_ALL is enabled. +# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all +# undocumented members inside documented classes or files. If set to NO these +# members will be included in the various overviews, but no documentation +# section is generated. This option has no effect if EXTRACT_ALL is enabled. +# The default value is: NO. HIDE_UNDOC_MEMBERS = NO -# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all -# undocumented classes that are normally visible in the class hierarchy. -# If set to NO (the default) these classes will be included in the various -# overviews. This option has no effect if EXTRACT_ALL is enabled. +# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. If set +# to NO these classes will be included in the various overviews. This option has +# no effect if EXTRACT_ALL is enabled. +# The default value is: NO. HIDE_UNDOC_CLASSES = NO -# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all -# friend (class|struct|union) declarations. -# If set to NO (the default) these declarations will be included in the -# documentation. +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend +# (class|struct|union) declarations. If set to NO these declarations will be +# included in the documentation. +# The default value is: NO. -HIDE_FRIEND_COMPOUNDS = NO +HIDE_FRIEND_COMPOUNDS = YES -# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any -# documentation blocks found inside the body of a function. -# If set to NO (the default) these blocks will be appended to the -# function's detailed documentation block. +# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any +# documentation blocks found inside the body of a function. If set to NO these +# blocks will be appended to the function's detailed documentation block. +# The default value is: NO. HIDE_IN_BODY_DOCS = NO -# The INTERNAL_DOCS tag determines if documentation -# that is typed after a \internal command is included. If the tag is set -# to NO (the default) then the documentation will be excluded. -# Set it to YES to include the internal documentation. +# The INTERNAL_DOCS tag determines if documentation that is typed after a +# \internal command is included. If the tag is set to NO then the documentation +# will be excluded. Set it to YES to include the internal documentation. +# The default value is: NO. INTERNAL_DOCS = NO -# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate -# file names in lower-case letters. If set to YES upper-case letters are also +# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file +# names in lower-case letters. If set to YES upper-case letters are also # allowed. This is useful if you have classes or files whose names only differ # in case and if your file system supports case sensitive file names. Windows # and Mac users are advised to set this option to NO. +# The default value is: system dependent. CASE_SENSE_NAMES = NO -# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen -# will show members with their full class and namespace scopes in the -# documentation. If set to YES the scope will be hidden. +# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with +# their full class and namespace scopes in the documentation. If set to YES the +# scope will be hidden. +# The default value is: NO. HIDE_SCOPE_NAMES = NO -# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen -# will put a list of the files that are included by a file in the documentation -# of that file. +# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of +# the files that are included by a file in the documentation of that file. +# The default value is: YES. SHOW_INCLUDE_FILES = YES -# If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen -# will list include files with double quotes in the documentation -# rather than with sharp brackets. +# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each +# grouped member an include statement to the documentation, telling the reader +# which file to include in order to use the member. +# The default value is: NO. + +SHOW_GROUPED_MEMB_INC = NO + +# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include +# files with double quotes in the documentation rather than with sharp brackets. +# The default value is: NO. FORCE_LOCAL_INCLUDES = NO -# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] -# is inserted in the documentation for inline members. +# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the +# documentation for inline members. +# The default value is: YES. INLINE_INFO = YES -# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen -# will sort the (detailed) documentation of file and class members -# alphabetically by member name. If set to NO the members will appear in -# declaration order. +# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the +# (detailed) documentation of file and class members alphabetically by member +# name. If set to NO the members will appear in declaration order. +# The default value is: YES. SORT_MEMBER_DOCS = YES -# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the -# brief documentation of file, namespace and class members alphabetically -# by member name. If set to NO (the default) the members will appear in -# declaration order. +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief +# descriptions of file, namespace and class members alphabetically by member +# name. If set to NO the members will appear in declaration order. Note that +# this will also influence the order of the classes in the class list. +# The default value is: NO. SORT_BRIEF_DOCS = NO -# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen -# will sort the (brief and detailed) documentation of class members so that -# constructors and destructors are listed first. If set to NO (the default) -# the constructors will appear in the respective orders defined by -# SORT_MEMBER_DOCS and SORT_BRIEF_DOCS. -# This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO -# and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO. +# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the +# (brief and detailed) documentation of class members so that constructors and +# destructors are listed first. If set to NO the constructors will appear in the +# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS. +# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief +# member documentation. +# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting +# detailed member documentation. +# The default value is: NO. SORT_MEMBERS_CTORS_1ST = YES -# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the -# hierarchy of group names into alphabetical order. If set to NO (the default) -# the group names will appear in their defined order. +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy +# of group names into alphabetical order. If set to NO the group names will +# appear in their defined order. +# The default value is: NO. SORT_GROUP_NAMES = NO -# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be -# sorted by fully-qualified names, including namespaces. If set to -# NO (the default), the class list will be sorted only by class name, -# not including the namespace part. +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by +# fully-qualified names, including namespaces. If set to NO, the class list will +# be sorted only by class name, not including the namespace part. # Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. -# Note: This option applies only to the class list, not to the -# alphabetical list. +# Note: This option applies only to the class list, not to the alphabetical +# list. +# The default value is: NO. SORT_BY_SCOPE_NAME = NO -# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to -# do proper type resolution of all parameters of a function it will reject a -# match between the prototype and the implementation of a member function even -# if there is only one candidate or it is obvious which candidate to choose -# by doing a simple string match. By disabling STRICT_PROTO_MATCHING doxygen -# will still accept a match between prototype and implementation in such cases. +# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper +# type resolution of all parameters of a function it will reject a match between +# the prototype and the implementation of a member function even if there is +# only one candidate or it is obvious which candidate to choose by doing a +# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still +# accept a match between prototype and implementation in such cases. +# The default value is: NO. STRICT_PROTO_MATCHING = NO -# The GENERATE_TODOLIST tag can be used to enable (YES) or -# disable (NO) the todo list. This list is created by putting \todo -# commands in the documentation. +# The GENERATE_TODOLIST tag can be used to enable ( YES) or disable ( NO) the +# todo list. This list is created by putting \todo commands in the +# documentation. +# The default value is: YES. GENERATE_TODOLIST = NO -# The GENERATE_TESTLIST tag can be used to enable (YES) or -# disable (NO) the test list. This list is created by putting \test -# commands in the documentation. +# The GENERATE_TESTLIST tag can be used to enable ( YES) or disable ( NO) the +# test list. This list is created by putting \test commands in the +# documentation. +# The default value is: YES. GENERATE_TESTLIST = NO -# The GENERATE_BUGLIST tag can be used to enable (YES) or -# disable (NO) the bug list. This list is created by putting \bug -# commands in the documentation. +# The GENERATE_BUGLIST tag can be used to enable ( YES) or disable ( NO) the bug +# list. This list is created by putting \bug commands in the documentation. +# The default value is: YES. GENERATE_BUGLIST = NO -# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or -# disable (NO) the deprecated list. This list is created by putting -# \deprecated commands in the documentation. +# The GENERATE_DEPRECATEDLIST tag can be used to enable ( YES) or disable ( NO) +# the deprecated list. This list is created by putting \deprecated commands in +# the documentation. +# The default value is: YES. GENERATE_DEPRECATEDLIST= YES -# The ENABLED_SECTIONS tag can be used to enable conditional -# documentation sections, marked by \if sectionname ... \endif. +# The ENABLED_SECTIONS tag can be used to enable conditional documentation +# sections, marked by \if ... \endif and \cond +# ... \endcond blocks. ENABLED_SECTIONS = -# The MAX_INITIALIZER_LINES tag determines the maximum number of lines -# the initial value of a variable or macro consists of for it to appear in -# the documentation. If the initializer consists of more lines than specified -# here it will be hidden. Use a value of 0 to hide initializers completely. -# The appearance of the initializer of individual variables and macros in the -# documentation can be controlled using \showinitializer or \hideinitializer -# command in the documentation regardless of this setting. +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the +# initial value of a variable or macro / define can have for it to appear in the +# documentation. If the initializer consists of more lines than specified here +# it will be hidden. Use a value of 0 to hide initializers completely. The +# appearance of the value of individual variables and macros / defines can be +# controlled using \showinitializer or \hideinitializer command in the +# documentation regardless of this setting. +# Minimum value: 0, maximum value: 10000, default value: 30. MAX_INITIALIZER_LINES = 30 -# Set the SHOW_USED_FILES tag to NO to disable the list of files generated -# at the bottom of the documentation of classes and structs. If set to YES the -# list will mention the files that were used to generate the documentation. +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at +# the bottom of the documentation of classes and structs. If set to YES the list +# will mention the files that were used to generate the documentation. +# The default value is: YES. SHOW_USED_FILES = NO -# Set the SHOW_FILES tag to NO to disable the generation of the Files page. -# This will remove the Files entry from the Quick Index and from the -# Folder Tree View (if specified). The default is YES. +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This +# will remove the Files entry from the Quick Index and from the Folder Tree View +# (if specified). +# The default value is: YES. SHOW_FILES = NO -# Set the SHOW_NAMESPACES tag to NO to disable the generation of the -# Namespaces page. -# This will remove the Namespaces entry from the Quick Index -# and from the Folder Tree View (if specified). The default is YES. +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces +# page. This will remove the Namespaces entry from the Quick Index and from the +# Folder Tree View (if specified). +# The default value is: YES. SHOW_NAMESPACES = YES # The FILE_VERSION_FILTER tag can be used to specify a program or script that # doxygen should invoke to get the current version for each file (typically from # the version control system). Doxygen will invoke the program by executing (via -# popen()) the command , where is the value of -# the FILE_VERSION_FILTER tag, and is the name of an input file -# provided by doxygen. Whatever the program writes to standard output -# is used as the file version. See the manual for examples. +# popen()) the command command input-file, where command is the value of the +# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided +# by doxygen. Whatever the program writes to standard output is used as the file +# version. For an example see the documentation. FILE_VERSION_FILTER = # The LAYOUT_FILE tag can be used to specify a layout file which will be parsed # by doxygen. The layout file controls the global structure of the generated -# output files in an output format independent way. The create the layout file -# that represents doxygen's defaults, run doxygen with the -l option. -# You can optionally specify a file name after the option, if omitted -# DoxygenLayout.xml will be used as the name of the layout file. +# output files in an output format independent way. To create the layout file +# that represents doxygen's defaults, run doxygen with the -l option. You can +# optionally specify a file name after the option, if omitted DoxygenLayout.xml +# will be used as the name of the layout file. +# +# Note that if you run doxygen from a directory containing a file called +# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE +# tag is left empty. LAYOUT_FILE = -# The CITE_BIB_FILES tag can be used to specify one or more bib files -# containing the references data. This must be a list of .bib files. The -# .bib extension is automatically appended if omitted. Using this command -# requires the bibtex tool to be installed. See also -# http://en.wikipedia.org/wiki/BibTeX for more info. For LaTeX the style -# of the bibliography can be controlled using LATEX_BIB_STYLE. To use this -# feature you need bibtex and perl available in the search path. +# The CITE_BIB_FILES tag can be used to specify one or more bib files containing +# the reference definitions. This must be a list of .bib files. The .bib +# extension is automatically appended if omitted. This requires the bibtex tool +# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info. +# For LaTeX the style of the bibliography can be controlled using +# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the +# search path. Do not use file names with spaces, bibtex cannot handle them. See +# also \cite for info how to create references. CITE_BIB_FILES = #--------------------------------------------------------------------------- -# configuration options related to warning and progress messages +# Configuration options related to warning and progress messages #--------------------------------------------------------------------------- -# The QUIET tag can be used to turn on/off the messages that are generated -# by doxygen. Possible values are YES and NO. If left blank NO is used. +# The QUIET tag can be used to turn on/off the messages that are generated to +# standard output by doxygen. If QUIET is set to YES this implies that the +# messages are off. +# The default value is: NO. QUIET = YES # The WARNINGS tag can be used to turn on/off the warning messages that are -# generated by doxygen. Possible values are YES and NO. If left blank -# NO is used. +# generated to standard error ( stderr) by doxygen. If WARNINGS is set to YES +# this implies that the warnings are on. +# +# Tip: Turn warnings on while writing the documentation. +# The default value is: YES. WARNINGS = YES -# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings -# for undocumented members. If EXTRACT_ALL is set to YES then this flag will -# automatically be disabled. +# If the WARN_IF_UNDOCUMENTED tag is set to YES, then doxygen will generate +# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag +# will automatically be disabled. +# The default value is: YES. WARN_IF_UNDOCUMENTED = YES -# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for -# potential errors in the documentation, such as not documenting some -# parameters in a documented function, or documenting parameters that -# don't exist or using markup commands wrongly. +# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some parameters +# in a documented function, or documenting parameters that don't exist or using +# markup commands wrongly. +# The default value is: YES. WARN_IF_DOC_ERROR = YES -# The WARN_NO_PARAMDOC option can be enabled to get warnings for -# functions that are documented, but have no documentation for their parameters -# or return value. If set to NO (the default) doxygen will only warn about -# wrong or incomplete parameter documentation, but not about the absence of -# documentation. +# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that +# are documented, but have no documentation for their parameters or return +# value. If set to NO doxygen will only warn about wrong or incomplete parameter +# documentation, but not about the absence of documentation. +# The default value is: NO. WARN_NO_PARAMDOC = YES -# The WARN_FORMAT tag determines the format of the warning messages that -# doxygen can produce. The string should contain the $file, $line, and $text -# tags, which will be replaced by the file and line number from which the -# warning originated and the warning text. Optionally the format may contain -# $version, which will be replaced by the version of the file (if it could -# be obtained via FILE_VERSION_FILTER) +# The WARN_FORMAT tag determines the format of the warning messages that doxygen +# can produce. The string should contain the $file, $line, and $text tags, which +# will be replaced by the file and line number from which the warning originated +# and the warning text. Optionally the format may contain $version, which will +# be replaced by the version of the file (if it could be obtained via +# FILE_VERSION_FILTER) +# The default value is: $file:$line: $text. WARN_FORMAT = "$file:$line: $text" -# The WARN_LOGFILE tag can be used to specify a file to which warning -# and error messages should be written. If left blank the output is written -# to stderr. +# The WARN_LOGFILE tag can be used to specify a file to which warning and error +# messages should be written. If left blank the output is written to standard +# error (stderr). WARN_LOGFILE = Doxygen.log #--------------------------------------------------------------------------- -# configuration options related to the input files +# Configuration options related to the input files #--------------------------------------------------------------------------- -# The INPUT tag can be used to specify the files and/or directories that contain -# documented source files. You may enter file names like "myfile.cpp" or -# directories like "/usr/src/myproject". Separate the files or directories -# with spaces. +# The INPUT tag is used to specify the files and/or directories that contain +# documented source files. You may enter file names like myfile.cpp or +# directories like /usr/src/myproject. Separate the files or directories with +# spaces. +# Note: If this tag is empty the current directory is searched. INPUT = . \ ../src \ ../textengines/mathml # This tag can be used to specify the character encoding of the source files -# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is -# also the default input encoding. Doxygen uses libiconv (or the iconv built -# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for -# the list of possible encodings. +# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses +# libiconv (or the iconv built into libc) for the transcoding. See the libiconv +# documentation (see: http://www.gnu.org/software/libiconv) for the list of +# possible encodings. +# The default value is: UTF-8. INPUT_ENCODING = UTF-8 # If the value of the INPUT tag contains directories, you can use the -# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp -# and *.h) to filter out the source-files in the directories. If left -# blank the following patterns are tested: -# *.c *.cc *.cxx *.cpp *.c++ *.d *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh -# *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py -# *.f90 *.f *.for *.vhd *.vhdl +# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and +# *.h) to filter out the source-files in the directories. If left blank the +# following patterns are tested:*.c, *.cc, *.cxx, *.cpp, *.c++, *.java, *.ii, +# *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp, +# *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown, +# *.md, *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf, +# *.qsf, *.as and *.js. FILE_PATTERNS = -# The RECURSIVE tag can be used to turn specify whether or not subdirectories -# should be searched for input files as well. Possible values are YES and NO. -# If left blank NO is used. +# The RECURSIVE tag can be used to specify whether or not subdirectories should +# be searched for input files as well. +# The default value is: NO. RECURSIVE = NO # The EXCLUDE tag can be used to specify files and/or directories that should be # excluded from the INPUT source files. This way you can easily exclude a # subdirectory from a directory tree whose root is specified with the INPUT tag. +# # Note that relative paths are relative to the directory from which doxygen is # run. @@ -694,14 +785,16 @@ EXCLUDE = # The EXCLUDE_SYMLINKS tag can be used to select whether or not files or # directories that are symbolic links (a Unix file system feature) are excluded # from the input. +# The default value is: NO. EXCLUDE_SYMLINKS = NO # If the value of the INPUT tag contains directories, you can use the # EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude -# certain files from those directories. Note that the wildcards are matched -# against the file with absolute path, so to exclude all test directories -# for example use the pattern */test/* +# certain files from those directories. +# +# Note that the wildcards are matched against the file with absolute path, so to +# exclude all test directories for example use the pattern */test/* EXCLUDE_PATTERNS = qwt.h @@ -710,6 +803,9 @@ EXCLUDE_PATTERNS = qwt.h # output. The symbol name can be a fully qualified name, a word, or if the # wildcard * is used, a substring. Examples: ANamespace, AClass, # AClass::ANamespace, ANamespace::*Test +# +# Note that the wildcards are matched against the file with absolute path, so to +# exclude all test directories use the pattern */test/* EXCLUDE_SYMBOLS = \ QwtMathMLDocument \ @@ -717,753 +813,1063 @@ EXCLUDE_SYMBOLS = \ QwtPainterCommand::ImageData \ QwtPainterCommand::StateData -# The EXAMPLE_PATH tag can be used to specify one or more files or -# directories that contain example code fragments that are included (see -# the \include command). +# The EXAMPLE_PATH tag can be used to specify one or more files or directories +# that contain example code fragments that are included (see the \include +# command). EXAMPLE_PATH = . # If the value of the EXAMPLE_PATH tag contains directories, you can use the -# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp -# and *.h) to filter out the source-files in the directories. If left -# blank all files are included. +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and +# *.h) to filter out the source-files in the directories. If left blank all +# files are included. EXAMPLE_PATTERNS = # If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be -# searched for input files to be used with the \include or \dontinclude -# commands irrespective of the value of the RECURSIVE tag. -# Possible values are YES and NO. If left blank NO is used. +# searched for input files to be used with the \include or \dontinclude commands +# irrespective of the value of the RECURSIVE tag. +# The default value is: NO. EXAMPLE_RECURSIVE = NO -# The IMAGE_PATH tag can be used to specify one or more files or -# directories that contain image that are included in the documentation (see -# the \image command). +# The IMAGE_PATH tag can be used to specify one or more files or directories +# that contain images that are to be included in the documentation (see the +# \image command). IMAGE_PATH = images # The INPUT_FILTER tag can be used to specify a program that doxygen should # invoke to filter for each input file. Doxygen will invoke the filter program -# by executing (via popen()) the command , where -# is the value of the INPUT_FILTER tag, and is the name of an -# input file. Doxygen will then use the output that the filter program writes -# to standard output. -# If FILTER_PATTERNS is specified, this tag will be -# ignored. +# by executing (via popen()) the command: +# +# +# +# where is the value of the INPUT_FILTER tag, and is the +# name of an input file. Doxygen will then use the output that the filter +# program writes to standard output. If FILTER_PATTERNS is specified, this tag +# will be ignored. +# +# Note that the filter must not add or remove lines; it is applied before the +# code is scanned, but not when the output code is generated. If lines are added +# or removed, the anchors will not be placed correctly. INPUT_FILTER = # The FILTER_PATTERNS tag can be used to specify filters on a per file pattern -# basis. -# Doxygen will compare the file name with each pattern and apply the -# filter if there is a match. -# The filters are a list of the form: -# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further -# info on how filters are used. If FILTER_PATTERNS is empty or if -# non of the patterns match the file name, INPUT_FILTER is applied. +# basis. Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. The filters are a list of the form: pattern=filter +# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how +# filters are used. If the FILTER_PATTERNS tag is empty or if none of the +# patterns match the file name, INPUT_FILTER is applied. FILTER_PATTERNS = # If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using -# INPUT_FILTER) will be used to filter the input files when producing source -# files to browse (i.e. when SOURCE_BROWSER is set to YES). +# INPUT_FILTER ) will also be used to filter the input files that are used for +# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES). +# The default value is: NO. FILTER_SOURCE_FILES = NO # The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file -# pattern. A pattern will override the setting for FILTER_PATTERN (if any) -# and it is also possible to disable source filtering for a specific pattern -# using *.ext= (so without naming a filter). This option only has effect when -# FILTER_SOURCE_FILES is enabled. +# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and +# it is also possible to disable source filtering for a specific pattern using +# *.ext= (so without naming a filter). +# This tag requires that the tag FILTER_SOURCE_FILES is set to YES. FILTER_SOURCE_PATTERNS = +# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that +# is part of the input, its contents will be placed on the main page +# (index.html). This can be useful if you have a project on for instance GitHub +# and want to reuse the introduction page also for the doxygen output. + +USE_MDFILE_AS_MAINPAGE = + #--------------------------------------------------------------------------- -# configuration options related to source browsing +# Configuration options related to source browsing #--------------------------------------------------------------------------- -# If the SOURCE_BROWSER tag is set to YES then a list of source files will -# be generated. Documented entities will be cross-referenced with these sources. -# Note: To get rid of all source code in the generated output, make sure also -# VERBATIM_HEADERS is set to NO. +# If the SOURCE_BROWSER tag is set to YES then a list of source files will be +# generated. Documented entities will be cross-referenced with these sources. +# +# Note: To get rid of all source code in the generated output, make sure that +# also VERBATIM_HEADERS is set to NO. +# The default value is: NO. SOURCE_BROWSER = NO -# Setting the INLINE_SOURCES tag to YES will include the body -# of functions and classes directly in the documentation. +# Setting the INLINE_SOURCES tag to YES will include the body of functions, +# classes and enums directly into the documentation. +# The default value is: NO. INLINE_SOURCES = NO -# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct -# doxygen to hide any special comment blocks from generated source code -# fragments. Normal C and C++ comments will always remain visible. +# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any +# special comment blocks from generated source code fragments. Normal C, C++ and +# Fortran comments will always remain visible. +# The default value is: YES. STRIP_CODE_COMMENTS = YES -# If the REFERENCED_BY_RELATION tag is set to YES -# then for each documented function all documented -# functions referencing it will be listed. +# If the REFERENCED_BY_RELATION tag is set to YES then for each documented +# function all documented functions referencing it will be listed. +# The default value is: NO. REFERENCED_BY_RELATION = NO -# If the REFERENCES_RELATION tag is set to YES -# then for each documented function all documented entities -# called/used by that function will be listed. +# If the REFERENCES_RELATION tag is set to YES then for each documented function +# all documented entities called/used by that function will be listed. +# The default value is: NO. REFERENCES_RELATION = NO -# If the REFERENCES_LINK_SOURCE tag is set to YES (the default) -# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from -# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will -# link to the source code. -# Otherwise they will link to the documentation. +# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set +# to YES, then the hyperlinks from functions in REFERENCES_RELATION and +# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will +# link to the documentation. +# The default value is: YES. REFERENCES_LINK_SOURCE = YES -# If the USE_HTAGS tag is set to YES then the references to source code -# will point to the HTML generated by the htags(1) tool instead of doxygen -# built-in source browser. The htags tool is part of GNU's global source -# tagging system (see http://www.gnu.org/software/global/global.html). You -# will need version 4.8.6 or higher. +# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the +# source code will show a tooltip with additional information such as prototype, +# brief description and links to the definition and documentation. Since this +# will make the HTML file larger and loading of large files a bit slower, you +# can opt to disable this feature. +# The default value is: YES. +# This tag requires that the tag SOURCE_BROWSER is set to YES. + +SOURCE_TOOLTIPS = YES + +# If the USE_HTAGS tag is set to YES then the references to source code will +# point to the HTML generated by the htags(1) tool instead of doxygen built-in +# source browser. The htags tool is part of GNU's global source tagging system +# (see http://www.gnu.org/software/global/global.html). You will need version +# 4.8.6 or higher. +# +# To use it do the following: +# - Install the latest version of global +# - Enable SOURCE_BROWSER and USE_HTAGS in the config file +# - Make sure the INPUT points to the root of the source tree +# - Run doxygen as normal +# +# Doxygen will invoke htags (and that will in turn invoke gtags), so these +# tools must be available from the command line (i.e. in the search path). +# +# The result: instead of the source browser generated by doxygen, the links to +# source code will now point to the output of htags. +# The default value is: NO. +# This tag requires that the tag SOURCE_BROWSER is set to YES. USE_HTAGS = NO -# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen -# will generate a verbatim copy of the header file for each class for -# which an include is specified. Set to NO to disable this. +# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a +# verbatim copy of the header file for each class for which an include is +# specified. Set to NO to disable this. +# See also: Section \class. +# The default value is: YES. VERBATIM_HEADERS = YES #--------------------------------------------------------------------------- -# configuration options related to the alphabetical class index +# Configuration options related to the alphabetical class index #--------------------------------------------------------------------------- -# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index -# of all compounds will be generated. Enable this if the project -# contains a lot of classes, structs, unions or interfaces. +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all +# compounds will be generated. Enable this if the project contains a lot of +# classes, structs, unions or interfaces. +# The default value is: YES. ALPHABETICAL_INDEX = YES -# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then -# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns -# in which this list will be split (can be a number in the range [1..20]) +# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in +# which the alphabetical index list will be split. +# Minimum value: 1, maximum value: 20, default value: 5. +# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. COLS_IN_ALPHA_INDEX = 5 -# In case all classes in a project start with a common prefix, all -# classes will be put under the same header in the alphabetical index. -# The IGNORE_PREFIX tag can be used to specify one or more prefixes that -# should be ignored while generating the index headers. +# In case all classes in a project start with a common prefix, all classes will +# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag +# can be used to specify a prefix (or a list of prefixes) that should be ignored +# while generating the index headers. +# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. IGNORE_PREFIX = Qwt \ Q #--------------------------------------------------------------------------- -# configuration options related to the HTML output +# Configuration options related to the HTML output #--------------------------------------------------------------------------- -# If the GENERATE_HTML tag is set to YES (the default) Doxygen will -# generate HTML output. +# If the GENERATE_HTML tag is set to YES doxygen will generate HTML output +# The default value is: YES. GENERATE_HTML = YES -# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `html' will be used as the default path. +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a +# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of +# it. +# The default directory is: html. +# This tag requires that the tag GENERATE_HTML is set to YES. HTML_OUTPUT = html -# The HTML_FILE_EXTENSION tag can be used to specify the file extension for -# each generated HTML page (for example: .htm,.php,.asp). If it is left blank -# doxygen will generate files with .html extension. +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each +# generated HTML page (for example: .htm, .php, .asp). +# The default value is: .html. +# This tag requires that the tag GENERATE_HTML is set to YES. HTML_FILE_EXTENSION = .html -# The HTML_HEADER tag can be used to specify a personal HTML header for -# each generated HTML page. If it is left blank doxygen will generate a -# standard header. Note that when using a custom header you are responsible -# for the proper inclusion of any scripts and style sheets that doxygen -# needs, which is dependent on the configuration options used. -# It is advised to generate a default header using "doxygen -w html -# header.html footer.html stylesheet.css YourConfigFile" and then modify -# that header. Note that the header is subject to change so you typically -# have to redo this when upgrading to a newer version of doxygen or when -# changing the value of configuration settings such as GENERATE_TREEVIEW! +# The HTML_HEADER tag can be used to specify a user-defined HTML header file for +# each generated HTML page. If the tag is left blank doxygen will generate a +# standard header. +# +# To get valid HTML the header file that includes any scripts and style sheets +# that doxygen needs, which is dependent on the configuration options used (e.g. +# the setting GENERATE_TREEVIEW). It is highly recommended to start with a +# default header using +# doxygen -w html new_header.html new_footer.html new_stylesheet.css +# YourConfigFile +# and then modify the file new_header.html. See also section "Doxygen usage" +# for information on how to generate the default header that doxygen normally +# uses. +# Note: The header is subject to change so you typically have to regenerate the +# default header when upgrading to a newer version of doxygen. For a description +# of the possible markers and block names see the documentation. +# This tag requires that the tag GENERATE_HTML is set to YES. HTML_HEADER = -# The HTML_FOOTER tag can be used to specify a personal HTML footer for -# each generated HTML page. If it is left blank doxygen will generate a -# standard footer. +# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each +# generated HTML page. If the tag is left blank doxygen will generate a standard +# footer. See HTML_HEADER for more information on how to generate a default +# footer and what special commands can be used inside the footer. See also +# section "Doxygen usage" for information on how to generate the default footer +# that doxygen normally uses. +# This tag requires that the tag GENERATE_HTML is set to YES. HTML_FOOTER = -# The HTML_STYLESHEET tag can be used to specify a user-defined cascading -# style sheet that is used by each HTML page. It can be used to -# fine-tune the look of the HTML output. If the tag is left blank doxygen -# will generate a default style sheet. Note that doxygen will try to copy -# the style sheet file to the HTML output directory, so don't put your own -# style sheet in the HTML output directory as well, or it will be erased! +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style +# sheet that is used by each HTML page. It can be used to fine-tune the look of +# the HTML output. If left blank doxygen will generate a default style sheet. +# See also section "Doxygen usage" for information on how to generate the style +# sheet that doxygen normally uses. +# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as +# it is more robust and this tag (HTML_STYLESHEET) will in the future become +# obsolete. +# This tag requires that the tag GENERATE_HTML is set to YES. HTML_STYLESHEET = +# The HTML_EXTRA_STYLESHEET tag can be used to specify an additional user- +# defined cascading style sheet that is included after the standard style sheets +# created by doxygen. Using this option one can overrule certain style aspects. +# This is preferred over using HTML_STYLESHEET since it does not replace the +# standard style sheet and is therefor more robust against future updates. +# Doxygen will copy the style sheet file to the output directory. For an example +# see the documentation. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_EXTRA_STYLESHEET = + # The HTML_EXTRA_FILES tag can be used to specify one or more extra images or # other source files which should be copied to the HTML output directory. Note # that these files will be copied to the base HTML output directory. Use the -# $relpath$ marker in the HTML_HEADER and/or HTML_FOOTER files to load these -# files. In the HTML_STYLESHEET file, use the file name only. Also note that -# the files will be copied as-is; there are no commands or markers available. +# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these +# files. In the HTML_STYLESHEET file, use the file name only. Also note that the +# files will be copied as-is; there are no commands or markers available. +# This tag requires that the tag GENERATE_HTML is set to YES. HTML_EXTRA_FILES = -# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. -# Doxygen will adjust the colors in the style sheet and background images -# according to this color. Hue is specified as an angle on a colorwheel, -# see http://en.wikipedia.org/wiki/Hue for more information. -# For instance the value 0 represents red, 60 is yellow, 120 is green, -# 180 is cyan, 240 is blue, 300 purple, and 360 is red again. -# The allowed range is 0 to 359. +# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen +# will adjust the colors in the stylesheet and background images according to +# this color. Hue is specified as an angle on a colorwheel, see +# http://en.wikipedia.org/wiki/Hue for more information. For instance the value +# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300 +# purple, and 360 is red again. +# Minimum value: 0, maximum value: 359, default value: 220. +# This tag requires that the tag GENERATE_HTML is set to YES. HTML_COLORSTYLE_HUE = 220 -# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of -# the colors in the HTML output. For a value of 0 the output will use -# grayscales only. A value of 255 will produce the most vivid colors. +# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors +# in the HTML output. For a value of 0 the output will use grayscales only. A +# value of 255 will produce the most vivid colors. +# Minimum value: 0, maximum value: 255, default value: 100. +# This tag requires that the tag GENERATE_HTML is set to YES. HTML_COLORSTYLE_SAT = 100 -# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to -# the luminance component of the colors in the HTML output. Values below -# 100 gradually make the output lighter, whereas values above 100 make -# the output darker. The value divided by 100 is the actual gamma applied, -# so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2, -# and 100 does not change the gamma. +# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the +# luminance component of the colors in the HTML output. Values below 100 +# gradually make the output lighter, whereas values above 100 make the output +# darker. The value divided by 100 is the actual gamma applied, so 80 represents +# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not +# change the gamma. +# Minimum value: 40, maximum value: 240, default value: 80. +# This tag requires that the tag GENERATE_HTML is set to YES. HTML_COLORSTYLE_GAMMA = 80 # If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML -# page will contain the date and time when the page was generated. Setting -# this to NO can help when comparing the output of multiple runs. +# page will contain the date and time when the page was generated. Setting this +# to NO can help when comparing the output of multiple runs. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. HTML_TIMESTAMP = NO # If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML # documentation will contain sections that can be hidden and shown after the # page has loaded. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. HTML_DYNAMIC_SECTIONS = NO -# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of -# entries shown in the various tree structured indices initially; the user -# can expand and collapse entries dynamically later on. Doxygen will expand -# the tree to such a level that at most the specified number of entries are -# visible (unless a fully collapsed tree already exceeds this amount). -# So setting the number of entries 1 will produce a full collapsed tree by -# default. 0 is a special value representing an infinite number of entries -# and will result in a full expanded tree by default. +# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries +# shown in the various tree structured indices initially; the user can expand +# and collapse entries dynamically later on. Doxygen will expand the tree to +# such a level that at most the specified number of entries are visible (unless +# a fully collapsed tree already exceeds this amount). So setting the number of +# entries 1 will produce a full collapsed tree by default. 0 is a special value +# representing an infinite number of entries and will result in a full expanded +# tree by default. +# Minimum value: 0, maximum value: 9999, default value: 100. +# This tag requires that the tag GENERATE_HTML is set to YES. HTML_INDEX_NUM_ENTRIES = 100 -# If the GENERATE_DOCSET tag is set to YES, additional index files -# will be generated that can be used as input for Apple's Xcode 3 -# integrated development environment, introduced with OSX 10.5 (Leopard). -# To create a documentation set, doxygen will generate a Makefile in the -# HTML output directory. Running make will produce the docset in that -# directory and running "make install" will install the docset in -# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find -# it at startup. -# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html +# If the GENERATE_DOCSET tag is set to YES, additional index files will be +# generated that can be used as input for Apple's Xcode 3 integrated development +# environment (see: http://developer.apple.com/tools/xcode/), introduced with +# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a +# Makefile in the HTML output directory. Running make will produce the docset in +# that directory and running make install will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at +# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html # for more information. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_DOCSET = NO -# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the -# feed. A documentation feed provides an umbrella under which multiple -# documentation sets from a single provider (such as a company or product suite) -# can be grouped. +# This tag determines the name of the docset feed. A documentation feed provides +# an umbrella under which multiple documentation sets from a single provider +# (such as a company or product suite) can be grouped. +# The default value is: Doxygen generated docs. +# This tag requires that the tag GENERATE_DOCSET is set to YES. DOCSET_FEEDNAME = "Doxygen generated docs" -# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that -# should uniquely identify the documentation set bundle. This should be a -# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen -# will append .docset to the name. +# This tag specifies a string that should uniquely identify the documentation +# set bundle. This should be a reverse domain-name style string, e.g. +# com.mycompany.MyDocSet. Doxygen will append .docset to the name. +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_DOCSET is set to YES. DOCSET_BUNDLE_ID = org.doxygen.Project -# When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely identify +# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify # the documentation publisher. This should be a reverse domain-name style # string, e.g. com.mycompany.MyDocSet.documentation. +# The default value is: org.doxygen.Publisher. +# This tag requires that the tag GENERATE_DOCSET is set to YES. DOCSET_PUBLISHER_ID = org.doxygen.Publisher -# The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher. +# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher. +# The default value is: Publisher. +# This tag requires that the tag GENERATE_DOCSET is set to YES. DOCSET_PUBLISHER_NAME = Publisher -# If the GENERATE_HTMLHELP tag is set to YES, additional index files -# will be generated that can be used as input for tools like the -# Microsoft HTML help workshop to generate a compiled HTML help file (.chm) -# of the generated HTML documentation. +# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three +# additional HTML index files: index.hhp, index.hhc, and index.hhk. The +# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop +# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on +# Windows. +# +# The HTML Help Workshop contains a compiler that can convert all HTML output +# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML +# files are now used as the Windows 98 help format, and will replace the old +# Windows help format (.hlp) on all Windows platforms in the future. Compressed +# HTML files also contain an index, a table of contents, and you can search for +# words in the documentation. The HTML workshop also contains a viewer for +# compressed HTML files. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_HTMLHELP = NO -# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can -# be used to specify the file name of the resulting .chm file. You -# can add a path in front of the file if the result should not be +# The CHM_FILE tag can be used to specify the file name of the resulting .chm +# file. You can add a path in front of the file if the result should not be # written to the html output directory. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. CHM_FILE = -# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can -# be used to specify the location (absolute path including file name) of -# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run -# the HTML help compiler on the generated index.hhp. +# The HHC_LOCATION tag can be used to specify the location (absolute path +# including file name) of the HTML help compiler ( hhc.exe). If non-empty +# doxygen will try to run the HTML help compiler on the generated index.hhp. +# The file has to be specified with full path. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. HHC_LOCATION = -# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag -# controls if a separate .chi index file is generated (YES) or that -# it should be included in the master .chm file (NO). +# The GENERATE_CHI flag controls if a separate .chi index file is generated ( +# YES) or that it should be included in the master .chm file ( NO). +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. GENERATE_CHI = NO -# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING -# is used to encode HtmlHelp index (hhk), content (hhc) and project file -# content. +# The CHM_INDEX_ENCODING is used to encode HtmlHelp index ( hhk), content ( hhc) +# and project file content. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. CHM_INDEX_ENCODING = -# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag -# controls whether a binary table of contents is generated (YES) or a -# normal table of contents (NO) in the .chm file. +# The BINARY_TOC flag controls whether a binary table of contents is generated ( +# YES) or a normal table of contents ( NO) in the .chm file. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. BINARY_TOC = NO -# The TOC_EXPAND flag can be set to YES to add extra items for group members -# to the contents of the HTML help documentation and to the tree view. +# The TOC_EXPAND flag can be set to YES to add extra items for group members to +# the table of contents of the HTML help documentation and to the tree view. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. TOC_EXPAND = NO # If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and -# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated -# that can be used as input for Qt's qhelpgenerator to generate a -# Qt Compressed Help (.qch) of the generated HTML documentation. +# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that +# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help +# (.qch) of the generated HTML documentation. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_QHP = NO -# If the QHG_LOCATION tag is specified, the QCH_FILE tag can -# be used to specify the file name of the resulting .qch file. -# The path specified is relative to the HTML output folder. +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify +# the file name of the resulting .qch file. The path specified is relative to +# the HTML output folder. +# This tag requires that the tag GENERATE_QHP is set to YES. QCH_FILE = qwtdoc.qch -# The QHP_NAMESPACE tag specifies the namespace to use when generating -# Qt Help Project output. For more information please see -# http://doc.trolltech.com/qthelpproject.html#namespace +# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help +# Project output. For more information please see Qt Help Project / Namespace +# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace). +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_QHP is set to YES. QHP_NAMESPACE = net.sourceforge.qwt-svn -# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating -# Qt Help Project output. For more information please see -# http://doc.trolltech.com/qthelpproject.html#virtual-folders +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt +# Help Project output. For more information please see Qt Help Project / Virtual +# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual- +# folders). +# The default value is: doc. +# This tag requires that the tag GENERATE_QHP is set to YES. QHP_VIRTUAL_FOLDER = qwt-svn -# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to -# add. For more information please see -# http://doc.trolltech.com/qthelpproject.html#custom-filters +# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom +# filter to add. For more information please see Qt Help Project / Custom +# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- +# filters). +# This tag requires that the tag GENERATE_QHP is set to YES. QHP_CUST_FILTER_NAME = -# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the -# custom filter to add. For more information please see -# -# Qt Help Project / Custom Filters. +# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the +# custom filter to add. For more information please see Qt Help Project / Custom +# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- +# filters). +# This tag requires that the tag GENERATE_QHP is set to YES. QHP_CUST_FILTER_ATTRS = # The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this -# project's -# filter section matches. -# -# Qt Help Project / Filter Attributes. +# project's filter section matches. Qt Help Project / Filter Attributes (see: +# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes). +# This tag requires that the tag GENERATE_QHP is set to YES. QHP_SECT_FILTER_ATTRS = -# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can -# be used to specify the location of Qt's qhelpgenerator. -# If non-empty doxygen will try to run qhelpgenerator on the generated -# .qhp file. +# The QHG_LOCATION tag can be used to specify the location of Qt's +# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the +# generated .qhp file. +# This tag requires that the tag GENERATE_QHP is set to YES. QHG_LOCATION = qhelpgenerator -# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files -# will be generated, which together with the HTML files, form an Eclipse help -# plugin. To install this plugin and make it available under the help contents -# menu in Eclipse, the contents of the directory containing the HTML and XML -# files needs to be copied into the plugins directory of eclipse. The name of -# the directory within the plugins directory should be the same as -# the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before -# the help appears. +# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be +# generated, together with the HTML files, they form an Eclipse help plugin. To +# install this plugin and make it available under the help contents menu in +# Eclipse, the contents of the directory containing the HTML and XML files needs +# to be copied into the plugins directory of eclipse. The name of the directory +# within the plugins directory should be the same as the ECLIPSE_DOC_ID value. +# After copying Eclipse needs to be restarted before the help appears. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_ECLIPSEHELP = NO -# A unique identifier for the eclipse help plugin. When installing the plugin -# the directory name containing the HTML and XML files should also have -# this name. +# A unique identifier for the Eclipse help plugin. When installing the plugin +# the directory name containing the HTML and XML files should also have this +# name. Each documentation set should have its own identifier. +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES. ECLIPSE_DOC_ID = org.doxygen.Project -# The DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) -# at top of each HTML page. The value NO (the default) enables the index and -# the value YES disables it. Since the tabs have the same information as the -# navigation tree you can set this option to NO if you already set -# GENERATE_TREEVIEW to YES. +# If you want full control over the layout of the generated HTML pages it might +# be necessary to disable the index and replace it with your own. The +# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top +# of each HTML page. A value of NO enables the index and the value YES disables +# it. Since the tabs in the index contain the same information as the navigation +# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. DISABLE_INDEX = NO # The GENERATE_TREEVIEW tag is used to specify whether a tree-like index -# structure should be generated to display hierarchical information. -# If the tag value is set to YES, a side panel will be generated -# containing a tree-like index structure (just like the one that -# is generated for HTML Help). For this to work a browser that supports -# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser). -# Windows users are probably better off using the HTML help feature. -# Since the tree basically has the same information as the tab index you -# could consider to set DISABLE_INDEX to NO when enabling this option. - -GENERATE_TREEVIEW = NO - -# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values -# (range [0,1..20]) that doxygen will group on one line in the generated HTML -# documentation. Note that a value of 0 will completely suppress the enum -# values from appearing in the overview section. +# structure should be generated to display hierarchical information. If the tag +# value is set to YES, a side panel will be generated containing a tree-like +# index structure (just like the one that is generated for HTML Help). For this +# to work a browser that supports JavaScript, DHTML, CSS and frames is required +# (i.e. any modern browser). Windows users are probably better off using the +# HTML help feature. Via custom stylesheets (see HTML_EXTRA_STYLESHEET) one can +# further fine-tune the look of the index. As an example, the default style +# sheet generated by doxygen has an example that shows how to put an image at +# the root of the tree instead of the PROJECT_NAME. Since the tree basically has +# the same information as the tab index, you could consider setting +# DISABLE_INDEX to YES when enabling this option. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_TREEVIEW = YES + +# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that +# doxygen will group on one line in the generated HTML documentation. +# +# Note that a value of 0 will completely suppress the enum values from appearing +# in the overview section. +# Minimum value: 0, maximum value: 20, default value: 4. +# This tag requires that the tag GENERATE_HTML is set to YES. ENUM_VALUES_PER_LINE = 4 -# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be -# used to set the initial width (in pixels) of the frame in which the tree -# is shown. +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used +# to set the initial width (in pixels) of the frame in which the tree is shown. +# Minimum value: 0, maximum value: 1500, default value: 250. +# This tag requires that the tag GENERATE_HTML is set to YES. TREEVIEW_WIDTH = 250 -# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open -# links to external symbols imported via tag files in a separate window. +# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open links to +# external symbols imported via tag files in a separate window. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. EXT_LINKS_IN_WINDOW = NO -# Use this tag to change the font size of Latex formulas included -# as images in the HTML documentation. The default is 10. Note that -# when you change the font size after a successful doxygen run you need -# to manually remove any form_*.png images from the HTML output directory -# to force them to be regenerated. +# Use this tag to change the font size of LaTeX formulas included as images in +# the HTML documentation. When you change the font size after a successful +# doxygen run you need to manually remove any form_*.png images from the HTML +# output directory to force them to be regenerated. +# Minimum value: 8, maximum value: 50, default value: 10. +# This tag requires that the tag GENERATE_HTML is set to YES. FORMULA_FONTSIZE = 10 # Use the FORMULA_TRANPARENT tag to determine whether or not the images -# generated for formulas are transparent PNGs. Transparent PNGs are -# not supported properly for IE 6.0, but are supported on all modern browsers. -# Note that when changing this option you need to delete any form_*.png files -# in the HTML output before the changes have effect. +# generated for formulas are transparent PNGs. Transparent PNGs are not +# supported properly for IE 6.0, but are supported on all modern browsers. +# +# Note that when changing this option you need to delete any form_*.png files in +# the HTML output directory before the changes have effect. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. FORMULA_TRANSPARENT = YES -# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax -# (see http://www.mathjax.org) which uses client side Javascript for the -# rendering instead of using prerendered bitmaps. Use this if you do not -# have LaTeX installed or if you want to formulas look prettier in the HTML -# output. When enabled you may also need to install MathJax separately and -# configure the path to it using the MATHJAX_RELPATH option. +# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see +# http://www.mathjax.org) which uses client side Javascript for the rendering +# instead of using prerendered bitmaps. Use this if you do not have LaTeX +# installed or if you want to formulas look prettier in the HTML output. When +# enabled you may also need to install MathJax separately and configure the path +# to it using the MATHJAX_RELPATH option. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. USE_MATHJAX = NO -# When MathJax is enabled you need to specify the location relative to the -# HTML output directory using the MATHJAX_RELPATH option. The destination -# directory should contain the MathJax.js script. For instance, if the mathjax -# directory is located at the same level as the HTML output directory, then -# MATHJAX_RELPATH should be ../mathjax. The default value points to -# the MathJax Content Delivery Network so you can quickly see the result without -# installing MathJax. -# However, it is strongly recommended to install a local -# copy of MathJax from http://www.mathjax.org before deployment. +# When MathJax is enabled you can set the default output format to be used for +# the MathJax output. See the MathJax site (see: +# http://docs.mathjax.org/en/latest/output.html) for more details. +# Possible values are: HTML-CSS (which is slower, but has the best +# compatibility), NativeMML (i.e. MathML) and SVG. +# The default value is: HTML-CSS. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_FORMAT = HTML-CSS + +# When MathJax is enabled you need to specify the location relative to the HTML +# output directory using the MATHJAX_RELPATH option. The destination directory +# should contain the MathJax.js script. For instance, if the mathjax directory +# is located at the same level as the HTML output directory, then +# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax +# Content Delivery Network so you can quickly see the result without installing +# MathJax. However, it is strongly recommended to install a local copy of +# MathJax from http://www.mathjax.org before deployment. +# The default value is: http://cdn.mathjax.org/mathjax/latest. +# This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest -# The MATHJAX_EXTENSIONS tag can be used to specify one or MathJax extension -# names that should be enabled during MathJax rendering. +# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax +# extension names that should be enabled during MathJax rendering. For example +# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols +# This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_EXTENSIONS = -# When the SEARCHENGINE tag is enabled doxygen will generate a search box -# for the HTML output. The underlying search engine uses javascript -# and DHTML and should work on any modern browser. Note that when using -# HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets -# (GENERATE_DOCSET) there is already a search function so this one should -# typically be disabled. For large projects the javascript based search engine -# can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution. +# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces +# of code that will be used on startup of the MathJax code. See the MathJax site +# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an +# example see the documentation. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_CODEFILE = + +# When the SEARCHENGINE tag is enabled doxygen will generate a search box for +# the HTML output. The underlying search engine uses javascript and DHTML and +# should work on any modern browser. Note that when using HTML help +# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET) +# there is already a search function so this one should typically be disabled. +# For large projects the javascript based search engine can be slow, then +# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to +# search using the keyboard; to jump to the search box use + S +# (what the is depends on the OS and browser, but it is typically +# , /