Destructuring records into custom variable names - elm

Consider this function:
mix : Color -> Color -> Color
mix c1 c2 =
let
{ red, green, blue, alpha } = toRgb c1
{ red, green, blue, alpha } = toRgb c2
in
...
The above won't work because it's introducing duplicate variable names. Is it possible to destructure the above values into r1, r2, g1, g2, etc?
For clarification, toRgb has this signature:
toRgb : Color -> { red:Int, green:Int, blue:Int, alpha:Float }
A hypothetical syntax might express better what I'd like to do:
mix : Color -> Color -> Color
mix c1 c2 =
let
{ red as r1, green as g1, blue as b1, alpha as a1 } = toRgb c1
{ red as r2, green as g2, blue as b2, alpha as a2 } = toRgb c2
in
...

I had trouble figuring out if this was possible and realized that field accessors are so powerful that it didn't matter.
Presumably your code might look something like:
mix : Color -> Color -> Color
mix c1 c2 =
{ red = avg c1.red c2.red
, green = avg c1.green c2.green
, blue = avg c1.blue c2.blue
, alpha = avg c1.alpha c2.alpha
}
Not so terrible or unreadable. BUT, you could even do something like:
mix : Color -> Color -> Color
mix c1 c2 =
{ red = avg .red c1 c2
, green = avg .green c1 c2
, blue = avg .blue c1 c2
, alpha = avg .alpha c1 c2
}
Are those worse than:
mix : Color -> Color -> Color
mix c1 c2 =
let
{ red1, green1, blue1, alpha1 } = toRgb c1
{ red2, green2, blue2, alpha2 } = toRgb c2
in
{ red = avg red1 red2
, green = avg green1 green2
, blue = avg blue1 blue2
, alpha = avg alpha1 alpha2
}

EDIT:
I did not realize Color is part of Core, so I edit.
You can destruct Record with property names.
In case of having multiple values, then you have to have some helper.
Following example, I defined toTuple to do that.
import Color exposing (Color)
toTuple {red, green, blue, alpha}
= (red, green, blue, alpha)
mix : Color -> Color -> Color
mix c1 c2 =
let
(r1, g1, b1, a1) = toTuple <| Color.toRgb c1
(r2, g2, b2, a2) = toTuple <| Color.toRgb c2
in
Color.rgba
(avg r1 r2)
(avg g1 g2)
(avg b1 b2)
(avgf a1 a2)
avg i j = (i + j) // 2
avgf p q = 0.5 * (p + q)
Original:
I'm not sure this is what you are looking for but, you do not need to convert it to record.
case of allows you to pattern match via constructor function. e.g.
type Color = RGB Int Int Int
purple = RGB 255 0 255
printRedVal =
case purple of
RGB r g b -> text (toString r)

Related

How to round and resize two rectangles and four circles creating a square shape in Kotlin?

