Image reprojection - projection

I have a GridCoverage2D in EPSG:4054. I want to transform it to EPSG:4326.
I have tried to do it this way:
/** gc2d is an GridCoverage2D in EPSG:4054 */
CoordinateReferenceSystem targetCRS = crsAuthorityFactory.createCoordinateReferenceSystem("EPSG:4326");
GridCoverage2D gc2d_projected_2 = Resample(gc2d, targetCRS);
where Resample function is:
public static GridCoverage2D Resample(GridCoverage2D input, CoordinateReferenceSystem targetCRS) throws FactoryException {
final CoverageProcessor processor = CoverageProcessor.getInstance(null);
final ParameterValueGroup param=processor.getOperation("Resample").getParameters();
param.parameter("Source").setValue(input);
param.parameter("CoordinateReferenceSystem").setValue(targetCRS);
param.parameter("InterpolationType").setValue("bilinear");
return (GridCoverage2D) processor.doOperation(param);
}
Here I get "Bursa wolf parameters required" error. I think that's because EPSG:4054 and EPSG:4326 are based on the different ellipsoids (Hughes 1980 and WGS84).
What is the proper way to do this?

Related

OptaPlanner: How to read game armor data from JSON and find optimal set of armor based on weight + stats?

Elden Ring is a hit game that has some interesting theorycrafting behind it.
There are hundreds of armor pieces, weapons, and spells. Finding optimal combinations of them based on player & item stats is an interesting practical problem.
I've always wanted to learn how to use Constraint Solvers and it seems a good usecase exists!
Goal:
Given a list of all armor in the game in JSON format
Find the set of armor (head, chest, legs, arms) that has:
The highest POISE and PHYSICAL_DEFENSE
For the lowest WEIGHT
Here is the repo:
https://github.com/GavinRay97/elden-ring-optimizer-optaplanner
My attempt so far:
Put the armor data here
Created data class that matches JSON
Created #PlanningEntity class for a combination of armor
Created #PlanningSolution class (not sure if this is correct)
Tried to write Solver, doesn't work
Update
I managed to solve it after advice below
The trick was to change to use PlanningEntityProperty:
#PlanningSolution
public class ArmorSetComboPlanningSolution {
public List<ArmorPiece> armorPieces;
public Map<Integer, List<ArmorPiece>> armorByType;
#ValueRangeProvider(id = "headRange")
#ProblemFactCollectionProperty
public List<ArmorPiece> headList;
#ValueRangeProvider(id = "chestRange")
#ProblemFactCollectionProperty
public List<ArmorPiece> chestList;
#ValueRangeProvider(id = "armsRange")
#ProblemFactCollectionProperty
public List<ArmorPiece> armsList;
#ValueRangeProvider(id = "legsRange")
#ProblemFactCollectionProperty
public List<ArmorPiece> legsList;
#PlanningEntityProperty
public ArmorSet armorSet;
#PlanningScore(bendableHardLevelsSize = 1, bendableSoftLevelsSize = 5)
BendableLongScore score;
ArmorSetComboPlanningSolution() {
}
ArmorSetComboPlanningSolution(List<ArmorPiece> armorPieces) {
this.armorPieces = armorPieces;
this.armorByType = armorPieces.stream().collect(groupingBy(ArmorPiece::armorCategoryID));
this.headList = armorByType.get(0);
this.chestList = armorByType.get(1);
this.armsList = armorByType.get(2);
this.legsList = armorByType.get(3);
// Need to initialize a starting value
this.armorSet = new ArmorSet(0L, this.headList.get(0), this.chestList.get(0), this.armsList.get(0), this.legsList.get(0));
}
}
Then the scorer:
public class ArmorSetEasyOptimizer implements EasyScoreCalculator<ArmorSetComboPlanningSolution, BendableLongScore> {
private final int TARGE_POISE = 61;
private final double MAX_WEIGHT = 60.64;
public ArmorSetEasyOptimizer() {
}
#Override
public BendableLongScore calculateScore(ArmorSetComboPlanningSolution solution) {
long hardScore = 0L;
ArmorSet armorSet = solution.armorSet;
if (armorSet.getTotalPoise() < TARGE_POISE) {
hardScore--;
}
if (armorSet.getTotalWeight() > MAX_WEIGHT) {
hardScore--;
}
long poiseRatio = (long) (armorSet.getTotalPoise() / (double) armorSet.getTotalWeight() * 100);
long physicalDefenseScaled = (long) (armorSet.getTotalPhysicalDefense() * 100);
long physicalDefenseToWeightRatio = (long) (physicalDefenseScaled / armorSet.getTotalWeight());
long magicDefenseScaled = (long) (armorSet.getTotalMagicDefense() * 100);
long magicDefenseToWeightRatio = (long) (magicDefenseScaled / armorSet.getTotalWeight());
return BendableLongScore.of(
new long[]{
hardScore
},
new long[]{
poiseRatio,
physicalDefenseScaled,
physicalDefenseToWeightRatio,
magicDefenseScaled,
magicDefenseToWeightRatio
}
);
}
}
Results
19:02:12.707 [main] INFO org.optaplanner.core.impl.localsearch.DefaultLocalSearchPhase - Local Search phase (1) ended: time spent (10000), best score ([0]hard/[179/3540/97/2750/75]soft), score calculation speed (987500/sec), step total (4046).
19:02:12.709 [main] INFO org.optaplanner.core.impl.solver.DefaultSolver - Solving ended: time spent (10000), best score ([0]hard/[179/3540/97/2750/75]soft), score calculation speed (985624/sec), phase total (2), environment mode (REPRODUCIBLE), move thread count (NONE).
[0]hard/[179/3540/97/2750/75]soft
ArmorSet (Weight: 36.3, Poise: 65, Physical: 35.4, Phys/Weight: 0.97, Magic: 27.5, Magic/Weight: 0.75 ) [
head: Radahn Soldier Helm (Weight: 4.0, Poise: 5),
chest: Veteran's Armor (Weight: 18.9, Poise: 37),
arms: Godskin Noble Bracelets (Weight: 1.7, Poise: 1),
legs: Veteran's Greaves (Weight: 11.7, Poise: 22)
]
This is a bit of a strange problem, because you only need one planning entity instance. There only ever needs to be one ArmorSet object - and the solver will be assigning different armor pieces as it comes closer and closer to an optimal combination.
Therefore your easy score calculator doesn't ever need to do any looping. It simply takes the single ArmorSet's weight and poise and creates a score out of it.
However, even though I think that this use case may be useful as a learning path towards constraint solvers, some sort of a brute force algorithm could work as well - your data set isn't too large. More importantly, with an exhaustive algorithm such as brute force, you're eventually guaranteed to reach the optimal solution.
(That said, if you want to enhance the problem with matching these armor sets to particular character traits, then it perhaps may be complex enough for brute force to become inadequate.)
On a personal note, I attempted Elden Ring and found it too hardcore for me. :-) I prefer games that guide you a bit more.

