How to find whether two line segment(not two straight lines) intersect - c

I want to find a way to check whether two line segments intersects or not.I am using Xlib programming to implement this.
I checked on internet but i only found the ways to find the intersection point of two lines but not of two line segments.
How can i implement this using X lib programming?

You don't need Xlib for this. Let the two segments be
A1 = (x1, y1) -> B1 = (x1 + dx1, y1 + dy1) and
A2 = (x2, y2) -> B2 = (x2 + dx2, y2 + dy2).
Let
vp = dx1 * dy2 - dx2 * dy1
If vp == 0 the segments are parallel and there is no intersection.
Otherwise, let v = (vx, vy) be the vector between A1 and A2
vx = x2 - x1
vy = y2 - y1
Compute
k1 = (vx * dy2 - vy * dx2) / vp
k2 = (vx * dy1 - vy * dx1) / vp
If either k1 or k2 fall outside the [0, 1] interval, the segments don't intersect (but the underlying lines do intersect). Otherwise, the intersection is at
(x1 + k1 * dx1, y1 + k1 * dy1)
which incidentally, if you wonder about symmetry, will be the same point as
(x2 + k2 * dx2, y2 + k2 * dy2)
These formulas are basically similar to the answer on How do you detect where two line segments intersect? except coding from there would not necessarily be trivial for either a newbie or someone in a rush (like I have been myself many times).

Related

MATLAB - Index in position 2 exceeds array bounds (must not exceed 1)