I am learning Kotlin and I am facing a challenge here:
How can I round and resize two rectangles and four circles creating a square shape in Kotlin using canvas, until it gets a ball or a perfect square?
We have this code already:
import pt.isel.canvas.*
private fun Canvas.drawSquare(r: RoundSquare) {
erase()
val f = (r.side/2 * r.round/100f).toInt()
val pos = Position(r.center.x,r.center.y)
val square =
drawRect(pos.x-150, pos.y-100,r.side+100,r.side, r.color)
drawRect(pos.x-100, pos.y-150, r.side, r.side+100, r.color)
drawCircle(pos.x-100, pos.y-100, f, r.color)
drawCircle(pos.x+100, pos.y-100, f, r.color)
drawCircle(pos.x-100, pos.y+100, f, r.color)
drawCircle(pos.x+100, pos.y+100, f, r.color)
return square
}
fun main () {
onStart {
val cv = Canvas(600, 400, WHITE)
var roundSquare = RoundSquare(Position(300, 200), 200, 50, GREEN)
cv.drawSquare(roundSquare)
cv.drawText(10,400,"center=(${roundSquare.center.x},${roundSquare.center.y}) side=${roundSquare.side} round=${roundSquare.round}% color=0x${roundSquare.color.toString(16).padStart(6, '0').toUpperCase()}",BLACK,15)
cv.onMouseDown {
roundSquare = roundSquare.copy(center = Position(it.x, it.y))
cv.drawSquare(roundSquare)
return#onMouseDown cv.drawText(10,390,"center=(${roundSquare.center.x},${roundSquare.center.y}) side=${roundSquare.side} round=${roundSquare.round}% color=0x${roundSquare.color.toString(16).padStart(6, '0').toUpperCase()}",BLACK,15)
}
cv.onKeyPressed {
roundSquare = roundSquare.processKey(it.char)
cv.drawSquare(roundSquare)
return#onKeyPressed cv.drawText(10,400,"center=(${roundSquare.center.x},${roundSquare.center.y}) side=${roundSquare.side} round=${roundSquare.round}% color=0x${roundSquare.color.toString(16).padStart(6, '0').toUpperCase()}",BLACK,15)
}
onFinish { println("Bye") }
}
}
import pt.isel.canvas.BLACK
import pt.isel.canvas.WHITE
data class Position (val x:Int, val y:Int)
data class RoundSquare (val center:Position, val side:Int, val round:Int, val color:Int)
val RANGE_SIZE = 10..400
val ROUND = 0..100
val RANDOM_COLOR = BLACK..WHITE
fun RoundSquare.processKey(key: Char) = when {
key=='r' && round > ROUND.first -> copy(round = round - 1, side = side -1)
key=='R' && round < ROUND.last -> copy(round = round + 1, side = side + 1)
key=='s' && side > RANGE_SIZE.first -> copy(side = side - 1, round = round - 1)
key=='S' && side < RANGE_SIZE.last -> copy(side = side + 1, round = round + 1)
key == 'c' -> copy(color = RANDOM_COLOR.random())
else -> this
}
But it doesn't give me the output I need. This is the output:
Which can be resized till it shows a perfect ball or perfect square, by resizing sides and rounding circles.
If anyone could help me, I would really appreciate it.
Thanks in advance,
Let rounded shape center is (cx, cy), halfsize is hs.
Left x-coordinate is lx = cx - hs
Top y-coordinate is ty = cy - hs
Right x-coordinate is rx = cx + hs
Bottom y-coordinate is by = cy + hs
We want to change parameter t from 0 to 1 (or from 0 to 100%) to make needed roundness.
Circles radius is (round to integer if needed)
R = hs * t
Circle centers coordinates:
lx + R, ty + R
rx - R, ty + R
rx - R, by - R
lx + R, by - R
Two corners of rectangles:
(lx + R, ty) - (rx - R, by)
(lx, ty + R) - (rx, by - R)

Create a mask where the Green channel is brighter than Blue and Red?

I'm trying to extract the display of a green LED display from a photo, and I found that the easiest way pre-process the photo is by masking (blacken) all pixels where the green channel isn't the brightest channel. I created an algorithm to do that, but it is very slow:
def mask_dominant(image, color):
# For example, if color == "green", then we blacken out
# all pixels where green isn't the brightest pixel
image_copy = np.copy(image)
black_pixel = np.array([0, 0, 0], dtype=np.uint8)
height, width, _ = image_copy.shape
for row in range(height):
for col in range(width):
# OpenCV stores colors in BGR
b, g, r = image_copy[row, col]
zero = False
if color == 'blue':
if b < g or b < r:
zero = True
elif color == 'green':
if g < b or g < r:
zero = True
elif color == 'red':
if r < b or r < g:
zero = True
else:
raise AssertionError("Color must be one of blue, green, or red")
if zero:
image_copy[row, col] = black_pixel
return image_copy
How to run it:
import cv2
import numpy as np
image = cv2.imread("image1.jpg")
dominant = mask_dominant(image, 'green')
The algorithm above takes 40 seconds to run on a photo, which is way too large. Is there a built-in algorithm that does the same thing or a numpy optimization that I can use?
This solution works:
def mask_dominant(image, color):
# For example, if color == Green, then it blacks out
# all pixels where green isn't the brightest pixel
b,g,r = cv2.split(image)
if color == 'green':
target = g
other1 = b
other2 = r
elif color == 'red':
target = r
other1 = g
other2 = b
elif color == 'blue':
target = b
other1 = g
other2 = r
else:
raise AssertionError("invalid color: " + color)
# Figure out which ones we need to zero & zero them
should_zero = (target < other1) | (target < other2)
g[should_zero] = 0
r[should_zero] = 0
b[should_zero] = 0
# Merge channels back
return cv2.merge((b,g,r))