How to use MDX constants/functions in icCube Reporting?

I have several functions/constants defined in the schema. An example is:
_latestPeriodWithData() which returns a date.
Goal: I want to use this value in the Reporting to set a Guide in a chart, using the demo example 'On Widget Options':
This is what I tried so far:
I have assigned this function as 'MDX / Value' for a Report Constant _lastDate and obtained the value for this constant using the java script function: context.eventValue('_lastDate'); but that just gives me the caption. The function context.eventObject("_lastDate").options.asMdx gives me _latestPeriodWithData(), but not its value.
On Widget Options
/**
* Result will be used while rendering.
*/
function(context, options, $box) {
// for debugging purpose
console.log(context.eventObject("_lastDate").options.asMdx);
options.guides[0].value = context.eventObject("_lastDate").options.asMdx; // <-- gives me _latestPeriodeWith data
// but not its value
options.guides[0].toValue = context.eventObject("_lastDate").options.asMdx;
options.guides[0].lineAlpha = 1;
options.guides[0].lineColor = "#c44";
return options;
}

How is the field SourceBaseAmountCur from TmpTaxWorkTrans table computed?

I need to find how is the SourceBaseAmountCur being computed, in my case I am getting an error in Amount Origin on the SST window where it doesn't show 0 when it needs to be.
I am coming from General Ledger > Journals > General Journal > (select a record, going to Lines) > then SST window. Then, the Amount Origin field.
The Amount Origin is a display field:
display TaxBaseCur displaySourceBaseAmountCur(TmpTaxWorkTrans _tmpTaxWorkTrans)
{
return taxTmpWorkTransForm.getSourceBaseAmountCur(_tmpTaxWorkTrans);
}
As seen on the code above, it already passes a TmpTaxWorkTrans record. Going to that method on the class TaxTmpWorkTransForm this is the method:
public TaxAmountCur getSourceBaseAmountCur(TmpTaxWorkTrans _tmpTaxWorkTrans = null, TmpTaxRegulation _tmpTaxRegulation = null)
{
if (_tmpTaxRegulation)
{
return _tmpTaxRegulation.SourceBaseAmountCur;
}
else
{
return _tmpTaxWorkTrans.SourceBaseAmountCur * _tmpTaxWorkTrans.taxChangeDisplaySign(accountTypeMap);
}
}
I found this article: https://dynamicsuser.net/ax/f/technical/92855/how-tmptaxworktrans-populated
and I started from there Class\Tax\insertIntersection and unfortunately I couldn't find what I was looking for, been debugging for days.
An important distinction is tax calculation for a posted vs non-posted journal. It appears you are looking at non-posted journals.
I don't have great data to test this with, but I just hacked this POC job together in 20 minutes, but it should have enough "bits" that you can run with it and get the information you need.
static void Job3(Args _args)
{
TaxCalculation taxCalculation;
LedgerJournalTrans ledgerJournalTrans;
TmpTaxWorkTrans tmpTaxWorkTrans;
TaxAmountCur taxAmountCur;
ledgerJournalTrans = LedgerJournalTrans::findRecId(5637293082, false); // Use your own journal line
// The reason we call the below stuff is `element.getShowTax()` and is called from `\Forms\LedgerJournalTransDaily\Designs\Design\[ActionPane:ActionPane]\[ActionPaneTab:ActionPaneTab]\[ButtonGroup:ButtonGroup]\MenuItemButton:TaxTransSource\Methods\clicked`
// This is from `\Classes\LedgerJournalEngine\getShowTax`
taxCalculation = LedgerJournalTrans::getTaxInstance(ledgerJournalTrans.JournalNum, ledgerJournalTrans.Voucher, ledgerJournalTrans.Invoice, true, null, false, ledgerJournalTrans.TransDate);
taxCalculation.sourceSingleLine(true, false);
// This is from `\Classes\TaxTmpWorkTransForm\initTax`
tmpTaxWorkTrans.setTmpData(taxCalculation.tmpTaxWorkTrans());
// This is the temporary table that is populated
while select tmpTaxWorkTrans
{
// This is from `\Classes\TaxTmpWorkTransForm\getSourceBaseAmountCur`
taxAmountCur = (tmpTaxWorkTrans.SourceTaxAmountCur * tmpTaxWorkTrans.taxChangeDisplaySign(null)); // I pass null because the map doesn't appear used...investigate?
// This just outputs some data
info(strFmt("%1: %2", tmpTaxWorkTrans.TaxCode, taxAmountCur));
}
}