This code tries to solve 6 ODEs with 6 state variables [horizontal position (x1 and x2), altitude (x3), the true airspeed (x4), the heading angle (x5) and the mass of the aircraft (x6)] and 3 control inputs [engine thrust (u1), the bank angle (u2) and the flight path angle (u3)] by using Euler's Method.
Different flight maneuvers are performed for the specified time intervals.
Velocities.m, Cruise_Vel.m, Des_Vel.m, Thr_cl.m, Thr_cr.m, Thr_des.m, fuel_cl.m, fuel_cr.m, fuel_des.m,den.m,den_cr.m,den_des.m,drag.m,drag_cr.m,drag_des.m,lift.m,lift_cr.m,lift_des.m are functions in seperate tabs.
Main code is:
% Climb from h1=1100 [m] to h2=1600 [m] with α=5 flight path angle.
% Perform cruise flight for t=60 minutes.
% Turn with β=30 bank angle until heading is changed by η=270◦.
% Descent from h2=1600 [m] to h1=1100 [m] with ζ=4◦ flight path angle.
% Complete a 360◦ turn (loiter) at level flight.
% Descent to h3=800 [m] with κ=4.5◦ flight path angle.
% Aircraft Properties
W = .44225E+06; % .44225E+03 tons = .44225E+06 kg
S = .51097E+03; % Surface Area [m^2]
g0 = 9.80665; % Gravitational acceleration [m/s2]
% solving 1st order ODE using numerical methods
t0=0;
tend=3960;
h=0.05;
N=(tend-t0)/h;
t=t0:h:tend;
% Preallocations
x = zeros(6,length(t));
x1 = zeros(1,length(t));
x2 = zeros(1,length(t));
x3 = zeros(1,length(t));
x4 = zeros(1,length(t));
x5 = zeros(1,length(t));
x6 = zeros(1,length(t));
u1 = zeros(1,length(t));
u2 = zeros(1,length(t));
u3 = zeros(1,length(t));
C_D= zeros(1,length(t));
p = zeros(1,length(t));
Cl = zeros(1,length(t));
f = zeros(1,length(t));
dx1dt = zeros(1,length(t));
dx2dt = zeros(1,length(t));
dx3dt = zeros(1,length(t));
dx4dt = zeros(1,length(t));
dx5dt = zeros(1,length(t));
dx6dt = zeros(1,length(t));
% Initial conditions
x(:,1)=[0;0;3608.92;1.0e+02 * 1.161544478045788;0;W];
for i=2:length(t)
if and (t(1,i-1) >= 0,t(1,i-1)<60) % Climb from h1=1100 [m] to h2=1600 [m] with α=5 flight path angle.
x3 = linspace(3608.92,5249.3,79201);
x4 = Velocities(x3); % Changing speed [m/s]
x5 = 0; % Changing head angle [deg]
f = fuel_cl(x3); % Changing fuel flow [kg/min]
u1 = Thr_cl(x3); % Changing thrust [N]
u2 = 0; % Changing bank angle [deg]
u3 = 5; % Changing flight path angle [deg]
V_ver = x4*sin(u3); % Changing vertical speed [m/s]
C_D = drag(x3,x4); % Changing drag coefficient
Cl = lift(x3,x4); % Changing lift coefficient
p = den(x3); % Changing density [kg/m3]
elseif and (t(1,i-1) >= 60,t(1,i-1)<3660) % Perform cruise flight for t=60 minutes.
x3 = 5249.3;
x4 = Cruise_Vel(x3); % Changing speed [m/s]
x5 = 0; % Changing head angle [deg]
f = fuel_cr(x3); % Changing fuel flow [kg/min]
u1 = Thr_cr(x3); % Changing thrust [N]
u2 = 0; % Changing bank angle [deg]
u3 = 0; % Changing flight path angle [deg]
V_ver = x4*sin(u3); % Changing vertical speed [m/s]
C_D = drag_cr(x3,x4); % Changing drag coefficient
Cl = lift_cr(x3,x4); % Changing lift coefficient
p = den_cr(x3); % Changing density [kg/m3]
elseif and (t(1,i-1) >= 3660,t(1,i-1)<3720) % Turn with β=30 bank angle until heading is changed by η=270◦.
x3 = 5249.3;
x4 = Cruise_Vel(x3); % Changing speed [m/s]
x5 = 0:30:270; % Changing head angle [deg]
f = fuel_cr(x3); % Changing fuel flow [kg/min]
u1 = Thr_cr(x3); % Changing thrust [N]
u2 = 30; % Changing bank angle [deg]
u3 = 0; % Changing flight path angle [deg]
V_ver = x4*sin(u3); % Changing vertical speed [m/s]
C_D = drag_cr(x3,x4); % Changing drag coefficient
Cl = lift_cr(x3,x4); % Changing lift coefficient
p = den_cr(x3); % Changing density [kg/m3]
elseif and (t(1,i-1) >= 3720,t(1,i-1)<3780) % Descent from h2=1600 [m] to h1=1100 [m] with ζ=4◦ flight path angle.
x3 = linspace(5249.3,3608.92,79201);
x4 = Des_Vel(x3); % Changing speed [m/s]
x5 = 270; % Changing head angle [deg]
f = fuel_des(x3); % Changing fuel flow [kg/min]
u1 = Thr_des(x3); % Changing thrust [N]
u2 = 0; % Changing bank angle [deg]
u3 = 4; % Changing flight path angle [deg]
V_ver = x4*sin(u3); % Changing vertical speed [m/s]
C_D = drag_des(x3,x4); % Changing drag coefficient
Cl = lift_des(x3,x4); % Changing lift coefficient
p = den_des(x3); % Changing density [kg/m3]
elseif and (t(1,i-1) >= 3780,t(1,i-1)<3900) % Complete a 360◦ turn (loiter) at level flight.
x3 = 3608.9;
x4 = Cruise_Vel(x3); % Changing speed [m/s]
lon = [270 300 360 60 120 180 240 270];
x5 = wrapTo360(lon); % Changing head angle [deg]
f = fuel_cr(x3); % Changing fuel flow [kg/min]
u1 = Thr_cr(x3); % Changing thrust [N]
u2 = 0; % Changing bank angle [deg]
u3 = 0; % Changing flight path angle [deg]
V_ver = x4*sin(u3); % Changing vertical speed [m/s]
C_D = drag_cr(x3,x4); % Changing drag coefficient
Cl = lift_cr(x3,x4); % Changing lift coefficient
p = den_cr(x3); % Changing density [kg/m3]
elseif and (t(1,i-1) >= 3900,t(1,i-1)<3960) % Descent to h3=800 [m] with κ=4.5◦ flight path angle.
x3 = linspace(3608.92,2624.67,79201);
x4 = Des_Vel(x3); % Changing speed [m/s]
x5 = 270; % Changing head angle [deg]
f = fuel_des(x3); % Changing fuel flow [kg/min]
u1 = Thr_des(x3); % Changing thrust [N]
u2 = 0; % Changing bank angle [deg]
u3 = 4.5; % Changing flight path angle [deg]
V_ver = x4*sin(u3); % Changing vertical speed [m/s]
C_D = drag_des(x3,x4); % Changing drag coefficient
Cl = lift_des(x3,x4); % Changing lift coefficient
p = den_des(x3); % Changing density [kg/m3]
else
fprintf("A problem occured.");
end
dx1dt = x4 .* cos(x5) .* cos(u3);
dx2dt = x4 .* sin(x5) .* cos(u3);
dx3dt = x4 .* sin(u3);
dx4dt = -C_D.*S.*p.*(x4.^2)./(2.*x6)-g0.*sin(u3)+u1./x6;
dx5dt = -Cl.*S.*p.*x4./(2.*x6).*sin(u2);
dx6dt = -f;
x(1,i)= x(1,i-1) + h * dx1dt(1,i-1); %%%%%%%%% line 138 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
x(2,i)= x(2,i-1) + h * dx2dt(1,i-1);
x(3,i)= x(3,i-1) + h * dx3dt(1,i-1);
x(4,i)= x(4,i-1) + h * dx4dt(1,i-1);
x(5,i)= x(5,i-1) + h * dx5dt(1,i-1);
x(6,i)= x(6,i-1) + h * dx6dt(1,i-1);
end
tot=cell2mat(f); % Total fuel consumption during mission [kg/min]
Tot_fuel=sum(tot);
figure(1)
plot3(x1(:),x2(:),x3(:)); % 3D position graph
figure(2)
plot(t,x4(:)); % Vtas − Time graph
figure(3)
plot(t,V_ver(:)); % V_vertical − Time graph
figure(4)
plot(t,x5(:)); % Heading − Time graph
figure(5)
plot(t,x6(:)); % Mass − Time graph
figure(6)
plot(t,u1(:)); % Thrust − Time graph
figure(7)
plot(t,u2(:)); % Bank Angle − Time graph
figure(8)
plot(t,u3(:)); % Flight Path Angle − Time graph
fprintf('Total fuel consumption during mission is %.2f [kg]',Tot_fuel*tend/60);
The reason why I used 79201 sized array is length(t) = 79201.
And when I run:
Index in position 2 exceeds array bounds (must not exceed 1).
Error in forum (line 138)
x(1,i)= x(1,i-1) + h * dx1dt(1,i-1);
What should I do?
One of the functions in separate tabs is below, the rest is similar:
function [Vtas_cl] = Velocities(x3)
%%%%%%%%%%%%%%%%%%%% Constants %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Vcl_1 = 335; % Standard calibrated airspeed [kt]
Vcl_2 = 172.3; % Standard calibrated airspeed [kt] -> [m/s] (To find the Mach transition altitude)
Vcl_2_in_knots = 335; % Standard calibrated airspeed [kt] (To find the result in knots, if altitude is between 10,000 ft and Mach transition altitude)
M_cl = 0.86; % Standard calibrated airspeed [kt]
K = 1.4; % Adiabatic index of air
R = 287.05287; % Real gas constant for air [m2/(K·s2)]
Bt = - 0.0065; % ISA temperature gradient with altitude below the tropopause [K/m]
T0 = 288.15; % Standard atmospheric temperature at MSL [K]
g0 = 9.80665; % Gravitational acceleration [m/s2]
a0= 340.294; % Speed of Sound [m/s]
Vd_CL1 = 5; % Climb speed increment below 1500 ft (jet)
Vd_CL2 = 10; % Climb speed increment below 3000 ft (jet)
Vd_CL3 = 30; % Climb speed increment below 4000 ft (jet)
Vd_CL4 = 60; % Climb speed increment below 5000 ft (jet)
Vd_CL5 = 80; % Climb speed increment below 6000 ft (jet)
CV_min = 1.3; % Minimum speed coefficient
Vstall_TO = .14200E+03; % Stall speed at take-off [KCAS]
CAS_climb = Vcl_2;
Mach_climb = M_cl;
delta_trans = (((1+((K-1)/2)*(CAS_climb/a0)^2)^(K/(K-1)))-1)/(((1+(K-1)/2*Mach_climb^2)^(K/(K-1)))-1); % Pressure ratio at the transition altitude
teta_trans = delta_trans ^ (-Bt*R/g0); % Temperature ratio at the transition altitude
H_p_trans_climb = (1000/0.348/6.5)*(T0*(1-teta_trans)); % Transition altitude for climb [ft]
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% End of constants
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
H_climb = x3; %%%%%% Input %%%%%%%%%%%%%%%%%%%
Vnom_climb_jet = zeros(1, length(H_climb));
for k1 = 1:length(H_climb)
if (0<=H_climb(k1)&&H_climb(k1)<1500)
Vnom_climb_jet(k1) = CV_min * Vstall_TO + Vd_CL1;
elseif (1500<=H_climb(k1)&&H_climb(k1)<3000)
Vnom_climb_jet(k1) = CV_min * Vstall_TO + Vd_CL2;
elseif (3000<=H_climb(k1)&&H_climb(k1)<4000)
Vnom_climb_jet (k1)= CV_min * Vstall_TO + Vd_CL3;
elseif (4000<=H_climb(k1)&&H_climb(k1)<5000)
Vnom_climb_jet (k1)= CV_min * Vstall_TO + Vd_CL4;
elseif (5000<=H_climb(k1)&&H_climb(k1)<6000)
Vnom_climb_jet(k1) = CV_min * Vstall_TO + Vd_CL5;
elseif (6000<=H_climb(k1)&&H_climb(k1)<10000)
Vnom_climb_jet (k1)= min(Vcl_1,250);
elseif (10000<=H_climb(k1)&&H_climb(k1)<=H_p_trans_climb)
Vnom_climb_jet(k1) = Vcl_2_in_knots;
elseif (H_p_trans_climb<H_climb(k1))
Vnom_climb_jet(k1) = M_cl;
end
Vcas_cl(k1) = Vnom_climb_jet(k1)* 0.514; % [kn] -> [m/s]
H_climb (k1)= H_climb(k1) * 0.3048; % [feet] -> [m]
K = 1.4; % Adiabatic index of air
R = 287.05287; % Real gas constant for air [m2/(K·s2)]
Bt = - 0.0065; % ISA temperature gradient with altitude below the tropopause [K/m]
deltaT = 0; % Value of the real temperature T in ISA conditions [K]
T0 = 288.15; % Standard atmospheric temperature at MSL [K]
P0 = 101325; % Standard atmospheric pressure at MSL [Pa]
g0 = 9.80665; % Gravitational acceleration [m/s2]
p0 = 1.225; % Standard atmospheric density at MSL [kg/m3]
visc = (K-1)./K;
T(k1) = T0 + deltaT + Bt * H_climb(k1); % Temperature [K]
P (k1)= P0*((T(k1)-deltaT)/T0).^((-g0)/(Bt*R)); % Pressure [Pa]
p (k1)= P(k1) ./ (R*T(k1)); % Density [kg/m^3]
Vtas_cl(k1) = (2*P(k1)/visc/p(k1)*((1 + P0/P(k1)*((1 + visc*p0*Vcas_cl(k1)*Vcas_cl(k1)/2/P0).^(1/visc)-1)).^(visc)-1)).^(1/2); % True Air Speed [m/s]
end
% Output
end
Index in position 2 exceeds array bounds (must not exceed 1).
This is an error that occurs when you are trying to access and element
that does not exist. For instance, if I initialize a variable of x
to be sized (3,1), then try to extract a value from index (4,4),
it will throw this error.
x = zeros(3,1)
y = x(4,4)+1; % ERROR
There is an issue with your indexing of the variable dx1dt at line 138. It is trying to access element (1,2) which does not exist when i=3.
At the beginning of your code, you have initialized the size of dx1dt to a size of (1, 79201):
dx1dt = zeros(1,length(t));
However, when you compute each value, you overwrite the size of this array to (1,1):
dx1dt = x4 .* cos(x5) .* cos(u3);
So when i=3, the following indexes are called, and dx1dt does not have any value placed in the (1,2) location. This will throw you an error that the index exceeds the bounds.
x(1,i)= x(1,i-1) + h * dx1dt(1,i-1);
x(1,3)= x(1,2) + h * dx1dt(1,2);
The question is: Is the variable of dx1dt supposed to be an array of size (1,79201) or simply a double?