What are the methods to restrict ROI movement

I want to allow a user to change the diameter of an oval ROI or annotation with a fixed axes ratio (for circles, the ratio is 1:1). Also, the Oval should open up around the center only but not be allowed to shift sideways.
Currently, I have a script that reads the ROI and corrects when the user strays from the shape or the location of its center. However, it looks rather annoying and confusing, for example when the circle is changed to an oval and then pops back to a circle. I was hoping for commands that allow e.g., resize (with the option of fixed axes ratio) but restrict (lateral) movement.
Any suggestion is very welcome.
This question is a specific application of the more general question here.
The trick is to act whenever the size of a ROI is changed and then replace it with the restrictions in place. This is done by attaching a "listener" method
which is invoked when the ROI is changed.
There are two ways one can do this for ROIs:
1) Attaching the listener to the imageDisplay on which the ROI sits
// EXAMPLE using ImageDisplay listener
// This will handle ALL ROIs on the display, so one would like to
// "filter" specific ROIs. f.e. by using the ROI property "Name".
class CCircleRestrict
{
number x0,y0
object Init( object self, number cx, number cy ){ x0 = cx; y0 = cy; return self; }
void OnRestrict( object self, number e_fl, ImageDisplay idisp, number r_fl, number r_fl2, ROI theROI )
{
if ( theROI.ROIGetName() != "special" ) return; // Skip, if it isn't "our" ROI
if ( !theROI.ROIIsOval() ) return; // Skip, if it isn't an oval ROI
// get size of ROI ( as currently dragged by user )
number t, l, b, r
theROI.ROIGetOval( t, l, b, r )
number radius = max( b - t, r - l ) / 2
// Re-Set the ROI centered on x0/y0 with the new radius
theROI.ROISetOval( y0 - radius, x0 - radius, y0 + radius, x0 + radius )
}
}
// Main script "attaches" the display listener to
void main()
{
// Create and show test image
number size = 512
number r1 = 20
number r2 = 20
number off = 100
image test := realImage( "Test", 4, size, size )
test.ShowImage()
imageDisplay disp = test.ImageGetImageDisplay(0)
// Add two oval ROIs, name one of them "special" for identification
ROI specialROI = NewROI()
specialROI.ROISetName( "special" )
specialROI.ROISetOval( size/2 - r1, size/2 - r1, size/2 + r1, size/2 + r1 )
specialROI.ROISetVolatile(0)
specialROI.ROISetColor(0.1,0.9,0.1)
disp.ImageDisplayAddROI(specialROI)
ROI otherROI = NewROI()
otherROI.ROISetOval( off + size/2 - r2, off + size/2 - r2, off + size/2 + r2, off + size/2 + r2 )
otherROI.ROISetVolatile(0)
disp.ImageDisplayAddROI(otherROI)
// Create listener object and attach listener to display
object dispListener = Alloc(CCircleRestrict).Init( size/2, size/2 )
disp.ImageDisplayAddEventListener( dispListener, "roi_property_changed:OnRestrict" )
}
EGUPerformActionWithAllShownImages( "Delete" )
main()
EGUPerformActionWithAllShownImages( "Arrange" )
2) Attaching the listener to the ROI object itself
// EXAMPLE using ROI listener
// This will handle changes a specific ROI, regardless of the display(s) it is on
class CCircleRestrict
{
number x0,y0
object Init( object self, number cx, number cy ){ x0 = cx; y0 = cy; return self; }
void OnRestrict( object self, ROI theROI )
{
if ( !theROI.ROIIsOval() ) return; // Skip, if it isn't an oval ROI
// get size of ROI ( as currently dragged by user )
number t, l, b, r
theROI.ROIGetOval( t, l, b, r )
number radius = max( b - t, r - l ) / 2
// Re-Set the ROI centered on x0/y0 with the new radius
theROI.ROISetOval( y0 - radius, x0 - radius, y0 + radius, x0 + radius )
}
}
// Main script "attaches" the listener to the ROI
void main()
{
// Create and show test image
number size = 512
number r1 = 20
number r2 = 20
number off = 100
image test := realImage( "Test", 4, size, size )
test.ShowImage()
imageDisplay disp = test.ImageGetImageDisplay(0)
// Add two oval ROIs
ROI specialROI = NewROI()
specialROI.ROISetOval( size/2 - r1, size/2 - r1, size/2 + r1, size/2 + r1 )
specialROI.ROISetVolatile(0)
specialROI.ROISetColor(0.1,0.9,0.1)
disp.ImageDisplayAddROI(specialROI)
ROI otherROI = NewROI()
otherROI.ROISetOval( off + size/2 - r2, off + size/2 - r2, off + size/2 + r2, off + size/2 + r2 )
otherROI.ROISetVolatile(0)
disp.ImageDisplayAddROI(otherROI)
// Create listener object and attach listener to specific ROI
object roiListener = Alloc(CCircleRestrict).Init( size/2, size/2 )
ConnectObject( specialROI.ROIGetID(), "changed", "EventID_Name", roiListener, "OnRestrict" )
}
EGUPerformActionWithAllShownImages( "Delete" )
main()
EGUPerformActionWithAllShownImages( "Arrange" )
Both examples above restrict the oval ROI to a circle, but it is straight forward to change it such that a specific aspect ratio of the oval is achieved.
However, it is important to consider that the "newly set" and adjusted
ROI will itself again trigger the listener. It has to be ensured that
no infinite loop is created in this way, i.e. the triggering of the
method for the second time must not result in new restrictions.
A simple example for an oval ROI with a 1 : 2 aspect ratio would use a restriction method as in:
void OnRestrict( object self, ROI theROI )
{
ar = 2
if ( !theROI.ROIIsOval() ) return; // Skip, if it isn't an oval ROI
// get size of ROI ( as currently dragged by user )
number t, l, b, r
theROI.ROIGetOval( t, l, b, r )
number w = r - l
number h = b - t
number newW = max( W, AR*H )
number newH = newW/AR
// Re-Set the ROI centered on x0/y0 with the new radius
theROI.ROISetOval( y0 - newH/2, x0 - newW/2, y0 + newH/2, x0 + newW/2 )
}
The answer above specifies the type of restricitions asked for, but for completeness sake, it should also be mentioned that there are some ROI properties which can be useful in this context.
From the F1 help documentation:
However, the moveable property supersedes the resizable property, i.e if you can't move, you can't resize.