How to fix Adobe Flex simple multiplication error

We are using version 3.6. We call a rounding function to clean up the decimal part. Something like this...
private function ceilingRounding(value:Number, power:Number):Number
{
var scale:Number = Math.pow(10, power);
return (Math.ceil(value * scale) / scale);
}
The function result is unexpected for the following values:
value = 76.7549, scale = 10000.
The result should be 76.7549 but we get 76.7550
Using the debugger, we see that value * scale = 767549.0000000001. Of course this would be rounded up to 76.7550, but why are we getting .0000000001 and how can we fix this?
The "NUMBERS" values ​​hold this approximation operation, you can modify your function and add the following into operation, plus I let the function that I use regularly to do the rounding.
public static function roundToPrecision(numberVal:Number, precision:int = 0):Number
{
var decimalPlaces:Number = Math.pow(10, precision);
return Math.round(decimalPlaces * numberVal) / decimalPlaces;
}
If you need Fixed decimal Number try
var myNum:Number = 1.123556789
myNum.toFixed(3);
trace(myNum); // 1.123
If you need Precision decimal Number try
myNum.toPrecision(3);
trace(myNum); // 1.124;
For more options see rounding in link.
Reference NumberFormatter

How do I get the visual width and height of a rotated component?

I'm playing around with code like this:
<s:Button id="test" label="test" transformX="{Math.floor(test.width/2)}" rotationY="20" x="20" y="20" />
The button is rotated on the Y axis and the rotate pivot is in the middle of the button.
This will create a button that looks something like this:
(source: jeffryhouser.com)
The rotated button is, visually, filling a different space than the x, y, height, and width values would you have believe.
The "A" value in my image is the height of the button. But, what I want to use for calculation and placement purposes is the B value.
Additionally, I'd like to perform similar calculations with the width; getting the width from the top right corner to the bottom left corner.
How do I do this?
I put together a sample to show off the various approaches for calculating this that people are suggesting. The source code is also available. Nothing is quite working like I'd expect. For example, turn the rotationSlider to 85. The button is effectively invisible, yet all approaches are still giving it height and width.
My math may be a bit rusty, but this is how I would find the answer :
You would extend a right-triangle from the right edge of the button to the bottom-most point of the diagram you have (A-B). You can then use the Law of Sines to get three angles : 90', 20' and 70' (90 will always be there, and then your variable - 180 for the third angle).
You can then use the following formula to find your answer :
B = ((button.width * sin(button.rotationY)) / (sin(90 -button.rotationY)) + (button.height)
getBounds(..) and getRect(..) are supposed to be the methods for getting the width and height of transformed objects.
Not tried them in Flex 4 yet, but they always worked for me in Flex 3.
The answer was in one of the comments from James Ward on this question and is located at this blog post.
The one thing the blog post doesn't say is that in many cases, the perspectiveProjection property of the transform property on the class in question will be null. The linked to example took care of this by setting the maintainProjectionCenter property to true. But, you could also create a new perspectiveProjection object like this:
object.transform.perspectiveProjection = new PerspectiveProjection();
I wrapped up the function from evtimmy into a class:
/**
* DotComIt/Flextras
* Utils3D.as
* Utils3D
* jhouser
* Aug 5, 2010
*/
package com.flextras.coverflow
{
import flash.geom.Matrix3D;
import flash.geom.PerspectiveProjection;
import flash.geom.Rectangle;
import flash.geom.Utils3D;
import flash.geom.Vector3D;
public class TransformUtilities
{
public function TransformUtilities()
{
}
//--------------------------------------------------------------------------
//
// Methods
//
//--------------------------------------------------------------------------
//----------------------------------
// projectBounds
//----------------------------------
// info from
// http://evtimmy.com/2009/12/calculating-the-projected-bounds-using-utils3dprojectvector/
/**
* Method retrieved from
* http://evtimmy.com/2009/12/calculating-the-projected-bounds-using-utils3dprojectvector/
*
* #param bounds: The rectangle that makes up the object
* #param matrix The 3D Matrix of the item
* #param the projection of the item's parent.
*/
public static function projectBounds(bounds:Rectangle,
matrix:Matrix3D,
projection:PerspectiveProjection):Rectangle
{
// Setup the matrix
var centerX:Number = projection.projectionCenter.x;
var centerY:Number = projection.projectionCenter.y;
matrix.appendTranslation(-centerX, -centerY, projection.focalLength);
matrix.append(projection.toMatrix3D());
// Project the corner points
var pt1:Vector3D = new Vector3D(bounds.left, bounds.top, 0);
var pt2:Vector3D = new Vector3D(bounds.right, bounds.top, 0)
var pt3:Vector3D = new Vector3D(bounds.left, bounds.bottom, 0);
var pt4:Vector3D = new Vector3D(bounds.right, bounds.bottom, 0);
pt1 = Utils3D.projectVector(matrix, pt1);
pt2 = Utils3D.projectVector(matrix, pt2);
pt3 = Utils3D.projectVector(matrix, pt3);
pt4 = Utils3D.projectVector(matrix, pt4);
// Find the bounding box in 2D
var maxX:Number = Math.max(Math.max(pt1.x, pt2.x), Math.max(pt3.x, pt4.x));
var minX:Number = Math.min(Math.min(pt1.x, pt2.x), Math.min(pt3.x, pt4.x));
var maxY:Number = Math.max(Math.max(pt1.y, pt2.y), Math.max(pt3.y, pt4.y));
var minY:Number = Math.min(Math.min(pt1.y, pt2.y), Math.min(pt3.y, pt4.y));
// Add back the projection center
bounds.x = minX + centerX;
bounds.y = minY + centerY;
bounds.width = maxX - minX;
bounds.height = maxY - minY;
return bounds;
}
}
}
Although that is the answer to my question, I'm not sure if it was the solution to my problem. Thanks everyone!

Resources