How to know all the 6 hexagon vertices given two vertices only?

I am trying to let the program draw a hexagon, The program should let the user enter the coordinates of two points only, I will assume those points are the terminals of a side, then I need to calculate the coordinates of other four points, but how?
P.S: I use the library graphics.h that contains draw polygon which requires 2 arrays of x and y coordinates for all points
Given two points (x1, y1), (x2, y2), the next point on the hexagon can be computed with the formulas
dx = x2 - x1
dy = y2 - y1
x3 = x2 + ((√3)/2) dx - (1/2) dy
y3 = y2 + (1/2) dx + ((√3)/2) dy
These are derived from general rotation formulas; note that cos 60° = (√3)/2 and sin 60° = 1/2.

Unique hash function without any collisions

So I am given a key that is in the format XYYYYZ, where X is a char from 'A'-'Z', YYYY is and int from 0 to 9999, and Z is a char from 'A'-'C'. I am suppose to make a unique hash function without any collisions.
I was told the smallest someone has made is a table size of 780,000 but I have no idea how.
The one I can think of is X-'A' to get a number from 0 to 26 and multiplying that by 100,000 then multiplying YYYY by 10 and then add (Z - 'A')
So Z1025A would be 2,610,250 and L4444C would be 1,144,443
And the make possible combo is 2699993 and / 2,700,000 would have about a 29% usage rate.
But is there any other way to reduce the the size of the table?
just do
((Z - 'A') * 26 + (X - 'A')) * 10000 + YYYY
The smallest possible hash table size for a key in this format is 780000, because there are 26 ways to choose the first character, 10 ways to choose each of the next four, and 3 ways to choose the final character. That is, there are 26 * 10 * 10 * 10 * 10 * 3 = 780000 possible keys. To find a hash function, think of the hash key like a counter. Rearrange the elements like this:
ZXYYYY
Starting with all elements at zero, each of the 'Y' elements rolls over after reaching 9. 'X' rolls over after reaching 25, and 'Z' rolls over after reaching 2. So, we can assign a number to the four 'Y' elements with:
y4 y3 y2 y1 --> y1 + (y2 * 10) + (y3 * 100) + (y4 * 1000)
This part of the key is just a base 10 counter. The remaining pair of elements forms a base 26 counter, and you can assign a number to this pair by assigning a number from 0 to 25 to the first value ('X'), 26 times a number from 0 to 25 to the second, and adding the results:
z x --> x + (z * 26)
For y4 y3 y2 y1 we will get a value from 0 to 9999, and for z x we will get a value from 0 to 675. If we multiply this value by 10000, we can add the value obtained for y4 y3 y2 y1 to get a unique value for the key. That is, the four low order positions count from 0 to 9 in ones, 0 to 90 in tens, 0 to 900 in hundreds, and 0 to 9000 in thousands, while the two high order positions can be viewed as counting from 0 to 6750000 in ten-thousands. This gives a possible 6760000 unique keys with this hash function. But since your specific case limits 'z' to three characters, we only have 3 * 26 = 78 possibilities for z x, and so there are 780000 unique hashes obtainable with this method, and the hash function can then be written:
hval = y1 + (y2 * 10) + (y3 * 100) + (y4 * 1000) + (x + z * 26) * 10000
where y1, y2, y3, y4, x, and z all represent integer values. Or, using C chars:
int y1, y2, y3, y4;
char x, z;
long hval;
hval = y1 + (y2 * 10) + (y3 * 100) + (y4 * 1000) + ((x - 'A') + (z - 'A') * 26) * 10000;
I should add that, converting the characters of the Latin alphabet to integers in this way is not guaranteed to work by the standard, but so long as you have an ASCII or UTF-8 character set it will work.