Hardcore SQL(ite) : fetch segment intersection

So this one is a very difficult one I think, so I'll try to make it as clear as possible.
So basically, I have geographic datas :
Nodes (#ID,lat,lng)
WayNodes (#ID,#node_id,#way_id, sequence)
Ways(#id,name)
And what I want is to get the intersection of two GROUPS of ways.
For example I need to find intersection(s) between the ways called "name1" : {way1, way2, way3} and the ways called "name2" : {way4, way5, way6}
So what I need is to do an equivalent to this :
float x;
float y;
float A1 = Y2-Y1;
float B1 = X1-X2;
float C1 = A1*X1+B1*Y1;
float A2 = Y4-Y3;
float B2 = X3-X4;
float C2 = A2*X3+B2*Y3;
float det = A1*B2 - A2*B1;
if(det == 0){
//Lines are parallel
x = 0.0;
y = 0.0;
}else{
x = (B2*C1 - B1*C2)/det;
y = (A1*C2 - A2*C1)/det;
}
BOOL intersection = (x<MAX(X1,X2) && x<MAX(X3,X4) && x>MIN(X1,X2) && x>MIN(X3,X4));
But in SQL !
I kind of think it is possible, my request looks like that :
(F1, F2 and F3 replace two very long functions, which compute X, Y and det, they should be correct.)
SELECT F1(n1.lat,n1.lng,n2.lat,n2.lng,n3.lat,n3.lng,n4.lat,n4.lng) AS x,
F2(n1.lat,n1.lng,n2.lat,n2.lng,n3.lat,n3.lng,n4.lat,n4.lng) AS y,
F3(n1.lat,n1.lng,n2.lat,n2.lng,n3.lat,n3.lng,n4.lat,n4.lng) AS det,
FROM Nodes n1, Nodes n2, Nodes n3, Nodes n4
JOIN WayNodes wn1 ON n1.id = wn1.node_id
JOIN WayNodes wn2 ON n2.id = wn1.node_id
JOIN WayNodes wn3 ON n3.id = wn1.node_id
JOIN WayNodes wn4 ON n4.id = wn1.node_id
JOIN Way w1 ON wn1.way_id = w1.id AND wn2..way_id = w1.id
JOIN Way w2 ON wn3..way_id = w2.id AND wn4..way_id = w2.id
WHERE det != 0 AND
x < MAX(n1.lng, n2.lng)
AND x > MIN(n1.lng, n2.lng)
AND x < MAX(n3.lng, n4.lng)
AND x > MIN(n3.lng, n4.lng)
AND wn1.sequence=wn2.sequence - 1
AND wn3.sequence=wn4.sequence - 1
AND w1.name = "name1"
AND w2.name = "name2"
Apparently something doesn't work in the junction... any idea ?
Is it that you need...
JOIN WayNodes wn1 ON n1.id = wn1.node_id
JOIN WayNodes wn2 ON n2.id = wn2.node_id
JOIN WayNodes wn3 ON n3.id = wn3.node_id
JOIN WayNodes wn4 ON n4.id = wn4.node_id

Convert integer into a color, starting at red and cycling through

How do you convert an integer to a usable color (for PictureBox.CreateGraphics)?
The color should start at red, cycle to orange, yellow, etc. and come all the way back around to red again.
This is in vb.net. If I cannot do this, how do I use PictureBox.CreateGraphics with a hex code instead of a pen?
Thanks for the help!
You can use HSB (Hue, Saturation, Brightness) color instead of RGB color. .Net can convert RGB colors to HSB automatically (with the Color.GetHue, .GetSaturation and .GetBrightness methods) but doesn't go in the other direction. Here is a code sample that handles converting HSB colors to RGB:
http://splinter.com.au/blog/?p=29
(this code sample uses "V" instead of "B", probably for "value" instead of "brightness").
The advantage of using HSB color is that the Hue parameter ranges from 0 to 360, and can be interpreted as position on the color wheel, so the values wrap around nicely from 360 back to 0. For your purposes, you could create colors by setting the Saturation and Brightness values to 1.0 (their maximums) and then varying the Hue value to create the different colors of the spectrum.
In regards to your specific question (and to elaborate on Rubens' answer), you can create a Color from any int32 value like this:
int i = 4837429;
Color color = Color.FromArgb(i);
However, this won't achieve the wrap-around color effect that you describe in your question, and in fact much of the variation in your int32 values (assuming you range from the MinValue to the MaxValue) will apply to the alpha channel, or the opacity, which doesn't sound like what you want.
Update: here's something that should do what you need:
private const double ONE_SIXTH =
0.16666666666666666666666666666667;
private const double ONE_THIRD =
0.33333333333333333333333333333333;
private const double TWO_THIRDS =
0.66666666666666666666666666666667;
private const double FIVE_SIXTHS =
0.83333333333333333333333333333333;
public Color WheelColor(double d)
{
if ((d < 0.0) || (d > 1.0))
{
throw new ArgumentOutOfRangeException("d",
d, "d must be between 0.0 and 1.0, inclusive");
}
double R = 1;
double G = 1;
double B = 1;
if (d < ONE_SIXTH)
{
G = d / ONE_SIXTH;
B = 0;
}
else if (d < ONE_THIRD)
{
R = 1 - ((d - ONE_SIXTH) / ONE_SIXTH);
B = 0;
}
else if (d < 0.5)
{
R = 0;
B = (d - ONE_THIRD) / ONE_SIXTH;
}
else if (d < TWO_THIRDS)
{
R = 0;
G = 1 - ((d - 0.5) / ONE_SIXTH);
}
else if (d < FIVE_SIXTHS)
{
R = (d - TWO_THIRDS) / ONE_SIXTH;
G = 0;
}
else
{
B = 1 - ((d - FIVE_SIXTHS) / ONE_SIXTH);
G = 0;
}
return Color.FromArgb((int)(R * 255),
(int)(G * 255), (int)(B * 255));
}
The d parameter in WheelColor is meant to go from 0.0 to 1.0, and will cycle through the color wheel (sort of), starting at red when d = 0.0 and coming back to red when d = 1.0.
How about using System.Drawing.Color.FromArgb() method ?