Convert from qubit operation to axis-angle Bloch sphere rotation

Given the 2x2 unitary matrix representation of an operation to apply to a single qubit, how do I figure out the rotation it corresponds to on the Bloch sphere?
For example, the Hadamard matrix is a 180 degree rotation around the X+Z axis. How do I get from [[1,1],[1,-1]]*sqrt(0.5) to (X+Z, 180 deg)?
Single-qubit operations are basically just unit quaternions, but with an extra phase factor. The similarity is because the Pauli matrices, times sqrt(-1), satisfy the i^2=j^2=k^2=ijk=-1 relation that defines quaternions.
As a result, the hard part of the conversion method is already taken care of by any "quaternion to axis angle" code. Just pull out the phased quaternion components, figure out the phase factor, then apply the quaternion-to-angle-axis method.
import math
import cmath
def toBlochAngleAxis(matrix):
"""
Breaksdown a matrix U into axis, angle, and phase_angle components satisfying
U = exp(i phase_angle) (I cos(angle/2) - axis sigma i sin(angle/2))
:param matrix: The 2x2 unitary matrix U
:return: The breakdown (axis(x, y, z), angle, phase_angle)
"""
[[a, b], [c, d]] = matrix
# --- Part 1: convert to a quaternion ---
# Phased components of quaternion.
wp = (a + d) / 2.0
xp = (b + c) / 2.0j
yp = (b - c) / 2.0
zp = (a - d) / 2.0j
# Arbitrarily use largest value to determine the global phase factor.
phase = max([wp, xp, yp, zp], key=abs)
phase /= abs(phase)
# Cancel global phase factor, recovering quaternion components.
w = complex(wp / phase).real
x = complex(xp / phase).real
y = complex(yp / phase).real
z = complex(zp / phase).real
# --- Part 2: convert from quaternion to angle-axis ---
# Floating point error may have pushed w outside of [-1, +1]. Fix that.
w = min(max(w, -1), +1)
# Recover angle.
angle = -2*math.acos(w)
# Normalize axis.
n = math.sqrt(x*x + y*y + z*z);
if n < 0.000001:
# There's an axis singularity near angle=0.
# Just default to no rotation around the Z axis in this case.
angle = 0
x = 0
y = 0
z = 1
n = 1
x /= n
y /= n
z /= n
# --- Part 3: (optional) canonicalize ---
# Prefer angle in [-pi, pi]
if angle <= -math.pi:
angle += 2*math.pi
phase *= -1
# Prefer axes that point positive-ward.
if x + y + z < 0:
x *= -1
y *= -1
z *= -1
angle *= -1
phase_angle = cmath.polar(phase)[1]
return (x, y, z), angle, phase_angle
Testing it out:
print(toBlochAngleAxis([[1, 0], [0, 1]])) # Identity
# ([0, 0, 1], 0, 0.0)
print(toBlochAngleAxis([[0, 1], [1, 0]])) # Pauli X, 180 deg around X
# ([1.0, -0.0, -0.0], 3.141592653589793, 1.5707963267948966)
print(toBlochAngleAxis([[0, -1j], [1j, 0]])) # Pauli Y, 180 deg around Y
# ([-0.0, 1.0, -0.0], 3.141592653589793, 1.5707963267948966)
print(toBlochAngleAxis([[1, 0], [0, -1]])) # Pauli Z, 180 deg around Z
# ([-0.0, -0.0, 1.0], 3.141592653589793, 1.5707963267948966)
s = math.sqrt(0.5)
print(toBlochAngleAxis([[s, s], [s, -s]])) # Hadamard, 180 deg around X+Z
# ([0.7071067811865476, -0.0, 0.7071067811865476], 3.141592653589793, 1.5707963267948966)
print(toBlochAngleAxis([[s, s*1j], [s*1j, s]])) # -90 deg X axis, no phase
# ((1.0, 0.0, 0.0), -1.5707963267948966, 0.0)

How to define some variables as non-commutative in Maxima

For example, I'd like to define x and y as non-commutative, and a and b as commutative (as usual). In other words,
x y ≠ y x, a x = x a, a b = b a .
Further,
(x + a y) (x - a y) = x^2 + a (y x - x y) - a^2 y^2 .
What is a code for defining x and y, and a symbol for multiplication (such as * and . ) ?
You can work with Maxima's commutative * and non-commutative . products in the way that you want by following the next two steps:
Declare the symbols a and b as scalars:
declare([a, b], scalar)$
Enable dotscrules:
dotscrules: true$
This simplifies non-commutative products involving scalars to commutative products (i.e., a.x becomes a*x).
Now you are ready. For example,
expand((a*x + b*y) . (a*x - b*y))
returns
a*b*y.x - b^2*y^^2 - a*b*x.y + a^2*x^^2
(note that ^^ is the non-commutative exponentiation operator).

Resources